3 * Copyright (C) 2001, 2002, 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * FILE: services/storage/class2/class2.c
24 * PURPOSE: SCSI class driver
25 * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
30 * - finish ScsiClassDeviceControl().
33 /* INCLUDES *****************************************************************/
35 #include <ddk/ntddk.h>
37 #include <ddk/class2.h>
43 #define VERSION "0.0.1"
45 #define TAG_SRBT TAG('S', 'r', 'b', 'T')
47 #define INQUIRY_DATA_SIZE 2048
50 static NTSTATUS STDCALL
51 ScsiClassCreateClose(IN PDEVICE_OBJECT DeviceObject,
54 static NTSTATUS STDCALL
55 ScsiClassReadWrite(IN PDEVICE_OBJECT DeviceObject,
58 static NTSTATUS STDCALL
59 ScsiClassDeviceDispatch(IN PDEVICE_OBJECT DeviceObject,
62 static NTSTATUS STDCALL
63 ScsiClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
67 ScsiClassRetryRequest(PDEVICE_OBJECT DeviceObject,
68 PIRP Irp, PSCSI_REQUEST_BLOCK Srb, BOOLEAN Associated);
70 /* FUNCTIONS ****************************************************************/
72 /**********************************************************************
77 * This function initializes the driver.
84 * System allocated Driver Object for this driver.
86 * Name of registry driver service key.
93 DriverEntry(IN PDRIVER_OBJECT DriverObject,
94 IN PUNICODE_STRING RegistryPath)
96 DPRINT("Class Driver %s\n", VERSION);
97 return(STATUS_SUCCESS);
102 ScsiClassDebugPrint(IN ULONG DebugPrintLevel,
103 IN PCHAR DebugMessage,
110 if (DebugPrintLevel > InternalDebugLevel)
114 va_start(ap, DebugMessage);
115 vsprintf(Buffer, DebugMessage, ap);
126 ScsiClassAsynchronousCompletion(IN PDEVICE_OBJECT DeviceObject,
138 ScsiClassBuildRequest(IN PDEVICE_OBJECT DeviceObject,
141 PDEVICE_EXTENSION DeviceExtension;
142 PIO_STACK_LOCATION CurrentIrpStack;
143 PIO_STACK_LOCATION NextIrpStack;
144 LARGE_INTEGER StartingOffset;
145 LARGE_INTEGER StartingBlock;
146 PSCSI_REQUEST_BLOCK Srb;
148 ULONG LogicalBlockAddress;
149 USHORT TransferBlocks;
151 DeviceExtension = DeviceObject->DeviceExtension;
152 CurrentIrpStack = IoGetCurrentIrpStackLocation(Irp);
153 NextIrpStack = IoGetNextIrpStackLocation(Irp);
154 StartingOffset = CurrentIrpStack->Parameters.Read.ByteOffset;
156 /* Calculate logical block address */
157 StartingBlock.QuadPart = StartingOffset.QuadPart >> DeviceExtension->SectorShift;
158 LogicalBlockAddress = (ULONG)StartingBlock.u.LowPart;
160 DPRINT("Logical block address: %lu\n", LogicalBlockAddress);
162 /* Allocate and initialize an SRB */
163 Srb = ExAllocateFromNPagedLookasideList(&DeviceExtension->SrbLookasideListHead);
166 Srb->Length = sizeof(SCSI_REQUEST_BLOCK); //SCSI_REQUEST_BLOCK_SIZE;
167 Srb->OriginalRequest = Irp;
168 Srb->PathId = DeviceExtension->PathId;
169 Srb->TargetId = DeviceExtension->TargetId;
170 Srb->Lun = DeviceExtension->Lun;
171 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
172 //FIXME: NT4 DDK sample uses MmGetMdlVirtualAddress! Why shouldn't we?
173 Srb->DataBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
174 Srb->DataTransferLength = CurrentIrpStack->Parameters.Read.Length;
175 Srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
176 Srb->QueueSortKey = LogicalBlockAddress;
178 Srb->SenseInfoBuffer = DeviceExtension->SenseData;
179 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
182 ((Srb->DataTransferLength + 0xFFFF) >> 16) * DeviceExtension->TimeOutValue;
184 Srb->SrbStatus = SRB_STATUS_SUCCESS;
189 Cdb = (PCDB)Srb->Cdb;
191 /* Initialize ATAPI packet (12 bytes) */
195 Cdb->CDB10.LogicalUnitNumber = DeviceExtension->Lun;
196 TransferBlocks = (USHORT)(CurrentIrpStack->Parameters.Read.Length >> DeviceExtension->SectorShift);
198 /* Copy little endian values into CDB in big endian format */
199 Cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte3;
200 Cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte2;
201 Cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte1;
202 Cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte0;
204 Cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&TransferBlocks)->Byte1;
205 Cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&TransferBlocks)->Byte0;
208 if (CurrentIrpStack->MajorFunction == IRP_MJ_READ)
210 DPRINT("ScsiClassBuildRequest: Read Command\n");
212 Srb->SrbFlags |= SRB_FLAGS_DATA_IN;
213 Cdb->CDB10.OperationCode = SCSIOP_READ;
217 DPRINT("ScsiClassBuildRequest: Write Command\n");
219 Srb->SrbFlags |= SRB_FLAGS_DATA_OUT;
220 Cdb->CDB10.OperationCode = SCSIOP_WRITE;
224 /* if this is not a write-through request, then allow caching */
225 if (!(CurrentIrpStack->Flags & SL_WRITE_THROUGH))
227 Srb->SrbFlags |= SRB_FLAGS_ADAPTER_CACHE_ENABLE;
229 else if (DeviceExtension->DeviceFlags & DEV_WRITE_CACHE)
231 /* if write caching is enable then force media access in the cdb */
232 Cdb->CDB10.ForceUnitAccess = TRUE;
236 /* Update srb flags */
237 Srb->SrbFlags |= DeviceExtension->SrbFlags;
239 /* Initialize next stack location */
240 NextIrpStack->MajorFunction = IRP_MJ_SCSI;
241 NextIrpStack->Parameters.Scsi.Srb = Srb;
243 /* Set retry count */
244 CurrentIrpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
246 DPRINT("IoSetCompletionRoutine (Irp %p Srb %p)\n", Irp, Srb);
247 IoSetCompletionRoutine(Irp,
260 ScsiClassClaimDevice(PDEVICE_OBJECT PortDeviceObject,
261 PSCSI_INQUIRY_DATA LunInfo,
263 PDEVICE_OBJECT *NewPortDeviceObject OPTIONAL)
265 PIO_STACK_LOCATION IoStack;
266 IO_STATUS_BLOCK IoStatusBlock;
267 SCSI_REQUEST_BLOCK Srb;
272 DPRINT("ScsiClassClaimDevice() called\n");
274 if (NewPortDeviceObject != NULL)
275 *NewPortDeviceObject = NULL;
277 /* initialize an SRB */
279 sizeof(SCSI_REQUEST_BLOCK));
280 Srb.Length = SCSI_REQUEST_BLOCK_SIZE;
281 Srb.PathId = LunInfo->PathId;
282 Srb.TargetId = LunInfo->TargetId;
283 Srb.Lun = LunInfo->Lun;
285 (Release == TRUE) ? SRB_FUNCTION_RELEASE_DEVICE : SRB_FUNCTION_CLAIM_DEVICE;
287 KeInitializeEvent(&Event,
291 Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_NONE,
302 DPRINT("Failed to allocate Irp!\n");
303 return(STATUS_INSUFFICIENT_RESOURCES);
306 /* Link Srb and Irp */
307 IoStack = IoGetNextIrpStackLocation(Irp);
308 IoStack->Parameters.Scsi.Srb = &Srb;
309 Srb.OriginalRequest = Irp;
311 /* Call SCSI port driver */
312 Status = IoCallDriver(PortDeviceObject,
314 if (Status == STATUS_PENDING)
316 KeWaitForSingleObject(&Event,
321 Status = IoStatusBlock.Status;
326 ObDereferenceObject(PortDeviceObject);
327 return(STATUS_SUCCESS);
330 // Status = ObReferenceObjectByPointer(Srb.DataBuffer,
331 Status = ObReferenceObjectByPointer(PortDeviceObject,
336 if (NewPortDeviceObject != NULL)
338 // *NewPortDeviceObject = Srb.DataBuffer;
339 *NewPortDeviceObject = PortDeviceObject;
342 return(STATUS_SUCCESS);
350 ScsiClassCreateDeviceObject(IN PDRIVER_OBJECT DriverObject,
351 IN PCCHAR ObjectNameBuffer,
352 IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL,
353 IN OUT PDEVICE_OBJECT *DeviceObject,
354 IN PCLASS_INIT_DATA InitializationData)
356 PDEVICE_OBJECT InternalDeviceObject;
357 PDEVICE_EXTENSION DeviceExtension;
358 ANSI_STRING AnsiName;
359 UNICODE_STRING DeviceName;
362 DPRINT("ScsiClassCreateDeviceObject() called\n");
364 *DeviceObject = NULL;
366 RtlInitAnsiString(&AnsiName,
369 Status = RtlAnsiStringToUnicodeString(&DeviceName,
372 if (!NT_SUCCESS(Status))
377 DPRINT("Device name: '%wZ'\n", &DeviceName);
379 Status = IoCreateDevice(DriverObject,
380 InitializationData->DeviceExtensionSize,
382 InitializationData->DeviceType,
383 InitializationData->DeviceCharacteristics,
385 &InternalDeviceObject);
386 if (NT_SUCCESS(Status))
388 DeviceExtension = InternalDeviceObject->DeviceExtension;
390 DeviceExtension->ClassError = InitializationData->ClassError;
391 DeviceExtension->ClassReadWriteVerification = InitializationData->ClassReadWriteVerification;
392 DeviceExtension->ClassFindDevices = InitializationData->ClassFindDevices;
393 DeviceExtension->ClassDeviceControl = InitializationData->ClassDeviceControl;
394 DeviceExtension->ClassShutdownFlush = InitializationData->ClassShutdownFlush;
395 DeviceExtension->ClassCreateClose = InitializationData->ClassCreateClose;
396 DeviceExtension->ClassStartIo = InitializationData->ClassStartIo;
398 DeviceExtension->MediaChangeCount = 0;
400 if (PhysicalDeviceObject != NULL)
402 DeviceExtension->PhysicalDevice = PhysicalDeviceObject;
406 DeviceExtension->PhysicalDevice = InternalDeviceObject;
409 *DeviceObject = InternalDeviceObject;
412 RtlFreeUnicodeString(&DeviceName);
422 ScsiClassDeviceControl(IN PDEVICE_OBJECT DeviceObject,
425 PDEVICE_EXTENSION DeviceExtension;
426 PIO_STACK_LOCATION NextStack;
427 PIO_STACK_LOCATION Stack;
429 ULONG InputBufferLength;
430 ULONG OutputBufferLength;
431 ULONG ModifiedControlCode;
432 PSCSI_REQUEST_BLOCK Srb;
435 DPRINT("ScsiClassDeviceControl() called\n");
437 DeviceExtension = DeviceObject->DeviceExtension;
438 Stack = IoGetCurrentIrpStackLocation(Irp);
440 IoControlCode = Stack->Parameters.DeviceIoControl.IoControlCode;
441 InputBufferLength = Stack->Parameters.DeviceIoControl.InputBufferLength;
442 OutputBufferLength = Stack->Parameters.DeviceIoControl.OutputBufferLength;
444 if (IoControlCode == IOCTL_SCSI_GET_DUMP_POINTERS)
446 PDUMP_POINTERS DumpPointers;
448 if (OutputBufferLength < sizeof(DUMP_POINTERS))
450 Irp->IoStatus.Information = 0;
451 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
452 IoCompleteRequest(Irp, IO_NO_INCREMENT);
454 return(STATUS_BUFFER_TOO_SMALL);
456 DumpPointers = (PDUMP_POINTERS)Irp->AssociatedIrp.SystemBuffer;
458 /* Initialize next stack location for call to the port driver */
459 NextStack = IoGetNextIrpStackLocation(Irp);
461 NextStack->Parameters = Stack->Parameters;
462 NextStack->MajorFunction = Stack->MajorFunction;
463 NextStack->MinorFunction = Stack->MinorFunction;
465 /* Call port driver */
466 return(IoCallDriver(DeviceExtension->PortDeviceObject,
469 if (IoControlCode == IOCTL_SCSI_GET_ADDRESS)
471 PSCSI_ADDRESS ScsiAddress;
473 if (OutputBufferLength < sizeof(SCSI_ADDRESS))
475 Irp->IoStatus.Information = 0;
476 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
477 IoCompleteRequest(Irp, IO_NO_INCREMENT);
479 return(STATUS_BUFFER_TOO_SMALL);
482 ScsiAddress = Irp->AssociatedIrp.SystemBuffer;
483 ScsiAddress->Length = sizeof(SCSI_ADDRESS);
484 ScsiAddress->PortNumber = DeviceExtension->PortNumber;
485 ScsiAddress->PathId = DeviceExtension->PathId;
486 ScsiAddress->TargetId = DeviceExtension->TargetId;
487 ScsiAddress->Lun = DeviceExtension->Lun;
489 Irp->IoStatus.Information = sizeof(SCSI_ADDRESS);
490 Irp->IoStatus.Status = STATUS_SUCCESS;
491 IoCompleteRequest(Irp, IO_NO_INCREMENT);
493 return(STATUS_SUCCESS);
496 if (IoControlCode == IOCTL_SCSI_PASS_THROUGH ||
497 IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT)
499 PSCSI_PASS_THROUGH ScsiPassThrough;
501 DPRINT("IOCTL_SCSI_PASS_THROUGH/IOCTL_SCSI_PASS_THROUGH_DIRECT\n");
503 /* Check input size */
504 if (InputBufferLength < sizeof(SCSI_PASS_THROUGH))
506 Irp->IoStatus.Information = 0;
507 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
508 IoCompleteRequest(Irp, IO_NO_INCREMENT);
509 return(STATUS_INVALID_PARAMETER);
512 /* Initialize next stack location for call to the port driver */
513 NextStack = IoGetNextIrpStackLocation(Irp);
515 ScsiPassThrough = Irp->AssociatedIrp.SystemBuffer;
516 ScsiPassThrough->PathId = DeviceExtension->PathId;
517 ScsiPassThrough->TargetId = DeviceExtension->TargetId;
518 ScsiPassThrough->Lun = DeviceExtension->Lun;
519 ScsiPassThrough->Cdb[1] |= DeviceExtension->Lun << 5;
521 NextStack->Parameters = Stack->Parameters;
522 NextStack->MajorFunction = Stack->MajorFunction;
523 NextStack->MinorFunction = Stack->MinorFunction;
525 /* Call port driver */
526 return(IoCallDriver(DeviceExtension->PortDeviceObject,
530 /* Allocate an SRB */
531 Srb = ExAllocatePool (NonPagedPool,
532 sizeof(SCSI_REQUEST_BLOCK));
535 Irp->IoStatus.Information = 0;
536 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
537 IoCompleteRequest(Irp,
539 return(STATUS_INSUFFICIENT_RESOURCES);
542 /* Initialize the SRB */
544 sizeof(SCSI_REQUEST_BLOCK));
545 Cdb = (PCDB)Srb->Cdb;
547 ModifiedControlCode = (IoControlCode & 0x0000FFFF) | (IOCTL_DISK_BASE << 16);
548 switch (ModifiedControlCode)
550 case IOCTL_DISK_CHECK_VERIFY:
551 DPRINT("IOCTL_DISK_CHECK_VERIFY\n");
553 /* Initialize SRB operation */
555 Srb->TimeOutValue = DeviceExtension->TimeOutValue;
556 Cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
558 return(ScsiClassSendSrbAsynchronous(DeviceObject,
566 DPRINT1("Unknown device io control code %lx\n",
567 ModifiedControlCode);
570 /* Pass the IOCTL down to the port driver */
571 NextStack = IoGetNextIrpStackLocation(Irp);
572 NextStack->Parameters = Stack->Parameters;
573 NextStack->MajorFunction = Stack->MajorFunction;
574 NextStack->MinorFunction = Stack->MinorFunction;
576 /* Call port driver */
577 return(IoCallDriver(DeviceExtension->PortDeviceObject,
581 Irp->IoStatus.Information = 0;
582 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
583 IoCompleteRequest(Irp, IO_NO_INCREMENT);
585 return(STATUS_UNSUCCESSFUL);
593 ScsiClassFindModePage(IN PCHAR ModeSenseBuffer,
598 ULONG DescriptorLength;
603 DPRINT("ScsiClassFindModePage() called\n");
605 /* Get header length */
606 HeaderLength = (Use6Byte) ? sizeof(MODE_PARAMETER_HEADER) : sizeof(MODE_PARAMETER_HEADER10);
608 /* Check header length */
609 if (Length < HeaderLength)
612 /* Get descriptor length */
613 if (Use6Byte == TRUE)
615 DescriptorLength = ((PMODE_PARAMETER_HEADER)ModeSenseBuffer)->BlockDescriptorLength;
619 DescriptorLength = ((PMODE_PARAMETER_HEADER10)ModeSenseBuffer)->BlockDescriptorLength[1];
622 /* Set page pointers */
623 Ptr = ModeSenseBuffer + HeaderLength + DescriptorLength;
624 End = ModeSenseBuffer + Length;
626 /* Search for page */
629 /* Check page code */
630 if (((PMODE_DISCONNECT_PAGE)Ptr)->PageCode == PageMode)
633 /* Skip to next page */
634 Ptr += ((PMODE_DISCONNECT_PAGE)Ptr)->PageLength;
645 ScsiClassFindUnclaimedDevices(IN PCLASS_INIT_DATA InitializationData,
646 IN PSCSI_ADAPTER_BUS_INFO AdapterInformation)
648 PSCSI_INQUIRY_DATA UnitInfo;
649 PINQUIRYDATA InquiryData;
652 ULONG UnclaimedDevices = 0;
655 DPRINT("ScsiClassFindUnclaimedDevices() called\n");
657 DPRINT("NumberOfBuses: %lu\n",AdapterInformation->NumberOfBuses);
658 Buffer = (PUCHAR)AdapterInformation;
659 for (Bus = 0; Bus < (ULONG)AdapterInformation->NumberOfBuses; Bus++)
661 DPRINT("Searching bus %lu\n", Bus);
663 UnitInfo = (PSCSI_INQUIRY_DATA)(Buffer + AdapterInformation->BusData[Bus].InquiryDataOffset);
665 while (AdapterInformation->BusData[Bus].InquiryDataOffset)
667 InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
669 DPRINT("Device: '%.8s'\n", InquiryData->VendorId);
671 if ((InitializationData->ClassFindDeviceCallBack(InquiryData) == TRUE) &&
672 (UnitInfo->DeviceClaimed == FALSE))
677 if (UnitInfo->NextInquiryDataOffset == 0)
680 UnitInfo = (PSCSI_INQUIRY_DATA) (Buffer + UnitInfo->NextInquiryDataOffset);
684 return(UnclaimedDevices);
692 ScsiClassGetCapabilities(IN PDEVICE_OBJECT PortDeviceObject,
693 OUT PIO_SCSI_CAPABILITIES *PortCapabilities)
695 IO_STATUS_BLOCK IoStatusBlock;
700 KeInitializeEvent(&Event,
704 Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_CAPABILITIES,
715 return(STATUS_INSUFFICIENT_RESOURCES);
718 Status = IoCallDriver(PortDeviceObject,
720 if (Status == STATUS_PENDING)
722 KeWaitForSingleObject(&Event,
727 Status = IoStatusBlock.Status;
730 DPRINT("PortCapabilities at %p\n", *PortCapabilities);
740 ScsiClassGetInquiryData(IN PDEVICE_OBJECT PortDeviceObject,
741 IN PSCSI_ADAPTER_BUS_INFO *ConfigInfo)
743 PSCSI_ADAPTER_BUS_INFO Buffer;
744 IO_STATUS_BLOCK IoStatusBlock;
749 DPRINT("ScsiClassGetInquiryData() called\n");
752 Buffer = ExAllocatePool(NonPagedPool,
756 return(STATUS_INSUFFICIENT_RESOURCES);
759 KeInitializeEvent(&Event,
763 Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA,
775 return(STATUS_INSUFFICIENT_RESOURCES);
778 Status = IoCallDriver(PortDeviceObject,
780 if (Status == STATUS_PENDING)
782 KeWaitForSingleObject(&Event,
787 Status = IoStatusBlock.Status;
790 if (!NT_SUCCESS(Status))
796 *ConfigInfo = Buffer;
799 DPRINT("ScsiClassGetInquiryData() done\n");
809 ScsiClassInitialize(IN PVOID Argument1,
811 IN PCLASS_INIT_DATA InitializationData)
813 PCONFIGURATION_INFORMATION ConfigInfo;
814 PDRIVER_OBJECT DriverObject = Argument1;
815 WCHAR NameBuffer[80];
816 UNICODE_STRING PortName;
818 PDEVICE_OBJECT PortDeviceObject;
819 PFILE_OBJECT FileObject;
820 BOOLEAN DiskFound = FALSE;
823 DPRINT("ScsiClassInitialize() called!\n");
825 DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiClassCreateClose;
826 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiClassCreateClose;
827 DriverObject->MajorFunction[IRP_MJ_READ] = ScsiClassReadWrite;
828 DriverObject->MajorFunction[IRP_MJ_WRITE] = ScsiClassReadWrite;
829 DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiClassInternalIoControl;
830 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiClassDeviceDispatch;
831 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = ScsiClassShutdownFlush;
832 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = ScsiClassShutdownFlush;
833 if (InitializationData->ClassStartIo)
835 DriverObject->DriverStartIo = InitializationData->ClassStartIo;
838 ConfigInfo = IoGetConfigurationInformation();
840 DPRINT("ScsiPorts: %lu\n", ConfigInfo->ScsiPortCount);
842 /* look for ScsiPortX scsi port devices */
843 for (PortNumber = 0; PortNumber < ConfigInfo->ScsiPortCount; PortNumber++)
846 L"\\Device\\ScsiPort%lu",
848 RtlInitUnicodeString(&PortName,
850 DPRINT("Checking scsi port %ld\n", PortNumber);
851 Status = IoGetDeviceObjectPointer(&PortName,
852 FILE_READ_ATTRIBUTES,
855 DPRINT("Status 0x%08lX\n", Status);
856 if (NT_SUCCESS(Status))
858 DPRINT("ScsiPort%lu found.\n", PortNumber);
860 /* check scsi port for attached disk drives */
861 if (InitializationData->ClassFindDevices(DriverObject,
872 DbgPrint("Couldn't find ScsiPort%lu (Status %lx)\n", PortNumber, Status);
876 DPRINT("ScsiClassInitialize() done!\n");
878 return((DiskFound == TRUE) ? STATUS_SUCCESS : STATUS_NO_SUCH_DEVICE);
882 /**********************************************************************
884 * ScsiClassInitializeSrbLookasideList
887 * Initializes a lookaside list for SRBs.
894 * Class specific device extension.
897 * Maximum number of elements of the lookaside list.
905 ScsiClassInitializeSrbLookasideList(IN PDEVICE_EXTENSION DeviceExtension,
906 IN ULONG NumberElements)
908 ExInitializeNPagedLookasideList(&DeviceExtension->SrbLookasideListHead,
912 sizeof(SCSI_REQUEST_BLOCK),
914 (USHORT)NumberElements);
922 ScsiClassInternalIoControl(IN PDEVICE_OBJECT DeviceObject,
925 DPRINT1("ScsiClassInternalIoContol() called\n");
927 Irp->IoStatus.Status = STATUS_SUCCESS;
928 Irp->IoStatus.Information = 0;
929 IoCompleteRequest(Irp, IO_NO_INCREMENT);
931 return(STATUS_SUCCESS);
939 ScsiClassInterpretSenseInfo(IN PDEVICE_OBJECT DeviceObject,
940 IN PSCSI_REQUEST_BLOCK Srb,
941 IN UCHAR MajorFunctionCode,
942 IN ULONG IoDeviceCode,
944 OUT NTSTATUS *Status)
946 PDEVICE_EXTENSION DeviceExtension;
948 PIO_ERROR_LOG_PACKET LogPacket;
950 PSENSE_DATA SenseData;
955 DPRINT("ScsiClassInterpretSenseInfo() called\n");
957 DPRINT("Srb->SrbStatus %lx\n", Srb->SrbStatus);
959 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_PENDING)
961 *Status = STATUS_SUCCESS;
965 DeviceExtension = DeviceObject->DeviceExtension;
966 SenseData = Srb->SenseInfoBuffer;
970 if ((Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
971 (Srb->SenseInfoBufferLength > 0))
973 /* Got valid sense data, interpret them */
975 DPRINT("ErrorCode: %x\n", SenseData->ErrorCode);
976 DPRINT("SenseKey: %x\n", SenseData->SenseKey);
977 DPRINT("SenseCode: %x\n", SenseData->AdditionalSenseCode);
979 switch (SenseData->SenseKey & 0xf)
981 case SCSI_SENSE_NO_SENSE:
982 DPRINT("SCSI_SENSE_NO_SENSE\n");
983 if (SenseData->IncorrectLength)
985 DPRINT("Incorrect block length\n");
986 *Status = STATUS_INVALID_BLOCK_LENGTH;
991 DPRINT("Unspecified error\n");
992 *Status = STATUS_IO_DEVICE_ERROR;
997 case SCSI_SENSE_RECOVERED_ERROR:
998 DPRINT("SCSI_SENSE_RECOVERED_ERROR\n");
999 *Status = STATUS_SUCCESS;
1003 case SCSI_SENSE_NOT_READY:
1004 DPRINT("SCSI_SENSE_NOT_READY\n");
1005 *Status = STATUS_DEVICE_NOT_READY;
1006 switch (SenseData->AdditionalSenseCode)
1008 case SCSI_ADSENSE_LUN_NOT_READY:
1009 DPRINT("SCSI_ADSENSE_LUN_NOT_READY\n");
1012 case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE:
1013 DPRINT("SCSI_ADSENSE_NO_MEDIA_IN_DEVICE\n");
1014 *Status = STATUS_NO_MEDIA_IN_DEVICE;
1020 case SCSI_SENSE_MEDIUM_ERROR:
1021 DPRINT("SCSI_SENSE_MEDIUM_ERROR\n");
1022 *Status = STATUS_DEVICE_DATA_ERROR;
1026 case SCSI_SENSE_HARDWARE_ERROR:
1027 DPRINT("SCSI_SENSE_HARDWARE_ERROR\n");
1028 *Status = STATUS_IO_DEVICE_ERROR;
1031 case SCSI_SENSE_ILLEGAL_REQUEST:
1032 DPRINT("SCSI_SENSE_ILLEGAL_REQUEST\n");
1033 *Status = STATUS_INVALID_DEVICE_REQUEST;
1034 switch (SenseData->AdditionalSenseCode)
1036 case SCSI_ADSENSE_ILLEGAL_COMMAND:
1037 DPRINT("SCSI_ADSENSE_ILLEGAL_COMMAND\n");
1041 case SCSI_ADSENSE_ILLEGAL_BLOCK:
1042 DPRINT("SCSI_ADSENSE_ILLEGAL_BLOCK\n");
1043 *Status = STATUS_NONEXISTENT_SECTOR;
1047 case SCSI_ADSENSE_INVALID_LUN:
1048 DPRINT("SCSI_ADSENSE_INVALID_LUN\n");
1049 *Status = STATUS_NO_SUCH_DEVICE;
1053 case SCSI_ADSENSE_MUSIC_AREA:
1054 DPRINT("SCSI_ADSENSE_MUSIC_AREA\n");
1058 case SCSI_ADSENSE_DATA_AREA:
1059 DPRINT("SCSI_ADSENSE_DATA_AREA\n");
1063 case SCSI_ADSENSE_VOLUME_OVERFLOW:
1064 DPRINT("SCSI_ADSENSE_VOLUME_OVERFLOW\n");
1068 case SCSI_ADSENSE_INVALID_CDB:
1069 DPRINT("SCSI_ADSENSE_INVALID_CDB\n");
1075 case SCSI_SENSE_UNIT_ATTENTION:
1076 DPRINT("SCSI_SENSE_UNIT_ATTENTION\n");
1077 if ((DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) &&
1078 (DeviceObject->Vpb->Flags & VPB_MOUNTED))
1080 DeviceObject->Flags |= DO_VERIFY_VOLUME;
1081 *Status = STATUS_VERIFY_REQUIRED;
1086 *Status = STATUS_IO_DEVICE_ERROR;
1090 case SCSI_SENSE_DATA_PROTECT:
1091 DPRINT("SCSI_SENSE_DATA_PROTECT\n");
1092 *Status = STATUS_MEDIA_WRITE_PROTECTED;
1096 case SCSI_SENSE_ABORTED_COMMAND:
1097 DPRINT("SCSI_SENSE_ABORTED_COMMAND\n");
1098 *Status = STATUS_IO_DEVICE_ERROR;
1102 DPRINT1("SCSI error (sense key: %x)\n",
1103 SenseData->SenseKey & 0xf);
1104 *Status = STATUS_IO_DEVICE_ERROR;
1110 /* Got no or invalid sense data, return generic error codes */
1111 switch (SRB_STATUS(Srb->SrbStatus))
1113 /* FIXME: add more srb status codes */
1115 case SRB_STATUS_INVALID_PATH_ID:
1116 case SRB_STATUS_INVALID_TARGET_ID:
1117 case SRB_STATUS_INVALID_LUN:
1118 case SRB_STATUS_NO_DEVICE:
1119 case SRB_STATUS_NO_HBA:
1120 *Status = STATUS_NO_SUCH_DEVICE;
1124 case SRB_STATUS_BUSY:
1125 *Status = STATUS_DEVICE_BUSY;
1129 case SRB_STATUS_DATA_OVERRUN:
1130 *Status = STATUS_DATA_OVERRUN;
1135 DPRINT1("SCSI error (SRB status: %x)\n",
1136 SRB_STATUS(Srb->SrbStatus));
1138 *Status = STATUS_IO_DEVICE_ERROR;
1143 /* Call the class driver specific error function */
1144 if (DeviceExtension->ClassError != NULL)
1146 DeviceExtension->ClassError(DeviceObject,
1152 if (LogError == TRUE)
1155 /* Allocate error packet */
1156 LogPacket = IoAllocateErrorLogEntry (DeviceObject,
1157 sizeof(IO_ERROR_LOG_PACKET) +
1159 if (LogPacket == NULL)
1161 DPRINT1 ("Failed to allocate a log packet!\n");
1165 /* Initialize error packet */
1166 LogPacket->MajorFunctionCode = MajorFunctionCode;
1167 LogPacket->RetryCount = (UCHAR)RetryCount;
1168 LogPacket->DumpDataSize = 6 * sizeof(ULONG);
1169 LogPacket->ErrorCode = 0; /* FIXME */
1170 LogPacket->FinalStatus = *Status;
1171 LogPacket->IoControlCode = IoDeviceCode;
1172 LogPacket->DeviceOffset.QuadPart = 0; /* FIXME */
1173 LogPacket->DumpData[0] = Srb->PathId;
1174 LogPacket->DumpData[1] = Srb->TargetId;
1175 LogPacket->DumpData[2] = Srb->Lun;
1176 LogPacket->DumpData[3] = 0;
1177 LogPacket->DumpData[4] = (Srb->SrbStatus << 8) | Srb->ScsiStatus;
1178 if (SenseData != NULL)
1180 LogPacket->DumpData[5] = (SenseData->SenseKey << 16) |
1181 (SenseData->AdditionalSenseCode << 8) |
1182 SenseData->AdditionalSenseCodeQualifier;
1185 /* Write error packet */
1186 IoWriteErrorLogEntry (LogPacket);
1190 DPRINT("ScsiClassInterpretSenseInfo() done\n");
1200 ScsiClassIoComplete(IN PDEVICE_OBJECT DeviceObject,
1204 PDEVICE_EXTENSION DeviceExtension;
1205 PIO_STACK_LOCATION IrpStack;
1206 PSCSI_REQUEST_BLOCK Srb;
1210 DPRINT("ScsiClassIoComplete(DeviceObject %p Irp %p Context %p) called\n",
1211 DeviceObject, Irp, Context);
1213 DeviceExtension = DeviceObject->DeviceExtension;
1215 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1218 * BUGBUG -> Srb = IrpStack->Parameters.Scsi.Srb;
1219 * Must pass Srb as Context arg!! See comment about Completion routines in
1220 * IofCallDriver for more info.
1223 Srb = (PSCSI_REQUEST_BLOCK)Context;
1225 DPRINT("Srb %p\n", Srb);
1227 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
1229 Status = STATUS_SUCCESS;
1233 Retry = ScsiClassInterpretSenseInfo(DeviceObject,
1235 IrpStack->MajorFunction,
1237 MAXIMUM_RETRIES - ((ULONG)IrpStack->Parameters.Others.Argument4),
1240 ((ULONG)IrpStack->Parameters.Others.Argument4 > 0))
1242 ((ULONG)IrpStack->Parameters.Others.Argument4)--;
1244 ScsiClassRetryRequest(DeviceObject,
1249 return(STATUS_MORE_PROCESSING_REQUIRED);
1254 ExFreeToNPagedLookasideList(&DeviceExtension->SrbLookasideListHead,
1257 Irp->IoStatus.Status = Status;
1258 if (!NT_SUCCESS(Status))
1260 Irp->IoStatus.Information = 0;
1261 if (IoIsErrorUserInduced(Status))
1263 IoSetHardErrorOrVerifyDevice(Irp,
1268 if (DeviceExtension->ClassStartIo != NULL)
1270 if (IrpStack->MajorFunction != IRP_MJ_DEVICE_CONTROL)
1272 IoStartNextPacket(DeviceObject,
1277 DPRINT("ScsiClassIoComplete() done (Status %lx)\n", Status);
1287 ScsiClassIoCompleteAssociated(IN PDEVICE_OBJECT DeviceObject,
1291 PDEVICE_EXTENSION DeviceExtension;
1292 PIO_STACK_LOCATION IrpStack;
1293 PSCSI_REQUEST_BLOCK Srb;
1299 DPRINT("ScsiClassIoCompleteAssociated(DeviceObject %p Irp %p Context %p) called\n",
1300 DeviceObject, Irp, Context);
1302 MasterIrp = Irp->AssociatedIrp.MasterIrp;
1303 DeviceExtension = DeviceObject->DeviceExtension;
1305 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1308 * BUGBUG -> Srb = Srb = IrpStack->Parameters.Scsi.Srb;
1309 * Must pass Srb as Context arg!! See comment about Completion routines in
1310 * IofCallDriver for more info.
1313 Srb = (PSCSI_REQUEST_BLOCK)Context;
1315 DPRINT("Srb %p\n", Srb);
1317 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
1319 Status = STATUS_SUCCESS;
1323 /* Get more detailed status information */
1324 Retry = ScsiClassInterpretSenseInfo(DeviceObject,
1326 IrpStack->MajorFunction,
1328 MAXIMUM_RETRIES - ((ULONG)IrpStack->Parameters.Others.Argument4),
1332 ((ULONG)IrpStack->Parameters.Others.Argument4 > 0))
1334 ((ULONG)IrpStack->Parameters.Others.Argument4)--;
1336 ScsiClassRetryRequest(DeviceObject,
1341 return(STATUS_MORE_PROCESSING_REQUIRED);
1346 ExFreeToNPagedLookasideList(&DeviceExtension->SrbLookasideListHead,
1349 Irp->IoStatus.Status = Status;
1351 IrpStack = IoGetNextIrpStackLocation(MasterIrp);
1352 if (!NT_SUCCESS(Status))
1354 MasterIrp->IoStatus.Status = Status;
1355 MasterIrp->IoStatus.Information = 0;
1357 if (IoIsErrorUserInduced(Status))
1359 IoSetHardErrorOrVerifyDevice(MasterIrp,
1364 /* Decrement the request counter in the Master IRP */
1365 RequestCount = InterlockedDecrement((PLONG)&IrpStack->Parameters.Others.Argument1);
1367 if (RequestCount == 0)
1369 /* Complete the Master IRP */
1370 IoCompleteRequest(MasterIrp,
1373 if (DeviceExtension->ClassStartIo)
1375 IoStartNextPacket(DeviceObject,
1380 /* Free the current IRP */
1383 return(STATUS_MORE_PROCESSING_REQUIRED);
1391 ScsiClassModeSense(IN PDEVICE_OBJECT DeviceObject,
1392 IN PCHAR ModeSenseBuffer,
1396 PDEVICE_EXTENSION DeviceExtension;
1397 SCSI_REQUEST_BLOCK Srb;
1402 DPRINT("ScsiClassModeSense() called\n");
1404 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1407 /* Initialize the SRB */
1408 RtlZeroMemory (&Srb,
1409 sizeof(SCSI_REQUEST_BLOCK));
1411 Srb.TimeOutValue = DeviceExtension->TimeOutValue;
1413 /* Initialize the CDB */
1414 Cdb = (PCDB)&Srb.Cdb;
1415 Cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
1416 Cdb->MODE_SENSE.PageCode = PageMode;
1417 Cdb->MODE_SENSE.AllocationLength = (UCHAR)Length;
1420 Status = ScsiClassSendSrbSynchronous (DeviceObject,
1425 if (Status == STATUS_VERIFY_REQUIRED)
1427 if (RetryCount != 0)
1433 else if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN)
1435 Status = STATUS_SUCCESS;
1438 if (!NT_SUCCESS(Status))
1443 return Srb.DataTransferLength;
1451 ScsiClassQueryTimeOutRegistryValue(IN PUNICODE_STRING RegistryPath)
1453 PRTL_QUERY_REGISTRY_TABLE Table;
1460 if (RegistryPath == NULL)
1468 /* Allocate zero-terminated path string */
1469 Size = RegistryPath->Length + sizeof(WCHAR);
1470 Path = (PWSTR)ExAllocatePool (NonPagedPool,
1476 RtlZeroMemory (Path,
1478 RtlCopyMemory (Path,
1479 RegistryPath->Buffer,
1480 Size - sizeof(WCHAR));
1482 /* Allocate query table */
1483 Size = sizeof(RTL_QUERY_REGISTRY_TABLE) * 2;
1484 Table = (PRTL_QUERY_REGISTRY_TABLE)ExAllocatePool (NonPagedPool,
1491 RtlZeroMemory (Table,
1494 Table[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
1495 Table[0].Name = L"TimeOutValue";
1496 Table[0].EntryContext = &TimeOutValue;
1497 Table[0].DefaultType = REG_DWORD;
1498 Table[0].DefaultData = &ZeroTimeOut;
1499 Table[0].DefaultLength = sizeof(ULONG);
1501 Status = RtlQueryRegistryValues (RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
1506 if (!NT_SUCCESS(Status))
1508 DPRINT("RtlQueryRegistryValue() failed (Status %lx)\n", Status);
1515 DPRINT("TimeOut: %lu\n", TimeOutValue);
1517 return TimeOutValue;
1525 ScsiClassReadDriveCapacity(IN PDEVICE_OBJECT DeviceObject)
1527 PDEVICE_EXTENSION DeviceExtension;
1528 PREAD_CAPACITY_DATA CapacityBuffer;
1529 SCSI_REQUEST_BLOCK Srb;
1535 DPRINT("ScsiClassReadDriveCapacity() called\n");
1537 DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1539 CapacityBuffer = ExAllocatePool(NonPagedPool,
1540 sizeof(READ_CAPACITY_DATA));
1541 if (CapacityBuffer == NULL)
1543 return(STATUS_INSUFFICIENT_RESOURCES);
1546 RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
1549 Srb.TimeOutValue = DeviceExtension->TimeOutValue;
1551 Cdb = (PCDB)Srb.Cdb;
1552 Cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
1555 Status = ScsiClassSendSrbSynchronous(DeviceObject,
1558 sizeof(READ_CAPACITY_DATA),
1560 DPRINT("Status: %lx\n", Status);
1561 DPRINT("Srb: %p\n", &Srb);
1562 if (NT_SUCCESS(Status))
1564 SectorSize = (((PUCHAR)&CapacityBuffer->BytesPerBlock)[0] << 24) |
1565 (((PUCHAR)&CapacityBuffer->BytesPerBlock)[1] << 16) |
1566 (((PUCHAR)&CapacityBuffer->BytesPerBlock)[2] << 8) |
1567 ((PUCHAR)&CapacityBuffer->BytesPerBlock)[3];
1570 LastSector = (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[0] << 24) |
1571 (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[1] << 16) |
1572 (((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[2] << 8) |
1573 ((PUCHAR)&CapacityBuffer->LogicalBlockAddress)[3];
1575 DeviceExtension->DiskGeometry->BytesPerSector = SectorSize;
1577 DeviceExtension->PartitionLength.QuadPart = (LONGLONG)(LastSector + 1);
1578 WHICH_BIT(DeviceExtension->DiskGeometry->BytesPerSector,
1579 DeviceExtension->SectorShift);
1580 DeviceExtension->PartitionLength.QuadPart =
1581 (DeviceExtension->PartitionLength.QuadPart << DeviceExtension->SectorShift);
1583 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
1585 DeviceExtension->DiskGeometry->MediaType = RemovableMedia;
1589 DeviceExtension->DiskGeometry->MediaType = FixedMedia;
1591 DeviceExtension->DiskGeometry->Cylinders.QuadPart = (LONGLONG)((LastSector + 1)/(32 * 64));
1592 DeviceExtension->DiskGeometry->SectorsPerTrack = 32;
1593 DeviceExtension->DiskGeometry->TracksPerCylinder = 64;
1595 DPRINT("SectorSize: %lu SectorCount: %lu\n", SectorSize, LastSector + 1);
1599 /* Use default values if disk geometry cannot be read */
1600 RtlZeroMemory(DeviceExtension->DiskGeometry,
1601 sizeof(DISK_GEOMETRY));
1602 DeviceExtension->DiskGeometry->BytesPerSector = 512;
1603 DeviceExtension->SectorShift = 9;
1604 DeviceExtension->PartitionLength.QuadPart = 0;
1606 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
1608 DeviceExtension->DiskGeometry->MediaType = RemovableMedia;
1612 DeviceExtension->DiskGeometry->MediaType = FixedMedia;
1615 DPRINT("SectorSize: 512 SectorCount: 0\n");
1618 ExFreePool(CapacityBuffer);
1620 DPRINT("ScsiClassReadDriveCapacity() done\n");
1630 ScsiClassReleaseQueue(IN PDEVICE_OBJECT DeviceObject)
1640 ScsiClassSendSrbAsynchronous(PDEVICE_OBJECT DeviceObject,
1641 PSCSI_REQUEST_BLOCK Srb,
1643 PVOID BufferAddress,
1645 BOOLEAN WriteToDevice)
1647 PDEVICE_EXTENSION DeviceExtension;
1648 PIO_STACK_LOCATION Stack;
1650 DPRINT("ScsiClassSendSrbAsynchronous() called\n");
1652 DeviceExtension = DeviceObject->DeviceExtension;
1654 /* Initialize the SRB */
1655 Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1656 Srb->PathId = DeviceExtension->PathId;
1657 Srb->TargetId = DeviceExtension->TargetId;
1658 Srb->Lun = DeviceExtension->Lun;
1659 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1660 Srb->Cdb[1] |= DeviceExtension->Lun << 5;
1662 Srb->SenseInfoBuffer = DeviceExtension->SenseData;
1663 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1665 Srb->DataBuffer = BufferAddress;
1666 Srb->DataTransferLength = BufferLength;
1668 Srb->ScsiStatus = 0;
1670 Srb->NextSrb = NULL;
1672 if (BufferAddress != NULL)
1674 if (Irp->MdlAddress == NULL)
1676 /* Allocate an MDL */
1677 if (!IoAllocateMdl(BufferAddress,
1683 DPRINT1("Mdl-Allocation failed\n");
1684 return(STATUS_INSUFFICIENT_RESOURCES);
1687 MmBuildMdlForNonPagedPool(Irp->MdlAddress);
1690 /* Set data direction */
1691 Srb->SrbFlags = (WriteToDevice) ? SRB_FLAGS_DATA_OUT : SRB_FLAGS_DATA_IN;
1695 /* Set data direction */
1696 Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
1699 /* Set the retry counter */
1700 Stack = IoGetCurrentIrpStackLocation(Irp);
1701 Stack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
1703 /* Set the completion routine */
1704 IoSetCompletionRoutine(Irp,
1705 ScsiClassIoComplete,
1711 /* Attach Srb to the Irp */
1712 Stack = IoGetNextIrpStackLocation(Irp);
1713 Stack->MajorFunction = IRP_MJ_SCSI;
1714 Stack->Parameters.Scsi.Srb = Srb;
1715 Srb->OriginalRequest = Irp;
1717 /* Call the port driver */
1718 return(IoCallDriver(DeviceExtension->PortDeviceObject,
1727 ScsiClassSendSrbSynchronous(PDEVICE_OBJECT DeviceObject,
1728 PSCSI_REQUEST_BLOCK Srb,
1729 PVOID BufferAddress,
1731 BOOLEAN WriteToDevice)
1733 PDEVICE_EXTENSION DeviceExtension;
1734 IO_STATUS_BLOCK IoStatusBlock;
1735 PIO_STACK_LOCATION IrpStack;
1743 DPRINT("ScsiClassSendSrbSynchronous() called\n");
1745 RetryCount = MAXIMUM_RETRIES;
1746 DeviceExtension = DeviceObject->DeviceExtension;
1748 Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
1749 Srb->PathId = DeviceExtension->PathId;
1750 Srb->TargetId = DeviceExtension->TargetId;
1751 Srb->Lun = DeviceExtension->Lun;
1752 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1754 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
1755 Srb->SenseInfoBuffer = ExAllocatePool(NonPagedPool,
1757 if (Srb->SenseInfoBuffer == NULL)
1758 return(STATUS_INSUFFICIENT_RESOURCES);
1760 if (BufferAddress == NULL)
1763 RequestType = IOCTL_SCSI_EXECUTE_NONE;
1764 Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
1768 if (WriteToDevice == TRUE)
1770 RequestType = IOCTL_SCSI_EXECUTE_IN; // needs _in_ to the device
1771 Srb->SrbFlags = SRB_FLAGS_DATA_OUT; // needs _out_ from the caller
1775 RequestType = IOCTL_SCSI_EXECUTE_OUT;
1776 Srb->SrbFlags = SRB_FLAGS_DATA_IN;
1780 Srb->DataTransferLength = BufferLength;
1781 Srb->DataBuffer = BufferAddress;
1783 Event = ExAllocatePool(NonPagedPool,
1786 KeInitializeEvent(Event,
1790 Irp = IoBuildDeviceIoControlRequest(RequestType,
1791 DeviceExtension->PortDeviceObject,
1801 DPRINT("IoBuildDeviceIoControlRequest() failed\n");
1802 ExFreePool(Srb->SenseInfoBuffer);
1804 return(STATUS_INSUFFICIENT_RESOURCES);
1807 /* Attach Srb to the Irp */
1808 IrpStack = IoGetNextIrpStackLocation(Irp);
1809 IrpStack->Parameters.Scsi.Srb = Srb;
1810 Srb->OriginalRequest = Irp;
1812 /* Call the SCSI port driver */
1813 Status = IoCallDriver(DeviceExtension->PortDeviceObject,
1815 if (Status == STATUS_PENDING)
1817 KeWaitForSingleObject(Event,
1824 if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS)
1826 Retry = ScsiClassInterpretSenseInfo(DeviceObject,
1830 MAXIMUM_RETRIES - RetryCount,
1834 DPRINT("Try again (RetryCount %lu)\n", RetryCount);
1836 /* FIXME: Wait a little if we got a timeout error */
1844 Status = STATUS_SUCCESS;
1847 ExFreePool(Srb->SenseInfoBuffer);
1850 DPRINT("ScsiClassSendSrbSynchronous() done\n");
1860 ScsiClassSplitRequest(IN PDEVICE_OBJECT DeviceObject,
1862 IN ULONG MaximumBytes)
1864 PDEVICE_EXTENSION DeviceExtension;
1865 PIO_STACK_LOCATION CurrentStack;
1866 PIO_STACK_LOCATION NextStack;
1867 PIO_STACK_LOCATION NewStack;
1868 PSCSI_REQUEST_BLOCK Srb;
1869 LARGE_INTEGER Offset;
1872 ULONG TransferLength;
1877 DPRINT("ScsiClassSplitRequest(DeviceObject %lx Irp %lx MaximumBytes %lu)\n",
1878 DeviceObject, Irp, MaximumBytes);
1880 DeviceExtension = DeviceObject->DeviceExtension;
1881 CurrentStack = IoGetCurrentIrpStackLocation(Irp);
1882 NextStack = IoGetNextIrpStackLocation(Irp);
1883 DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
1885 /* Initialize transfer data for first request */
1886 Offset = CurrentStack->Parameters.Read.ByteOffset;
1887 TransferLength = CurrentStack->Parameters.Read.Length;
1888 DataLength = MaximumBytes;
1889 RequestCount = ROUND_UP(TransferLength, MaximumBytes) / MaximumBytes;
1891 /* Save request count in the original IRP */
1892 NextStack->Parameters.Others.Argument1 = (PVOID)RequestCount;
1894 DPRINT("RequestCount %lu\n", RequestCount);
1896 for (i = 0; i < RequestCount; i++)
1898 /* Create a new IRP */
1899 NewIrp = IoAllocateIrp(DeviceObject->StackSize,
1903 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1904 Irp->IoStatus.Information = 0;
1907 IoCompleteRequest(Irp,
1912 /* Initialize the new IRP */
1913 NewIrp->MdlAddress = Irp->MdlAddress;
1915 IoSetNextIrpStackLocation(NewIrp);
1916 NewStack = IoGetCurrentIrpStackLocation(NewIrp);
1918 NewStack->MajorFunction = CurrentStack->MajorFunction;
1919 NewStack->Parameters.Read.ByteOffset = Offset;
1920 NewStack->Parameters.Read.Length = DataLength;
1921 NewStack->DeviceObject = DeviceObject;
1923 ScsiClassBuildRequest(DeviceObject,
1926 NewStack = IoGetNextIrpStackLocation(NewIrp);
1927 Srb = NewStack->Parameters.Others.Argument1;
1928 Srb->DataBuffer = DataBuffer;
1930 NewIrp->AssociatedIrp.MasterIrp = Irp;
1932 /* Initialize completion routine */
1933 IoSetCompletionRoutine(NewIrp,
1934 ScsiClassIoCompleteAssociated,
1940 /* Send the new IRP down to the port driver */
1941 IoCallDriver(DeviceExtension->PortDeviceObject,
1944 /* Adjust transfer data for next request */
1945 DataBuffer = (PCHAR)DataBuffer + MaximumBytes;
1946 TransferLength -= MaximumBytes;
1947 DataLength = (TransferLength > MaximumBytes) ? MaximumBytes : TransferLength;
1948 Offset.QuadPart = Offset.QuadPart + MaximumBytes;
1953 /* INTERNAL FUNCTIONS *******************************************************/
1955 static NTSTATUS STDCALL
1956 ScsiClassCreateClose(IN PDEVICE_OBJECT DeviceObject,
1959 PDEVICE_EXTENSION DeviceExtension;
1961 DPRINT("ScsiClassCreateClose() called\n");
1963 DeviceExtension = DeviceObject->DeviceExtension;
1965 if (DeviceExtension->ClassCreateClose)
1966 return(DeviceExtension->ClassCreateClose(DeviceObject,
1969 Irp->IoStatus.Status = STATUS_SUCCESS;
1970 Irp->IoStatus.Information = 0;
1971 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1973 return(STATUS_SUCCESS);
1977 static NTSTATUS STDCALL
1978 ScsiClassReadWrite(IN PDEVICE_OBJECT DeviceObject,
1981 PDEVICE_EXTENSION DeviceExtension;
1982 PIO_STACK_LOCATION IrpStack;
1983 ULONG MaximumTransferLength;
1984 ULONG CurrentTransferLength;
1985 ULONG MaximumTransferPages;
1986 ULONG CurrentTransferPages;
1989 DPRINT("ScsiClassReadWrite() called\n");
1991 DeviceExtension = DeviceObject->DeviceExtension;
1992 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1994 DPRINT("Relative Offset: %I64u Length: %lu\n",
1995 IrpStack->Parameters.Read.ByteOffset.QuadPart,
1996 IrpStack->Parameters.Read.Length);
1998 MaximumTransferLength = DeviceExtension->PortCapabilities->MaximumTransferLength;
1999 MaximumTransferPages = DeviceExtension->PortCapabilities->MaximumPhysicalPages;
2001 CurrentTransferLength = IrpStack->Parameters.Read.Length;
2003 if ((DeviceObject->Flags & DO_VERIFY_VOLUME) &&
2004 !(IrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME))
2006 IoSetHardErrorOrVerifyDevice(Irp,
2009 Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
2010 Irp->IoStatus.Information = 0;
2012 IoCompleteRequest(Irp,
2014 return(STATUS_VERIFY_REQUIRED);
2017 /* Class driver verifies the IRP */
2018 Status = DeviceExtension->ClassReadWriteVerification(DeviceObject,
2020 if (!NT_SUCCESS(Status))
2022 IoCompleteRequest(Irp,
2026 else if (Status == STATUS_PENDING)
2028 IoMarkIrpPending(Irp);
2029 return(STATUS_PENDING);
2032 /* Finish a zero-byte transfer */
2033 if (CurrentTransferLength == 0)
2035 Irp->IoStatus.Status = STATUS_SUCCESS;
2036 Irp->IoStatus.Information = 0;
2037 IoCompleteRequest(Irp,
2039 return(STATUS_SUCCESS);
2042 if (DeviceExtension->ClassStartIo != NULL)
2044 DPRINT("ScsiClassReadWrite() starting packet\n");
2046 IoMarkIrpPending(Irp);
2047 IoStartPacket(DeviceObject,
2052 return(STATUS_PENDING);
2055 /* Adjust partition-relative starting offset to absolute offset */
2056 IrpStack->Parameters.Read.ByteOffset.QuadPart +=
2057 (DeviceExtension->StartingOffset.QuadPart + DeviceExtension->DMByteSkew);
2059 /* Calculate number of pages in this transfer */
2060 CurrentTransferPages =
2061 ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
2062 IrpStack->Parameters.Read.Length);
2064 if (CurrentTransferLength > MaximumTransferLength ||
2065 CurrentTransferPages > MaximumTransferPages)
2067 DPRINT("Split current request: MaximumTransferLength %lu CurrentTransferLength %lu\n",
2068 MaximumTransferLength, CurrentTransferLength);
2070 /* Adjust the maximum transfer length */
2071 CurrentTransferPages = DeviceExtension->PortCapabilities->MaximumPhysicalPages;
2073 if (MaximumTransferLength > CurrentTransferPages * PAGE_SIZE)
2074 MaximumTransferLength = CurrentTransferPages * PAGE_SIZE;
2076 if (MaximumTransferLength == 0)
2077 MaximumTransferLength = PAGE_SIZE;
2079 IoMarkIrpPending(Irp);
2081 /* Split current request */
2082 ScsiClassSplitRequest(DeviceObject,
2084 MaximumTransferLength);
2086 return(STATUS_PENDING);
2089 ScsiClassBuildRequest(DeviceObject,
2092 DPRINT("ScsiClassReadWrite() done\n");
2094 /* Call the port driver */
2095 return(IoCallDriver(DeviceExtension->PortDeviceObject,
2100 static NTSTATUS STDCALL
2101 ScsiClassDeviceDispatch(IN PDEVICE_OBJECT DeviceObject,
2104 PDEVICE_EXTENSION DeviceExtension;
2106 DPRINT("ScsiClassDeviceDispatch() called\n");
2108 DeviceExtension = DeviceObject->DeviceExtension;
2109 if (DeviceExtension->ClassDeviceControl)
2111 return(DeviceExtension->ClassDeviceControl(DeviceObject, Irp));
2114 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
2115 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2117 return(STATUS_INVALID_DEVICE_REQUEST);
2121 static NTSTATUS STDCALL
2122 ScsiClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
2125 PDEVICE_EXTENSION DeviceExtension;
2127 DPRINT("ScsiClassShutdownFlush() called\n");
2129 DeviceExtension = DeviceObject->DeviceExtension;
2130 if (DeviceExtension->ClassShutdownFlush)
2132 return(DeviceExtension->ClassShutdownFlush(DeviceObject, Irp));
2135 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
2136 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2138 return(STATUS_INVALID_DEVICE_REQUEST);
2143 ScsiClassRetryRequest(PDEVICE_OBJECT DeviceObject,
2145 PSCSI_REQUEST_BLOCK Srb,
2148 PDEVICE_EXTENSION DeviceExtension;
2149 PIO_STACK_LOCATION CurrentIrpStack;
2150 PIO_STACK_LOCATION NextIrpStack;
2152 ULONG TransferLength;
2154 DPRINT("ScsiPortRetryRequest() called\n");
2156 DeviceExtension = DeviceObject->DeviceExtension;
2157 CurrentIrpStack = IoGetCurrentIrpStackLocation(Irp);
2158 NextIrpStack = IoGetNextIrpStackLocation(Irp);
2160 if (CurrentIrpStack->MajorFunction != IRP_MJ_READ &&
2161 CurrentIrpStack->MajorFunction != IRP_MJ_WRITE)
2163 /* We shouldn't setup the buffer pointer and transfer length on read/write requests. */
2164 if (Irp->MdlAddress != NULL)
2166 TransferLength = Irp->MdlAddress->ByteCount;
2173 Srb->DataBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
2174 Srb->DataTransferLength = TransferLength;
2178 Srb->ScsiStatus = 0;
2180 /* Don't modify the flags */
2182 // Srb->QueueTag = SP_UNTAGGED;
2184 NextIrpStack->MajorFunction = IRP_MJ_SCSI;
2185 NextIrpStack->Parameters.Scsi.Srb = Srb;
2187 if (Associated == FALSE)
2189 IoSetCompletionRoutine(Irp,
2190 ScsiClassIoComplete,
2198 IoSetCompletionRoutine(Irp,
2199 ScsiClassIoCompleteAssociated,
2206 IoCallDriver(DeviceExtension->PortDeviceObject,
2209 DPRINT("ScsiPortRetryRequest() done\n");