3 * Copyright (C) 2001, 2002 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: scsiport.c,v 1.12 2002/03/27 00:35:52 ekohl Exp $
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * FILE: services/storage/scsiport/scsiport.c
24 * PURPOSE: SCSI port driver
25 * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
28 /* INCLUDES *****************************************************************/
30 #include <ddk/ntddk.h>
31 #include "../include/srb.h"
32 #include "../include/scsi.h"
33 #include "../include/ntddscsi.h"
39 #define VERSION "0.0.1"
42 /* TYPES *********************************************************************/
45 typedef enum _SCSI_PORT_TIMER_STATES
49 IDETimerResetWaitForBusyNegate
,
50 IDETimerResetWaitForDrdyAssert
51 } SCSI_PORT_TIMER_STATES
;
55 * SCSI_PORT_DEVICE_EXTENSION
58 * First part of the port objects device extension. The second
59 * part is the miniport-specific device extension.
62 typedef struct _SCSI_PORT_DEVICE_EXTENSION
65 ULONG MiniPortExtensionSize
;
66 PORT_CONFIGURATION_INFORMATION PortConfig
;
69 PKINTERRUPT Interrupt
;
73 SCSI_PORT_TIMER_STATES TimerState
;
78 ULONG PortBusInfoSize
;
79 PSCSI_ADAPTER_BUS_INFO PortBusInfo
;
81 PDEVICE_OBJECT DeviceObject
;
82 PCONTROLLER_OBJECT ControllerObject
;
84 PHW_STARTIO HwStartIo
;
85 PHW_INTERRUPT HwInterrupt
;
87 PSCSI_REQUEST_BLOCK OriginalSrb
;
88 SCSI_REQUEST_BLOCK InternalSrb
;
89 SENSE_DATA InternalSenseData
;
91 UCHAR MiniPortDeviceExtension
[1]; /* must be the last entry */
92 } SCSI_PORT_DEVICE_EXTENSION
, *PSCSI_PORT_DEVICE_EXTENSION
;
96 * SCSI_PORT_TIMER_STATES
99 * An enumeration containing the states in the timer DFA
104 #define IRP_FLAG_COMPLETE 0x00000001
105 #define IRP_FLAG_NEXT 0x00000002
108 /* GLOBALS *******************************************************************/
110 static NTSTATUS STDCALL
111 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
114 static NTSTATUS STDCALL
115 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
118 static NTSTATUS STDCALL
119 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
123 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
126 static IO_ALLOCATION_ACTION STDCALL
127 ScsiPortAllocateController(IN PDEVICE_OBJECT DeviceObject
,
129 IN PVOID MapRegisterBase
,
132 static BOOLEAN STDCALL
133 ScsiPortStartPacket(IN OUT PVOID Context
);
136 ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject
,
137 IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension
,
141 ScsiPortInquire(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
143 static BOOLEAN STDCALL
144 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
145 IN PVOID ServiceContext
);
148 ScsiPortDpcForIsr(IN PKDPC Dpc
,
149 IN PDEVICE_OBJECT DpcDeviceObject
,
151 IN PVOID DpcContext
);
154 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
157 static PSCSI_REQUEST_BLOCK
158 ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
159 PSCSI_REQUEST_BLOCK OriginalSrb
);
161 /* FUNCTIONS *****************************************************************/
163 /**********************************************************************
168 * This function initializes the driver.
175 * System allocated Driver Object for this driver.
178 * Name of registry driver service key.
185 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
186 IN PUNICODE_STRING RegistryPath
)
188 DbgPrint("ScsiPort Driver %s\n", VERSION
);
189 return(STATUS_SUCCESS
);
193 /**********************************************************************
198 * Prints debugging messages.
205 * Debug level of the given message.
208 * Pointer to printf()-compatible format string.
211 Additional output data (see printf()).
218 ScsiDebugPrint(IN ULONG DebugPrintLevel
,
219 IN PCHAR DebugMessage
,
226 if (DebugPrintLevel
> InternalDebugLevel
)
230 va_start(ap
, DebugMessage
);
231 vsprintf(Buffer
, DebugMessage
, ap
);
239 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension
,
250 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address
)
252 return(Address
.u
.LowPart
);
257 ScsiPortFlushDma(IN PVOID HwDeviceExtension
)
264 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension
,
265 IN PVOID MappedAddress
)
272 ScsiPortGetBusData(IN PVOID DeviceExtension
,
273 IN ULONG BusDataType
,
274 IN ULONG SystemIoBusNumber
,
279 return(HalGetBusData(BusDataType
,
288 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension
,
289 IN INTERFACE_TYPE BusType
,
290 IN ULONG SystemIoBusNumber
,
291 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
292 IN ULONG NumberOfBytes
,
293 IN BOOLEAN InIoSpace
)
296 PHYSICAL_ADDRESS TranslatedAddress
;
297 PVOID VirtualAddress
;
301 AddressSpace
= (ULONG
)InIoSpace
;
303 if (!HalTranslateBusAddress(BusType
,
311 if (AddressSpace
!= 0)
312 return (PVOID
)TranslatedAddress
.u
.LowPart
;
314 VirtualAddress
= MmMapIoSpace(TranslatedAddress
,
318 Buffer
= ExAllocatePool(NonPagedPool
,0x20);
320 return VirtualAddress
;
322 return NULL
; /* ?? */
327 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension
,
336 SCSI_PHYSICAL_ADDRESS STDCALL
337 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension
,
338 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
339 IN PVOID VirtualAddress
,
346 PSCSI_REQUEST_BLOCK STDCALL
347 ScsiPortGetSrb(IN PVOID DeviceExtension
,
358 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension
,
359 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
360 IN ULONG NumberOfBytes
)
367 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension
,
368 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress
)
374 /**********************************************************************
379 * Initializes SCSI port driver specific data.
386 * Pointer to the miniport driver's driver object.
389 * Pointer to the miniport driver's registry path.
391 * HwInitializationData
392 * Pointer to port driver specific configuration data.
395 Miniport driver specific context.
402 ScsiPortInitialize(IN PVOID Argument1
,
404 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
407 PDRIVER_OBJECT DriverObject
= (PDRIVER_OBJECT
)Argument1
;
408 PUNICODE_STRING RegistryPath
= (PUNICODE_STRING
)Argument2
;
409 PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension
;
410 PCONFIGURATION_INFORMATION SystemConfig
;
411 PPORT_CONFIGURATION_INFORMATION PortConfig
;
417 PACCESS_RANGE AccessRanges
;
420 DPRINT("ScsiPortInitialize() called!\n");
422 if ((HwInitializationData
->HwInitialize
== NULL
) ||
423 (HwInitializationData
->HwStartIo
== NULL
) ||
424 (HwInitializationData
->HwInterrupt
== NULL
) ||
425 (HwInitializationData
->HwFindAdapter
== NULL
) ||
426 (HwInitializationData
->HwResetBus
== NULL
))
427 return(STATUS_INVALID_PARAMETER
);
429 DriverObject
->DriverStartIo
= ScsiPortStartIo
;
430 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ScsiPortCreateClose
;
431 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ScsiPortCreateClose
;
432 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ScsiPortDeviceControl
;
433 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = ScsiPortDispatchScsi
;
436 SystemConfig
= IoGetConfigurationInformation();
438 ExtensionSize
= sizeof(SCSI_PORT_DEVICE_EXTENSION
) +
439 HwInitializationData
->DeviceExtensionSize
;
440 PseudoDeviceExtension
= ExAllocatePool(PagedPool
,
442 RtlZeroMemory(PseudoDeviceExtension
,
444 PseudoDeviceExtension
->Length
= ExtensionSize
;
445 PseudoDeviceExtension
->MiniPortExtensionSize
= HwInitializationData
->DeviceExtensionSize
;
446 PseudoDeviceExtension
->HwStartIo
= HwInitializationData
->HwStartIo
;
447 PseudoDeviceExtension
->HwInterrupt
= HwInitializationData
->HwInterrupt
;
449 PortConfig
= &PseudoDeviceExtension
->PortConfig
;
451 PortConfig
->Length
= sizeof(PORT_CONFIGURATION_INFORMATION
);
452 PortConfig
->AdapterInterfaceType
= HwInitializationData
->AdapterInterfaceType
;
453 PortConfig
->InterruptMode
=
454 (PortConfig
->AdapterInterfaceType
== PCIBus
) ? LevelSensitive
: Latched
;
455 PortConfig
->AtdiskPrimaryClaimed
= SystemConfig
->AtDiskPrimaryAddressClaimed
;
456 PortConfig
->AtdiskSecondaryClaimed
= SystemConfig
->AtDiskSecondaryAddressClaimed
;
457 PortConfig
->NumberOfAccessRanges
= HwInitializationData
->NumberOfAccessRanges
;
459 PortConfig
->AccessRanges
=
460 ExAllocatePool(PagedPool
,
461 sizeof(ACCESS_RANGE
) * PortConfig
->NumberOfAccessRanges
);
464 PortConfig
->SystemIoBusNumber
= 0;
465 PortConfig
->SlotNumber
= 0;
467 MaxBus
= (PortConfig
->AdapterInterfaceType
== PCIBus
) ? 8 : 1;
469 DPRINT("MaxBus: %lu\n", MaxBus
);
473 DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig
->SystemIoBusNumber
);
475 // RtlZeroMemory(AccessRanges,
476 // sizeof(ACCESS_RANGE) * PortConfig->NumberOfAccessRanges);
478 RtlZeroMemory(PseudoDeviceExtension
->MiniPortDeviceExtension
,
479 PseudoDeviceExtension
->MiniPortExtensionSize
);
481 /* Note: HwFindAdapter is called once for each bus */
482 Result
= (HwInitializationData
->HwFindAdapter
)(&PseudoDeviceExtension
->MiniPortDeviceExtension
,
484 NULL
, /* BusInformation */
485 NULL
, /* ArgumentString */
486 &PseudoDeviceExtension
->PortConfig
,
488 DPRINT("HwFindAdapter() result: %lu\n", Result
);
490 if (Result
== SP_RETURN_FOUND
)
492 DPRINT("ScsiPortInitialize(): Found HBA!\n");
494 Status
= ScsiPortCreatePortDevice(DriverObject
,
495 PseudoDeviceExtension
,
496 SystemConfig
->ScsiPortCount
);
498 if (!NT_SUCCESS(Status
))
500 DbgPrint("ScsiPortCreatePortDevice() failed! (Status 0x%lX)\n", Status
);
502 ExFreePool(PortConfig
->AccessRanges
);
503 ExFreePool(PseudoDeviceExtension
);
508 /* Update the configuration info */
509 SystemConfig
->AtDiskPrimaryAddressClaimed
= PortConfig
->AtdiskPrimaryClaimed
;
510 SystemConfig
->AtDiskSecondaryAddressClaimed
= PortConfig
->AtdiskSecondaryClaimed
;
511 SystemConfig
->ScsiPortCount
++;
516 PortConfig
->SystemIoBusNumber
++;
517 PortConfig
->SlotNumber
= 0;
520 DPRINT("Bus: %lu MaxBus: %lu\n", PortConfig
->SystemIoBusNumber
, MaxBus
);
521 if (PortConfig
->SystemIoBusNumber
>= MaxBus
)
523 DPRINT("Scanned all buses!\n");
528 ExFreePool(PortConfig
->AccessRanges
);
529 ExFreePool(PseudoDeviceExtension
);
531 DPRINT("ScsiPortInitialize() done!\n");
533 return(STATUS_SUCCESS
);
538 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension
,
539 IN PSCSI_REQUEST_BLOCK Srb
,
540 IN ULONG LogicalAddress
,
548 ScsiPortLogError(IN PVOID HwDeviceExtension
,
549 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
561 ScsiPortMoveMemory(OUT PVOID Destination
,
565 RtlMoveMemory(Destination
,
572 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType
,
573 IN PVOID HwDeviceExtension
,
576 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
578 DPRINT("ScsiPortNotification() called\n");
580 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
581 SCSI_PORT_DEVICE_EXTENSION
,
582 MiniPortDeviceExtension
);
584 DPRINT("DeviceExtension %p\n", DeviceExtension
);
586 DPRINT("Initializing = %s\n", (DeviceExtension
->Initializing
)?"TRUE":"FALSE");
588 if (DeviceExtension
->Initializing
== TRUE
)
591 switch (NotificationType
)
593 case RequestComplete
:
594 DPRINT("Notify: RequestComplete\n");
595 DeviceExtension
->IrpFlags
|= IRP_FLAG_COMPLETE
;
599 DPRINT("Notify: NextRequest\n");
600 DeviceExtension
->IrpFlags
|= IRP_FLAG_NEXT
;
610 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension
,
611 IN ULONG BusDataType
,
612 IN ULONG SystemIoBusNumber
,
618 return(HalSetBusDataByOffset(BusDataType
,
628 ScsiPortValidateRange(IN PVOID HwDeviceExtension
,
629 IN INTERFACE_TYPE BusType
,
630 IN ULONG SystemIoBusNumber
,
631 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
632 IN ULONG NumberOfBytes
,
633 IN BOOLEAN InIoSpace
)
639 /* INTERNAL FUNCTIONS ********************************************************/
641 /**********************************************************************
643 * ScsiPortCreateClose
646 * Answer requests for Create/Close calls: a null operation.
653 * Pointer to a device object.
659 Additional output data (see printf()).
665 static NTSTATUS STDCALL
666 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
669 DPRINT("ScsiPortCreateClose()\n");
671 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
672 Irp
->IoStatus
.Information
= FILE_OPENED
;
674 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
676 return(STATUS_SUCCESS
);
680 /**********************************************************************
682 * ScsiPortDispatchScsi
685 * Answer requests for SCSI calls
691 * Standard dispatch arguments
697 static NTSTATUS STDCALL
698 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
701 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
702 PIO_STACK_LOCATION Stack
;
703 PSCSI_REQUEST_BLOCK Srb
;
704 NTSTATUS Status
= STATUS_SUCCESS
;
708 DPRINT("ScsiPortDispatchScsi()\n");
710 DeviceExtension
= DeviceObject
->DeviceExtension
;
711 Stack
= IoGetCurrentIrpStackLocation(Irp
);
713 DeviceExtension
->IrpFlags
= 0;
715 switch(Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
717 case IOCTL_SCSI_EXECUTE_IN
:
719 DPRINT(" IOCTL_SCSI_EXECUTE_IN\n");
723 case IOCTL_SCSI_EXECUTE_OUT
:
725 DPRINT(" IOCTL_SCSI_EXECUTE_OUT\n");
729 case IOCTL_SCSI_EXECUTE_NONE
:
731 DPRINT(" IOCTL_SCSI_EXECUTE_NONE\n");
736 Srb
= Stack
->Parameters
.Scsi
.Srb
;
740 Status
= STATUS_UNSUCCESSFUL
;
743 Irp
->IoStatus
.Status
= Status
;
744 Irp
->IoStatus
.Information
= 0;
746 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
751 DPRINT("Srb: %p\n", Srb
);
752 DPRINT("Srb->Function: %lu\n", Srb
->Function
);
754 switch (Srb
->Function
)
756 case SRB_FUNCTION_EXECUTE_SCSI
:
757 DPRINT(" SRB_FUNCTION_EXECUTE_SCSI\n");
758 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
759 DPRINT("Returning STATUS_PENDING\n");
760 return(STATUS_PENDING
);
762 case SRB_FUNCTION_CLAIM_DEVICE
:
764 PSCSI_ADAPTER_BUS_INFO AdapterInfo
;
765 PSCSI_INQUIRY_DATA UnitInfo
;
766 PINQUIRYDATA InquiryData
;
768 DPRINT(" SRB_FUNCTION_CLAIM_DEVICE\n");
770 if (DeviceExtension
->PortBusInfo
!= NULL
)
772 AdapterInfo
= (PSCSI_ADAPTER_BUS_INFO
)DeviceExtension
->PortBusInfo
;
774 UnitInfo
= (PSCSI_INQUIRY_DATA
)((PUCHAR
)AdapterInfo
+
775 AdapterInfo
->BusData
[Srb
->PathId
].InquiryDataOffset
);
777 while (AdapterInfo
->BusData
[Srb
->PathId
].InquiryDataOffset
)
779 InquiryData
= (PINQUIRYDATA
)UnitInfo
->InquiryData
;
781 if ((UnitInfo
->TargetId
== Srb
->TargetId
) &&
782 (UnitInfo
->Lun
== Srb
->Lun
) &&
783 (UnitInfo
->DeviceClaimed
== FALSE
))
785 UnitInfo
->DeviceClaimed
= TRUE
;
786 DPRINT("Claimed device!\n");
790 if (UnitInfo
->NextInquiryDataOffset
== 0)
793 UnitInfo
= (PSCSI_INQUIRY_DATA
)((PUCHAR
)AdapterInfo
+ UnitInfo
->NextInquiryDataOffset
);
797 /* FIXME: Hack!!!!! */
798 Srb
->DataBuffer
= DeviceObject
;
802 case SRB_FUNCTION_RELEASE_DEVICE
:
804 PSCSI_ADAPTER_BUS_INFO AdapterInfo
;
805 PSCSI_INQUIRY_DATA UnitInfo
;
806 PINQUIRYDATA InquiryData
;
808 DPRINT(" SRB_FUNCTION_RELEASE_DEVICE\n");
810 if (DeviceExtension
->PortBusInfo
!= NULL
)
812 AdapterInfo
= (PSCSI_ADAPTER_BUS_INFO
)DeviceExtension
->PortBusInfo
;
814 UnitInfo
= (PSCSI_INQUIRY_DATA
)((PUCHAR
)AdapterInfo
+
815 AdapterInfo
->BusData
[Srb
->PathId
].InquiryDataOffset
);
818 while (AdapterInfo
->BusData
[Srb
->PathId
].InquiryDataOffset
)
820 InquiryData
= (PINQUIRYDATA
)UnitInfo
->InquiryData
;
822 if ((UnitInfo
->TargetId
== Srb
->TargetId
) &&
823 (UnitInfo
->Lun
== Srb
->Lun
) &&
824 (UnitInfo
->DeviceClaimed
== TRUE
))
826 UnitInfo
->DeviceClaimed
= FALSE
;
827 DPRINT("Released device!\n");
831 if (UnitInfo
->NextInquiryDataOffset
== 0)
834 UnitInfo
= (PSCSI_INQUIRY_DATA
)((PUCHAR
)AdapterInfo
+ UnitInfo
->NextInquiryDataOffset
);
841 Irp
->IoStatus
.Status
= Status
;
842 Irp
->IoStatus
.Information
= DataSize
;
844 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
850 /**********************************************************************
852 * ScsiPortDeviceControl
855 * Answer requests for device control calls
861 * Standard dispatch arguments
867 static NTSTATUS STDCALL
868 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
871 PIO_STACK_LOCATION Stack
;
872 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
874 DPRINT("ScsiPortDeviceControl()\n");
876 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
877 Irp
->IoStatus
.Information
= 0;
880 Stack
= IoGetCurrentIrpStackLocation(Irp
);
881 DeviceExtension
= DeviceObject
->DeviceExtension
;
883 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
886 case IOCTL_SCSI_GET_CAPABILITIES
:
888 PIO_SCSI_CAPABILITIES Capabilities
;
890 DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
892 Capabilities
= (PIO_SCSI_CAPABILITIES
)Irp
->AssociatedIrp
.SystemBuffer
;
893 Capabilities
->Length
= sizeof(IO_SCSI_CAPABILITIES
);
894 Capabilities
->MaximumTransferLength
=
895 DeviceExtension
->PortConfig
.MaximumTransferLength
;
896 Capabilities
->MaximumPhysicalPages
= 1;
897 Capabilities
->SupportedAsynchronousEvents
= 0;
898 Capabilities
->AlignmentMask
=
899 DeviceExtension
->PortConfig
.AlignmentMask
;
900 Capabilities
->TaggedQueuing
=
901 DeviceExtension
->PortConfig
.TaggedQueuing
;
902 Capabilities
->AdapterScansDown
=
903 DeviceExtension
->PortConfig
.AdapterScansDown
;
904 Capabilities
->AdapterUsesPio
= TRUE
;
906 Irp
->IoStatus
.Information
= sizeof(IO_SCSI_CAPABILITIES
);
910 case IOCTL_SCSI_GET_INQUIRY_DATA
:
912 DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
914 /* Copy inquiry data to the port device extension */
915 memcpy(Irp
->AssociatedIrp
.SystemBuffer
,
916 DeviceExtension
->PortBusInfo
,
917 DeviceExtension
->PortBusInfoSize
);
919 DPRINT("BufferSize: %lu\n", DeviceExtension
->PortBusInfoSize
);
920 Irp
->IoStatus
.Information
= DeviceExtension
->PortBusInfoSize
;
925 DPRINT1(" unknown ioctl code: 0x%lX\n",
926 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
930 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
932 return(STATUS_SUCCESS
);
937 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
940 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
941 PIO_STACK_LOCATION IrpStack
;
944 DPRINT("ScsiPortStartIo() called!\n");
946 DeviceExtension
= DeviceObject
->DeviceExtension
;
947 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
949 // FIXME: implement the supported functions
951 switch (IrpStack
->MajorFunction
)
956 PSCSI_REQUEST_BLOCK Srb
;
958 DPRINT("IRP_MJ_SCSI\n");
960 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
962 DPRINT("DeviceExtension %p\n", DeviceExtension
);
964 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
965 Irp
->IoStatus
.Information
= Srb
->DataTransferLength
;
967 DeviceExtension
->CurrentIrp
= Irp
;
969 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
973 DPRINT("Synchronization failed!\n");
975 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
976 Irp
->IoStatus
.Information
= 0;
977 IoCompleteRequest(Irp
,
979 IoStartNextPacket(DeviceObject
,
982 if (DeviceExtension
->IrpFlags
& IRP_FLAG_COMPLETE
)
984 DeviceExtension
->IrpFlags
&= ~IRP_FLAG_COMPLETE
;
985 IoCompleteRequest(Irp
,
989 if (DeviceExtension
->IrpFlags
& IRP_FLAG_NEXT
)
991 DeviceExtension
->IrpFlags
&= ~IRP_FLAG_NEXT
;
992 IoStartNextPacket(DeviceObject
,
999 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
1000 Irp
->IoStatus
.Information
= 0;
1001 IoCompleteRequest(Irp
,
1003 IoStartNextPacket(DeviceObject
,
1007 DPRINT("ScsiPortStartIo() done\n");
1011 static BOOLEAN STDCALL
1012 ScsiPortStartPacket(IN OUT PVOID Context
)
1014 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1015 PIO_STACK_LOCATION IrpStack
;
1016 PSCSI_REQUEST_BLOCK Srb
;
1018 DPRINT("ScsiPortStartPacket() called\n");
1020 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)Context
;
1022 IrpStack
= IoGetCurrentIrpStackLocation(DeviceExtension
->CurrentIrp
);
1023 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
1025 return(DeviceExtension
->HwStartIo(&DeviceExtension
->MiniPortDeviceExtension
,
1030 /**********************************************************************
1032 * ScsiPortCreatePortDevice
1035 * Creates and initializes a SCSI port device object.
1044 * PseudoDeviceExtension
1055 ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject
,
1056 IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension
,
1057 IN ULONG PortNumber
)
1059 PSCSI_PORT_DEVICE_EXTENSION PortDeviceExtension
;
1060 PDEVICE_OBJECT PortDeviceObject
;
1061 WCHAR NameBuffer
[80];
1062 UNICODE_STRING DeviceName
;
1063 WCHAR DosNameBuffer
[80];
1064 UNICODE_STRING DosDeviceName
;
1066 ULONG AccessRangeSize
;
1074 DPRINT("ScsiPortCreatePortDevice() called\n");
1077 MappedIrq
= HalGetInterruptVector(PseudoDeviceExtension
->PortConfig
.AdapterInterfaceType
,
1078 PseudoDeviceExtension
->PortConfig
.SystemIoBusNumber
,
1080 PseudoDeviceExtension
->PortConfig
.BusInterruptLevel
,
1085 /* Create a unicode device name */
1086 swprintf(NameBuffer
,
1087 L
"\\Device\\ScsiPort%lu",
1089 RtlInitUnicodeString(&DeviceName
,
1092 DPRINT("Creating device: %wZ\n", &DeviceName
);
1094 /* Create the port device */
1095 Status
= IoCreateDevice(DriverObject
,
1096 PseudoDeviceExtension
->Length
,
1098 FILE_DEVICE_CONTROLLER
,
1102 if (!NT_SUCCESS(Status
))
1104 DbgPrint("IoCreateDevice call failed! (Status 0x%lX)\n", Status
);
1108 DPRINT("Created device: %wZ\n", &DeviceName
);
1110 /* Set the buffering strategy here... */
1111 PortDeviceObject
->Flags
|= DO_DIRECT_IO
;
1112 PortDeviceObject
->AlignmentRequirement
= FILE_WORD_ALIGNMENT
;
1114 PortDeviceExtension
= PortDeviceObject
->DeviceExtension
;
1116 /* Copy pseudo device extension into the real device extension */
1117 memcpy(PortDeviceExtension
,
1118 PseudoDeviceExtension
,
1119 PseudoDeviceExtension
->Length
);
1121 /* Copy access ranges */
1123 sizeof(ACCESS_RANGE
) * PseudoDeviceExtension
->PortConfig
.NumberOfAccessRanges
;
1124 PortDeviceExtension
->PortConfig
.AccessRanges
= ExAllocatePool(NonPagedPool
,
1126 memcpy(PortDeviceExtension
->PortConfig
.AccessRanges
,
1127 PseudoDeviceExtension
->PortConfig
.AccessRanges
,
1130 PortDeviceExtension
->DeviceObject
= PortDeviceObject
;
1133 /* Initialize the spin lock in the controller extension */
1134 KeInitializeSpinLock(&PortDeviceExtension
->SpinLock
);
1136 /* Register an interrupt handler for this device */
1137 Status
= IoConnectInterrupt(&PortDeviceExtension
->Interrupt
,
1139 PortDeviceExtension
,
1140 &PortDeviceExtension
->SpinLock
,
1141 PortDeviceExtension
->PortConfig
.BusInterruptVector
, // MappedIrq,
1142 PortDeviceExtension
->PortConfig
.BusInterruptLevel
, // Dirql,
1144 PortDeviceExtension
->PortConfig
.InterruptMode
,
1148 if (!NT_SUCCESS(Status
))
1150 DbgPrint("Could not Connect Interrupt %d\n",
1151 PortDeviceExtension
->PortConfig
.BusInterruptVector
);
1155 /* Initialize the DPC object */
1156 IoInitializeDpcRequest(PortDeviceExtension
->DeviceObject
,
1159 /* Initialize the device timer */
1160 PortDeviceExtension
->TimerState
= IDETimerIdle
;
1161 PortDeviceExtension
->TimerCount
= 0;
1162 IoInitializeTimer(PortDeviceExtension
->DeviceObject
,
1164 PortDeviceExtension
);
1166 /* Initialize inquiry data */
1167 PortDeviceExtension
->PortBusInfoSize
= 0;
1168 PortDeviceExtension
->PortBusInfo
= NULL
;
1170 DPRINT("DeviceExtension %p\n", PortDeviceExtension
);
1171 ScsiPortInquire(PortDeviceExtension
);
1174 /* FIXME: Copy more configuration data? */
1176 /* Create the dos device link */
1177 swprintf(DosNameBuffer
,
1180 RtlInitUnicodeString(&DosDeviceName
,
1183 IoCreateSymbolicLink(&DosDeviceName
,
1186 DPRINT("ScsiPortCreatePortDevice() done\n");
1188 return(STATUS_SUCCESS
);
1193 ScsiPortInquire(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
1195 PSCSI_ADAPTER_BUS_INFO AdapterInfo
;
1196 PSCSI_INQUIRY_DATA UnitInfo
, PrevUnit
;
1197 SCSI_REQUEST_BLOCK Srb
;
1204 DPRINT("ScsiPortInquire() called\n");
1206 DeviceExtension
->Initializing
= TRUE
;
1208 /* Copy inquiry data to the port device extension */
1209 AdapterInfo
=(PSCSI_ADAPTER_BUS_INFO
)ExAllocatePool(NonPagedPool
, 4096);
1210 RtlZeroMemory(AdapterInfo
, 4096);
1211 AdapterInfo
->NumberOfBuses
= DeviceExtension
->PortConfig
.NumberOfBuses
;
1213 UnitInfo
= (PSCSI_INQUIRY_DATA
)
1214 ((PUCHAR
)AdapterInfo
+ sizeof(SCSI_ADAPTER_BUS_INFO
) +
1215 (sizeof(SCSI_BUS_DATA
) * (AdapterInfo
->NumberOfBuses
- 1)));
1217 Srb
.DataBuffer
= ExAllocatePool(NonPagedPool
, 256);
1219 sizeof(SCSI_REQUEST_BLOCK
));
1220 Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1221 Srb
.DataTransferLength
= 256;
1222 Srb
.Cdb
[0] = SCSIOP_INQUIRY
;
1224 for (Bus
= 0; Bus
< AdapterInfo
->NumberOfBuses
; Bus
++)
1228 AdapterInfo
->BusData
[Bus
].InitiatorBusId
= 0; /* ? */
1229 AdapterInfo
->BusData
[Bus
].InquiryDataOffset
=
1230 (ULONG
)((PUCHAR
)UnitInfo
- (PUCHAR
)AdapterInfo
);
1235 for (Target
= 0; Target
< DeviceExtension
->PortConfig
.MaximumNumberOfTargets
; Target
++)
1237 Srb
.TargetId
= Target
;
1240 Result
= DeviceExtension
->HwStartIo(&DeviceExtension
->MiniPortDeviceExtension
,
1242 if (Result
== TRUE
&& Srb
.SrbStatus
== SRB_STATUS_SUCCESS
)
1244 UnitInfo
->PathId
= Bus
;
1245 UnitInfo
->TargetId
= Target
;
1247 UnitInfo
->InquiryDataLength
= INQUIRYDATABUFFERSIZE
;
1248 memcpy(&UnitInfo
->InquiryData
,
1250 INQUIRYDATABUFFERSIZE
);
1251 if (PrevUnit
!= NULL
)
1252 PrevUnit
->NextInquiryDataOffset
= (ULONG
)((PUCHAR
)UnitInfo
-(PUCHAR
)AdapterInfo
);
1253 PrevUnit
= UnitInfo
;
1254 UnitInfo
= (PSCSI_INQUIRY_DATA
)((PUCHAR
)UnitInfo
+ sizeof(SCSI_INQUIRY_DATA
)+INQUIRYDATABUFFERSIZE
-1);
1258 AdapterInfo
->BusData
[Bus
].NumberOfLogicalUnits
= UnitCount
;
1260 DataSize
= (ULONG
)((PUCHAR
)UnitInfo
-(PUCHAR
)AdapterInfo
);
1262 ExFreePool(Srb
.DataBuffer
);
1264 DeviceExtension
->Initializing
= FALSE
;
1266 /* copy inquiry data to the port driver's device extension */
1267 DeviceExtension
->PortBusInfoSize
= DataSize
;
1268 DeviceExtension
->PortBusInfo
= ExAllocatePool(NonPagedPool
,
1270 RtlCopyMemory(DeviceExtension
->PortBusInfo
,
1274 ExFreePool(AdapterInfo
);
1276 DPRINT("ScsiPortInquire() done\n");
1280 static BOOLEAN STDCALL
1281 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
1282 IN PVOID ServiceContext
)
1284 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1287 DPRINT("ScsiPortIsr() called!\n");
1289 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)ServiceContext
;
1291 Result
= DeviceExtension
->HwInterrupt(&DeviceExtension
->MiniPortDeviceExtension
);
1292 if (Result
== FALSE
)
1297 if (DeviceExtension
->IrpFlags
)
1299 IoRequestDpc(DeviceExtension
->DeviceObject
,
1300 DeviceExtension
->CurrentIrp
,
1308 // ScsiPortDpcForIsr
1315 // IN PDEVICE_OBJECT DpcDeviceObject
1317 // IN PVOID DpcContext
1320 ScsiPortDpcForIsr(IN PKDPC Dpc
,
1321 IN PDEVICE_OBJECT DpcDeviceObject
,
1323 IN PVOID DpcContext
)
1325 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1326 PIO_STACK_LOCATION IrpStack
;
1327 PSCSI_REQUEST_BLOCK Srb
;
1329 DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
1330 Dpc
, DpcDeviceObject
, DpcIrp
, DpcContext
);
1332 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DpcContext
;
1334 IrpStack
= IoGetCurrentIrpStackLocation(DeviceExtension
->CurrentIrp
);
1335 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
1337 if (DeviceExtension
->OriginalSrb
!= NULL
)
1339 DPRINT("Got sense data!\n");
1341 DPRINT("Valid: %x\n", DeviceExtension
->InternalSenseData
.Valid
);
1342 DPRINT("ErrorCode: %x\n", DeviceExtension
->InternalSenseData
.ErrorCode
);
1343 DPRINT("SenseKey: %x\n", DeviceExtension
->InternalSenseData
.SenseKey
);
1344 DPRINT("SenseCode: %x\n", DeviceExtension
->InternalSenseData
.AdditionalSenseCode
);
1346 /* Copy sense data */
1347 if (DeviceExtension
->OriginalSrb
->SenseInfoBufferLength
!= 0)
1349 RtlCopyMemory(DeviceExtension
->OriginalSrb
->SenseInfoBuffer
,
1350 &DeviceExtension
->InternalSenseData
,
1351 sizeof(SENSE_DATA
));
1352 DeviceExtension
->OriginalSrb
->SrbStatus
|= SRB_STATUS_AUTOSENSE_VALID
;
1355 /* Clear current sense data */
1356 RtlZeroMemory(&DeviceExtension
->InternalSenseData
, sizeof(SENSE_DATA
));
1358 IrpStack
->Parameters
.Scsi
.Srb
= DeviceExtension
->OriginalSrb
;
1359 DeviceExtension
->OriginalSrb
= NULL
;
1361 else if ((SRB_STATUS(Srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) &&
1362 (Srb
->ScsiStatus
== SCSISTAT_CHECK_CONDITION
))
1364 DPRINT("SCSIOP_REQUEST_SENSE required!\n");
1366 DeviceExtension
->OriginalSrb
= Srb
;
1367 IrpStack
->Parameters
.Scsi
.Srb
= ScsiPortInitSenseRequestSrb(DeviceExtension
,
1370 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
1371 ScsiPortStartPacket
,
1374 DPRINT("Synchronization failed!\n");
1376 DpcIrp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
1377 DpcIrp
->IoStatus
.Information
= 0;
1378 IoCompleteRequest(DpcIrp
,
1380 IoStartNextPacket(DpcDeviceObject
,
1387 DeviceExtension
->CurrentIrp
= NULL
;
1390 // DpcIrp->IoStatus.Information = 0;
1391 // DpcIrp->IoStatus.Status = STATUS_SUCCESS;
1393 if (DeviceExtension
->IrpFlags
& IRP_FLAG_COMPLETE
)
1395 DeviceExtension
->IrpFlags
&= ~IRP_FLAG_COMPLETE
;
1396 IoCompleteRequest(DpcIrp
, IO_NO_INCREMENT
);
1399 if (DeviceExtension
->IrpFlags
& IRP_FLAG_NEXT
)
1401 DeviceExtension
->IrpFlags
&= ~IRP_FLAG_NEXT
;
1402 IoStartNextPacket(DpcDeviceObject
, FALSE
);
1405 DPRINT("ScsiPortDpcForIsr() done\n");
1411 // This function handles timeouts and other time delayed processing
1416 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
1417 // IN PVOID Context the Controller extension for the
1418 // controller the device is on
1421 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
1424 DPRINT1("ScsiPortIoTimer()\n");
1428 static PSCSI_REQUEST_BLOCK
1429 ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
1430 PSCSI_REQUEST_BLOCK OriginalSrb
)
1432 PSCSI_REQUEST_BLOCK Srb
;
1435 Srb
= &DeviceExtension
->InternalSrb
;
1438 sizeof(SCSI_REQUEST_BLOCK
));
1440 Srb
->PathId
= OriginalSrb
->PathId
;
1441 Srb
->TargetId
= OriginalSrb
->TargetId
;
1442 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1443 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
);
1444 Srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
1446 Srb
->TimeOutValue
= 4;
1449 Srb
->DataBuffer
= &DeviceExtension
->InternalSenseData
;
1450 Srb
->DataTransferLength
= sizeof(SENSE_DATA
);
1452 Cdb
= (PCDB
)Srb
->Cdb
;
1453 Cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_REQUEST_SENSE
;
1454 Cdb
->CDB6INQUIRY
.AllocationLength
= sizeof(SENSE_DATA
);
1461 ScsiPortFreeSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
1463 DeviceExtension
->OriginalSrb
= NULL
;