|
|
1.1 ! root 1: /*++ ! 2: ! 3: Copyright (c) 1991 Microsoft Corporation ! 4: ! 5: Module Name: ! 6: ! 7: class.c ! 8: ! 9: Abstract: ! 10: ! 11: SCSI class driver routines ! 12: ! 13: Author: ! 14: ! 15: Mike Glass (mglass) ! 16: ! 17: Environment: ! 18: ! 19: kernel mode only ! 20: ! 21: Notes: ! 22: ! 23: ! 24: Revision History: ! 25: ! 26: --*/ ! 27: ! 28: #include "stddef.h" ! 29: #include "ntddk.h" ! 30: #include "scsi.h" ! 31: #include "class.h" ! 32: #include "ntddscsi.h" ! 33: ! 34: #ifdef ALLOC_PRAGMA ! 35: #pragma alloc_text(init, ScsiClassGetInquiryData) ! 36: #pragma alloc_text(init, ScsiClassGetCapabilities) ! 37: #endif ! 38: ! 39: #define INQUIRY_DATA_SIZE 2048 ! 40: #define START_UNIT_TIMEOUT 30 ! 41: ! 42: VOID ! 43: RetryRequest( ! 44: PDEVICE_OBJECT DeviceObject, ! 45: PIRP Irp, ! 46: PSCSI_REQUEST_BLOCK Srb, ! 47: BOOLEAN Associated ! 48: ); ! 49: ! 50: VOID ! 51: StartUnit( ! 52: IN PDEVICE_OBJECT DeviceObject ! 53: ); ! 54: ! 55: NTSTATUS ! 56: ClassIoCompletion( ! 57: IN PDEVICE_OBJECT DeviceObject, ! 58: IN PIRP Irp, ! 59: IN PVOID Context ! 60: ); ! 61: ! 62: ! 63: NTSTATUS ! 64: ScsiClassGetCapabilities( ! 65: IN PDEVICE_OBJECT PortDeviceObject, ! 66: OUT PIO_SCSI_CAPABILITIES *PortCapabilities ! 67: ) ! 68: ! 69: /*++ ! 70: ! 71: Routine Description: ! 72: ! 73: This routine builds and sends a request to the port driver to ! 74: get a pointer to a structure that describes the adapter's ! 75: capabilities/limitations. This routine is sychronous. ! 76: ! 77: Arguments: ! 78: ! 79: PortDeviceObject - Port driver device object representing the HBA. ! 80: ! 81: PortCapabilities - Location to store pointer to capabilities structure. ! 82: ! 83: Return Value: ! 84: ! 85: Nt status indicating the results of the operation. ! 86: ! 87: Notes: ! 88: ! 89: This routine should only be called at initialization time. ! 90: ! 91: --*/ ! 92: ! 93: { ! 94: PIRP irp; ! 95: IO_STATUS_BLOCK ioStatus; ! 96: KEVENT event; ! 97: NTSTATUS status; ! 98: ! 99: // ! 100: // Create notification event object to be used to signal the ! 101: // request completion. ! 102: // ! 103: ! 104: KeInitializeEvent(&event, NotificationEvent, FALSE); ! 105: ! 106: // ! 107: // Build the synchronous request to be sent to the port driver ! 108: // to perform the request. ! 109: // ! 110: ! 111: irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_CAPABILITIES, ! 112: PortDeviceObject, ! 113: NULL, ! 114: 0, ! 115: PortCapabilities, ! 116: sizeof(PVOID), ! 117: FALSE, ! 118: &event, ! 119: &ioStatus); ! 120: ! 121: if (irp == NULL) { ! 122: return STATUS_INSUFFICIENT_RESOURCES; ! 123: } ! 124: ! 125: // ! 126: // Pass request to port driver and wait for request to complete. ! 127: // ! 128: ! 129: status = IoCallDriver(PortDeviceObject, irp); ! 130: ! 131: if (status == STATUS_PENDING) { ! 132: KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL); ! 133: return(ioStatus.Status); ! 134: } ! 135: ! 136: return status; ! 137: ! 138: } // end ScsiClassGetCapabilities() ! 139: ! 140: ! 141: NTSTATUS ! 142: ScsiClassGetInquiryData( ! 143: IN PDEVICE_OBJECT PortDeviceObject, ! 144: OUT PSCSI_ADAPTER_BUS_INFO *ConfigInfo ! 145: ) ! 146: ! 147: /*++ ! 148: ! 149: Routine Description: ! 150: ! 151: This routine sends a request to a port driver to return ! 152: configuration information. Space for the information is ! 153: allocated by this routine. The caller is responsible for ! 154: freeing the configuration information. This routine is ! 155: synchronous. ! 156: ! 157: Arguments: ! 158: ! 159: PortDeviceObject - Port driver device object representing the HBA. ! 160: ! 161: ConfigInfo - Returns a pointer to the configuration information. ! 162: ! 163: Return Value: ! 164: ! 165: Nt status indicating the results of the operation. ! 166: ! 167: Notes: ! 168: ! 169: This routine should be called only at initialization time. ! 170: ! 171: --*/ ! 172: ! 173: { ! 174: PIRP irp; ! 175: IO_STATUS_BLOCK ioStatus; ! 176: KEVENT event; ! 177: NTSTATUS status; ! 178: PSCSI_ADAPTER_BUS_INFO buffer; ! 179: ! 180: buffer = ExAllocatePool(PagedPool, INQUIRY_DATA_SIZE); ! 181: *ConfigInfo = buffer; ! 182: ! 183: if (buffer == NULL) { ! 184: return(STATUS_INSUFFICIENT_RESOURCES); ! 185: } ! 186: ! 187: // ! 188: // Create notification event object to be used to signal the inquiry ! 189: // request completion. ! 190: // ! 191: ! 192: KeInitializeEvent(&event, NotificationEvent, FALSE); ! 193: ! 194: // ! 195: // Build the synchronous request to be sent to the port driver ! 196: // to perform the inquiries. ! 197: // ! 198: ! 199: irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA, ! 200: PortDeviceObject, ! 201: NULL, ! 202: 0, ! 203: buffer, ! 204: INQUIRY_DATA_SIZE, ! 205: FALSE, ! 206: &event, ! 207: &ioStatus); ! 208: ! 209: if (irp == NULL) { ! 210: return(STATUS_INSUFFICIENT_RESOURCES); ! 211: } ! 212: ! 213: // ! 214: // Pass request to port driver and wait for request to complete. ! 215: // ! 216: ! 217: status = IoCallDriver(PortDeviceObject, irp); ! 218: ! 219: if (status == STATUS_PENDING) { ! 220: KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL); ! 221: status = ioStatus.Status; ! 222: } ! 223: ! 224: if (!NT_SUCCESS(status)) { ! 225: ! 226: // ! 227: // Free the buffer on an error. ! 228: // ! 229: ! 230: ExFreePool(buffer); ! 231: *ConfigInfo = NULL; ! 232: ! 233: } ! 234: ! 235: return status; ! 236: ! 237: } // end ScsiClassGetInquiryData() ! 238: ! 239: ! 240: NTSTATUS ! 241: ScsiClassReadDriveCapacity( ! 242: IN PDEVICE_OBJECT DeviceObject ! 243: ) ! 244: ! 245: /*++ ! 246: ! 247: Routine Description: ! 248: ! 249: This routine sends a READ CAPACITY to the requested device, updates ! 250: the geometry information in the device object and returns ! 251: when it is complete. This routine is synchronous. ! 252: ! 253: Arguments: ! 254: ! 255: DeviceObject - Supplies a pointer to the device object that represents ! 256: the device whose capacity is to be read. ! 257: ! 258: Return Value: ! 259: ! 260: Status is returned. ! 261: ! 262: --*/ ! 263: { ! 264: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; ! 265: PCDB cdb; ! 266: PREAD_CAPACITY_DATA readCapacityBuffer; ! 267: SCSI_REQUEST_BLOCK srb; ! 268: ULONG lastSector; ! 269: ULONG retries = 1; ! 270: NTSTATUS status; ! 271: ! 272: // ! 273: // Allocate read capacity buffer from nonpaged pool. ! 274: // ! 275: ! 276: readCapacityBuffer = ExAllocatePool(NonPagedPoolCacheAligned, ! 277: sizeof(READ_CAPACITY_DATA)); ! 278: ! 279: if (!readCapacityBuffer) { ! 280: return(STATUS_INSUFFICIENT_RESOURCES); ! 281: } ! 282: ! 283: RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); ! 284: ! 285: // ! 286: // Build the read capacity CDB. ! 287: // ! 288: ! 289: srb.CdbLength = 10; ! 290: cdb = (PCDB)srb.Cdb; ! 291: ! 292: // ! 293: // Set timeout value from device extension. ! 294: // ! 295: ! 296: srb.TimeOutValue = deviceExtension->TimeOutValue; ! 297: ! 298: cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY; ! 299: ! 300: Retry: ! 301: ! 302: status = ScsiClassSendSrbSynchronous(DeviceObject, ! 303: &srb, ! 304: readCapacityBuffer, ! 305: sizeof(READ_CAPACITY_DATA), ! 306: FALSE); ! 307: ! 308: if (NT_SUCCESS(status)) { ! 309: ! 310: // ! 311: // Copy sector size from read capacity buffer to device extension ! 312: // in reverse byte order. ! 313: // ! 314: ! 315: deviceExtension->DiskGeometry->BytesPerSector = 0; ! 316: ! 317: ((PFOUR_BYTE)&deviceExtension->DiskGeometry->BytesPerSector)->Byte0 = ! 318: ((PFOUR_BYTE)&readCapacityBuffer->BytesPerBlock)->Byte3; ! 319: ! 320: ((PFOUR_BYTE)&deviceExtension->DiskGeometry->BytesPerSector)->Byte1 = ! 321: ((PFOUR_BYTE)&readCapacityBuffer->BytesPerBlock)->Byte2; ! 322: ! 323: // ! 324: // Copy last sector in reverse byte order. ! 325: // ! 326: ! 327: ((PFOUR_BYTE)&lastSector)->Byte0 = ! 328: ((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte3; ! 329: ! 330: ((PFOUR_BYTE)&lastSector)->Byte1 = ! 331: ((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte2; ! 332: ! 333: ((PFOUR_BYTE)&lastSector)->Byte2 = ! 334: ((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte1; ! 335: ! 336: ((PFOUR_BYTE)&lastSector)->Byte3 = ! 337: ((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte0; ! 338: ! 339: // ! 340: // Calculate sector to byte shift. ! 341: // ! 342: ! 343: WHICH_BIT(deviceExtension->DiskGeometry->BytesPerSector, deviceExtension->SectorShift); ! 344: ! 345: DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n", ! 346: deviceExtension->DiskGeometry->BytesPerSector)); ! 347: ! 348: DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n", ! 349: lastSector + 1)); ! 350: ! 351: // ! 352: // Calculate media capacity in bytes. ! 353: // ! 354: ! 355: deviceExtension->PartitionLength = ! 356: LiFromLong(lastSector + 1); ! 357: ! 358: // ! 359: // Calculate number of cylinders. ! 360: // ! 361: ! 362: deviceExtension->DiskGeometry->Cylinders = ! 363: LiFromLong((lastSector + 1)/(32 * 64)); ! 364: ! 365: deviceExtension->PartitionLength = ! 366: LiShl(deviceExtension->PartitionLength, ! 367: deviceExtension->SectorShift); ! 368: ! 369: if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) { ! 370: ! 371: // ! 372: // This device supports removable media. ! 373: // ! 374: ! 375: deviceExtension->DiskGeometry->MediaType = RemovableMedia; ! 376: ! 377: } else { ! 378: ! 379: // ! 380: // Assume media type is fixed disk. ! 381: // ! 382: ! 383: deviceExtension->DiskGeometry->MediaType = FixedMedia; ! 384: } ! 385: ! 386: // ! 387: // Assume sectors per track are 32; ! 388: // ! 389: ! 390: deviceExtension->DiskGeometry->SectorsPerTrack = 32; ! 391: ! 392: // ! 393: // Assume tracks per cylinder (number of heads) is 64. ! 394: // ! 395: ! 396: deviceExtension->DiskGeometry->TracksPerCylinder = 64; ! 397: } ! 398: ! 399: if (status == STATUS_VERIFY_REQUIRED) { ! 400: ! 401: // ! 402: // Routine ScsiClassSendSrbSynchronous does not retry ! 403: // requests returned with this status. ! 404: // Read Capacities should be retried ! 405: // anyway. ! 406: // ! 407: ! 408: if (retries--) { ! 409: ! 410: // ! 411: // Retry request. ! 412: // ! 413: ! 414: goto Retry; ! 415: } ! 416: } ! 417: ! 418: if (!NT_SUCCESS(status)) { ! 419: ! 420: // ! 421: // If the read capacity fails, set the geometry to reasonable parameter ! 422: // so things don't fail at unexpected places. Zero the geometry ! 423: // except for the bytes per sector and sector shift. ! 424: // ! 425: ! 426: RtlZeroMemory(deviceExtension->DiskGeometry, sizeof(DISK_GEOMETRY)); ! 427: ! 428: deviceExtension->DiskGeometry->BytesPerSector = 512; ! 429: ! 430: deviceExtension->SectorShift = 9; ! 431: ! 432: deviceExtension->PartitionLength = LiFromUlong(0); ! 433: ! 434: if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) { ! 435: ! 436: // ! 437: // This device supports removable media. ! 438: // ! 439: ! 440: deviceExtension->DiskGeometry->MediaType = RemovableMedia; ! 441: ! 442: } else { ! 443: ! 444: // ! 445: // Assume media type is fixed disk. ! 446: // ! 447: ! 448: deviceExtension->DiskGeometry->MediaType = FixedMedia; ! 449: } ! 450: } ! 451: ! 452: // ! 453: // Deallocate read capacity buffer. ! 454: // ! 455: ! 456: ExFreePool(readCapacityBuffer); ! 457: ! 458: return status; ! 459: ! 460: } // end ScsiClassReadDriveCapacity() ! 461: ! 462: ! 463: VOID ! 464: ScsiClassReleaseQueue( ! 465: IN PDEVICE_OBJECT DeviceObject ! 466: ) ! 467: ! 468: /*++ ! 469: ! 470: Routine Description: ! 471: ! 472: This routine issues an internal device control command ! 473: to the port driver to release a frozen queue. The call ! 474: is issued asynchronously as ScsiClassReleaseQueue will be invoked ! 475: from the IO completion DPC (and will have no context to ! 476: wait for a synchronous call to complete). ! 477: ! 478: Arguments: ! 479: ! 480: DeviceObject - The device object for the logical unit with ! 481: the frozen queue. ! 482: ! 483: Return Value: ! 484: ! 485: None. ! 486: ! 487: --*/ ! 488: { ! 489: PIO_STACK_LOCATION irpStack; ! 490: PIRP irp; ! 491: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; ! 492: PCOMPLETION_CONTEXT context; ! 493: PSCSI_REQUEST_BLOCK srb; ! 494: ! 495: // ! 496: // Allocate context from nonpaged pool. ! 497: // ! 498: ! 499: context = ExAllocatePool(NonPagedPoolMustSucceed, ! 500: sizeof(COMPLETION_CONTEXT)); ! 501: ! 502: // ! 503: // Save the device object in the context for use by the completion ! 504: // routine. ! 505: // ! 506: ! 507: context->DeviceObject = DeviceObject; ! 508: srb = &context->Srb; ! 509: ! 510: // ! 511: // Zero out srb. ! 512: // ! 513: ! 514: RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE); ! 515: ! 516: // ! 517: // Write length to SRB. ! 518: // ! 519: ! 520: srb->Length = SCSI_REQUEST_BLOCK_SIZE; ! 521: ! 522: // ! 523: // Set up SCSI bus address. ! 524: // ! 525: ! 526: srb->PathId = deviceExtension->PathId; ! 527: srb->TargetId = deviceExtension->TargetId; ! 528: srb->Lun = deviceExtension->Lun; ! 529: ! 530: // ! 531: // If this device is removable then flush the queue. This will also ! 532: // release it. ! 533: // ! 534: ! 535: if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) { ! 536: ! 537: srb->Function = SRB_FUNCTION_FLUSH_QUEUE; ! 538: ! 539: } else { ! 540: ! 541: srb->Function = SRB_FUNCTION_RELEASE_QUEUE; ! 542: ! 543: } ! 544: ! 545: // ! 546: // Build the asynchronous request to be sent to the port driver. ! 547: // ! 548: ! 549: irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); ! 550: ! 551: IoSetCompletionRoutine(irp, ! 552: (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion, ! 553: context, ! 554: TRUE, ! 555: TRUE, ! 556: TRUE); ! 557: ! 558: irpStack = IoGetNextIrpStackLocation(irp); ! 559: ! 560: irpStack->MajorFunction = IRP_MJ_SCSI; ! 561: ! 562: srb->OriginalRequest = irp; ! 563: ! 564: // ! 565: // Store the SRB address in next stack for port driver. ! 566: // ! 567: ! 568: irpStack->Parameters.Scsi.Srb = srb; ! 569: ! 570: IoCallDriver(deviceExtension->PortDeviceObject, irp); ! 571: ! 572: return; ! 573: ! 574: } // end ScsiClassReleaseQueue() ! 575: ! 576: ! 577: VOID ! 578: StartUnit( ! 579: IN PDEVICE_OBJECT DeviceObject ! 580: ) ! 581: ! 582: /*++ ! 583: ! 584: Routine Description: ! 585: ! 586: Send command to SCSI unit to start or power up. ! 587: Because this command is issued asynchronounsly, that is, without ! 588: waiting on it to complete, the IMMEDIATE flag is not set. This ! 589: means that the CDB will not return until the drive has powered up. ! 590: This should keep subsequent requests from being submitted to the ! 591: device before it has completely spun up. ! 592: This routine is called from the InterpretSense routine, when a ! 593: request sense returns data indicating that a drive must be ! 594: powered up. ! 595: ! 596: Arguments: ! 597: ! 598: DeviceObject - The device object for the logical unit with ! 599: the frozen queue. ! 600: ! 601: Return Value: ! 602: ! 603: None. ! 604: ! 605: --*/ ! 606: { ! 607: PIO_STACK_LOCATION irpStack; ! 608: PIRP irp; ! 609: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; ! 610: PSCSI_REQUEST_BLOCK srb; ! 611: PCOMPLETION_CONTEXT context; ! 612: PCDB cdb; ! 613: ! 614: // ! 615: // Allocate Srb from nonpaged pool. ! 616: // ! 617: ! 618: context = ExAllocatePool(NonPagedPoolMustSucceed, ! 619: sizeof(COMPLETION_CONTEXT)); ! 620: ! 621: // ! 622: // Save the device object in the context for use by the completion ! 623: // routine. ! 624: // ! 625: ! 626: context->DeviceObject = DeviceObject; ! 627: srb = &context->Srb; ! 628: ! 629: // ! 630: // Zero out srb. ! 631: // ! 632: ! 633: RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE); ! 634: ! 635: // ! 636: // Write length to SRB. ! 637: // ! 638: ! 639: srb->Length = SCSI_REQUEST_BLOCK_SIZE; ! 640: ! 641: // ! 642: // Set up SCSI bus address. ! 643: // ! 644: ! 645: srb->PathId = deviceExtension->PathId; ! 646: srb->TargetId = deviceExtension->TargetId; ! 647: srb->Lun = deviceExtension->Lun; ! 648: ! 649: srb->Function = SRB_FUNCTION_EXECUTE_SCSI; ! 650: ! 651: // ! 652: // Set timeout value large enough for drive to spin up. ! 653: // ! 654: ! 655: srb->TimeOutValue = START_UNIT_TIMEOUT; ! 656: ! 657: // ! 658: // Set the transfer length. ! 659: // ! 660: ! 661: srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER | SRB_FLAGS_DISABLE_AUTOSENSE | SRB_FLAGS_DISABLE_SYNCH_TRANSFER; ! 662: ! 663: // ! 664: // Build the start unit CDB. ! 665: // ! 666: ! 667: srb->CdbLength = 6; ! 668: cdb = (PCDB)srb->Cdb; ! 669: ! 670: cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT; ! 671: cdb->START_STOP.Start = 1; ! 672: cdb->START_STOP.LogicalUnitNumber = srb->Lun; ! 673: ! 674: // ! 675: // Build the asynchronous request to be sent to the port driver. ! 676: // Since this routine is called from a DPC the IRP should always be ! 677: // available. ! 678: // ! 679: ! 680: irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); ! 681: ! 682: IoSetCompletionRoutine(irp, ! 683: (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion, ! 684: context, ! 685: TRUE, ! 686: TRUE, ! 687: TRUE); ! 688: ! 689: irpStack = IoGetNextIrpStackLocation(irp); ! 690: ! 691: irpStack->MajorFunction = IRP_MJ_SCSI; ! 692: ! 693: srb->OriginalRequest = irp; ! 694: ! 695: // ! 696: // Store the SRB address in next stack for port driver. ! 697: // ! 698: ! 699: irpStack->Parameters.Scsi.Srb = srb; ! 700: ! 701: // ! 702: // Call the port driver with the IRP. ! 703: // ! 704: ! 705: IoCallDriver(deviceExtension->PortDeviceObject, irp); ! 706: ! 707: return; ! 708: ! 709: } // end StartUnit() ! 710: ! 711: ! 712: NTSTATUS ! 713: ScsiClassAsynchronousCompletion( ! 714: PDEVICE_OBJECT DeviceObject, ! 715: PIRP Irp, ! 716: PVOID Context ! 717: ) ! 718: /*++ ! 719: ! 720: Routine Description: ! 721: ! 722: This routine is called when an asynchronous I/O request ! 723: which was issused by the class driver completes. Examples of such requests ! 724: are release queue or START UNIT. This routine releases the queue if ! 725: necessary. It then frees the context and the IRP. ! 726: ! 727: Arguments: ! 728: ! 729: DeviceObject - The device object for the logical unit; however since this ! 730: is the top stack location the value is NULL. ! 731: ! 732: Irp - Supplies a pointer to the Irp to be processed. ! 733: ! 734: Context - Supplies the context to be used to process this request. ! 735: ! 736: Return Value: ! 737: ! 738: None. ! 739: ! 740: --*/ ! 741: ! 742: { ! 743: PCOMPLETION_CONTEXT context = Context; ! 744: PSCSI_REQUEST_BLOCK srb; ! 745: ! 746: srb = &context->Srb; ! 747: ! 748: // ! 749: // If this is an execute srb, then check the return status and make sure. ! 750: // the queue is not frozen. ! 751: // ! 752: ! 753: if (srb->Function == SRB_FUNCTION_EXECUTE_SCSI) { ! 754: ! 755: // ! 756: // Check for a frozen queue. ! 757: // ! 758: ! 759: if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) { ! 760: ! 761: // ! 762: // Unfreeze the queue getting the device object from the context. ! 763: // ! 764: ! 765: ScsiClassReleaseQueue(context->DeviceObject); ! 766: } ! 767: } ! 768: ! 769: // ! 770: // Free the context and the Irp. ! 771: // ! 772: ! 773: if (Irp->MdlAddress != NULL) { ! 774: MmUnlockPages(Irp->MdlAddress); ! 775: IoFreeMdl(Irp->MdlAddress); ! 776: ! 777: Irp->MdlAddress = NULL; ! 778: } ! 779: ! 780: ExFreePool(context); ! 781: IoFreeIrp(Irp); ! 782: ! 783: // ! 784: // Indicate the I/O system should stop processing the Irp completion. ! 785: // ! 786: ! 787: return STATUS_MORE_PROCESSING_REQUIRED; ! 788: ! 789: } // ScsiClassAsynchronousCompletion() ! 790: ! 791: ! 792: VOID ! 793: ScsiClassSplitRequest( ! 794: IN PDEVICE_OBJECT DeviceObject, ! 795: IN PIRP Irp, ! 796: IN ULONG MaximumBytes ! 797: ) ! 798: ! 799: /*++ ! 800: ! 801: Routine Description: ! 802: ! 803: Break request into smaller requests. Each new request will be the ! 804: maximum transfer size that the port driver can handle or if it ! 805: is the final request, it may be the residual size. ! 806: ! 807: The number of IRPs required to process this request is written in the ! 808: current stack of the original IRP. Then as each new IRP completes ! 809: the count in the original IRP is decremented. When the count goes to ! 810: zero, the original IRP is completed. ! 811: ! 812: Arguments: ! 813: ! 814: DeviceObject - Pointer to the class device object to be addressed. ! 815: ! 816: Irp - Pointer to Irp the orginal request. ! 817: ! 818: Return Value: ! 819: ! 820: None. ! 821: ! 822: --*/ ! 823: ! 824: { ! 825: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; ! 826: PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); ! 827: PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp); ! 828: ULONG transferByteCount = currentIrpStack->Parameters.Read.Length; ! 829: LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset; ! 830: PVOID dataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress); ! 831: ULONG dataLength = MaximumBytes; ! 832: ULONG irpCount = (transferByteCount + MaximumBytes - 1) / MaximumBytes; ! 833: PSCSI_REQUEST_BLOCK srb; ! 834: ULONG i; ! 835: ! 836: DebugPrint((2, "ScsiClassSplitRequest: Requires %d IRPs\n", irpCount)); ! 837: DebugPrint((2, "ScsiClassSplitRequest: Original IRP %lx\n", Irp)); ! 838: ! 839: // ! 840: // If all partial transfers complete successfully then the status and ! 841: // bytes transferred are already set up. Failing a partial-transfer IRP ! 842: // will set status to error and bytes transferred to 0 during ! 843: // IoCompletion. Setting bytes transferred to 0 if an IRP fails allows ! 844: // asynchronous partial transfers. This is an optimization for the ! 845: // successful case. ! 846: // ! 847: ! 848: Irp->IoStatus.Status = STATUS_SUCCESS; ! 849: Irp->IoStatus.Information = transferByteCount; ! 850: ! 851: // ! 852: // Save number of IRPs to complete count on current stack ! 853: // of original IRP. ! 854: // ! 855: ! 856: nextIrpStack->Parameters.Others.Argument1 = (PVOID) irpCount; ! 857: ! 858: for (i = 0; i < irpCount; i++) { ! 859: ! 860: PIRP newIrp; ! 861: PIO_STACK_LOCATION newIrpStack; ! 862: ! 863: // ! 864: // Allocate new IRP. ! 865: // ! 866: ! 867: newIrp = IoAllocateIrp(DeviceObject->StackSize, FALSE); ! 868: ! 869: if (newIrp == NULL) { ! 870: ! 871: DebugPrint((1,"ScsiClassSplitRequest: Can't allocate Irp\n")); ! 872: ! 873: // ! 874: // If an Irp can't be allocated then the orginal request cannot ! 875: // be executed. If this is the first request then just fail the ! 876: // orginal request; otherwise just return. When the pending ! 877: // requests complete, they will complete the original request. ! 878: // In either case set the IRP status to failure. ! 879: // ! 880: ! 881: Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; ! 882: Irp->IoStatus.Information = 0; ! 883: ! 884: if (i == 0) { ! 885: IoCompleteRequest(Irp, IO_NO_INCREMENT); ! 886: } ! 887: ! 888: return; ! 889: } ! 890: ! 891: DebugPrint((2, "ScsiClassSplitRequest: New IRP %lx\n", newIrp)); ! 892: ! 893: // ! 894: // Write MDL address to new IRP. In the port driver the SRB data ! 895: // buffer field is used as an offset into the MDL, so the same MDL ! 896: // can be used for each partial transfer. This saves having to build ! 897: // a new MDL for each partial transfer. ! 898: // ! 899: ! 900: newIrp->MdlAddress = Irp->MdlAddress; ! 901: ! 902: // ! 903: // At this point there is no current stack. IoSetNextIrpStackLocation ! 904: // will make the first stack location the current stack so that the ! 905: // SRB address can be written there. ! 906: // ! 907: ! 908: IoSetNextIrpStackLocation(newIrp); ! 909: newIrpStack = IoGetCurrentIrpStackLocation(newIrp); ! 910: ! 911: newIrpStack->MajorFunction = currentIrpStack->MajorFunction; ! 912: newIrpStack->Parameters.Read.Length = dataLength; ! 913: newIrpStack->Parameters.Read.ByteOffset = startingOffset; ! 914: newIrpStack->DeviceObject = DeviceObject; ! 915: ! 916: // ! 917: // Build SRB and CDB. ! 918: // ! 919: ! 920: ScsiClassBuildRequest(DeviceObject, newIrp); ! 921: ! 922: // ! 923: // Adjust SRB for this partial transfer. ! 924: // ! 925: ! 926: newIrpStack = IoGetNextIrpStackLocation(newIrp); ! 927: ! 928: srb = newIrpStack->Parameters.Others.Argument1; ! 929: srb->DataBuffer = dataBuffer; ! 930: ! 931: // ! 932: // Write original IRP address to new IRP. ! 933: // ! 934: ! 935: newIrp->AssociatedIrp.MasterIrp = Irp; ! 936: ! 937: // ! 938: // Set the completion routine to ScsiClassIoCompleteAssociated. ! 939: // ! 940: ! 941: IoSetCompletionRoutine(newIrp, ! 942: ScsiClassIoCompleteAssociated, ! 943: srb, ! 944: TRUE, ! 945: TRUE, ! 946: TRUE); ! 947: ! 948: // ! 949: // Call port driver with new request. ! 950: // ! 951: ! 952: IoCallDriver(deviceExtension->PortDeviceObject, newIrp); ! 953: ! 954: // ! 955: // Set up for next request. ! 956: // ! 957: ! 958: dataBuffer = (PCHAR)dataBuffer + MaximumBytes; ! 959: ! 960: transferByteCount -= MaximumBytes; ! 961: ! 962: if (transferByteCount > MaximumBytes) { ! 963: ! 964: dataLength = MaximumBytes; ! 965: ! 966: } else { ! 967: ! 968: dataLength = transferByteCount; ! 969: } ! 970: ! 971: // ! 972: // Adjust disk byte offset. ! 973: // ! 974: ! 975: startingOffset = LiAdd(startingOffset, LiFromUlong(MaximumBytes)); ! 976: } ! 977: ! 978: return; ! 979: ! 980: } // end ScsiClassSplitRequest() ! 981: ! 982: ! 983: NTSTATUS ! 984: ScsiClassIoComplete( ! 985: IN PDEVICE_OBJECT DeviceObject, ! 986: IN PIRP Irp, ! 987: IN PVOID Context ! 988: ) ! 989: ! 990: /*++ ! 991: ! 992: Routine Description: ! 993: ! 994: This routine executes when the port driver has completed a request. ! 995: It looks at the SRB status in the completing SRB and if not success ! 996: it checks for valid request sense buffer information. If valid, the ! 997: info is used to update status with more precise message of type of ! 998: error. This routine deallocates the SRB. ! 999: ! 1000: Arguments: ! 1001: ! 1002: DeviceObject - Supplies the device object which represents the logical ! 1003: unit. ! 1004: ! 1005: Irp - Supplies the Irp which has completed. ! 1006: ! 1007: Context - Supplies a pointer to the SRB. ! 1008: ! 1009: Return Value: ! 1010: ! 1011: NT status ! 1012: ! 1013: --*/ ! 1014: ! 1015: { ! 1016: PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); ! 1017: PSCSI_REQUEST_BLOCK srb = Context; ! 1018: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; ! 1019: NTSTATUS status; ! 1020: BOOLEAN retry; ! 1021: ! 1022: // ! 1023: // Check SRB status for success of completing request. ! 1024: // ! 1025: ! 1026: if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) { ! 1027: ! 1028: DebugPrint((2,"ScsiClassIoComplete: IRP %lx, SRB %lx", Irp, srb)); ! 1029: ! 1030: // ! 1031: // Release the queue if it is frozen. ! 1032: // ! 1033: ! 1034: if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) { ! 1035: ScsiClassReleaseQueue(DeviceObject); ! 1036: } ! 1037: ! 1038: retry = ScsiClassInterpretSenseInfo( ! 1039: DeviceObject, ! 1040: srb, ! 1041: irpStack->MajorFunction, ! 1042: irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ? irpStack->Parameters.DeviceIoControl.IoControlCode : 0, ! 1043: MAXIMUM_RETRIES - ((ULONG)irpStack->Parameters.Others.Argument4), ! 1044: &status); ! 1045: ! 1046: // ! 1047: // If the status is verified required and the this request ! 1048: // should bypass verify required then retry the request. ! 1049: // ! 1050: ! 1051: if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME && ! 1052: status == STATUS_VERIFY_REQUIRED) { ! 1053: ! 1054: status = STATUS_IO_DEVICE_ERROR; ! 1055: retry = TRUE; ! 1056: ! 1057: } ! 1058: ! 1059: if (retry && ((ULONG)irpStack->Parameters.Others.Argument4)--) { ! 1060: ! 1061: // ! 1062: // Retry request. ! 1063: // ! 1064: ! 1065: DebugPrint((1, "Retry request %lx\n", Irp)); ! 1066: ! 1067: RetryRequest(DeviceObject, Irp, srb, FALSE); ! 1068: ! 1069: return STATUS_MORE_PROCESSING_REQUIRED; ! 1070: } ! 1071: ! 1072: ! 1073: ! 1074: } else { ! 1075: ! 1076: // ! 1077: // Set status for successful request. ! 1078: // ! 1079: ! 1080: status = STATUS_SUCCESS; ! 1081: ! 1082: } // end if (SRB_STATUS(srb->SrbStatus) ... ! 1083: ! 1084: // ! 1085: // Return SRB to nonpaged pool. ! 1086: // ! 1087: ! 1088: if (srb->SrbFlags & SRB_FLAGS_ALLOCATED_FROM_ZONE) { ! 1089: ! 1090: ExInterlockedFreeToZone( deviceExtension->SrbZone, ! 1091: srb, ! 1092: deviceExtension->SrbZoneSpinLock); ! 1093: ! 1094: } else { ! 1095: ! 1096: ExFreePool(srb); ! 1097: ! 1098: } ! 1099: ! 1100: // ! 1101: // Set status in completing IRP. ! 1102: // ! 1103: ! 1104: Irp->IoStatus.Status = status; ! 1105: ! 1106: // ! 1107: // Set the hard error if necessary. ! 1108: // ! 1109: ! 1110: if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) { ! 1111: ! 1112: // ! 1113: // Store DeviceObject for filesystem, and clear ! 1114: // in IoStatus.Information field. ! 1115: // ! 1116: ! 1117: IoSetHardErrorOrVerifyDevice(Irp, DeviceObject); ! 1118: Irp->IoStatus.Information = 0; ! 1119: ! 1120: } ! 1121: ! 1122: // ! 1123: // If pending has be returned for this irp then mark the current stack as ! 1124: // pending. ! 1125: // ! 1126: ! 1127: if (Irp->PendingReturned) { ! 1128: IoMarkIrpPending(Irp); ! 1129: } ! 1130: ! 1131: return status; ! 1132: ! 1133: } // end ScsiClassIoComplete() ! 1134: ! 1135: ! 1136: NTSTATUS ! 1137: ScsiClassIoCompleteAssociated( ! 1138: IN PDEVICE_OBJECT DeviceObject, ! 1139: IN PIRP Irp, ! 1140: IN PVOID Context ! 1141: ) ! 1142: ! 1143: /*++ ! 1144: ! 1145: Routine Description: ! 1146: ! 1147: This routine executes when the port driver has completed a request. ! 1148: It looks at the SRB status in the completing SRB and if not success ! 1149: it checks for valid request sense buffer information. If valid, the ! 1150: info is used to update status with more precise message of type of ! 1151: error. This routine deallocates the SRB. This routine is used for ! 1152: requests which were build by split request. After it has processed ! 1153: the request it decrements the Irp count in the master Irp. If the ! 1154: count goes to zero then the master Irp is completed. ! 1155: ! 1156: Arguments: ! 1157: ! 1158: DeviceObject - Supplies the device object which represents the logical ! 1159: unit. ! 1160: ! 1161: Irp - Supplies the Irp which has completed. ! 1162: ! 1163: Context - Supplies a pointer to the SRB. ! 1164: ! 1165: Return Value: ! 1166: ! 1167: NT status ! 1168: ! 1169: --*/ ! 1170: ! 1171: { ! 1172: PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); ! 1173: PSCSI_REQUEST_BLOCK srb = Context; ! 1174: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; ! 1175: INTERLOCKED_RESULT irpCount; ! 1176: PIRP originalIrp = Irp->AssociatedIrp.MasterIrp; ! 1177: NTSTATUS status; ! 1178: BOOLEAN retry; ! 1179: ! 1180: // ! 1181: // Check SRB status for success of completing request. ! 1182: // ! 1183: ! 1184: if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) { ! 1185: ! 1186: DebugPrint((2,"ScsiClassIoCompleteAssociated: IRP %lx, SRB %lx", Irp, srb)); ! 1187: ! 1188: // ! 1189: // Release the queue if it is frozen. ! 1190: // ! 1191: ! 1192: if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) { ! 1193: ScsiClassReleaseQueue(DeviceObject); ! 1194: } ! 1195: ! 1196: retry = ScsiClassInterpretSenseInfo( ! 1197: DeviceObject, ! 1198: srb, ! 1199: irpStack->MajorFunction, ! 1200: irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ? irpStack->Parameters.DeviceIoControl.IoControlCode : 0, ! 1201: MAXIMUM_RETRIES - ((ULONG)irpStack->Parameters.Others.Argument4), ! 1202: &status); ! 1203: ! 1204: // ! 1205: // If the status is verified required and the this request ! 1206: // should bypass verify required then retry the request. ! 1207: // ! 1208: ! 1209: if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME && ! 1210: status == STATUS_VERIFY_REQUIRED) { ! 1211: ! 1212: status = STATUS_IO_DEVICE_ERROR; ! 1213: retry = TRUE; ! 1214: ! 1215: } ! 1216: ! 1217: if (retry && ((ULONG)irpStack->Parameters.Others.Argument4)--) { ! 1218: ! 1219: // ! 1220: // Retry request. ! 1221: // ! 1222: ! 1223: DebugPrint((1, "Retry request %lx\n", Irp)); ! 1224: ! 1225: RetryRequest(DeviceObject, Irp, srb, TRUE); ! 1226: ! 1227: return STATUS_MORE_PROCESSING_REQUIRED; ! 1228: } ! 1229: ! 1230: ! 1231: ! 1232: } else { ! 1233: ! 1234: // ! 1235: // Set status for successful request. ! 1236: // ! 1237: ! 1238: status = STATUS_SUCCESS; ! 1239: ! 1240: } // end if (SRB_STATUS(srb->SrbStatus) ... ! 1241: ! 1242: // ! 1243: // Return SRB to nonpaged pool. ! 1244: // ! 1245: ! 1246: if (srb->SrbFlags & SRB_FLAGS_ALLOCATED_FROM_ZONE) { ! 1247: ! 1248: ExInterlockedFreeToZone( deviceExtension->SrbZone, ! 1249: srb, ! 1250: deviceExtension->SrbZoneSpinLock); ! 1251: ! 1252: } else { ! 1253: ! 1254: ExFreePool(srb); ! 1255: ! 1256: } ! 1257: ! 1258: ! 1259: // ! 1260: // Set status in completing IRP. ! 1261: // ! 1262: ! 1263: Irp->IoStatus.Status = status; ! 1264: ! 1265: DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial xfer IRP %lx\n", Irp)); ! 1266: ! 1267: // ! 1268: // Get next stack location. This original request is unused ! 1269: // except to keep track of the completing partial IRPs so the ! 1270: // stack location is valid. ! 1271: // ! 1272: ! 1273: irpStack = IoGetNextIrpStackLocation(originalIrp); ! 1274: ! 1275: // ! 1276: // Update status only if error so that if any partial transfer ! 1277: // completes with error, then the original IRP will return with ! 1278: // error. If any of the asynchronous partial transfer IRPs fail, ! 1279: // with an error then the original IRP will return 0 bytes transfered. ! 1280: // This is an optimization for successful transfers. ! 1281: // ! 1282: ! 1283: if (!NT_SUCCESS(status)) { ! 1284: ! 1285: originalIrp->IoStatus.Status = status; ! 1286: originalIrp->IoStatus.Information = 0; ! 1287: ! 1288: ! 1289: // ! 1290: // Set the hard error if necessary. ! 1291: // ! 1292: ! 1293: if (IoIsErrorUserInduced(status)) { ! 1294: ! 1295: // ! 1296: // Store DeviceObject for filesystem. ! 1297: // ! 1298: ! 1299: IoSetHardErrorOrVerifyDevice(originalIrp, DeviceObject); ! 1300: ! 1301: } ! 1302: ! 1303: } ! 1304: ! 1305: // ! 1306: // Decrement and get the count of remaining IRPs. ! 1307: // ! 1308: ! 1309: irpCount = ExInterlockedDecrementLong( ! 1310: (PLONG)&irpStack->Parameters.Others.Argument1, ! 1311: &deviceExtension->SplitRequestSpinLock); ! 1312: ! 1313: DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial IRPs left %d\n", ! 1314: irpCount)); ! 1315: ! 1316: if (irpCount == ResultZero) { ! 1317: ! 1318: // ! 1319: // All partial IRPs have completed. ! 1320: // ! 1321: ! 1322: DebugPrint((2, ! 1323: "ScsiClassIoCompleteAssociated: All partial IRPs complete %lx\n", ! 1324: originalIrp)); ! 1325: ! 1326: IoCompleteRequest(originalIrp, IO_DISK_INCREMENT); ! 1327: } ! 1328: ! 1329: // ! 1330: // Deallocate IRP and indicate the I/O system should not attempt any more ! 1331: // processing. ! 1332: // ! 1333: ! 1334: IoFreeIrp(Irp); ! 1335: ! 1336: return STATUS_MORE_PROCESSING_REQUIRED; ! 1337: ! 1338: } // end ScsiClassIoCompleteAssociated() ! 1339: ! 1340: ! 1341: NTSTATUS ! 1342: ScsiClassSendSrbSynchronous( ! 1343: PDEVICE_OBJECT DeviceObject, ! 1344: PSCSI_REQUEST_BLOCK Srb, ! 1345: PVOID BufferAddress, ! 1346: ULONG BufferLength, ! 1347: BOOLEAN WriteToDevice ! 1348: ) ! 1349: ! 1350: /*++ ! 1351: ! 1352: Routine Description: ! 1353: ! 1354: This routine is called by SCSI device controls to complete an ! 1355: SRB and send it to the port driver synchronously (ie wait for ! 1356: completion). The CDB is already completed along with the SRB CDB ! 1357: size and request timeout value. ! 1358: ! 1359: Arguments: ! 1360: ! 1361: DeviceObject - Supplies the device object which represents the logical ! 1362: unit. ! 1363: ! 1364: Srb - Supplies a partially initialized SRB. The SRB cannot come from zone. ! 1365: ! 1366: BufferAddress - Supplies the address of the buffer. ! 1367: ! 1368: BufferLength - Supplies the length in bytes of the buffer. ! 1369: ! 1370: WriteToDevice - Indicates the data should be transfer to the device. ! 1371: ! 1372: Return Value: ! 1373: ! 1374: Nt status indicating the final results of the operation. ! 1375: ! 1376: --*/ ! 1377: ! 1378: { ! 1379: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; ! 1380: IO_STATUS_BLOCK ioStatus; ! 1381: ULONG controlType; ! 1382: PIRP irp; ! 1383: PIO_STACK_LOCATION irpStack; ! 1384: KEVENT event; ! 1385: PUCHAR senseInfoBuffer; ! 1386: ULONG retryCount = MAXIMUM_RETRIES; ! 1387: NTSTATUS status; ! 1388: BOOLEAN retry; ! 1389: ! 1390: // ! 1391: // Write length to SRB. ! 1392: // ! 1393: ! 1394: Srb->Length = SCSI_REQUEST_BLOCK_SIZE; ! 1395: ! 1396: // ! 1397: // Set SCSI bus address. ! 1398: // ! 1399: ! 1400: Srb->PathId = deviceExtension->PathId; ! 1401: Srb->TargetId = deviceExtension->TargetId; ! 1402: Srb->Lun = deviceExtension->Lun; ! 1403: ! 1404: Srb->Function = SRB_FUNCTION_EXECUTE_SCSI; ! 1405: ! 1406: // ! 1407: // NOTICE: The SCSI-II specification indicates that this field should be ! 1408: // zero; however, some target controllers ignore the logical unit number ! 1409: // in the INDENTIFY message and only look at the logical unit number field ! 1410: // in the CDB. ! 1411: // ! 1412: ! 1413: Srb->Cdb[1] |= deviceExtension->Lun << 5; ! 1414: ! 1415: // ! 1416: // Enable auto request sense. ! 1417: // ! 1418: ! 1419: Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE; ! 1420: ! 1421: // ! 1422: // Sense buffer is in aligned nonpaged pool. ! 1423: // ! 1424: ! 1425: senseInfoBuffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE); ! 1426: ! 1427: if (senseInfoBuffer == NULL) { ! 1428: ! 1429: DebugPrint((1, ! 1430: "ScsiClassSendSrbSynchronous: Can't allocate request sense buffer\n")); ! 1431: return(STATUS_INSUFFICIENT_RESOURCES); ! 1432: } ! 1433: ! 1434: Srb->SenseInfoBuffer = senseInfoBuffer; ! 1435: ! 1436: Srb->DataBuffer = BufferAddress; ! 1437: ! 1438: // ! 1439: // Start retries here. ! 1440: // ! 1441: ! 1442: retry: ! 1443: ! 1444: // ! 1445: // Set the event object to the unsignaled state. ! 1446: // It will be used to signal request completion. ! 1447: // ! 1448: ! 1449: KeInitializeEvent(&event, NotificationEvent, FALSE); ! 1450: ! 1451: // ! 1452: // Set controlType and Srb direction flags. ! 1453: // ! 1454: ! 1455: if (BufferAddress != NULL) { ! 1456: ! 1457: if (WriteToDevice) { ! 1458: ! 1459: controlType = IOCTL_SCSI_EXECUTE_OUT; ! 1460: Srb->SrbFlags = SRB_FLAGS_DATA_OUT; ! 1461: ! 1462: } else { ! 1463: ! 1464: controlType = IOCTL_SCSI_EXECUTE_IN; ! 1465: Srb->SrbFlags = SRB_FLAGS_DATA_IN; ! 1466: ! 1467: } ! 1468: ! 1469: } else { ! 1470: ! 1471: BufferLength = 0; ! 1472: controlType = IOCTL_SCSI_EXECUTE_NONE; ! 1473: Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER; ! 1474: } ! 1475: ! 1476: // ! 1477: // Build device I/O control request with data transfer. ! 1478: // ! 1479: ! 1480: irp = IoBuildDeviceIoControlRequest( controlType, ! 1481: deviceExtension->PortDeviceObject, ! 1482: NULL, ! 1483: 0, ! 1484: BufferAddress, ! 1485: BufferLength, ! 1486: TRUE, ! 1487: &event, ! 1488: &ioStatus); ! 1489: ! 1490: if (irp == NULL) { ! 1491: ExFreePool(senseInfoBuffer); ! 1492: DebugPrint((1, "ScsiClassSendSrbSynchronous: Can't allocate Irp\n")); ! 1493: return(STATUS_INSUFFICIENT_RESOURCES); ! 1494: } ! 1495: ! 1496: // ! 1497: // Disable synchronous transfer for these requests. ! 1498: // ! 1499: ! 1500: Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER; ! 1501: ! 1502: // ! 1503: // Set the transfer length. ! 1504: // ! 1505: ! 1506: Srb->DataTransferLength = BufferLength; ! 1507: ! 1508: // ! 1509: // Zero out status. ! 1510: // ! 1511: ! 1512: Srb->ScsiStatus = Srb->SrbStatus = 0; ! 1513: ! 1514: Srb->NextSrb = 0; ! 1515: ! 1516: // ! 1517: // Get next stack location. ! 1518: // ! 1519: ! 1520: irpStack = IoGetNextIrpStackLocation(irp); ! 1521: ! 1522: // ! 1523: // Set up SRB for execute scsi request. Save SRB address in next stack ! 1524: // for the port driver. ! 1525: // ! 1526: ! 1527: irpStack->Parameters.Scsi.Srb = Srb; ! 1528: ! 1529: // ! 1530: // Set up IRP Address. ! 1531: // ! 1532: ! 1533: Srb->OriginalRequest = irp; ! 1534: ! 1535: // ! 1536: // Call the port driver with the request and wait for it to complete. ! 1537: // ! 1538: ! 1539: status = IoCallDriver(deviceExtension->PortDeviceObject, irp); ! 1540: ! 1541: if (status == STATUS_PENDING) { ! 1542: KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL); ! 1543: } ! 1544: ! 1545: // ! 1546: // Check that request completed without error. ! 1547: // ! 1548: ! 1549: if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) { ! 1550: ! 1551: // ! 1552: // Release the queue if it is frozen. ! 1553: // ! 1554: ! 1555: if (Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) { ! 1556: ScsiClassReleaseQueue(DeviceObject); ! 1557: } ! 1558: ! 1559: // ! 1560: // Update status and determine if request should be retried. ! 1561: // ! 1562: ! 1563: retry = ScsiClassInterpretSenseInfo(DeviceObject, ! 1564: Srb, ! 1565: IRP_MJ_SCSI, ! 1566: 0, ! 1567: MAXIMUM_RETRIES - retryCount, ! 1568: &status); ! 1569: ! 1570: if (retry) { ! 1571: ! 1572: if ((status == STATUS_DEVICE_NOT_READY && ((PSENSE_DATA) senseInfoBuffer) ! 1573: ->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) || ! 1574: SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT) { ! 1575: ! 1576: LARGE_INTEGER delay; ! 1577: ! 1578: // ! 1579: // Delay for 2 seconds. ! 1580: // ! 1581: ! 1582: delay = LiFromLong( - 10 * 1000 * 1000 * 2 ); ! 1583: ! 1584: // ! 1585: // Stall for a while to let the controller spinup. ! 1586: // ! 1587: ! 1588: KeDelayExecutionThread(KernelMode, ! 1589: FALSE, ! 1590: &delay); ! 1591: ! 1592: } ! 1593: ! 1594: ! 1595: // ! 1596: // If retries are not exhausted then retry this operation. ! 1597: // ! 1598: ! 1599: if (retryCount--) { ! 1600: goto retry; ! 1601: } ! 1602: } ! 1603: ! 1604: } else { ! 1605: ! 1606: status = STATUS_SUCCESS; ! 1607: } ! 1608: ! 1609: ExFreePool(senseInfoBuffer); ! 1610: return status; ! 1611: ! 1612: } // end ScsiClassSendSrbSynchronous() ! 1613: ! 1614: ! 1615: BOOLEAN ! 1616: ScsiClassInterpretSenseInfo( ! 1617: IN PDEVICE_OBJECT DeviceObject, ! 1618: IN PSCSI_REQUEST_BLOCK Srb, ! 1619: IN UCHAR MajorFunctionCode, ! 1620: IN ULONG IoDeviceCode, ! 1621: IN ULONG RetryCount, ! 1622: OUT NTSTATUS *Status ! 1623: ) ! 1624: ! 1625: /*++ ! 1626: ! 1627: Routine Description: ! 1628: ! 1629: This routine interprets the data returned from the SCSI ! 1630: request sense. It determines the status to return in the ! 1631: IRP and whether this request can be retried. ! 1632: ! 1633: Arguments: ! 1634: ! 1635: DeviceObject - Supplies the device object associated with this request. ! 1636: ! 1637: Srb - Supplies the scsi request block which failed. ! 1638: ! 1639: MajorFunctionCode - Supplies the function code to be used for logging. ! 1640: ! 1641: IoDeviceCode - Supplies the device code to be used for logging. ! 1642: ! 1643: Status - Returns the status for the request. ! 1644: ! 1645: Return Value: ! 1646: ! 1647: BOOLEAN TRUE: Drivers should retry this request. ! 1648: FALSE: Drivers should not retry this request. ! 1649: ! 1650: --*/ ! 1651: ! 1652: { ! 1653: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; ! 1654: PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer; ! 1655: BOOLEAN retry; ! 1656: BOOLEAN logError; ! 1657: ULONG uniqueId; ! 1658: NTSTATUS logStatus; ! 1659: PIO_ERROR_LOG_PACKET errorLogEntry; ! 1660: ULONG badSector; ! 1661: ULONG readSector; ! 1662: ULONG index; ! 1663: ! 1664: logError = FALSE; ! 1665: retry = TRUE; ! 1666: badSector = 0; ! 1667: ! 1668: // ! 1669: // Check that request sense buffer is valid. ! 1670: // ! 1671: ! 1672: if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID && ! 1673: Srb->SenseInfoBufferLength >= offsetof(SENSE_DATA, CommandSpecificInformation)) { ! 1674: ! 1675: DebugPrint((1,"ScsiClassInterpretSenseInfo: Error code is %x\n", ! 1676: senseBuffer->ErrorCode)); ! 1677: DebugPrint((1,"ScsiClassInterpretSenseInfo: Sense key is %x\n", ! 1678: senseBuffer->SenseKey)); ! 1679: DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code is %x\n", ! 1680: senseBuffer->AdditionalSenseCode)); ! 1681: DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code qualifier is %x\n", ! 1682: senseBuffer->AdditionalSenseCodeQualifier)); ! 1683: ! 1684: // ! 1685: // Zero the additional sense code and additional sense code qualifier ! 1686: // if they were not returned by the device. ! 1687: // ! 1688: ! 1689: readSector = senseBuffer->AdditionalSenseLength + ! 1690: offsetof(SENSE_DATA, AdditionalSenseLength); ! 1691: ! 1692: if (readSector > Srb->SenseInfoBufferLength) { ! 1693: readSector = Srb->SenseInfoBufferLength; ! 1694: } ! 1695: ! 1696: if (readSector <= offsetof(SENSE_DATA, AdditionalSenseCode)) { ! 1697: senseBuffer->AdditionalSenseCode = 0; ! 1698: } ! 1699: ! 1700: if (readSector <= offsetof(SENSE_DATA, AdditionalSenseCodeQualifier)) { ! 1701: senseBuffer->AdditionalSenseCodeQualifier = 0; ! 1702: } ! 1703: ! 1704: switch (senseBuffer->SenseKey & 0xf) { ! 1705: ! 1706: case SCSI_SENSE_NOT_READY: ! 1707: ! 1708: DebugPrint((1,"ScsiClassInterpretSenseInfo: Device not ready\n")); ! 1709: *Status = STATUS_DEVICE_NOT_READY; ! 1710: ! 1711: switch (senseBuffer->AdditionalSenseCode) { ! 1712: ! 1713: case SCSI_ADSENSE_LUN_NOT_READY: ! 1714: ! 1715: DebugPrint((1,"ScsiClassInterpretSenseInfo: Lun not ready\n")); ! 1716: ! 1717: switch (senseBuffer->AdditionalSenseCodeQualifier) { ! 1718: ! 1719: case SCSI_SENSEQ_BECOMING_READY: ! 1720: ! 1721: DebugPrint((1, "ScsiClassInterpretSenseInfo:" ! 1722: " In process of becoming ready\n")); ! 1723: break; ! 1724: ! 1725: case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED: ! 1726: ! 1727: DebugPrint((1, "ScsiClassInterpretSenseInfo:" ! 1728: " Manual intervention required\n")); ! 1729: *Status = STATUS_NO_MEDIA_IN_DEVICE; ! 1730: retry = FALSE; ! 1731: break; ! 1732: ! 1733: case SCSI_SENSEQ_FORMAT_IN_PROGRESS: ! 1734: ! 1735: DebugPrint((1, "ScsiClassInterpretSenseInfo: Format in progress\n")); ! 1736: retry = FALSE; ! 1737: break; ! 1738: ! 1739: case SCSI_SENSEQ_INIT_COMMAND_REQUIRED: ! 1740: default: ! 1741: ! 1742: DebugPrint((1, "ScsiClassInterpretSenseInfo:" ! 1743: " Initializing command required\n")); ! 1744: ! 1745: // ! 1746: // This sense code/additional sense code ! 1747: // combination may indicate that the device ! 1748: // needs to be started. Send an start unit if this ! 1749: // is a disk device. ! 1750: // ! 1751: ! 1752: if (DeviceObject->DeviceType == FILE_DEVICE_DISK) { ! 1753: StartUnit(DeviceObject); ! 1754: } ! 1755: ! 1756: break; ! 1757: ! 1758: } // end switch (senseBuffer->AdditionalSenseCodeQualifier) ! 1759: ! 1760: break; ! 1761: ! 1762: case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE: ! 1763: ! 1764: DebugPrint((1, ! 1765: "ScsiClassInterpretSenseInfo:" ! 1766: " No Media in device.\n")); ! 1767: *Status = STATUS_NO_MEDIA_IN_DEVICE; ! 1768: retry = FALSE; ! 1769: break; ! 1770: ! 1771: } // end switch (senseBuffer->AdditionalSenseCode) ! 1772: ! 1773: break; ! 1774: ! 1775: case SCSI_SENSE_DATA_PROTECT: ! 1776: ! 1777: DebugPrint((1, "ScsiClassInterpretSenseInfo: Media write protected\n")); ! 1778: *Status = STATUS_MEDIA_WRITE_PROTECTED; ! 1779: retry = FALSE; ! 1780: break; ! 1781: ! 1782: case SCSI_SENSE_MEDIUM_ERROR: ! 1783: ! 1784: DebugPrint((1,"ScsiClassInterpretSenseInfo: Bad media\n")); ! 1785: *Status = STATUS_DEVICE_DATA_ERROR; ! 1786: ! 1787: retry = FALSE; ! 1788: logError = TRUE; ! 1789: uniqueId = 256; ! 1790: logStatus = IO_ERR_BAD_BLOCK; ! 1791: break; ! 1792: ! 1793: case SCSI_SENSE_HARDWARE_ERROR: ! 1794: ! 1795: DebugPrint((1,"ScsiClassInterpretSenseInfo: Hardware error\n")); ! 1796: *Status = STATUS_IO_DEVICE_ERROR; ! 1797: ! 1798: logError = TRUE; ! 1799: uniqueId = 257; ! 1800: logStatus = IO_ERR_CONTROLLER_ERROR; ! 1801: ! 1802: break; ! 1803: ! 1804: case SCSI_SENSE_ILLEGAL_REQUEST: ! 1805: ! 1806: DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal SCSI request\n")); ! 1807: *Status = STATUS_INVALID_DEVICE_REQUEST; ! 1808: ! 1809: switch (senseBuffer->AdditionalSenseCode) { ! 1810: ! 1811: case SCSI_ADSENSE_ILLEGAL_COMMAND: ! 1812: DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal command\n")); ! 1813: break; ! 1814: ! 1815: case SCSI_ADSENSE_ILLEGAL_BLOCK: ! 1816: DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal block address\n")); ! 1817: *Status = STATUS_NONEXISTENT_SECTOR; ! 1818: break; ! 1819: ! 1820: case SCSI_ADSENSE_INVALID_LUN: ! 1821: DebugPrint((1,"ScsiClassInterpretSenseInfo: Invalid LUN\n")); ! 1822: *Status = STATUS_NO_SUCH_DEVICE; ! 1823: break; ! 1824: ! 1825: case SCSI_ADSENSE_MUSIC_AREA: ! 1826: DebugPrint((1,"ScsiClassInterpretSenseInfo: Music area\n")); ! 1827: break; ! 1828: ! 1829: case SCSI_ADSENSE_DATA_AREA: ! 1830: DebugPrint((1,"ScsiClassInterpretSenseInfo: Data area\n")); ! 1831: break; ! 1832: ! 1833: case SCSI_ADSENSE_VOLUME_OVERFLOW: ! 1834: DebugPrint((1, "ScsiClassInterpretSenseInfo: Volume overflow\n")); ! 1835: break; ! 1836: ! 1837: } // end switch (senseBuffer->AdditionalSenseCode) ! 1838: ! 1839: retry = FALSE; ! 1840: ! 1841: break; ! 1842: ! 1843: case SCSI_SENSE_UNIT_ATTENTION: ! 1844: ! 1845: switch (senseBuffer->AdditionalSenseCode) { ! 1846: case SCSI_ADSENSE_MEDIUM_CHANGED: ! 1847: DebugPrint((1, "ScsiClassInterpretSenseInfo: Media changed\n")); ! 1848: break; ! 1849: ! 1850: case SCSI_ADSENSE_BUS_RESET: ! 1851: DebugPrint((1,"ScsiClassInterpretSenseInfo: Bus reset\n")); ! 1852: break; ! 1853: ! 1854: default: ! 1855: DebugPrint((1,"ScsiClassInterpretSenseInfo: Unit attention\n")); ! 1856: break; ! 1857: ! 1858: } // end switch (senseBuffer->AdditionalSenseCode) ! 1859: ! 1860: if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA && ! 1861: DeviceObject->Vpb->Flags & VPB_MOUNTED) { ! 1862: ! 1863: // ! 1864: // Set bit to indicate that media may have changed ! 1865: // and volume needs verification. ! 1866: // ! 1867: ! 1868: DeviceObject->Flags |= DO_VERIFY_VOLUME; ! 1869: ! 1870: *Status = STATUS_VERIFY_REQUIRED; ! 1871: retry = FALSE; ! 1872: ! 1873: } else { ! 1874: ! 1875: *Status = STATUS_IO_DEVICE_ERROR; ! 1876: ! 1877: } ! 1878: ! 1879: break; ! 1880: ! 1881: case SCSI_SENSE_ABORTED_COMMAND: ! 1882: ! 1883: DebugPrint((1,"ScsiClassInterpretSenseInfo: Command aborted\n")); ! 1884: *Status = STATUS_IO_DEVICE_ERROR; ! 1885: break; ! 1886: ! 1887: case SCSI_SENSE_RECOVERED_ERROR: ! 1888: ! 1889: DebugPrint((1,"ScsiClassInterpretSenseInfo: Recovered error\n")); ! 1890: *Status = STATUS_SUCCESS; ! 1891: retry = FALSE; ! 1892: logError = TRUE; ! 1893: uniqueId = 258; ! 1894: ! 1895: switch(senseBuffer->AdditionalSenseCode) { ! 1896: case SCSI_ADSENSE_SEEK_ERROR: ! 1897: case SCSI_ADSENSE_TRACK_ERROR: ! 1898: logStatus = IO_ERR_SEEK_ERROR; ! 1899: break; ! 1900: ! 1901: case SCSI_ADSENSE_REC_DATA_NOECC: ! 1902: case SCSI_ADSENSE_REC_DATA_ECC: ! 1903: logStatus = STATUS_DEVICE_DATA_ERROR; ! 1904: break; ! 1905: ! 1906: default: ! 1907: logStatus = IO_ERR_CONTROLLER_ERROR; ! 1908: break; ! 1909: ! 1910: } // end switch(senseBuffer->AdditionalSenseCode) ! 1911: ! 1912: if (senseBuffer->IncorrectLength) { ! 1913: ! 1914: DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n")); ! 1915: *Status = STATUS_INVALID_BLOCK_LENGTH ; ! 1916: } ! 1917: ! 1918: break; ! 1919: ! 1920: case SCSI_SENSE_NO_SENSE: ! 1921: ! 1922: // ! 1923: // Check other indicators. ! 1924: // ! 1925: ! 1926: if (senseBuffer->IncorrectLength) { ! 1927: ! 1928: DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n")); ! 1929: *Status = STATUS_INVALID_BLOCK_LENGTH ; ! 1930: retry = FALSE; ! 1931: ! 1932: } else { ! 1933: ! 1934: DebugPrint((1, "ScsiClassInterpretSenseInfo: No specific sense key\n")); ! 1935: *Status = STATUS_IO_DEVICE_ERROR; ! 1936: retry = TRUE; ! 1937: } ! 1938: ! 1939: break; ! 1940: ! 1941: default: ! 1942: ! 1943: DebugPrint((1, "ScsiClassInterpretSenseInfo: Unrecognized sense code\n")); ! 1944: *Status = STATUS_IO_DEVICE_ERROR; ! 1945: break; ! 1946: ! 1947: } // end switch (senseBuffer->SenseKey & 0xf) ! 1948: ! 1949: // ! 1950: // Try to determine the bad sector from the inquiry data. ! 1951: // ! 1952: ! 1953: if ((((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_READ || ! 1954: ((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_VERIFY || ! 1955: ((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_WRITE)) { ! 1956: ! 1957: for (index = 0; index < 4; index++) { ! 1958: badSector = (badSector << 8) | senseBuffer->Information[index]; ! 1959: } ! 1960: ! 1961: readSector = 0; ! 1962: for (index = 0; index < 4; index++) { ! 1963: readSector = (readSector << 8) | Srb->Cdb[index+2]; ! 1964: } ! 1965: ! 1966: index = (((PCDB)Srb->Cdb)->CDB10.TransferBlocksMsb << 8) | ! 1967: ((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb; ! 1968: ! 1969: // ! 1970: // Make sure the bad sector is within the read sectors. ! 1971: // ! 1972: ! 1973: if (!(badSector >= readSector && badSector < readSector + index)) { ! 1974: badSector = readSector; ! 1975: } ! 1976: } ! 1977: ! 1978: } else { ! 1979: ! 1980: // ! 1981: // Request sense buffer not valid. No sense information ! 1982: // to pinpoint the error. Return general request fail. ! 1983: // ! 1984: ! 1985: DebugPrint((1,"ScsiClassInterpretSenseInfo: Request sense info not valid. SrbStatus %2x\n", ! 1986: SRB_STATUS(Srb->SrbStatus))); ! 1987: retry = TRUE; ! 1988: ! 1989: switch (SRB_STATUS(Srb->SrbStatus)) { ! 1990: case SRB_STATUS_INVALID_LUN: ! 1991: case SRB_STATUS_INVALID_TARGET_ID: ! 1992: case SRB_STATUS_NO_DEVICE: ! 1993: case SRB_STATUS_NO_HBA: ! 1994: case SRB_STATUS_INVALID_PATH_ID: ! 1995: *Status = STATUS_NO_SUCH_DEVICE; ! 1996: retry = FALSE; ! 1997: break; ! 1998: ! 1999: case SRB_STATUS_COMMAND_TIMEOUT: ! 2000: case SRB_STATUS_ABORTED: ! 2001: case SRB_STATUS_TIMEOUT: ! 2002: ! 2003: // ! 2004: // Update the error count for the device. ! 2005: // ! 2006: ! 2007: deviceExtension->ErrorCount++; ! 2008: ! 2009: *Status = STATUS_IO_TIMEOUT; ! 2010: break; ! 2011: ! 2012: case SRB_STATUS_SELECTION_TIMEOUT: ! 2013: logError = TRUE; ! 2014: logStatus = IO_ERR_NOT_READY; ! 2015: uniqueId = 260; ! 2016: *Status = STATUS_DEVICE_NOT_CONNECTED; ! 2017: retry = FALSE; ! 2018: break; ! 2019: ! 2020: case SRB_STATUS_DATA_OVERRUN: ! 2021: *Status = STATUS_DATA_OVERRUN; ! 2022: retry = FALSE; ! 2023: break; ! 2024: ! 2025: case SRB_STATUS_PHASE_SEQUENCE_FAILURE: ! 2026: ! 2027: // ! 2028: // Update the error count for the device. ! 2029: // ! 2030: ! 2031: deviceExtension->ErrorCount++; ! 2032: *Status = STATUS_IO_DEVICE_ERROR; ! 2033: ! 2034: // ! 2035: // If there was phase sequence error then limit the number of ! 2036: // retries. ! 2037: // ! 2038: ! 2039: if (RetryCount > 1 ) { ! 2040: retry = FALSE; ! 2041: } ! 2042: ! 2043: break; ! 2044: ! 2045: case SRB_STATUS_REQUEST_FLUSHED: ! 2046: ! 2047: // ! 2048: // If the status needs verification bit is set. Then set ! 2049: // the status to need verification and no retry; otherwise, ! 2050: // just retry the request. ! 2051: // ! 2052: ! 2053: if (DeviceObject->Flags & DO_VERIFY_VOLUME ) { ! 2054: ! 2055: *Status = STATUS_VERIFY_REQUIRED; ! 2056: retry = FALSE; ! 2057: } else { ! 2058: *Status = STATUS_IO_DEVICE_ERROR; ! 2059: } ! 2060: ! 2061: break; ! 2062: ! 2063: case SRB_STATUS_INVALID_REQUEST: ! 2064: ! 2065: // ! 2066: // An invalid request was attempted. ! 2067: // ! 2068: ! 2069: *Status = STATUS_INVALID_DEVICE_REQUEST; ! 2070: retry = FALSE; ! 2071: break; ! 2072: ! 2073: case SRB_STATUS_UNEXPECTED_BUS_FREE: ! 2074: case SRB_STATUS_PARITY_ERROR: ! 2075: ! 2076: // ! 2077: // Update the error count for the device. ! 2078: // ! 2079: ! 2080: deviceExtension->ErrorCount++; ! 2081: ! 2082: // ! 2083: // Fall through to below. ! 2084: // ! 2085: ! 2086: case SRB_STATUS_BUS_RESET: ! 2087: *Status = STATUS_IO_DEVICE_ERROR; ! 2088: break; ! 2089: ! 2090: case SRB_STATUS_ERROR: ! 2091: ! 2092: *Status = STATUS_IO_DEVICE_ERROR; ! 2093: if (Srb->ScsiStatus == 0) { ! 2094: ! 2095: // ! 2096: // This is some strange return code. Update the error ! 2097: // count for the device. ! 2098: // ! 2099: ! 2100: deviceExtension->ErrorCount++; ! 2101: ! 2102: } if (Srb->ScsiStatus == SCSISTAT_BUSY) { ! 2103: ! 2104: *Status = STATUS_DEVICE_NOT_READY; ! 2105: ! 2106: } if (Srb->ScsiStatus == SCSISTAT_RESERVATION_CONFLICT) { ! 2107: ! 2108: *Status = STATUS_DEVICE_BUSY; ! 2109: retry = FALSE; ! 2110: ! 2111: } ! 2112: ! 2113: break; ! 2114: ! 2115: default: ! 2116: logError = TRUE; ! 2117: logStatus = IO_ERR_CONTROLLER_ERROR; ! 2118: uniqueId = 259; ! 2119: *Status = STATUS_IO_DEVICE_ERROR; ! 2120: break; ! 2121: ! 2122: } ! 2123: ! 2124: // ! 2125: // If the error count has exceeded the error limit, the disable ! 2126: // any tagged queuing, multiple requests per lu queueing ! 2127: // and sychronous data transfers. ! 2128: // ! 2129: ! 2130: if (deviceExtension->ErrorCount == 4) { ! 2131: ! 2132: // ! 2133: // Clearing the no queue freeze flag prevents the port driver ! 2134: // from sending multiple requests per logical unit. ! 2135: // ! 2136: ! 2137: deviceExtension->SrbFlags &= ~(SRB_FLAGS_QUEUE_ACTION_ENABLE | ! 2138: SRB_FLAGS_NO_QUEUE_FREEZE); ! 2139: ! 2140: deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER; ! 2141: DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling tagged queuing and synchronous data tranfers.\n")); ! 2142: ! 2143: } else if (deviceExtension->ErrorCount == 8) { ! 2144: ! 2145: // ! 2146: // If a second threshold is reached, disable disconnects. ! 2147: // ! 2148: ! 2149: deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT; ! 2150: DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling disconnects.\n")); ! 2151: } ! 2152: } ! 2153: ! 2154: // ! 2155: // If there is a class specific error handler call it. ! 2156: // ! 2157: ! 2158: if (deviceExtension->ClassError != NULL) { ! 2159: ! 2160: deviceExtension->ClassError(DeviceObject, ! 2161: Srb, ! 2162: Status, ! 2163: &retry); ! 2164: } ! 2165: ! 2166: // ! 2167: // Log an error if necessary. ! 2168: // ! 2169: ! 2170: if (logError) { ! 2171: ! 2172: errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry( ! 2173: DeviceObject, ! 2174: sizeof(IO_ERROR_LOG_PACKET) + 5 * sizeof(ULONG)); ! 2175: ! 2176: if (errorLogEntry == NULL) { ! 2177: ! 2178: // ! 2179: // Return if no packet could be allocated. ! 2180: // ! 2181: ! 2182: return retry; ! 2183: ! 2184: } ! 2185: ! 2186: if (retry && RetryCount < MAXIMUM_RETRIES) { ! 2187: errorLogEntry->FinalStatus = STATUS_SUCCESS; ! 2188: } else { ! 2189: errorLogEntry->FinalStatus = *Status; ! 2190: } ! 2191: ! 2192: // ! 2193: // Calculate the device offset if there is a geometry. ! 2194: // ! 2195: ! 2196: if (deviceExtension->DiskGeometry != NULL) { ! 2197: ! 2198: errorLogEntry->DeviceOffset = LiFromLong( ! 2199: badSector); ! 2200: errorLogEntry->DeviceOffset = RtlExtendedIntegerMultiply( ! 2201: errorLogEntry->DeviceOffset, ! 2202: deviceExtension->DiskGeometry->BytesPerSector); ! 2203: } ! 2204: ! 2205: errorLogEntry->ErrorCode = logStatus; ! 2206: errorLogEntry->SequenceNumber = 0; ! 2207: errorLogEntry->MajorFunctionCode = MajorFunctionCode; ! 2208: errorLogEntry->IoControlCode = IoDeviceCode; ! 2209: errorLogEntry->RetryCount = (UCHAR) RetryCount; ! 2210: errorLogEntry->UniqueErrorValue = uniqueId; ! 2211: errorLogEntry->DumpDataSize = 6 * sizeof(ULONG); ! 2212: errorLogEntry->DumpData[0] = Srb->PathId; ! 2213: errorLogEntry->DumpData[1] = Srb->TargetId; ! 2214: errorLogEntry->DumpData[2] = Srb->Lun; ! 2215: errorLogEntry->DumpData[3] = 0; ! 2216: errorLogEntry->DumpData[4] = Srb->SrbStatus << 8 | Srb->ScsiStatus; ! 2217: ! 2218: if (senseBuffer != NULL) { ! 2219: errorLogEntry->DumpData[5] = senseBuffer->SenseKey << 16 | ! 2220: senseBuffer->AdditionalSenseCode << 8 | ! 2221: senseBuffer->AdditionalSenseCodeQualifier; ! 2222: ! 2223: } ! 2224: ! 2225: // ! 2226: // Write the error log packet. ! 2227: // ! 2228: ! 2229: IoWriteErrorLogEntry(errorLogEntry); ! 2230: } ! 2231: ! 2232: return retry; ! 2233: ! 2234: } // end ScsiClassInterpretSenseInfo() ! 2235: ! 2236: ! 2237: VOID ! 2238: RetryRequest( ! 2239: PDEVICE_OBJECT DeviceObject, ! 2240: PIRP Irp, ! 2241: PSCSI_REQUEST_BLOCK Srb, ! 2242: BOOLEAN Associated ! 2243: ) ! 2244: ! 2245: /*++ ! 2246: ! 2247: Routine Description: ! 2248: ! 2249: This routine reinitalizes the necessary fields, and sends the request ! 2250: to the port driver. ! 2251: ! 2252: Arguments: ! 2253: ! 2254: DeviceObject - Supplies the device object associated with this request. ! 2255: ! 2256: Irp - Supplies the request to be retried. ! 2257: ! 2258: Srb - Supplies a Pointer to the SCSI request block to be retied. ! 2259: ! 2260: Assocaiated - Indicates this is an assocatied Irp created by split request. ! 2261: ! 2262: Return Value: ! 2263: ! 2264: None ! 2265: ! 2266: --*/ ! 2267: ! 2268: { ! 2269: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; ! 2270: PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); ! 2271: PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp); ! 2272: ULONG transferByteCount; ! 2273: ! 2274: // ! 2275: // Determine the transfer count of the request. If this is a read or a ! 2276: // write then the transfer count is in the Irp stack. Otherwise assume ! 2277: // the MDL contains the correct length. If there is no MDL then the ! 2278: // transfer length must be zero. ! 2279: // ! 2280: ! 2281: if (currentIrpStack->MajorFunction == IRP_MJ_READ || ! 2282: currentIrpStack->MajorFunction == IRP_MJ_WRITE) { ! 2283: ! 2284: transferByteCount = currentIrpStack->Parameters.Read.Length; ! 2285: ! 2286: } else if (Irp->MdlAddress != NULL) { ! 2287: ! 2288: // ! 2289: // Note this assumes that only read and write requests are spilt and ! 2290: // other request do not need to be. If the data buffer address in ! 2291: // the MDL and the SRB don't match then transfer length is most ! 2292: // likely incorrect. ! 2293: // ! 2294: ! 2295: ASSERT(Srb->DataBuffer == MmGetMdlVirtualAddress(Irp->MdlAddress)); ! 2296: transferByteCount = Irp->MdlAddress->ByteCount; ! 2297: ! 2298: } else { ! 2299: ! 2300: transferByteCount = 0; ! 2301: } ! 2302: ! 2303: // ! 2304: // Reset byte count of transfer in SRB Extension. ! 2305: // ! 2306: ! 2307: Srb->DataTransferLength = transferByteCount; ! 2308: ! 2309: // ! 2310: // Zero SRB statuses. ! 2311: // ! 2312: ! 2313: Srb->SrbStatus = Srb->ScsiStatus = 0; ! 2314: ! 2315: // ! 2316: // Set the no disconnect flag, disable synchronous data transfers and ! 2317: // disable tagged queuing. This fixes some errors. ! 2318: // ! 2319: ! 2320: Srb->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT | ! 2321: SRB_FLAGS_DISABLE_SYNCH_TRANSFER; ! 2322: ! 2323: Srb->SrbFlags &= ~SRB_FLAGS_QUEUE_ACTION_ENABLE; ! 2324: ! 2325: // ! 2326: // Set up major SCSI function. ! 2327: // ! 2328: ! 2329: nextIrpStack->MajorFunction = IRP_MJ_SCSI; ! 2330: ! 2331: // ! 2332: // Save SRB address in next stack for port driver. ! 2333: // ! 2334: ! 2335: nextIrpStack->Parameters.Scsi.Srb = Srb; ! 2336: ! 2337: // ! 2338: // Set up IoCompletion routine address. ! 2339: // ! 2340: ! 2341: if (Associated) { ! 2342: ! 2343: IoSetCompletionRoutine(Irp, ScsiClassIoCompleteAssociated, Srb, TRUE, TRUE, TRUE); ! 2344: ! 2345: } else { ! 2346: ! 2347: IoSetCompletionRoutine(Irp, ScsiClassIoComplete, Srb, TRUE, TRUE, TRUE); ! 2348: ! 2349: } ! 2350: ! 2351: ! 2352: // ! 2353: // Pass the request to the port driver. ! 2354: // ! 2355: ! 2356: (PVOID)IoCallDriver(deviceExtension->PortDeviceObject, Irp); ! 2357: ! 2358: } // end RetryRequest() ! 2359: ! 2360: VOID ! 2361: ScsiClassBuildRequest( ! 2362: PDEVICE_OBJECT DeviceObject, ! 2363: PIRP Irp ! 2364: ) ! 2365: ! 2366: /*++ ! 2367: ! 2368: Routine Description: ! 2369: ! 2370: This routine allocates and builds an Srb for a read or write request. ! 2371: The block address and length are supplied by the Irp. The retry count ! 2372: is stored in the current stack for use by ScsiClassIoComplete which ! 2373: processes these requests when they complete. The Irp is ready to be ! 2374: passed to the port driver when this routine returns. ! 2375: ! 2376: Arguments: ! 2377: ! 2378: DeviceObject - Supplies the device object associated with this request. ! 2379: ! 2380: Irp - Supplies the request to be retried. ! 2381: ! 2382: Note: ! 2383: ! 2384: If the IRP is for a disk transfer, the byteoffset field ! 2385: will already have been adjusted to make it relative to ! 2386: the beginning of the disk. ! 2387: ! 2388: ! 2389: Return Value: ! 2390: ! 2391: None. ! 2392: ! 2393: --*/ ! 2394: ! 2395: { ! 2396: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; ! 2397: PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); ! 2398: PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp); ! 2399: PSCSI_REQUEST_BLOCK srb; ! 2400: PCDB cdb; ! 2401: ULONG logicalBlockAddress; ! 2402: LARGE_INTEGER startingOffset = ! 2403: currentIrpStack->Parameters.Read.ByteOffset; ! 2404: USHORT transferBlocks; ! 2405: ! 2406: // ! 2407: // Calculate relative sector address. ! 2408: // ! 2409: ! 2410: logicalBlockAddress = LiShr(startingOffset, ! 2411: deviceExtension->SectorShift).LowPart; ! 2412: ! 2413: // ! 2414: // Allocate an Srb. ! 2415: // ! 2416: ! 2417: if (deviceExtension->SrbZone != NULL && ! 2418: (srb = ExInterlockedAllocateFromZone( ! 2419: deviceExtension->SrbZone, ! 2420: deviceExtension->SrbZoneSpinLock)) != NULL) { ! 2421: ! 2422: srb->SrbFlags = SRB_FLAGS_ALLOCATED_FROM_ZONE; ! 2423: ! 2424: } else { ! 2425: ! 2426: // ! 2427: // Allocate Srb from nonpaged pool. ! 2428: // This call must succeed. ! 2429: // ! 2430: ! 2431: srb = ExAllocatePool(NonPagedPoolMustSucceed, SCSI_REQUEST_BLOCK_SIZE); ! 2432: ! 2433: srb->SrbFlags = 0; ! 2434: ! 2435: } ! 2436: ! 2437: // ! 2438: // Write length to SRB. ! 2439: // ! 2440: ! 2441: srb->Length = SCSI_REQUEST_BLOCK_SIZE; ! 2442: ! 2443: // ! 2444: // Set up IRP Address. ! 2445: // ! 2446: ! 2447: srb->OriginalRequest = Irp; ! 2448: ! 2449: // ! 2450: // Set up target ID and logical unit number. ! 2451: // ! 2452: ! 2453: srb->PathId = deviceExtension->PathId; ! 2454: srb->TargetId = deviceExtension->TargetId; ! 2455: srb->Lun = deviceExtension->Lun; ! 2456: ! 2457: srb->Function = SRB_FUNCTION_EXECUTE_SCSI; ! 2458: ! 2459: srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress); ! 2460: ! 2461: // ! 2462: // Save byte count of transfer in SRB Extension. ! 2463: // ! 2464: ! 2465: srb->DataTransferLength = currentIrpStack->Parameters.Read.Length; ! 2466: ! 2467: // ! 2468: // Initialize the queue actions field. ! 2469: // ! 2470: ! 2471: srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; ! 2472: ! 2473: // ! 2474: // Queue sort key is Relative Block Address. ! 2475: // ! 2476: ! 2477: srb->QueueSortKey = logicalBlockAddress; ! 2478: ! 2479: // ! 2480: // Indicate auto request sense by specifying buffer and size. ! 2481: // ! 2482: ! 2483: srb->SenseInfoBuffer = deviceExtension->SenseData; ! 2484: srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE; ! 2485: ! 2486: // ! 2487: // Set timeout value in seconds. ! 2488: // ! 2489: ! 2490: srb->TimeOutValue = deviceExtension->TimeOutValue; ! 2491: ! 2492: // ! 2493: // Zero statuses. ! 2494: // ! 2495: ! 2496: srb->SrbStatus = srb->ScsiStatus = 0; ! 2497: srb->NextSrb = 0; ! 2498: ! 2499: // ! 2500: // Indicate that 10-byte CDB's will be used. ! 2501: // ! 2502: ! 2503: srb->CdbLength = 10; ! 2504: ! 2505: // ! 2506: // Fill in CDB fields. ! 2507: // ! 2508: ! 2509: cdb = (PCDB)srb->Cdb; ! 2510: ! 2511: RtlZeroMemory(cdb, srb->CdbLength); ! 2512: ! 2513: cdb->CDB10.LogicalUnitNumber = deviceExtension->Lun; ! 2514: ! 2515: transferBlocks = (USHORT)(currentIrpStack->Parameters.Read.Length >> deviceExtension->SectorShift); ! 2516: ! 2517: // ! 2518: // Move little endian values into CDB in big endian format. ! 2519: // ! 2520: ! 2521: cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte3; ! 2522: cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte2; ! 2523: cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte1; ! 2524: cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte0; ! 2525: ! 2526: cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&transferBlocks)->Byte1; ! 2527: cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&transferBlocks)->Byte0; ! 2528: ! 2529: // ! 2530: // Set transfer direction flag and Cdb command. ! 2531: // ! 2532: ! 2533: if (currentIrpStack->MajorFunction == IRP_MJ_READ) { ! 2534: ! 2535: DebugPrint((3, "ScsiClassBuildRequest: Read Command\n")); ! 2536: ! 2537: srb->SrbFlags |= SRB_FLAGS_DATA_IN; ! 2538: cdb->CDB10.OperationCode = SCSIOP_READ; ! 2539: ! 2540: } else { ! 2541: ! 2542: DebugPrint((3, "ScsiClassBuildRequest: Write Command\n")); ! 2543: ! 2544: srb->SrbFlags |= SRB_FLAGS_DATA_OUT; ! 2545: cdb->CDB10.OperationCode = SCSIOP_WRITE; ! 2546: } ! 2547: ! 2548: // ! 2549: // If this is not a write-through request, then allow caching. ! 2550: // ! 2551: ! 2552: if (!(currentIrpStack->Flags & SL_WRITE_THROUGH)) { ! 2553: ! 2554: srb->SrbFlags |= SRB_FLAGS_ADAPTER_CACHE_ENABLE; ! 2555: ! 2556: } else { ! 2557: ! 2558: // ! 2559: // If write caching is enable then force media access in the ! 2560: // cdb. ! 2561: // ! 2562: ! 2563: if (deviceExtension->WriteCache) { ! 2564: cdb->CDB10.ForceUnitAccess = TRUE; ! 2565: } ! 2566: } ! 2567: ! 2568: // ! 2569: // Or in the default flags from the device object. ! 2570: // ! 2571: ! 2572: srb->SrbFlags |= deviceExtension->SrbFlags; ! 2573: ! 2574: // ! 2575: // Set up major SCSI function. ! 2576: // ! 2577: ! 2578: nextIrpStack->MajorFunction = IRP_MJ_SCSI; ! 2579: ! 2580: // ! 2581: // Save SRB address in next stack for port driver. ! 2582: // ! 2583: ! 2584: nextIrpStack->Parameters.Scsi.Srb = srb; ! 2585: ! 2586: // ! 2587: // Save retry count in current IRP stack. ! 2588: // ! 2589: ! 2590: currentIrpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES; ! 2591: ! 2592: // ! 2593: // Set up IoCompletion routine address. ! 2594: // ! 2595: ! 2596: IoSetCompletionRoutine(Irp, ScsiClassIoComplete, srb, TRUE, TRUE, TRUE); ! 2597: ! 2598: return; ! 2599: ! 2600: } // end ScsiClassBuildRequest() ! 2601: ! 2602: ULONG ! 2603: ScsiClassModeSense( ! 2604: IN PDEVICE_OBJECT DeviceObject, ! 2605: IN PCHAR ModeSenseBuffer, ! 2606: IN ULONG Length, ! 2607: IN UCHAR PageMode ! 2608: ) ! 2609: ! 2610: /*++ ! 2611: ! 2612: Routine Description: ! 2613: ! 2614: This routine sends a mode sense command to a target ID and returns ! 2615: when it is complete. ! 2616: ! 2617: Arguments: ! 2618: ! 2619: DeviceObject - Supplies the device object associated with this request. ! 2620: ! 2621: ModeSenseBuffer - Supplies a buffer to store the sense data. ! 2622: ! 2623: Length - Supplies the length in bytes of the mode sense buffer. ! 2624: ! 2625: PageMode - Supplies the page or pages of mode sense data to be retrived. ! 2626: ! 2627: Return Value: ! 2628: ! 2629: Length of the transferred data is returned. ! 2630: ! 2631: --*/ ! 2632: { ! 2633: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; ! 2634: PCDB cdb; ! 2635: SCSI_REQUEST_BLOCK srb; ! 2636: ULONG retries = 1; ! 2637: NTSTATUS status; ! 2638: ! 2639: RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); ! 2640: ! 2641: // ! 2642: // Build the MODE SENSE CDB. ! 2643: // ! 2644: ! 2645: srb.CdbLength = 6; ! 2646: cdb = (PCDB)srb.Cdb; ! 2647: ! 2648: // ! 2649: // Set timeout value from device extension. ! 2650: // ! 2651: ! 2652: srb.TimeOutValue = deviceExtension->TimeOutValue; ! 2653: ! 2654: cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE; ! 2655: cdb->MODE_SENSE.PageCode = PageMode; ! 2656: cdb->MODE_SENSE.AllocationLength = (UCHAR)Length; ! 2657: ! 2658: Retry: ! 2659: ! 2660: status = ScsiClassSendSrbSynchronous(DeviceObject, ! 2661: &srb, ! 2662: ModeSenseBuffer, ! 2663: Length, ! 2664: FALSE); ! 2665: ! 2666: ! 2667: if (status == STATUS_VERIFY_REQUIRED) { ! 2668: ! 2669: // ! 2670: // Routine ScsiClassSendSrbSynchronous does not retry requests returned with ! 2671: // this status. MODE SENSE commands should be retried anyway. ! 2672: // ! 2673: ! 2674: if (retries--) { ! 2675: ! 2676: // ! 2677: // Retry request. ! 2678: // ! 2679: ! 2680: goto Retry; ! 2681: } ! 2682: ! 2683: } else if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) { ! 2684: status = STATUS_SUCCESS; ! 2685: } ! 2686: ! 2687: if (NT_SUCCESS(status)) { ! 2688: return(srb.DataTransferLength); ! 2689: } else { ! 2690: return(0); ! 2691: } ! 2692: ! 2693: } // end ScsiClassModeSense() ! 2694: ! 2695: PVOID ! 2696: ScsiClassFindModePage( ! 2697: IN PCHAR ModeSenseBuffer, ! 2698: IN ULONG Length, ! 2699: IN UCHAR PageMode ! 2700: ) ! 2701: ! 2702: /*++ ! 2703: ! 2704: Routine Description: ! 2705: ! 2706: This routine scans through the mode sense data and finds the requested ! 2707: mode sense page code. ! 2708: ! 2709: Arguments: ! 2710: ModeSenseBuffer - Supplies a pointer to the mode sense data. ! 2711: ! 2712: Length - Indicates the length of valid data. ! 2713: ! 2714: PageMode - Supplies the page mode to be searched for. ! 2715: ! 2716: Return Value: ! 2717: ! 2718: A pointer to the the requested mode page. If the mode page was not found ! 2719: then NULL is return. ! 2720: ! 2721: --*/ ! 2722: { ! 2723: PUCHAR limit; ! 2724: ! 2725: limit = ModeSenseBuffer + Length; ! 2726: ! 2727: // ! 2728: // Skip the mode select header and block descriptors. ! 2729: // ! 2730: ! 2731: if (Length < sizeof(MODE_PARAMETER_HEADER)) { ! 2732: return(NULL); ! 2733: } ! 2734: ! 2735: ModeSenseBuffer += sizeof(MODE_PARAMETER_HEADER) + ! 2736: ((PMODE_PARAMETER_HEADER) ModeSenseBuffer)->BlockDescriptorLength; ! 2737: ! 2738: // ! 2739: // ModeSenseBuffer now points at pages. Walk the pages looking for the ! 2740: // requested page until the limit is reached. ! 2741: // ! 2742: ! 2743: while (ModeSenseBuffer < limit) { ! 2744: ! 2745: if (((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageCode == PageMode) { ! 2746: return(ModeSenseBuffer); ! 2747: } ! 2748: ! 2749: // ! 2750: // Adavance to the next page. ! 2751: // ! 2752: ! 2753: ModeSenseBuffer += ((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageLength + 2; ! 2754: } ! 2755: ! 2756: return(NULL); ! 2757: ! 2758: } ! 2759: ! 2760: NTSTATUS ! 2761: ScsiClassSendSrbAsynchronous( ! 2762: PDEVICE_OBJECT DeviceObject, ! 2763: PSCSI_REQUEST_BLOCK Srb, ! 2764: PIRP Irp, ! 2765: PVOID BufferAddress, ! 2766: ULONG BufferLength, ! 2767: BOOLEAN WriteToDevice ! 2768: ) ! 2769: /*++ ! 2770: ! 2771: Routine Description: ! 2772: ! 2773: This routine takes a partially built Srb and an Irp and sends it down to ! 2774: the port driver. ! 2775: ! 2776: Arguments: ! 2777: DeviceObject - Supplies the device object for the orginal request. ! 2778: ! 2779: Srb - Supplies a paritally build ScsiRequestBlock. In particular, the ! 2780: CDB and the SRB timeout value must be filled in. The SRB must not be ! 2781: allocated from zone. ! 2782: ! 2783: Irp - Supplies the requesting Irp. ! 2784: ! 2785: BufferAddress - Supplies a pointer to the buffer to be transfered. ! 2786: ! 2787: BufferLength - Supplies the length of data transfer. ! 2788: ! 2789: WriteToDevice - Indicates the data transfer will be from system memory to ! 2790: device. ! 2791: ! 2792: Return Value: ! 2793: ! 2794: Returns STATUS_INSUFFICIENT_RESOURCES or the status of IoCallDriver. ! 2795: ! 2796: --*/ ! 2797: { ! 2798: ! 2799: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; ! 2800: PIO_STACK_LOCATION irpStack; ! 2801: ! 2802: // ! 2803: // Write length to SRB. ! 2804: // ! 2805: ! 2806: Srb->Length = SCSI_REQUEST_BLOCK_SIZE; ! 2807: ! 2808: // ! 2809: // Set SCSI bus address. ! 2810: // ! 2811: ! 2812: Srb->PathId = deviceExtension->PathId; ! 2813: Srb->TargetId = deviceExtension->TargetId; ! 2814: Srb->Lun = deviceExtension->Lun; ! 2815: ! 2816: Srb->Function = SRB_FUNCTION_EXECUTE_SCSI; ! 2817: ! 2818: // ! 2819: // This is a violation of the SCSI spec but it is required for ! 2820: // some targets. ! 2821: // ! 2822: ! 2823: Srb->Cdb[1] |= deviceExtension->Lun << 5; ! 2824: ! 2825: // ! 2826: // Indicate auto request sense by specifying buffer and size. ! 2827: // ! 2828: ! 2829: Srb->SenseInfoBuffer = deviceExtension->SenseData; ! 2830: ! 2831: Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE; ! 2832: ! 2833: Srb->DataBuffer = BufferAddress; ! 2834: ! 2835: if (BufferAddress != NULL) { ! 2836: ! 2837: // ! 2838: // Build Mdl if necessary. ! 2839: // ! 2840: ! 2841: if (Irp->MdlAddress == NULL) { ! 2842: ! 2843: if (IoAllocateMdl(BufferAddress, ! 2844: BufferLength, ! 2845: FALSE, ! 2846: FALSE, ! 2847: Irp) == NULL) { ! 2848: ! 2849: return(STATUS_INSUFFICIENT_RESOURCES); ! 2850: } ! 2851: ! 2852: MmBuildMdlForNonPagedPool(Irp->MdlAddress); ! 2853: ! 2854: } else { ! 2855: ! 2856: // ! 2857: // Make sure the buffer requested matches the MDL. ! 2858: // ! 2859: ! 2860: ASSERT(BufferAddress == MmGetMdlVirtualAddress(Irp->MdlAddress)); ! 2861: } ! 2862: ! 2863: // ! 2864: // Set read flag. ! 2865: // ! 2866: ! 2867: Srb->SrbFlags = WriteToDevice ? SRB_FLAGS_DATA_OUT : SRB_FLAGS_DATA_IN; ! 2868: ! 2869: } else { ! 2870: ! 2871: // ! 2872: // Clear flags. ! 2873: // ! 2874: ! 2875: Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER; ! 2876: } ! 2877: ! 2878: // ! 2879: // Disable synchronous transfer for these requests. ! 2880: // ! 2881: ! 2882: Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER; ! 2883: ! 2884: // ! 2885: // Set the transfer length. ! 2886: // ! 2887: ! 2888: Srb->DataTransferLength = BufferLength; ! 2889: ! 2890: // ! 2891: // Zero out status. ! 2892: // ! 2893: ! 2894: Srb->ScsiStatus = Srb->SrbStatus = 0; ! 2895: ! 2896: Srb->NextSrb = 0; ! 2897: ! 2898: // ! 2899: // Save a few parameters in the current stack location. ! 2900: // ! 2901: ! 2902: irpStack = IoGetCurrentIrpStackLocation(Irp); ! 2903: ! 2904: // ! 2905: // Save retry count in current Irp stack. ! 2906: // ! 2907: ! 2908: irpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES; ! 2909: ! 2910: // ! 2911: // Set up IoCompletion routine address. ! 2912: // ! 2913: ! 2914: IoSetCompletionRoutine(Irp, ScsiClassIoComplete, Srb, TRUE, TRUE, TRUE); ! 2915: ! 2916: // ! 2917: // Get next stack location and ! 2918: // set major function code. ! 2919: // ! 2920: ! 2921: irpStack = IoGetNextIrpStackLocation(Irp); ! 2922: ! 2923: irpStack->MajorFunction = IRP_MJ_SCSI; ! 2924: ! 2925: // ! 2926: // Save SRB address in next stack for port driver. ! 2927: // ! 2928: ! 2929: irpStack->Parameters.Scsi.Srb = Srb; ! 2930: ! 2931: // ! 2932: // Set up Irp Address. ! 2933: // ! 2934: ! 2935: Srb->OriginalRequest = Irp; ! 2936: ! 2937: // ! 2938: // Call the port driver to process the request. ! 2939: // ! 2940: ! 2941: return(IoCallDriver(deviceExtension->PortDeviceObject, Irp)); ! 2942: ! 2943: } ! 2944: ! 2945: NTSTATUS ! 2946: ScsiClassDeviceControl( ! 2947: PDEVICE_OBJECT DeviceObject, ! 2948: PIRP Irp ! 2949: ) ! 2950: /*++ ! 2951: ! 2952: Routine Description: ! 2953: ! 2954: The routine is the common class driver device control dispatch function. ! 2955: This routine is called by a class driver when it get an unrecognized ! 2956: device control request. This routine will perform the correct action for ! 2957: common requests such as lock media. If the device request is unknown it ! 2958: passed down to the next level. ! 2959: ! 2960: Arguments: ! 2961: ! 2962: DeviceObject - Supplies a pointer to the device object for this request. ! 2963: ! 2964: Irp - Supplies the Irp making the request. ! 2965: ! 2966: Return Value: ! 2967: ! 2968: Returns back a STATUS_PENDING or a completion status. ! 2969: ! 2970: --*/ ! 2971: ! 2972: { ! 2973: PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); ! 2974: PIO_STACK_LOCATION nextStack; ! 2975: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; ! 2976: PSCSI_REQUEST_BLOCK srb; ! 2977: PCDB cdb; ! 2978: NTSTATUS status; ! 2979: ULONG modifiedIoControlCode; ! 2980: ! 2981: // ! 2982: // If this is a pass through I/O control, set the minor function code ! 2983: // and device address and pass it to the port driver. ! 2984: // ! 2985: ! 2986: if (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH ! 2987: || irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT) { ! 2988: ! 2989: PSCSI_PASS_THROUGH scsiPass; ! 2990: ! 2991: nextStack = IoGetNextIrpStackLocation(Irp); ! 2992: ! 2993: // ! 2994: // Validiate the user buffer. ! 2995: // ! 2996: ! 2997: if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH)){ ! 2998: ! 2999: Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; ! 3000: IoCompleteRequest(Irp, IO_NO_INCREMENT); ! 3001: return(STATUS_INVALID_PARAMETER); ! 3002: ! 3003: } ! 3004: ! 3005: // ! 3006: // Force the SCSI address to the correct value. ! 3007: // ! 3008: ! 3009: scsiPass = Irp->AssociatedIrp.SystemBuffer; ! 3010: scsiPass->PathId = deviceExtension->PathId; ! 3011: scsiPass->TargetId = deviceExtension->TargetId; ! 3012: scsiPass->Lun = deviceExtension->Lun; ! 3013: ! 3014: // ! 3015: // NOTICE: The SCSI-II specificaiton indicates that this field ! 3016: // should be zero; however, some target controllers ignore the logical ! 3017: // unit number in the INDENTIFY message and only look at the logical ! 3018: // unit number field in the CDB. ! 3019: // ! 3020: ! 3021: scsiPass->Cdb[1] |= deviceExtension->Lun << 5; ! 3022: ! 3023: nextStack->Parameters = irpStack->Parameters; ! 3024: nextStack->MajorFunction = irpStack->MajorFunction; ! 3025: nextStack->MinorFunction = IRP_MN_SCSI_CLASS; ! 3026: ! 3027: return(IoCallDriver(deviceExtension->PortDeviceObject, Irp)); ! 3028: } ! 3029: ! 3030: if (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_GET_ADDRESS) { ! 3031: ! 3032: PSCSI_ADDRESS scsiAddress = Irp->AssociatedIrp.SystemBuffer; ! 3033: ! 3034: if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < ! 3035: sizeof(SCSI_ADDRESS)) { ! 3036: ! 3037: // ! 3038: // Indicate unsuccessful status and no data transferred. ! 3039: // ! 3040: ! 3041: Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; ! 3042: Irp->IoStatus.Information = 0; ! 3043: IoCompleteRequest(Irp, IO_NO_INCREMENT); ! 3044: return(STATUS_BUFFER_TOO_SMALL); ! 3045: ! 3046: } ! 3047: ! 3048: scsiAddress->Length = sizeof(SCSI_ADDRESS); ! 3049: scsiAddress->PortNumber = deviceExtension->PortNumber; ! 3050: scsiAddress->PathId = deviceExtension->PathId; ! 3051: scsiAddress->TargetId = deviceExtension->TargetId; ! 3052: scsiAddress->Lun = deviceExtension->Lun; ! 3053: Irp->IoStatus.Information = sizeof(SCSI_ADDRESS); ! 3054: Irp->IoStatus.Status = STATUS_SUCCESS; ! 3055: IoCompleteRequest(Irp, IO_NO_INCREMENT); ! 3056: return(STATUS_SUCCESS); ! 3057: ! 3058: } ! 3059: ! 3060: srb = ExAllocatePool(NonPagedPool, SCSI_REQUEST_BLOCK_SIZE); ! 3061: ! 3062: if (srb == NULL) { ! 3063: ! 3064: Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; ! 3065: IoCompleteRequest(Irp, IO_NO_INCREMENT); ! 3066: return(STATUS_INSUFFICIENT_RESOURCES); ! 3067: } ! 3068: ! 3069: // ! 3070: // Write zeros to Srb. ! 3071: // ! 3072: ! 3073: RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE); ! 3074: ! 3075: cdb = (PCDB)srb->Cdb; ! 3076: ! 3077: // ! 3078: // Change the device type to disk for the switch statement. ! 3079: // ! 3080: ! 3081: modifiedIoControlCode = (irpStack->Parameters.DeviceIoControl.IoControlCode ! 3082: & ~0xffff0000) | (IOCTL_DISK_BASE << 16); ! 3083: ! 3084: switch (modifiedIoControlCode) { ! 3085: ! 3086: case IOCTL_DISK_CHECK_VERIFY: ! 3087: ! 3088: // ! 3089: // Test Unit Ready ! 3090: // ! 3091: ! 3092: DebugPrint((3,"ScsiDeviceIoControl: Check verify\n")); ! 3093: ! 3094: srb->CdbLength = 6; ! 3095: ! 3096: cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY; ! 3097: ! 3098: // ! 3099: // Set timeout value. ! 3100: // ! 3101: ! 3102: srb->TimeOutValue = deviceExtension->TimeOutValue; ! 3103: ! 3104: status = ScsiClassSendSrbAsynchronous(DeviceObject, ! 3105: srb, ! 3106: Irp, ! 3107: NULL, ! 3108: 0, ! 3109: FALSE); ! 3110: ! 3111: return(status); ! 3112: ! 3113: case IOCTL_DISK_MEDIA_REMOVAL: ! 3114: ! 3115: { ! 3116: ! 3117: PPREVENT_MEDIA_REMOVAL MediaRemoval = ! 3118: Irp->AssociatedIrp.SystemBuffer; ! 3119: ! 3120: // ! 3121: // Prevent/Allow media removal. ! 3122: // ! 3123: ! 3124: DebugPrint((3,"DiskIoControl: Prevent/Allow media removal\n")); ! 3125: ! 3126: if (irpStack->Parameters.DeviceIoControl.InputBufferLength < ! 3127: sizeof(PREVENT_MEDIA_REMOVAL)) { ! 3128: ! 3129: // ! 3130: // Indicate unsuccessful status and no data transferred. ! 3131: // ! 3132: ! 3133: Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; ! 3134: Irp->IoStatus.Information = 0; ! 3135: ExFreePool(srb); ! 3136: IoCompleteRequest(Irp, IO_NO_INCREMENT); ! 3137: return(STATUS_BUFFER_TOO_SMALL); ! 3138: } ! 3139: ! 3140: srb->CdbLength = 6; ! 3141: ! 3142: cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL; ! 3143: ! 3144: // ! 3145: // TRUE - prevent media removal. ! 3146: // FALSE - allow media removal. ! 3147: // ! 3148: ! 3149: cdb->MEDIA_REMOVAL.Prevent = MediaRemoval->PreventMediaRemoval; ! 3150: ! 3151: // ! 3152: // Set timeout value. ! 3153: // ! 3154: ! 3155: srb->TimeOutValue = deviceExtension->TimeOutValue; ! 3156: ! 3157: status = ScsiClassSendSrbAsynchronous(DeviceObject, ! 3158: srb, ! 3159: Irp, ! 3160: NULL, ! 3161: 0, ! 3162: FALSE); ! 3163: ! 3164: return(status); ! 3165: ! 3166: } ! 3167: ! 3168: case IOCTL_DISK_RESERVE: ! 3169: ! 3170: // ! 3171: // Reserve logical unit. ! 3172: // ! 3173: ! 3174: srb->CdbLength = 6; ! 3175: ! 3176: cdb->CDB6GENERIC.OperationCode = SCSIOP_RESERVE_UNIT; ! 3177: ! 3178: // ! 3179: // Set timeout value. ! 3180: // ! 3181: ! 3182: srb->TimeOutValue = deviceExtension->TimeOutValue; ! 3183: ! 3184: status = ScsiClassSendSrbAsynchronous(DeviceObject, ! 3185: srb, ! 3186: Irp, ! 3187: NULL, ! 3188: 0, ! 3189: FALSE); ! 3190: ! 3191: return(status); ! 3192: break; ! 3193: ! 3194: case IOCTL_DISK_RELEASE: ! 3195: ! 3196: // ! 3197: // Release logical unit. ! 3198: // ! 3199: ! 3200: srb->CdbLength = 6; ! 3201: ! 3202: cdb->CDB6GENERIC.OperationCode = SCSIOP_RELEASE_UNIT; ! 3203: ! 3204: // ! 3205: // Set timeout value. ! 3206: // ! 3207: ! 3208: srb->TimeOutValue = deviceExtension->TimeOutValue; ! 3209: ! 3210: status = ScsiClassSendSrbAsynchronous(DeviceObject, ! 3211: srb, ! 3212: Irp, ! 3213: NULL, ! 3214: 0, ! 3215: FALSE); ! 3216: ! 3217: return(status); ! 3218: break; ! 3219: ! 3220: case IOCTL_DISK_EJECT_MEDIA: ! 3221: ! 3222: // ! 3223: // Eject media. ! 3224: // ! 3225: ! 3226: srb->CdbLength = 6; ! 3227: ! 3228: cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT; ! 3229: ! 3230: cdb->START_STOP.LoadEject = 1; ! 3231: cdb->START_STOP.Start = 0; ! 3232: ! 3233: // ! 3234: // Set timeout value. ! 3235: // ! 3236: ! 3237: srb->TimeOutValue = deviceExtension->TimeOutValue; ! 3238: ! 3239: status = ScsiClassSendSrbAsynchronous(DeviceObject, ! 3240: srb, ! 3241: Irp, ! 3242: NULL, ! 3243: 0, ! 3244: FALSE); ! 3245: ! 3246: return(status); ! 3247: break; ! 3248: ! 3249: case IOCTL_DISK_LOAD_MEDIA: ! 3250: ! 3251: // ! 3252: // Load media. ! 3253: // ! 3254: ! 3255: DebugPrint((3,"CdRomDeviceControl: Load media\n")); ! 3256: ! 3257: srb->CdbLength = 6; ! 3258: ! 3259: cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT; ! 3260: ! 3261: cdb->START_STOP.LoadEject = 0; ! 3262: cdb->START_STOP.Start = 0; ! 3263: ! 3264: // ! 3265: // Set timeout value. ! 3266: // ! 3267: ! 3268: srb->TimeOutValue = deviceExtension->TimeOutValue; ! 3269: ! 3270: status = ScsiClassSendSrbAsynchronous(DeviceObject, ! 3271: srb, ! 3272: Irp, ! 3273: NULL, ! 3274: 0, ! 3275: FALSE); ! 3276: ! 3277: return(status); ! 3278: break; ! 3279: ! 3280: default: ! 3281: ! 3282: DebugPrint((3,"ScsiIoDeviceControl: Unsupported device IOCTL\n")); ! 3283: ! 3284: // ! 3285: // Pass the device control to the next driver. ! 3286: // ! 3287: ! 3288: ExFreePool(srb); ! 3289: ! 3290: // ! 3291: // Copy the Irp stack parameters to the next stack location. ! 3292: // ! 3293: ! 3294: nextStack = IoGetNextIrpStackLocation(Irp); ! 3295: ! 3296: nextStack->Parameters = irpStack->Parameters; ! 3297: nextStack->MajorFunction = irpStack->MajorFunction; ! 3298: nextStack->MinorFunction = irpStack->MinorFunction; ! 3299: ! 3300: return(IoCallDriver(deviceExtension->PortDeviceObject, Irp)); ! 3301: break; ! 3302: ! 3303: } // end switch( ... ! 3304: ! 3305: } ! 3306: ! 3307: NTSTATUS ! 3308: ScsiClassClaimDevice( ! 3309: IN PDEVICE_OBJECT PortDeviceObject, ! 3310: IN PSCSI_INQUIRY_DATA LunInfo, ! 3311: IN BOOLEAN Release, ! 3312: OUT PDEVICE_OBJECT *NewPortDeviceObject OPTIONAL ! 3313: ) ! 3314: /*++ ! 3315: ! 3316: Routine Description: ! 3317: ! 3318: This function claims a device in the port driver. The port driver object ! 3319: is updated with the correct driver object if the device is successfully ! 3320: claimed. ! 3321: ! 3322: Arguments: ! 3323: ! 3324: PortDeviceObject - Supplies the base port device object. ! 3325: ! 3326: LunInfo - Supplies the logical unit inforamtion of the device to be claimed. ! 3327: ! 3328: Release - Indicates the logical unit should be released rather than claimed. ! 3329: ! 3330: NewPortDeviceObject - Returns the updated port device object to be used ! 3331: for all future accesses. ! 3332: ! 3333: Return Value: ! 3334: ! 3335: Returns a status indicating success or failure of the operation. ! 3336: ! 3337: --*/ ! 3338: ! 3339: { ! 3340: IO_STATUS_BLOCK ioStatus; ! 3341: PIRP irp; ! 3342: PIO_STACK_LOCATION irpStack; ! 3343: KEVENT event; ! 3344: NTSTATUS status; ! 3345: SCSI_REQUEST_BLOCK srb; ! 3346: ! 3347: if (NewPortDeviceObject != NULL) { ! 3348: *NewPortDeviceObject = NULL; ! 3349: } ! 3350: ! 3351: // ! 3352: // Clear the SRB fields. ! 3353: // ! 3354: ! 3355: RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); ! 3356: ! 3357: // ! 3358: // Write length to SRB. ! 3359: // ! 3360: ! 3361: srb.Length = SCSI_REQUEST_BLOCK_SIZE; ! 3362: ! 3363: // ! 3364: // Set SCSI bus address. ! 3365: // ! 3366: ! 3367: srb.PathId = LunInfo->PathId; ! 3368: srb.TargetId = LunInfo->TargetId; ! 3369: srb.Lun = LunInfo->Lun; ! 3370: ! 3371: srb.Function = Release ? SRB_FUNCTION_RELEASE_DEVICE : ! 3372: SRB_FUNCTION_CLAIM_DEVICE; ! 3373: ! 3374: // ! 3375: // Set the event object to the unsignaled state. ! 3376: // It will be used to signal request completion. ! 3377: // ! 3378: ! 3379: KeInitializeEvent(&event, NotificationEvent, FALSE); ! 3380: ! 3381: // ! 3382: // Build synchronous request with no transfer. ! 3383: // ! 3384: ! 3385: irp = IoBuildDeviceIoControlRequest( IOCTL_SCSI_EXECUTE_NONE, ! 3386: PortDeviceObject, ! 3387: NULL, ! 3388: 0, ! 3389: NULL, ! 3390: 0, ! 3391: TRUE, ! 3392: &event, ! 3393: &ioStatus); ! 3394: ! 3395: if (irp == NULL) { ! 3396: ! 3397: DebugPrint((1, "ScsiClassClaimDevice: Can't allocate Irp\n")); ! 3398: return(STATUS_INSUFFICIENT_RESOURCES); ! 3399: } ! 3400: ! 3401: irpStack = IoGetNextIrpStackLocation(irp); ! 3402: ! 3403: // ! 3404: // Save SRB address in next stack for port driver. ! 3405: // ! 3406: ! 3407: irpStack->Parameters.Scsi.Srb = &srb; ! 3408: ! 3409: // ! 3410: // Set up IRP Address. ! 3411: // ! 3412: ! 3413: srb.OriginalRequest = irp; ! 3414: ! 3415: // ! 3416: // Call the port driver with the request and wait for it to complete. ! 3417: // ! 3418: ! 3419: status = IoCallDriver(PortDeviceObject, irp); ! 3420: if (status == STATUS_PENDING) { ! 3421: ! 3422: KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL); ! 3423: status = ioStatus.Status; ! 3424: } ! 3425: ! 3426: // ! 3427: // If this is a release request, then just decrement the reference count ! 3428: // and return. The status does not matter. ! 3429: // ! 3430: ! 3431: if (Release) { ! 3432: ! 3433: ObDereferenceObject(PortDeviceObject); ! 3434: return(STATUS_SUCCESS); ! 3435: } ! 3436: ! 3437: if (!NT_SUCCESS(status)) { ! 3438: return(status); ! 3439: } ! 3440: ! 3441: ASSERT(srb.DataBuffer != NULL); ! 3442: ! 3443: // ! 3444: // Reference the new port driver object so that it will not go away while ! 3445: // it is being used. ! 3446: // ! 3447: ! 3448: status = ObReferenceObjectByPointer(srb.DataBuffer, ! 3449: 0, ! 3450: NULL, ! 3451: KernelMode ); ! 3452: ! 3453: if (!NT_SUCCESS(status)) { ! 3454: ! 3455: return(status); ! 3456: ! 3457: } ! 3458: ! 3459: // ! 3460: // Return the new port device object pointer. ! 3461: // ! 3462: ! 3463: if (NewPortDeviceObject != NULL) { ! 3464: *NewPortDeviceObject = srb.DataBuffer; ! 3465: } ! 3466: ! 3467: return status; ! 3468: ! 3469: } ! 3470: ! 3471: ! 3472: NTSTATUS ! 3473: ScsiClassInternalIoControl ( ! 3474: IN PDEVICE_OBJECT DeviceObject, ! 3475: IN PIRP Irp ! 3476: ) ! 3477: ! 3478: /*++ ! 3479: ! 3480: Routine Description: ! 3481: ! 3482: This routine passes internal device controls to the port driver. ! 3483: Internal device controls are used by higher level class drivers to ! 3484: send scsi requests to a device that are not normally sent by a generic ! 3485: class driver. ! 3486: ! 3487: The path ID, target ID and logical unit ID are set in the srb so the ! 3488: higher level driver does not have to figure out what values are actually ! 3489: used. ! 3490: ! 3491: Arguments: ! 3492: ! 3493: DeviceObject - Supplies a pointer to the device object for this request. ! 3494: ! 3495: Irp - Supplies the Irp making the request. ! 3496: ! 3497: Return Value: ! 3498: ! 3499: Returns back a STATUS_PENDING or a completion status. ! 3500: ! 3501: --*/ ! 3502: { ! 3503: PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); ! 3504: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; ! 3505: PSCSI_REQUEST_BLOCK srb; ! 3506: ! 3507: // ! 3508: // Get a pointer to the SRB. ! 3509: // ! 3510: ! 3511: srb = irpStack->Parameters.Scsi.Srb; ! 3512: ! 3513: // ! 3514: // Set SCSI bus address. ! 3515: // ! 3516: ! 3517: srb->PathId = deviceExtension->PathId; ! 3518: srb->TargetId = deviceExtension->TargetId; ! 3519: srb->Lun = deviceExtension->Lun; ! 3520: ! 3521: // ! 3522: // NOTICE: The SCSI-II specificaiton indicates that this field should be ! 3523: // zero; however, some target controllers ignore the logical unit number ! 3524: // in the INDENTIFY message and only look at the logical unit number field ! 3525: // in the CDB. ! 3526: // ! 3527: ! 3528: srb->Cdb[1] |= deviceExtension->Lun << 5; ! 3529: ! 3530: // ! 3531: // Set the parameters in the next stack location. ! 3532: // ! 3533: ! 3534: irpStack = IoGetNextIrpStackLocation(Irp); ! 3535: ! 3536: irpStack->Parameters.Scsi.Srb = srb; ! 3537: irpStack->MajorFunction = IRP_MJ_SCSI; ! 3538: irpStack->MinorFunction = IRP_MN_SCSI_CLASS; ! 3539: ! 3540: IoSetCompletionRoutine(Irp, ClassIoCompletion, NULL, TRUE, TRUE, TRUE); ! 3541: ! 3542: return(IoCallDriver(deviceExtension->PortDeviceObject, Irp)); ! 3543: } ! 3544: ! 3545: NTSTATUS ! 3546: ClassIoCompletion( ! 3547: IN PDEVICE_OBJECT DeviceObject, ! 3548: IN PIRP Irp, ! 3549: IN PVOID Context ! 3550: ) ! 3551: ! 3552: /*++ ! 3553: ! 3554: Routine Description: ! 3555: ! 3556: This routine is called when an internal device control I/O request ! 3557: has completed. It marks the IRP pending if necessary and returns the ! 3558: status of the request. ! 3559: ! 3560: Arguments: ! 3561: ! 3562: DeviceObject - Target device object. ! 3563: ! 3564: Irp - Completed request. ! 3565: ! 3566: Context - not used. ! 3567: ! 3568: Return Value: ! 3569: ! 3570: Returns the status of the completed request. ! 3571: ! 3572: --*/ ! 3573: ! 3574: { ! 3575: UNREFERENCED_PARAMETER(Context); ! 3576: UNREFERENCED_PARAMETER(DeviceObject); ! 3577: ! 3578: ! 3579: // ! 3580: // If pending is returned for this Irp then mark current stack ! 3581: // as pending ! 3582: // ! 3583: ! 3584: if (Irp->PendingReturned) { ! 3585: ! 3586: IoMarkIrpPending( Irp ); ! 3587: ! 3588: } ! 3589: ! 3590: return Irp->IoStatus.Status; ! 3591: ! 3592: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.