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.
19 /* $Id: class2.c,v 1.39 2003/08/27 21:28:08 dwelch Exp $
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");