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.21 2002/09/19 16:18:50 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>
33 #include <ddk/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
;
70 PKINTERRUPT Interrupt
;
74 SCSI_PORT_TIMER_STATES TimerState
;
79 ULONG PortBusInfoSize
;
80 PSCSI_ADAPTER_BUS_INFO PortBusInfo
;
82 PIO_SCSI_CAPABILITIES PortCapabilities
;
84 PDEVICE_OBJECT DeviceObject
;
85 PCONTROLLER_OBJECT ControllerObject
;
87 PHW_STARTIO HwStartIo
;
88 PHW_INTERRUPT HwInterrupt
;
90 PSCSI_REQUEST_BLOCK OriginalSrb
;
91 SCSI_REQUEST_BLOCK InternalSrb
;
92 SENSE_DATA InternalSenseData
;
94 UCHAR MiniPortDeviceExtension
[1]; /* must be the last entry */
95 } SCSI_PORT_DEVICE_EXTENSION
, *PSCSI_PORT_DEVICE_EXTENSION
;
99 * SCSI_PORT_TIMER_STATES
102 * An enumeration containing the states in the timer DFA
107 #define IRP_FLAG_COMPLETE 0x00000001
108 #define IRP_FLAG_NEXT 0x00000002
111 /* GLOBALS *******************************************************************/
113 static NTSTATUS STDCALL
114 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
117 static NTSTATUS STDCALL
118 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
121 static NTSTATUS STDCALL
122 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
126 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
129 static IO_ALLOCATION_ACTION STDCALL
130 ScsiPortAllocateController(IN PDEVICE_OBJECT DeviceObject
,
132 IN PVOID MapRegisterBase
,
135 static BOOLEAN STDCALL
136 ScsiPortStartPacket(IN OUT PVOID Context
);
139 ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject
,
140 IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension
,
144 ScsiPortInquire(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
146 static BOOLEAN STDCALL
147 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
148 IN PVOID ServiceContext
);
151 ScsiPortDpcForIsr(IN PKDPC Dpc
,
152 IN PDEVICE_OBJECT DpcDeviceObject
,
154 IN PVOID DpcContext
);
157 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
160 static PSCSI_REQUEST_BLOCK
161 ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
162 PSCSI_REQUEST_BLOCK OriginalSrb
);
164 /* FUNCTIONS *****************************************************************/
166 /**********************************************************************
171 * This function initializes the driver.
178 * System allocated Driver Object for this driver.
181 * Name of registry driver service key.
188 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
189 IN PUNICODE_STRING RegistryPath
)
191 DPRINT("ScsiPort Driver %s\n", VERSION
);
192 return(STATUS_SUCCESS
);
196 /**********************************************************************
201 * Prints debugging messages.
208 * Debug level of the given message.
211 * Pointer to printf()-compatible format string.
214 Additional output data (see printf()).
221 ScsiDebugPrint(IN ULONG DebugPrintLevel
,
222 IN PCHAR DebugMessage
,
229 if (DebugPrintLevel
> InternalDebugLevel
)
233 va_start(ap
, DebugMessage
);
234 vsprintf(Buffer
, DebugMessage
, ap
);
242 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension
,
253 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address
)
255 return(Address
.u
.LowPart
);
260 ScsiPortFlushDma(IN PVOID HwDeviceExtension
)
267 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension
,
268 IN PVOID MappedAddress
)
275 ScsiPortGetBusData(IN PVOID DeviceExtension
,
276 IN ULONG BusDataType
,
277 IN ULONG SystemIoBusNumber
,
282 return(HalGetBusData(BusDataType
,
291 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension
,
292 IN INTERFACE_TYPE BusType
,
293 IN ULONG SystemIoBusNumber
,
294 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
295 IN ULONG NumberOfBytes
,
296 IN BOOLEAN InIoSpace
)
299 PHYSICAL_ADDRESS TranslatedAddress
;
300 PVOID VirtualAddress
;
304 AddressSpace
= (ULONG
)InIoSpace
;
306 if (!HalTranslateBusAddress(BusType
,
314 if (AddressSpace
!= 0)
315 return (PVOID
)TranslatedAddress
.u
.LowPart
;
317 VirtualAddress
= MmMapIoSpace(TranslatedAddress
,
321 Buffer
= ExAllocatePool(NonPagedPool
,0x20);
323 return VirtualAddress
;
325 return NULL
; /* ?? */
330 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension
,
339 SCSI_PHYSICAL_ADDRESS STDCALL
340 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension
,
341 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
342 IN PVOID VirtualAddress
,
349 PSCSI_REQUEST_BLOCK STDCALL
350 ScsiPortGetSrb(IN PVOID DeviceExtension
,
361 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension
,
362 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
363 IN ULONG NumberOfBytes
)
370 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension
,
371 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress
)
377 /**********************************************************************
382 * Initializes SCSI port driver specific data.
389 * Pointer to the miniport driver's driver object.
392 * Pointer to the miniport driver's registry path.
394 * HwInitializationData
395 * Pointer to port driver specific configuration data.
398 Miniport driver specific context.
405 ScsiPortInitialize(IN PVOID Argument1
,
407 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
410 PDRIVER_OBJECT DriverObject
= (PDRIVER_OBJECT
)Argument1
;
411 PUNICODE_STRING RegistryPath
= (PUNICODE_STRING
)Argument2
;
412 PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension
;
413 PCONFIGURATION_INFORMATION SystemConfig
;
414 PPORT_CONFIGURATION_INFORMATION PortConfig
;
420 PACCESS_RANGE AccessRanges
;
423 DPRINT("ScsiPortInitialize() called!\n");
425 if ((HwInitializationData
->HwInitialize
== NULL
) ||
426 (HwInitializationData
->HwStartIo
== NULL
) ||
427 (HwInitializationData
->HwInterrupt
== NULL
) ||
428 (HwInitializationData
->HwFindAdapter
== NULL
) ||
429 (HwInitializationData
->HwResetBus
== NULL
))
430 return(STATUS_INVALID_PARAMETER
);
432 DriverObject
->DriverStartIo
= ScsiPortStartIo
;
433 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ScsiPortCreateClose
;
434 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ScsiPortCreateClose
;
435 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ScsiPortDeviceControl
;
436 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = ScsiPortDispatchScsi
;
439 SystemConfig
= IoGetConfigurationInformation();
441 ExtensionSize
= sizeof(SCSI_PORT_DEVICE_EXTENSION
) +
442 HwInitializationData
->DeviceExtensionSize
;
443 PseudoDeviceExtension
= ExAllocatePool(PagedPool
,
445 RtlZeroMemory(PseudoDeviceExtension
,
447 PseudoDeviceExtension
->Length
= ExtensionSize
;
448 PseudoDeviceExtension
->MiniPortExtensionSize
= HwInitializationData
->DeviceExtensionSize
;
449 PseudoDeviceExtension
->HwStartIo
= HwInitializationData
->HwStartIo
;
450 PseudoDeviceExtension
->HwInterrupt
= HwInitializationData
->HwInterrupt
;
452 PortConfig
= &PseudoDeviceExtension
->PortConfig
;
454 PortConfig
->Length
= sizeof(PORT_CONFIGURATION_INFORMATION
);
455 PortConfig
->AdapterInterfaceType
= HwInitializationData
->AdapterInterfaceType
;
456 PortConfig
->InterruptMode
=
457 (PortConfig
->AdapterInterfaceType
== PCIBus
) ? LevelSensitive
: Latched
;
458 PortConfig
->AtdiskPrimaryClaimed
= SystemConfig
->AtDiskPrimaryAddressClaimed
;
459 PortConfig
->AtdiskSecondaryClaimed
= SystemConfig
->AtDiskSecondaryAddressClaimed
;
460 PortConfig
->NumberOfAccessRanges
= HwInitializationData
->NumberOfAccessRanges
;
462 PortConfig
->AccessRanges
=
463 ExAllocatePool(PagedPool
,
464 sizeof(ACCESS_RANGE
) * PortConfig
->NumberOfAccessRanges
);
467 PortConfig
->SystemIoBusNumber
= 0;
468 PortConfig
->SlotNumber
= 0;
470 MaxBus
= (PortConfig
->AdapterInterfaceType
== PCIBus
) ? 8 : 1;
472 DPRINT("MaxBus: %lu\n", MaxBus
);
476 DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig
->SystemIoBusNumber
);
478 // RtlZeroMemory(AccessRanges,
479 // sizeof(ACCESS_RANGE) * PortConfig->NumberOfAccessRanges);
481 RtlZeroMemory(PseudoDeviceExtension
->MiniPortDeviceExtension
,
482 PseudoDeviceExtension
->MiniPortExtensionSize
);
484 /* Note: HwFindAdapter is called once for each bus */
485 Result
= (HwInitializationData
->HwFindAdapter
)(&PseudoDeviceExtension
->MiniPortDeviceExtension
,
487 NULL
, /* BusInformation */
488 NULL
, /* ArgumentString */
489 &PseudoDeviceExtension
->PortConfig
,
491 DPRINT("HwFindAdapter() result: %lu\n", Result
);
493 if (Result
== SP_RETURN_FOUND
)
495 DPRINT("ScsiPortInitialize(): Found HBA!\n");
497 Status
= ScsiPortCreatePortDevice(DriverObject
,
498 PseudoDeviceExtension
,
499 SystemConfig
->ScsiPortCount
);
501 if (!NT_SUCCESS(Status
))
503 DbgPrint("ScsiPortCreatePortDevice() failed! (Status 0x%lX)\n", Status
);
505 ExFreePool(PortConfig
->AccessRanges
);
506 ExFreePool(PseudoDeviceExtension
);
511 /* Update the configuration info */
512 SystemConfig
->AtDiskPrimaryAddressClaimed
= PortConfig
->AtdiskPrimaryClaimed
;
513 SystemConfig
->AtDiskSecondaryAddressClaimed
= PortConfig
->AtdiskSecondaryClaimed
;
514 SystemConfig
->ScsiPortCount
++;
519 PortConfig
->SystemIoBusNumber
++;
520 PortConfig
->SlotNumber
= 0;
523 DPRINT("Bus: %lu MaxBus: %lu\n", PortConfig
->SystemIoBusNumber
, MaxBus
);
524 if (PortConfig
->SystemIoBusNumber
>= MaxBus
)
526 DPRINT("Scanned all buses!\n");
531 ExFreePool(PortConfig
->AccessRanges
);
532 ExFreePool(PseudoDeviceExtension
);
534 DPRINT("ScsiPortInitialize() done!\n");
536 return(STATUS_SUCCESS
);
541 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension
,
542 IN PSCSI_REQUEST_BLOCK Srb
,
543 IN ULONG LogicalAddress
,
551 ScsiPortLogError(IN PVOID HwDeviceExtension
,
552 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
564 ScsiPortMoveMemory(OUT PVOID Destination
,
568 RtlMoveMemory(Destination
,
575 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType
,
576 IN PVOID HwDeviceExtension
,
579 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
581 DPRINT("ScsiPortNotification() called\n");
583 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
584 SCSI_PORT_DEVICE_EXTENSION
,
585 MiniPortDeviceExtension
);
587 DPRINT("DeviceExtension %p\n", DeviceExtension
);
589 DPRINT("Initializing = %s\n", (DeviceExtension
->Initializing
)?"TRUE":"FALSE");
591 if (DeviceExtension
->Initializing
== TRUE
)
594 switch (NotificationType
)
596 case RequestComplete
:
597 DPRINT("Notify: RequestComplete\n");
598 DeviceExtension
->IrpFlags
|= IRP_FLAG_COMPLETE
;
602 DPRINT("Notify: NextRequest\n");
603 DeviceExtension
->IrpFlags
|= IRP_FLAG_NEXT
;
613 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension
,
614 IN ULONG BusDataType
,
615 IN ULONG SystemIoBusNumber
,
621 return(HalSetBusDataByOffset(BusDataType
,
631 ScsiPortValidateRange(IN PVOID HwDeviceExtension
,
632 IN INTERFACE_TYPE BusType
,
633 IN ULONG SystemIoBusNumber
,
634 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
635 IN ULONG NumberOfBytes
,
636 IN BOOLEAN InIoSpace
)
642 /* INTERNAL FUNCTIONS ********************************************************/
644 /**********************************************************************
646 * ScsiPortCreateClose
649 * Answer requests for Create/Close calls: a null operation.
656 * Pointer to a device object.
662 Additional output data (see printf()).
668 static NTSTATUS STDCALL
669 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
672 DPRINT("ScsiPortCreateClose()\n");
674 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
675 Irp
->IoStatus
.Information
= FILE_OPENED
;
677 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
679 return(STATUS_SUCCESS
);
683 /**********************************************************************
685 * ScsiPortDispatchScsi
688 * Answer requests for SCSI calls
694 * Standard dispatch arguments
700 static NTSTATUS STDCALL
701 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
704 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
705 PIO_STACK_LOCATION Stack
;
706 PSCSI_REQUEST_BLOCK Srb
;
707 NTSTATUS Status
= STATUS_SUCCESS
;
710 DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n",
713 DeviceExtension
= DeviceObject
->DeviceExtension
;
714 Stack
= IoGetCurrentIrpStackLocation(Irp
);
716 Srb
= Stack
->Parameters
.Scsi
.Srb
;
719 Status
= STATUS_UNSUCCESSFUL
;
721 Irp
->IoStatus
.Status
= Status
;
722 Irp
->IoStatus
.Information
= 0;
724 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
729 DPRINT("Srb: %p\n", Srb
);
730 DPRINT("Srb->Function: %lu\n", Srb
->Function
);
731 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb
->PathId
, Srb
->TargetId
, Srb
->Lun
);
733 switch (Srb
->Function
)
735 case SRB_FUNCTION_EXECUTE_SCSI
:
736 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
737 return(STATUS_PENDING
);
739 case SRB_FUNCTION_SHUTDOWN
:
740 case SRB_FUNCTION_FLUSH
:
741 if (DeviceExtension
->PortConfig
.CachesData
== TRUE
)
743 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
744 return(STATUS_PENDING
);
748 case SRB_FUNCTION_CLAIM_DEVICE
:
750 PSCSI_ADAPTER_BUS_INFO AdapterInfo
;
751 PSCSI_INQUIRY_DATA UnitInfo
;
752 PINQUIRYDATA InquiryData
;
754 DPRINT(" SRB_FUNCTION_CLAIM_DEVICE\n");
755 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb
->PathId
, Srb
->TargetId
, Srb
->Lun
);
757 Srb
->DataBuffer
= NULL
;
759 if (DeviceExtension
->PortBusInfo
!= NULL
)
761 AdapterInfo
= (PSCSI_ADAPTER_BUS_INFO
)DeviceExtension
->PortBusInfo
;
763 if (AdapterInfo
->BusData
[Srb
->PathId
].NumberOfLogicalUnits
== 0)
766 UnitInfo
= (PSCSI_INQUIRY_DATA
)((PUCHAR
)AdapterInfo
+
767 AdapterInfo
->BusData
[Srb
->PathId
].InquiryDataOffset
);
769 while (AdapterInfo
->BusData
[Srb
->PathId
].InquiryDataOffset
)
771 InquiryData
= (PINQUIRYDATA
)UnitInfo
->InquiryData
;
773 if ((UnitInfo
->TargetId
== Srb
->TargetId
) &&
774 (UnitInfo
->Lun
== Srb
->Lun
) &&
775 (UnitInfo
->DeviceClaimed
== FALSE
))
777 UnitInfo
->DeviceClaimed
= TRUE
;
778 DPRINT("Claimed device!\n");
780 /* FIXME: Hack!!!!! */
781 Srb
->DataBuffer
= DeviceObject
;
786 if (UnitInfo
->NextInquiryDataOffset
== 0)
789 UnitInfo
= (PSCSI_INQUIRY_DATA
)((PUCHAR
)AdapterInfo
+ UnitInfo
->NextInquiryDataOffset
);
795 case SRB_FUNCTION_RELEASE_DEVICE
:
797 PSCSI_ADAPTER_BUS_INFO AdapterInfo
;
798 PSCSI_INQUIRY_DATA UnitInfo
;
799 PINQUIRYDATA InquiryData
;
801 DPRINT(" SRB_FUNCTION_RELEASE_DEVICE\n");
802 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb
->PathId
, Srb
->TargetId
, Srb
->Lun
);
804 if (DeviceExtension
->PortBusInfo
!= NULL
)
806 AdapterInfo
= (PSCSI_ADAPTER_BUS_INFO
)DeviceExtension
->PortBusInfo
;
808 if (AdapterInfo
->BusData
[Srb
->PathId
].NumberOfLogicalUnits
== 0)
811 UnitInfo
= (PSCSI_INQUIRY_DATA
)((PUCHAR
)AdapterInfo
+
812 AdapterInfo
->BusData
[Srb
->PathId
].InquiryDataOffset
);
814 while (AdapterInfo
->BusData
[Srb
->PathId
].InquiryDataOffset
)
816 InquiryData
= (PINQUIRYDATA
)UnitInfo
->InquiryData
;
818 if ((UnitInfo
->TargetId
== Srb
->TargetId
) &&
819 (UnitInfo
->Lun
== Srb
->Lun
) &&
820 (UnitInfo
->DeviceClaimed
== TRUE
))
822 UnitInfo
->DeviceClaimed
= FALSE
;
823 DPRINT("Released device!\n");
827 if (UnitInfo
->NextInquiryDataOffset
== 0)
830 UnitInfo
= (PSCSI_INQUIRY_DATA
)((PUCHAR
)AdapterInfo
+ UnitInfo
->NextInquiryDataOffset
);
837 DPRINT1("SRB function not implemented (Function %lu)\n", Srb
->Function
);
838 Status
= STATUS_NOT_IMPLEMENTED
;
842 Irp
->IoStatus
.Status
= Status
;
843 Irp
->IoStatus
.Information
= DataSize
;
845 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
851 /**********************************************************************
853 * ScsiPortDeviceControl
856 * Answer requests for device control calls
862 * Standard dispatch arguments
868 static NTSTATUS STDCALL
869 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
872 PIO_STACK_LOCATION Stack
;
873 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
875 DPRINT("ScsiPortDeviceControl()\n");
877 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
878 Irp
->IoStatus
.Information
= 0;
881 Stack
= IoGetCurrentIrpStackLocation(Irp
);
882 DeviceExtension
= DeviceObject
->DeviceExtension
;
884 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
887 case IOCTL_SCSI_GET_CAPABILITIES
:
889 DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
891 *((PIO_SCSI_CAPABILITIES
*)Irp
->AssociatedIrp
.SystemBuffer
) =
892 DeviceExtension
->PortCapabilities
;
894 Irp
->IoStatus
.Information
= sizeof(PIO_SCSI_CAPABILITIES
);
898 case IOCTL_SCSI_GET_INQUIRY_DATA
:
900 DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
902 /* Copy inquiry data to the port device extension */
903 memcpy(Irp
->AssociatedIrp
.SystemBuffer
,
904 DeviceExtension
->PortBusInfo
,
905 DeviceExtension
->PortBusInfoSize
);
907 DPRINT("BufferSize: %lu\n", DeviceExtension
->PortBusInfoSize
);
908 Irp
->IoStatus
.Information
= DeviceExtension
->PortBusInfoSize
;
913 DPRINT1(" unknown ioctl code: 0x%lX\n",
914 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
918 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
920 return(STATUS_SUCCESS
);
925 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
928 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
929 PIO_STACK_LOCATION IrpStack
;
932 DPRINT("ScsiPortStartIo() called!\n");
934 DeviceExtension
= DeviceObject
->DeviceExtension
;
935 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
937 // FIXME: implement the supported functions
939 switch (IrpStack
->MajorFunction
)
944 PSCSI_REQUEST_BLOCK Srb
;
946 DPRINT("IRP_MJ_SCSI\n");
948 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
950 DPRINT("DeviceExtension %p\n", DeviceExtension
);
952 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
953 Irp
->IoStatus
.Information
= Srb
->DataTransferLength
;
955 DeviceExtension
->CurrentIrp
= Irp
;
957 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
961 DPRINT("Synchronization failed!\n");
963 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
964 Irp
->IoStatus
.Information
= 0;
965 IoCompleteRequest(Irp
,
967 IoStartNextPacket(DeviceObject
,
970 if (DeviceExtension
->IrpFlags
& IRP_FLAG_COMPLETE
)
972 DeviceExtension
->IrpFlags
&= ~IRP_FLAG_COMPLETE
;
973 IoCompleteRequest(Irp
,
977 if (DeviceExtension
->IrpFlags
& IRP_FLAG_NEXT
)
979 DeviceExtension
->IrpFlags
&= ~IRP_FLAG_NEXT
;
980 IoStartNextPacket(DeviceObject
,
987 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
988 Irp
->IoStatus
.Information
= 0;
989 IoCompleteRequest(Irp
,
991 IoStartNextPacket(DeviceObject
,
995 DPRINT("ScsiPortStartIo() done\n");
999 static BOOLEAN STDCALL
1000 ScsiPortStartPacket(IN OUT PVOID Context
)
1002 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1003 PIO_STACK_LOCATION IrpStack
;
1004 PSCSI_REQUEST_BLOCK Srb
;
1006 DPRINT("ScsiPortStartPacket() called\n");
1008 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)Context
;
1010 IrpStack
= IoGetCurrentIrpStackLocation(DeviceExtension
->CurrentIrp
);
1011 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
1013 return(DeviceExtension
->HwStartIo(&DeviceExtension
->MiniPortDeviceExtension
,
1018 /**********************************************************************
1020 * ScsiPortCreatePortDevice
1023 * Creates and initializes a SCSI port device object.
1032 * PseudoDeviceExtension
1043 ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject
,
1044 IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension
,
1045 IN ULONG PortNumber
)
1047 PSCSI_PORT_DEVICE_EXTENSION PortDeviceExtension
;
1048 PIO_SCSI_CAPABILITIES PortCapabilities
;
1049 PDEVICE_OBJECT PortDeviceObject
;
1050 WCHAR NameBuffer
[80];
1051 UNICODE_STRING DeviceName
;
1052 WCHAR DosNameBuffer
[80];
1053 UNICODE_STRING DosDeviceName
;
1055 ULONG AccessRangeSize
;
1063 DPRINT("ScsiPortCreatePortDevice() called\n");
1066 MappedIrq
= HalGetInterruptVector(PseudoDeviceExtension
->PortConfig
.AdapterInterfaceType
,
1067 PseudoDeviceExtension
->PortConfig
.SystemIoBusNumber
,
1069 PseudoDeviceExtension
->PortConfig
.BusInterruptLevel
,
1074 /* Create a unicode device name */
1075 swprintf(NameBuffer
,
1076 L
"\\Device\\ScsiPort%lu",
1078 RtlInitUnicodeString(&DeviceName
,
1081 DPRINT("Creating device: %wZ\n", &DeviceName
);
1083 /* Create the port device */
1084 Status
= IoCreateDevice(DriverObject
,
1085 PseudoDeviceExtension
->Length
,
1087 FILE_DEVICE_CONTROLLER
,
1091 if (!NT_SUCCESS(Status
))
1093 DbgPrint("IoCreateDevice call failed! (Status 0x%lX)\n", Status
);
1097 DPRINT("Created device: %wZ\n", &DeviceName
);
1099 /* Set the buffering strategy here... */
1100 PortDeviceObject
->Flags
|= DO_DIRECT_IO
;
1101 PortDeviceObject
->AlignmentRequirement
= FILE_WORD_ALIGNMENT
;
1103 PortDeviceExtension
= PortDeviceObject
->DeviceExtension
;
1105 /* Copy pseudo device extension into the real device extension */
1106 memcpy(PortDeviceExtension
,
1107 PseudoDeviceExtension
,
1108 PseudoDeviceExtension
->Length
);
1110 /* Copy access ranges */
1112 sizeof(ACCESS_RANGE
) * PseudoDeviceExtension
->PortConfig
.NumberOfAccessRanges
;
1113 PortDeviceExtension
->PortConfig
.AccessRanges
= ExAllocatePool(NonPagedPool
,
1115 memcpy(PortDeviceExtension
->PortConfig
.AccessRanges
,
1116 PseudoDeviceExtension
->PortConfig
.AccessRanges
,
1119 PortDeviceExtension
->DeviceObject
= PortDeviceObject
;
1120 PortDeviceExtension
->PortNumber
= PortNumber
;
1122 /* Initialize the spin lock in the controller extension */
1123 KeInitializeSpinLock(&PortDeviceExtension
->SpinLock
);
1125 /* Register an interrupt handler for this device */
1126 Status
= IoConnectInterrupt(&PortDeviceExtension
->Interrupt
,
1128 PortDeviceExtension
,
1129 &PortDeviceExtension
->SpinLock
,
1130 PortDeviceExtension
->PortConfig
.BusInterruptVector
, // MappedIrq,
1131 PortDeviceExtension
->PortConfig
.BusInterruptLevel
, // Dirql,
1133 PortDeviceExtension
->PortConfig
.InterruptMode
,
1137 if (!NT_SUCCESS(Status
))
1139 DbgPrint("Could not Connect Interrupt %d\n",
1140 PortDeviceExtension
->PortConfig
.BusInterruptVector
);
1144 /* Initialize the DPC object */
1145 IoInitializeDpcRequest(PortDeviceExtension
->DeviceObject
,
1148 /* Initialize the device timer */
1149 PortDeviceExtension
->TimerState
= IDETimerIdle
;
1150 PortDeviceExtension
->TimerCount
= 0;
1151 IoInitializeTimer(PortDeviceExtension
->DeviceObject
,
1153 PortDeviceExtension
);
1155 /* Initialize port capabilities */
1156 PortCapabilities
= ExAllocatePool(NonPagedPool
,
1157 sizeof(IO_SCSI_CAPABILITIES
));
1158 PortDeviceExtension
->PortCapabilities
= PortCapabilities
;
1159 PortCapabilities
->Length
= sizeof(IO_SCSI_CAPABILITIES
);
1160 PortCapabilities
->MaximumTransferLength
=
1161 PortDeviceExtension
->PortConfig
.MaximumTransferLength
;
1162 PortCapabilities
->MaximumPhysicalPages
=
1163 PortCapabilities
->MaximumTransferLength
/ PAGESIZE
;
1164 PortCapabilities
->SupportedAsynchronousEvents
= 0; /* FIXME */
1165 PortCapabilities
->AlignmentMask
=
1166 PortDeviceExtension
->PortConfig
.AlignmentMask
;
1167 PortCapabilities
->TaggedQueuing
=
1168 PortDeviceExtension
->PortConfig
.TaggedQueuing
;
1169 PortCapabilities
->AdapterScansDown
=
1170 PortDeviceExtension
->PortConfig
.AdapterScansDown
;
1171 PortCapabilities
->AdapterUsesPio
= TRUE
; /* FIXME */
1173 /* Initialize inquiry data */
1174 PortDeviceExtension
->PortBusInfoSize
= 0;
1175 PortDeviceExtension
->PortBusInfo
= NULL
;
1177 DPRINT("DeviceExtension %p\n", PortDeviceExtension
);
1178 ScsiPortInquire(PortDeviceExtension
);
1181 /* FIXME: Copy more configuration data? */
1183 /* Create the dos device link */
1184 swprintf(DosNameBuffer
,
1187 RtlInitUnicodeString(&DosDeviceName
,
1190 IoCreateSymbolicLink(&DosDeviceName
,
1193 DPRINT("ScsiPortCreatePortDevice() done\n");
1195 return(STATUS_SUCCESS
);
1200 ScsiPortInquire(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
1202 PSCSI_ADAPTER_BUS_INFO AdapterInfo
;
1203 PSCSI_INQUIRY_DATA UnitInfo
, PrevUnit
;
1204 SCSI_REQUEST_BLOCK Srb
;
1211 DPRINT("ScsiPortInquire() called\n");
1213 DeviceExtension
->Initializing
= TRUE
;
1215 /* Copy inquiry data to the port device extension */
1216 AdapterInfo
=(PSCSI_ADAPTER_BUS_INFO
)ExAllocatePool(NonPagedPool
, 4096);
1217 RtlZeroMemory(AdapterInfo
, 4096);
1218 AdapterInfo
->NumberOfBuses
= DeviceExtension
->PortConfig
.NumberOfBuses
;
1220 UnitInfo
= (PSCSI_INQUIRY_DATA
)
1221 ((PUCHAR
)AdapterInfo
+ sizeof(SCSI_ADAPTER_BUS_INFO
) +
1222 (sizeof(SCSI_BUS_DATA
) * (AdapterInfo
->NumberOfBuses
- 1)));
1225 sizeof(SCSI_REQUEST_BLOCK
));
1226 Srb
.DataBuffer
= ExAllocatePool(NonPagedPool
, 256);
1227 Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1228 Srb
.DataTransferLength
= 256;
1229 Srb
.Cdb
[0] = SCSIOP_INQUIRY
;
1231 for (Bus
= 0; Bus
< AdapterInfo
->NumberOfBuses
; Bus
++)
1235 AdapterInfo
->BusData
[Bus
].InitiatorBusId
= 0; /* ? */
1236 AdapterInfo
->BusData
[Bus
].InquiryDataOffset
=
1237 (ULONG
)((PUCHAR
)UnitInfo
- (PUCHAR
)AdapterInfo
);
1242 for (Target
= 0; Target
< DeviceExtension
->PortConfig
.MaximumNumberOfTargets
; Target
++)
1244 Srb
.TargetId
= Target
;
1246 Srb
.SrbStatus
= SRB_STATUS_SUCCESS
;
1248 Result
= DeviceExtension
->HwStartIo(&DeviceExtension
->MiniPortDeviceExtension
,
1250 DPRINT("Result: %s Srb.SrbStatus %lx\n", (Result
)?"True":"False", Srb
.SrbStatus
);
1252 if (Result
== TRUE
&& Srb
.SrbStatus
== SRB_STATUS_SUCCESS
)
1254 UnitInfo
->PathId
= Bus
;
1255 UnitInfo
->TargetId
= Target
;
1257 UnitInfo
->InquiryDataLength
= INQUIRYDATABUFFERSIZE
;
1258 memcpy(&UnitInfo
->InquiryData
,
1260 INQUIRYDATABUFFERSIZE
);
1261 if (PrevUnit
!= NULL
)
1262 PrevUnit
->NextInquiryDataOffset
= (ULONG
)((PUCHAR
)UnitInfo
-(PUCHAR
)AdapterInfo
);
1263 PrevUnit
= UnitInfo
;
1264 UnitInfo
= (PSCSI_INQUIRY_DATA
)((PUCHAR
)UnitInfo
+ sizeof(SCSI_INQUIRY_DATA
)+INQUIRYDATABUFFERSIZE
-1);
1268 DPRINT("UnitCount: %lu\n", UnitCount
);
1269 AdapterInfo
->BusData
[Bus
].NumberOfLogicalUnits
= UnitCount
;
1271 AdapterInfo
->BusData
[Bus
].InquiryDataOffset
= 0;
1273 DataSize
= (ULONG
)((PUCHAR
)UnitInfo
-(PUCHAR
)AdapterInfo
);
1275 ExFreePool(Srb
.DataBuffer
);
1277 DeviceExtension
->Initializing
= FALSE
;
1279 /* copy inquiry data to the port driver's device extension */
1280 DeviceExtension
->PortBusInfoSize
= DataSize
;
1281 DeviceExtension
->PortBusInfo
= ExAllocatePool(NonPagedPool
,
1283 RtlCopyMemory(DeviceExtension
->PortBusInfo
,
1287 ExFreePool(AdapterInfo
);
1289 DPRINT("ScsiPortInquire() done\n");
1293 static BOOLEAN STDCALL
1294 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
1295 IN PVOID ServiceContext
)
1297 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1300 DPRINT("ScsiPortIsr() called!\n");
1302 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)ServiceContext
;
1304 Result
= DeviceExtension
->HwInterrupt(&DeviceExtension
->MiniPortDeviceExtension
);
1305 if (Result
== FALSE
)
1310 if (DeviceExtension
->IrpFlags
)
1312 IoRequestDpc(DeviceExtension
->DeviceObject
,
1313 DeviceExtension
->CurrentIrp
,
1321 // ScsiPortDpcForIsr
1328 // IN PDEVICE_OBJECT DpcDeviceObject
1330 // IN PVOID DpcContext
1333 ScsiPortDpcForIsr(IN PKDPC Dpc
,
1334 IN PDEVICE_OBJECT DpcDeviceObject
,
1336 IN PVOID DpcContext
)
1338 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1339 PIO_STACK_LOCATION IrpStack
;
1340 PSCSI_REQUEST_BLOCK Srb
;
1342 DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
1343 Dpc
, DpcDeviceObject
, DpcIrp
, DpcContext
);
1345 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DpcContext
;
1347 IrpStack
= IoGetCurrentIrpStackLocation(DeviceExtension
->CurrentIrp
);
1348 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
1350 if (DeviceExtension
->OriginalSrb
!= NULL
)
1352 DPRINT("Got sense data!\n");
1354 DPRINT("Valid: %x\n", DeviceExtension
->InternalSenseData
.Valid
);
1355 DPRINT("ErrorCode: %x\n", DeviceExtension
->InternalSenseData
.ErrorCode
);
1356 DPRINT("SenseKey: %x\n", DeviceExtension
->InternalSenseData
.SenseKey
);
1357 DPRINT("SenseCode: %x\n", DeviceExtension
->InternalSenseData
.AdditionalSenseCode
);
1359 /* Copy sense data */
1360 if (DeviceExtension
->OriginalSrb
->SenseInfoBufferLength
!= 0)
1362 RtlCopyMemory(DeviceExtension
->OriginalSrb
->SenseInfoBuffer
,
1363 &DeviceExtension
->InternalSenseData
,
1364 sizeof(SENSE_DATA
));
1365 DeviceExtension
->OriginalSrb
->SrbStatus
|= SRB_STATUS_AUTOSENSE_VALID
;
1368 /* Clear current sense data */
1369 RtlZeroMemory(&DeviceExtension
->InternalSenseData
, sizeof(SENSE_DATA
));
1371 IrpStack
->Parameters
.Scsi
.Srb
= DeviceExtension
->OriginalSrb
;
1372 DeviceExtension
->OriginalSrb
= NULL
;
1374 else if ((SRB_STATUS(Srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) &&
1375 (Srb
->ScsiStatus
== SCSISTAT_CHECK_CONDITION
))
1377 DPRINT("SCSIOP_REQUEST_SENSE required!\n");
1379 DeviceExtension
->OriginalSrb
= Srb
;
1380 IrpStack
->Parameters
.Scsi
.Srb
= ScsiPortInitSenseRequestSrb(DeviceExtension
,
1383 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
1384 ScsiPortStartPacket
,
1387 DPRINT("Synchronization failed!\n");
1389 DpcIrp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
1390 DpcIrp
->IoStatus
.Information
= 0;
1391 IoCompleteRequest(DpcIrp
,
1393 IoStartNextPacket(DpcDeviceObject
,
1400 DeviceExtension
->CurrentIrp
= NULL
;
1403 // DpcIrp->IoStatus.Information = 0;
1404 // DpcIrp->IoStatus.Status = STATUS_SUCCESS;
1406 if (DeviceExtension
->IrpFlags
& IRP_FLAG_COMPLETE
)
1408 DeviceExtension
->IrpFlags
&= ~IRP_FLAG_COMPLETE
;
1409 IoCompleteRequest(DpcIrp
, IO_NO_INCREMENT
);
1412 if (DeviceExtension
->IrpFlags
& IRP_FLAG_NEXT
)
1414 DeviceExtension
->IrpFlags
&= ~IRP_FLAG_NEXT
;
1415 IoStartNextPacket(DpcDeviceObject
, FALSE
);
1418 DPRINT("ScsiPortDpcForIsr() done\n");
1424 // This function handles timeouts and other time delayed processing
1429 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
1430 // IN PVOID Context the Controller extension for the
1431 // controller the device is on
1434 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
1437 DPRINT1("ScsiPortIoTimer()\n");
1441 static PSCSI_REQUEST_BLOCK
1442 ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
1443 PSCSI_REQUEST_BLOCK OriginalSrb
)
1445 PSCSI_REQUEST_BLOCK Srb
;
1448 Srb
= &DeviceExtension
->InternalSrb
;
1451 sizeof(SCSI_REQUEST_BLOCK
));
1453 Srb
->PathId
= OriginalSrb
->PathId
;
1454 Srb
->TargetId
= OriginalSrb
->TargetId
;
1455 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1456 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
);
1457 Srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
1459 Srb
->TimeOutValue
= 4;
1462 Srb
->DataBuffer
= &DeviceExtension
->InternalSenseData
;
1463 Srb
->DataTransferLength
= sizeof(SENSE_DATA
);
1465 Cdb
= (PCDB
)Srb
->Cdb
;
1466 Cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_REQUEST_SENSE
;
1467 Cdb
->CDB6INQUIRY
.AllocationLength
= sizeof(SENSE_DATA
);
1474 ScsiPortFreeSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
1476 DeviceExtension
->OriginalSrb
= NULL
;
1482 ScsiPortBuildDeviceMap(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
1484 OBJECT_ATTRIBUTES ObjectAttributes
;
1485 UNICODE_STRING KeyName
;
1486 WCHAR NameBuffer
[32];
1491 HANDLE ScsiTargetKey
;
1496 /* Open or create the 'Scsi' subkey */
1497 RtlInitUnicodeStringFromLiteral(&KeyName
,
1498 L
"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
1499 InitializeObjectAttributes(&ObjectAttributes
,
1504 Status
= NtCreateKey(&ScsiKey
,
1509 REG_OPTION_VOLATILE
,
1511 if (!NT_SUCCESS(Status
))
1514 /* Create new 'Scsi Port X' subkey */
1515 swprintf(NameBuffer
,
1517 DeviceExtension
->PortNumber
);
1518 RtlInitUnicodeString(&KeyName
,
1520 InitializeObjectAttributes(&ObjectAttributes
,
1525 Status
= NtCreateKey(&ScsiPortKey
,
1530 REG_OPTION_VOLATILE
,
1532 if (!NT_SUCCESS(Status
))
1538 /* Add port-specific values */
1540 /* 'DMA Enabled' (REG_DWORD) */
1541 DPRINT1("DMA Enabled = %s\n",
1542 (DeviceExtension
->PortCapabilities
->AdapterUsesPio
)?"TRUE":"FALSE");
1544 /* 'Driver' (REG_SZ) */
1546 /* 'Interrupt' (REG_DWORD) (NT4 only) */
1547 DPRINT1("Interrupt = %lx\n", DeviceExtension
->PortConfig
.BusInterruptLevel
);
1549 /* 'IOAddress' (REG_DWORD) (NT4 only) */
1550 DPRINT1("IOAddress = %lx\n",
1551 ScsiPortConvertPhysicalAddressToUlong(DeviceExtension
->PortConfig
.AccessRanges
[0].RangeStart
));
1554 /* Create 'Scsi Bus X' keys */
1555 for (BusNumber
= 0; BusNumber
< DeviceExtension
->PortConfig
.NumberOfBuses
; BusNumber
++)
1557 swprintf(NameBuffer
,
1559 DeviceExtension
->PortNumber
);
1560 RtlInitUnicodeString(&KeyName
,
1562 InitializeObjectAttributes(&ObjectAttributes
,
1567 Status
= NtCreateKey(&ScsiBusKey
,
1572 REG_OPTION_VOLATILE
,
1574 if (!NT_SUCCESS(Status
))
1576 NtClose(ScsiPortKey
);
1581 /* Create target keys */
1584 NtClose(ScsiBusKey
);
1587 NtClose(ScsiPortKey
);