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.22 2002/09/20 05:40:28 ei 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
;
71 PKINTERRUPT Interrupt
;
75 SCSI_PORT_TIMER_STATES TimerState
;
80 ULONG PortBusInfoSize
;
81 PSCSI_ADAPTER_BUS_INFO PortBusInfo
;
83 PIO_SCSI_CAPABILITIES PortCapabilities
;
85 PDEVICE_OBJECT DeviceObject
;
86 PCONTROLLER_OBJECT ControllerObject
;
88 PHW_STARTIO HwStartIo
;
89 PHW_INTERRUPT HwInterrupt
;
91 PSCSI_REQUEST_BLOCK OriginalSrb
;
92 SCSI_REQUEST_BLOCK InternalSrb
;
93 SENSE_DATA InternalSenseData
;
95 UCHAR MiniPortDeviceExtension
[1]; /* must be the last entry */
96 } SCSI_PORT_DEVICE_EXTENSION
, *PSCSI_PORT_DEVICE_EXTENSION
;
100 * SCSI_PORT_TIMER_STATES
103 * An enumeration containing the states in the timer DFA
108 #define IRP_FLAG_COMPLETE 0x00000001
109 #define IRP_FLAG_NEXT 0x00000002
112 /* GLOBALS *******************************************************************/
114 static NTSTATUS STDCALL
115 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
118 static NTSTATUS STDCALL
119 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
122 static NTSTATUS STDCALL
123 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
127 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
130 static IO_ALLOCATION_ACTION STDCALL
131 ScsiPortAllocateController(IN PDEVICE_OBJECT DeviceObject
,
133 IN PVOID MapRegisterBase
,
136 static BOOLEAN STDCALL
137 ScsiPortStartPacket(IN OUT PVOID Context
);
140 ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject
,
141 IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension
,
145 ScsiPortInquire(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
147 static BOOLEAN STDCALL
148 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
149 IN PVOID ServiceContext
);
152 ScsiPortDpcForIsr(IN PKDPC Dpc
,
153 IN PDEVICE_OBJECT DpcDeviceObject
,
155 IN PVOID DpcContext
);
158 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
161 static PSCSI_REQUEST_BLOCK
162 ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
163 PSCSI_REQUEST_BLOCK OriginalSrb
);
165 /* FUNCTIONS *****************************************************************/
167 /**********************************************************************
172 * This function initializes the driver.
179 * System allocated Driver Object for this driver.
182 * Name of registry driver service key.
189 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
190 IN PUNICODE_STRING RegistryPath
)
192 DPRINT("ScsiPort Driver %s\n", VERSION
);
193 return(STATUS_SUCCESS
);
197 /**********************************************************************
202 * Prints debugging messages.
209 * Debug level of the given message.
212 * Pointer to printf()-compatible format string.
215 Additional output data (see printf()).
222 ScsiDebugPrint(IN ULONG DebugPrintLevel
,
223 IN PCHAR DebugMessage
,
230 if (DebugPrintLevel
> InternalDebugLevel
)
234 va_start(ap
, DebugMessage
);
235 vsprintf(Buffer
, DebugMessage
, ap
);
243 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension
,
254 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address
)
256 return(Address
.u
.LowPart
);
261 ScsiPortFlushDma(IN PVOID HwDeviceExtension
)
268 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension
,
269 IN PVOID MappedAddress
)
276 ScsiPortGetBusData(IN PVOID DeviceExtension
,
277 IN ULONG BusDataType
,
278 IN ULONG SystemIoBusNumber
,
283 return(HalGetBusData(BusDataType
,
292 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension
,
293 IN INTERFACE_TYPE BusType
,
294 IN ULONG SystemIoBusNumber
,
295 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
296 IN ULONG NumberOfBytes
,
297 IN BOOLEAN InIoSpace
)
300 PHYSICAL_ADDRESS TranslatedAddress
;
301 PVOID VirtualAddress
;
305 AddressSpace
= (ULONG
)InIoSpace
;
307 if (!HalTranslateBusAddress(BusType
,
315 if (AddressSpace
!= 0)
316 return (PVOID
)TranslatedAddress
.u
.LowPart
;
318 VirtualAddress
= MmMapIoSpace(TranslatedAddress
,
322 Buffer
= ExAllocatePool(NonPagedPool
,0x20);
324 return VirtualAddress
;
326 return NULL
; /* ?? */
331 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension
,
340 SCSI_PHYSICAL_ADDRESS STDCALL
341 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension
,
342 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
343 IN PVOID VirtualAddress
,
350 PSCSI_REQUEST_BLOCK STDCALL
351 ScsiPortGetSrb(IN PVOID DeviceExtension
,
362 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension
,
363 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
364 IN ULONG NumberOfBytes
)
371 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension
,
372 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress
)
378 /**********************************************************************
383 * Initializes SCSI port driver specific data.
390 * Pointer to the miniport driver's driver object.
393 * Pointer to the miniport driver's registry path.
395 * HwInitializationData
396 * Pointer to port driver specific configuration data.
399 Miniport driver specific context.
406 ScsiPortInitialize(IN PVOID Argument1
,
408 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
411 PDRIVER_OBJECT DriverObject
= (PDRIVER_OBJECT
)Argument1
;
412 PUNICODE_STRING RegistryPath
= (PUNICODE_STRING
)Argument2
;
413 PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension
;
414 PCONFIGURATION_INFORMATION SystemConfig
;
415 PPORT_CONFIGURATION_INFORMATION PortConfig
;
421 PACCESS_RANGE AccessRanges
;
424 DPRINT("ScsiPortInitialize() called!\n");
426 if ((HwInitializationData
->HwInitialize
== NULL
) ||
427 (HwInitializationData
->HwStartIo
== NULL
) ||
428 (HwInitializationData
->HwInterrupt
== NULL
) ||
429 (HwInitializationData
->HwFindAdapter
== NULL
) ||
430 (HwInitializationData
->HwResetBus
== NULL
))
431 return(STATUS_INVALID_PARAMETER
);
433 DriverObject
->DriverStartIo
= ScsiPortStartIo
;
434 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ScsiPortCreateClose
;
435 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ScsiPortCreateClose
;
436 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ScsiPortDeviceControl
;
437 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = ScsiPortDispatchScsi
;
440 SystemConfig
= IoGetConfigurationInformation();
442 ExtensionSize
= sizeof(SCSI_PORT_DEVICE_EXTENSION
) +
443 HwInitializationData
->DeviceExtensionSize
;
444 PseudoDeviceExtension
= ExAllocatePool(PagedPool
,
446 RtlZeroMemory(PseudoDeviceExtension
,
448 PseudoDeviceExtension
->Length
= ExtensionSize
;
449 PseudoDeviceExtension
->MiniPortExtensionSize
= HwInitializationData
->DeviceExtensionSize
;
450 PseudoDeviceExtension
->HwStartIo
= HwInitializationData
->HwStartIo
;
451 PseudoDeviceExtension
->HwInterrupt
= HwInitializationData
->HwInterrupt
;
453 PortConfig
= &PseudoDeviceExtension
->PortConfig
;
455 PortConfig
->Length
= sizeof(PORT_CONFIGURATION_INFORMATION
);
456 PortConfig
->AdapterInterfaceType
= HwInitializationData
->AdapterInterfaceType
;
457 PortConfig
->InterruptMode
=
458 (PortConfig
->AdapterInterfaceType
== PCIBus
) ? LevelSensitive
: Latched
;
459 PortConfig
->AtdiskPrimaryClaimed
= SystemConfig
->AtDiskPrimaryAddressClaimed
;
460 PortConfig
->AtdiskSecondaryClaimed
= SystemConfig
->AtDiskSecondaryAddressClaimed
;
461 PortConfig
->NumberOfAccessRanges
= HwInitializationData
->NumberOfAccessRanges
;
463 PortConfig
->AccessRanges
=
464 ExAllocatePool(PagedPool
,
465 sizeof(ACCESS_RANGE
) * PortConfig
->NumberOfAccessRanges
);
468 PortConfig
->SystemIoBusNumber
= 0;
469 PortConfig
->SlotNumber
= 0;
471 MaxBus
= (PortConfig
->AdapterInterfaceType
== PCIBus
) ? 8 : 1;
473 DPRINT("MaxBus: %lu\n", MaxBus
);
477 DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig
->SystemIoBusNumber
);
479 // RtlZeroMemory(AccessRanges,
480 // sizeof(ACCESS_RANGE) * PortConfig->NumberOfAccessRanges);
482 RtlZeroMemory(PseudoDeviceExtension
->MiniPortDeviceExtension
,
483 PseudoDeviceExtension
->MiniPortExtensionSize
);
485 /* Note: HwFindAdapter is called once for each bus */
486 Result
= (HwInitializationData
->HwFindAdapter
)(&PseudoDeviceExtension
->MiniPortDeviceExtension
,
488 NULL
, /* BusInformation */
489 NULL
, /* ArgumentString */
490 &PseudoDeviceExtension
->PortConfig
,
492 DPRINT("HwFindAdapter() result: %lu\n", Result
);
494 if (Result
== SP_RETURN_FOUND
)
496 DPRINT("ScsiPortInitialize(): Found HBA!\n");
498 Status
= ScsiPortCreatePortDevice(DriverObject
,
499 PseudoDeviceExtension
,
500 SystemConfig
->ScsiPortCount
);
502 if (!NT_SUCCESS(Status
))
504 DbgPrint("ScsiPortCreatePortDevice() failed! (Status 0x%lX)\n", Status
);
506 ExFreePool(PortConfig
->AccessRanges
);
507 ExFreePool(PseudoDeviceExtension
);
512 /* Update the configuration info */
513 SystemConfig
->AtDiskPrimaryAddressClaimed
= PortConfig
->AtdiskPrimaryClaimed
;
514 SystemConfig
->AtDiskSecondaryAddressClaimed
= PortConfig
->AtdiskSecondaryClaimed
;
515 SystemConfig
->ScsiPortCount
++;
520 PortConfig
->SystemIoBusNumber
++;
521 PortConfig
->SlotNumber
= 0;
524 DPRINT("Bus: %lu MaxBus: %lu\n", PortConfig
->SystemIoBusNumber
, MaxBus
);
525 if (PortConfig
->SystemIoBusNumber
>= MaxBus
)
527 DPRINT("Scanned all buses!\n");
532 ExFreePool(PortConfig
->AccessRanges
);
533 ExFreePool(PseudoDeviceExtension
);
535 DPRINT("ScsiPortInitialize() done!\n");
537 return(STATUS_SUCCESS
);
542 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension
,
543 IN PSCSI_REQUEST_BLOCK Srb
,
544 IN ULONG LogicalAddress
,
552 ScsiPortLogError(IN PVOID HwDeviceExtension
,
553 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
565 ScsiPortMoveMemory(OUT PVOID Destination
,
569 RtlMoveMemory(Destination
,
576 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType
,
577 IN PVOID HwDeviceExtension
,
580 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
582 DPRINT("ScsiPortNotification() called\n");
584 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
585 SCSI_PORT_DEVICE_EXTENSION
,
586 MiniPortDeviceExtension
);
588 DPRINT("DeviceExtension %p\n", DeviceExtension
);
590 DPRINT("Initializing = %s\n", (DeviceExtension
->Initializing
)?"TRUE":"FALSE");
592 if (DeviceExtension
->Initializing
== TRUE
)
595 switch (NotificationType
)
597 case RequestComplete
:
598 DPRINT("Notify: RequestComplete\n");
599 DeviceExtension
->IrpFlags
|= IRP_FLAG_COMPLETE
;
603 DPRINT("Notify: NextRequest\n");
604 DeviceExtension
->IrpFlags
|= IRP_FLAG_NEXT
;
614 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension
,
615 IN ULONG BusDataType
,
616 IN ULONG SystemIoBusNumber
,
622 return(HalSetBusDataByOffset(BusDataType
,
632 ScsiPortValidateRange(IN PVOID HwDeviceExtension
,
633 IN INTERFACE_TYPE BusType
,
634 IN ULONG SystemIoBusNumber
,
635 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
636 IN ULONG NumberOfBytes
,
637 IN BOOLEAN InIoSpace
)
643 /* INTERNAL FUNCTIONS ********************************************************/
645 /**********************************************************************
647 * ScsiPortCreateClose
650 * Answer requests for Create/Close calls: a null operation.
657 * Pointer to a device object.
663 Additional output data (see printf()).
669 static NTSTATUS STDCALL
670 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
673 DPRINT("ScsiPortCreateClose()\n");
675 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
676 Irp
->IoStatus
.Information
= FILE_OPENED
;
678 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
680 return(STATUS_SUCCESS
);
684 /**********************************************************************
686 * ScsiPortDispatchScsi
689 * Answer requests for SCSI calls
695 * Standard dispatch arguments
701 static NTSTATUS STDCALL
702 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
705 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
706 PIO_STACK_LOCATION Stack
;
707 PSCSI_REQUEST_BLOCK Srb
;
708 NTSTATUS Status
= STATUS_SUCCESS
;
711 DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n",
714 DeviceExtension
= DeviceObject
->DeviceExtension
;
715 Stack
= IoGetCurrentIrpStackLocation(Irp
);
717 Srb
= Stack
->Parameters
.Scsi
.Srb
;
720 Status
= STATUS_UNSUCCESSFUL
;
722 Irp
->IoStatus
.Status
= Status
;
723 Irp
->IoStatus
.Information
= 0;
725 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
730 DPRINT("Srb: %p\n", Srb
);
731 DPRINT("Srb->Function: %lu\n", Srb
->Function
);
732 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb
->PathId
, Srb
->TargetId
, Srb
->Lun
);
734 switch (Srb
->Function
)
736 case SRB_FUNCTION_EXECUTE_SCSI
:
737 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
738 return(STATUS_PENDING
);
740 case SRB_FUNCTION_SHUTDOWN
:
741 case SRB_FUNCTION_FLUSH
:
742 if (DeviceExtension
->PortConfig
.CachesData
== TRUE
)
744 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
745 return(STATUS_PENDING
);
749 case SRB_FUNCTION_CLAIM_DEVICE
:
751 PSCSI_ADAPTER_BUS_INFO AdapterInfo
;
752 PSCSI_INQUIRY_DATA UnitInfo
;
753 PINQUIRYDATA InquiryData
;
755 DPRINT(" SRB_FUNCTION_CLAIM_DEVICE\n");
756 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb
->PathId
, Srb
->TargetId
, Srb
->Lun
);
758 Srb
->DataBuffer
= NULL
;
760 if (DeviceExtension
->PortBusInfo
!= NULL
)
762 AdapterInfo
= (PSCSI_ADAPTER_BUS_INFO
)DeviceExtension
->PortBusInfo
;
764 if (AdapterInfo
->BusData
[Srb
->PathId
].NumberOfLogicalUnits
== 0)
767 UnitInfo
= (PSCSI_INQUIRY_DATA
)((PUCHAR
)AdapterInfo
+
768 AdapterInfo
->BusData
[Srb
->PathId
].InquiryDataOffset
);
770 while (AdapterInfo
->BusData
[Srb
->PathId
].InquiryDataOffset
)
772 InquiryData
= (PINQUIRYDATA
)UnitInfo
->InquiryData
;
774 if ((UnitInfo
->TargetId
== Srb
->TargetId
) &&
775 (UnitInfo
->Lun
== Srb
->Lun
) &&
776 (UnitInfo
->DeviceClaimed
== FALSE
))
778 UnitInfo
->DeviceClaimed
= TRUE
;
779 DPRINT("Claimed device!\n");
781 /* FIXME: Hack!!!!! */
782 Srb
->DataBuffer
= DeviceObject
;
787 if (UnitInfo
->NextInquiryDataOffset
== 0)
790 UnitInfo
= (PSCSI_INQUIRY_DATA
)((PUCHAR
)AdapterInfo
+ UnitInfo
->NextInquiryDataOffset
);
796 case SRB_FUNCTION_RELEASE_DEVICE
:
798 PSCSI_ADAPTER_BUS_INFO AdapterInfo
;
799 PSCSI_INQUIRY_DATA UnitInfo
;
800 PINQUIRYDATA InquiryData
;
802 DPRINT(" SRB_FUNCTION_RELEASE_DEVICE\n");
803 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb
->PathId
, Srb
->TargetId
, Srb
->Lun
);
805 if (DeviceExtension
->PortBusInfo
!= NULL
)
807 AdapterInfo
= (PSCSI_ADAPTER_BUS_INFO
)DeviceExtension
->PortBusInfo
;
809 if (AdapterInfo
->BusData
[Srb
->PathId
].NumberOfLogicalUnits
== 0)
812 UnitInfo
= (PSCSI_INQUIRY_DATA
)((PUCHAR
)AdapterInfo
+
813 AdapterInfo
->BusData
[Srb
->PathId
].InquiryDataOffset
);
815 while (AdapterInfo
->BusData
[Srb
->PathId
].InquiryDataOffset
)
817 InquiryData
= (PINQUIRYDATA
)UnitInfo
->InquiryData
;
819 if ((UnitInfo
->TargetId
== Srb
->TargetId
) &&
820 (UnitInfo
->Lun
== Srb
->Lun
) &&
821 (UnitInfo
->DeviceClaimed
== TRUE
))
823 UnitInfo
->DeviceClaimed
= FALSE
;
824 DPRINT("Released device!\n");
828 if (UnitInfo
->NextInquiryDataOffset
== 0)
831 UnitInfo
= (PSCSI_INQUIRY_DATA
)((PUCHAR
)AdapterInfo
+ UnitInfo
->NextInquiryDataOffset
);
838 DPRINT1("SRB function not implemented (Function %lu)\n", Srb
->Function
);
839 Status
= STATUS_NOT_IMPLEMENTED
;
843 Irp
->IoStatus
.Status
= Status
;
844 Irp
->IoStatus
.Information
= DataSize
;
846 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
852 /**********************************************************************
854 * ScsiPortDeviceControl
857 * Answer requests for device control calls
863 * Standard dispatch arguments
869 static NTSTATUS STDCALL
870 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
873 PIO_STACK_LOCATION Stack
;
874 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
876 DPRINT("ScsiPortDeviceControl()\n");
878 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
879 Irp
->IoStatus
.Information
= 0;
882 Stack
= IoGetCurrentIrpStackLocation(Irp
);
883 DeviceExtension
= DeviceObject
->DeviceExtension
;
885 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
888 case IOCTL_SCSI_GET_CAPABILITIES
:
890 DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
892 *((PIO_SCSI_CAPABILITIES
*)Irp
->AssociatedIrp
.SystemBuffer
) =
893 DeviceExtension
->PortCapabilities
;
895 Irp
->IoStatus
.Information
= sizeof(PIO_SCSI_CAPABILITIES
);
899 case IOCTL_SCSI_GET_INQUIRY_DATA
:
901 DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
903 /* Copy inquiry data to the port device extension */
904 memcpy(Irp
->AssociatedIrp
.SystemBuffer
,
905 DeviceExtension
->PortBusInfo
,
906 DeviceExtension
->PortBusInfoSize
);
908 DPRINT("BufferSize: %lu\n", DeviceExtension
->PortBusInfoSize
);
909 Irp
->IoStatus
.Information
= DeviceExtension
->PortBusInfoSize
;
914 DPRINT1(" unknown ioctl code: 0x%lX\n",
915 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
919 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
921 return(STATUS_SUCCESS
);
926 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
929 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
930 PIO_STACK_LOCATION IrpStack
;
933 DPRINT("ScsiPortStartIo() called!\n");
935 DeviceExtension
= DeviceObject
->DeviceExtension
;
936 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
938 // FIXME: implement the supported functions
940 switch (IrpStack
->MajorFunction
)
945 PSCSI_REQUEST_BLOCK Srb
;
948 DPRINT("IRP_MJ_SCSI\n");
950 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
952 DPRINT("DeviceExtension %p\n", DeviceExtension
);
954 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
955 Irp
->IoStatus
.Information
= Srb
->DataTransferLength
;
957 DeviceExtension
->CurrentIrp
= Irp
;
959 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
963 DPRINT("Synchronization failed!\n");
965 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
966 Irp
->IoStatus
.Information
= 0;
967 IoCompleteRequest(Irp
,
969 IoStartNextPacket(DeviceObject
,
972 KeAcquireSpinLock(&DeviceExtension
->IrpLock
, &oldIrql
);
973 if (DeviceExtension
->IrpFlags
& IRP_FLAG_COMPLETE
)
975 DeviceExtension
->IrpFlags
&= ~IRP_FLAG_COMPLETE
;
976 IoCompleteRequest(Irp
,
980 if (DeviceExtension
->IrpFlags
& IRP_FLAG_NEXT
)
982 DeviceExtension
->IrpFlags
&= ~IRP_FLAG_NEXT
;
983 KeReleaseSpinLock(&DeviceExtension
->IrpLock
, oldIrql
);
984 IoStartNextPacket(DeviceObject
,
989 KeReleaseSpinLock(&DeviceExtension
->IrpLock
, oldIrql
);
995 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
996 Irp
->IoStatus
.Information
= 0;
997 IoCompleteRequest(Irp
,
999 IoStartNextPacket(DeviceObject
,
1003 DPRINT("ScsiPortStartIo() done\n");
1007 static BOOLEAN STDCALL
1008 ScsiPortStartPacket(IN OUT PVOID Context
)
1010 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1011 PIO_STACK_LOCATION IrpStack
;
1012 PSCSI_REQUEST_BLOCK Srb
;
1014 DPRINT("ScsiPortStartPacket() called\n");
1016 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)Context
;
1018 IrpStack
= IoGetCurrentIrpStackLocation(DeviceExtension
->CurrentIrp
);
1019 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
1021 return(DeviceExtension
->HwStartIo(&DeviceExtension
->MiniPortDeviceExtension
,
1026 /**********************************************************************
1028 * ScsiPortCreatePortDevice
1031 * Creates and initializes a SCSI port device object.
1040 * PseudoDeviceExtension
1051 ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject
,
1052 IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension
,
1053 IN ULONG PortNumber
)
1055 PSCSI_PORT_DEVICE_EXTENSION PortDeviceExtension
;
1056 PIO_SCSI_CAPABILITIES PortCapabilities
;
1057 PDEVICE_OBJECT PortDeviceObject
;
1058 WCHAR NameBuffer
[80];
1059 UNICODE_STRING DeviceName
;
1060 WCHAR DosNameBuffer
[80];
1061 UNICODE_STRING DosDeviceName
;
1063 ULONG AccessRangeSize
;
1071 DPRINT("ScsiPortCreatePortDevice() called\n");
1074 MappedIrq
= HalGetInterruptVector(PseudoDeviceExtension
->PortConfig
.AdapterInterfaceType
,
1075 PseudoDeviceExtension
->PortConfig
.SystemIoBusNumber
,
1077 PseudoDeviceExtension
->PortConfig
.BusInterruptLevel
,
1082 /* Create a unicode device name */
1083 swprintf(NameBuffer
,
1084 L
"\\Device\\ScsiPort%lu",
1086 RtlInitUnicodeString(&DeviceName
,
1089 DPRINT("Creating device: %wZ\n", &DeviceName
);
1091 /* Create the port device */
1092 Status
= IoCreateDevice(DriverObject
,
1093 PseudoDeviceExtension
->Length
,
1095 FILE_DEVICE_CONTROLLER
,
1099 if (!NT_SUCCESS(Status
))
1101 DbgPrint("IoCreateDevice call failed! (Status 0x%lX)\n", Status
);
1105 DPRINT("Created device: %wZ\n", &DeviceName
);
1107 /* Set the buffering strategy here... */
1108 PortDeviceObject
->Flags
|= DO_DIRECT_IO
;
1109 PortDeviceObject
->AlignmentRequirement
= FILE_WORD_ALIGNMENT
;
1111 PortDeviceExtension
= PortDeviceObject
->DeviceExtension
;
1113 /* Copy pseudo device extension into the real device extension */
1114 memcpy(PortDeviceExtension
,
1115 PseudoDeviceExtension
,
1116 PseudoDeviceExtension
->Length
);
1118 /* Copy access ranges */
1120 sizeof(ACCESS_RANGE
) * PseudoDeviceExtension
->PortConfig
.NumberOfAccessRanges
;
1121 PortDeviceExtension
->PortConfig
.AccessRanges
= ExAllocatePool(NonPagedPool
,
1123 memcpy(PortDeviceExtension
->PortConfig
.AccessRanges
,
1124 PseudoDeviceExtension
->PortConfig
.AccessRanges
,
1127 PortDeviceExtension
->DeviceObject
= PortDeviceObject
;
1128 PortDeviceExtension
->PortNumber
= PortNumber
;
1130 /* Initialize the spin lock in the controller extension */
1131 KeInitializeSpinLock(&PortDeviceExtension
->IrpLock
);
1132 KeInitializeSpinLock(&PortDeviceExtension
->SpinLock
);
1134 /* Register an interrupt handler for this device */
1135 Status
= IoConnectInterrupt(&PortDeviceExtension
->Interrupt
,
1137 PortDeviceExtension
,
1138 &PortDeviceExtension
->SpinLock
,
1139 PortDeviceExtension
->PortConfig
.BusInterruptVector
, // MappedIrq,
1140 PortDeviceExtension
->PortConfig
.BusInterruptLevel
, // Dirql,
1142 PortDeviceExtension
->PortConfig
.InterruptMode
,
1146 if (!NT_SUCCESS(Status
))
1148 DbgPrint("Could not Connect Interrupt %d\n",
1149 PortDeviceExtension
->PortConfig
.BusInterruptVector
);
1153 /* Initialize the DPC object */
1154 IoInitializeDpcRequest(PortDeviceExtension
->DeviceObject
,
1157 /* Initialize the device timer */
1158 PortDeviceExtension
->TimerState
= IDETimerIdle
;
1159 PortDeviceExtension
->TimerCount
= 0;
1160 IoInitializeTimer(PortDeviceExtension
->DeviceObject
,
1162 PortDeviceExtension
);
1164 /* Initialize port capabilities */
1165 PortCapabilities
= ExAllocatePool(NonPagedPool
,
1166 sizeof(IO_SCSI_CAPABILITIES
));
1167 PortDeviceExtension
->PortCapabilities
= PortCapabilities
;
1168 PortCapabilities
->Length
= sizeof(IO_SCSI_CAPABILITIES
);
1169 PortCapabilities
->MaximumTransferLength
=
1170 PortDeviceExtension
->PortConfig
.MaximumTransferLength
;
1171 PortCapabilities
->MaximumPhysicalPages
=
1172 PortCapabilities
->MaximumTransferLength
/ PAGESIZE
;
1173 PortCapabilities
->SupportedAsynchronousEvents
= 0; /* FIXME */
1174 PortCapabilities
->AlignmentMask
=
1175 PortDeviceExtension
->PortConfig
.AlignmentMask
;
1176 PortCapabilities
->TaggedQueuing
=
1177 PortDeviceExtension
->PortConfig
.TaggedQueuing
;
1178 PortCapabilities
->AdapterScansDown
=
1179 PortDeviceExtension
->PortConfig
.AdapterScansDown
;
1180 PortCapabilities
->AdapterUsesPio
= TRUE
; /* FIXME */
1182 /* Initialize inquiry data */
1183 PortDeviceExtension
->PortBusInfoSize
= 0;
1184 PortDeviceExtension
->PortBusInfo
= NULL
;
1186 DPRINT("DeviceExtension %p\n", PortDeviceExtension
);
1187 ScsiPortInquire(PortDeviceExtension
);
1190 /* FIXME: Copy more configuration data? */
1192 /* Create the dos device link */
1193 swprintf(DosNameBuffer
,
1196 RtlInitUnicodeString(&DosDeviceName
,
1199 IoCreateSymbolicLink(&DosDeviceName
,
1202 DPRINT("ScsiPortCreatePortDevice() done\n");
1204 return(STATUS_SUCCESS
);
1209 ScsiPortInquire(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
1211 PSCSI_ADAPTER_BUS_INFO AdapterInfo
;
1212 PSCSI_INQUIRY_DATA UnitInfo
, PrevUnit
;
1213 SCSI_REQUEST_BLOCK Srb
;
1220 DPRINT("ScsiPortInquire() called\n");
1222 DeviceExtension
->Initializing
= TRUE
;
1224 /* Copy inquiry data to the port device extension */
1225 AdapterInfo
=(PSCSI_ADAPTER_BUS_INFO
)ExAllocatePool(NonPagedPool
, 4096);
1226 RtlZeroMemory(AdapterInfo
, 4096);
1227 AdapterInfo
->NumberOfBuses
= DeviceExtension
->PortConfig
.NumberOfBuses
;
1229 UnitInfo
= (PSCSI_INQUIRY_DATA
)
1230 ((PUCHAR
)AdapterInfo
+ sizeof(SCSI_ADAPTER_BUS_INFO
) +
1231 (sizeof(SCSI_BUS_DATA
) * (AdapterInfo
->NumberOfBuses
- 1)));
1234 sizeof(SCSI_REQUEST_BLOCK
));
1235 Srb
.DataBuffer
= ExAllocatePool(NonPagedPool
, 256);
1236 Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1237 Srb
.DataTransferLength
= 256;
1238 Srb
.Cdb
[0] = SCSIOP_INQUIRY
;
1240 for (Bus
= 0; Bus
< AdapterInfo
->NumberOfBuses
; Bus
++)
1244 AdapterInfo
->BusData
[Bus
].InitiatorBusId
= 0; /* ? */
1245 AdapterInfo
->BusData
[Bus
].InquiryDataOffset
=
1246 (ULONG
)((PUCHAR
)UnitInfo
- (PUCHAR
)AdapterInfo
);
1251 for (Target
= 0; Target
< DeviceExtension
->PortConfig
.MaximumNumberOfTargets
; Target
++)
1253 Srb
.TargetId
= Target
;
1255 Srb
.SrbStatus
= SRB_STATUS_SUCCESS
;
1257 Result
= DeviceExtension
->HwStartIo(&DeviceExtension
->MiniPortDeviceExtension
,
1259 DPRINT("Result: %s Srb.SrbStatus %lx\n", (Result
)?"True":"False", Srb
.SrbStatus
);
1261 if (Result
== TRUE
&& Srb
.SrbStatus
== SRB_STATUS_SUCCESS
)
1263 UnitInfo
->PathId
= Bus
;
1264 UnitInfo
->TargetId
= Target
;
1266 UnitInfo
->InquiryDataLength
= INQUIRYDATABUFFERSIZE
;
1267 memcpy(&UnitInfo
->InquiryData
,
1269 INQUIRYDATABUFFERSIZE
);
1270 if (PrevUnit
!= NULL
)
1271 PrevUnit
->NextInquiryDataOffset
= (ULONG
)((PUCHAR
)UnitInfo
-(PUCHAR
)AdapterInfo
);
1272 PrevUnit
= UnitInfo
;
1273 UnitInfo
= (PSCSI_INQUIRY_DATA
)((PUCHAR
)UnitInfo
+ sizeof(SCSI_INQUIRY_DATA
)+INQUIRYDATABUFFERSIZE
-1);
1277 DPRINT("UnitCount: %lu\n", UnitCount
);
1278 AdapterInfo
->BusData
[Bus
].NumberOfLogicalUnits
= UnitCount
;
1280 AdapterInfo
->BusData
[Bus
].InquiryDataOffset
= 0;
1282 DataSize
= (ULONG
)((PUCHAR
)UnitInfo
-(PUCHAR
)AdapterInfo
);
1284 ExFreePool(Srb
.DataBuffer
);
1286 DeviceExtension
->Initializing
= FALSE
;
1288 /* copy inquiry data to the port driver's device extension */
1289 DeviceExtension
->PortBusInfoSize
= DataSize
;
1290 DeviceExtension
->PortBusInfo
= ExAllocatePool(NonPagedPool
,
1292 RtlCopyMemory(DeviceExtension
->PortBusInfo
,
1296 ExFreePool(AdapterInfo
);
1298 DPRINT("ScsiPortInquire() done\n");
1302 static BOOLEAN STDCALL
1303 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
1304 IN PVOID ServiceContext
)
1306 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1309 DPRINT("ScsiPortIsr() called!\n");
1311 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)ServiceContext
;
1313 Result
= DeviceExtension
->HwInterrupt(&DeviceExtension
->MiniPortDeviceExtension
);
1314 if (Result
== FALSE
)
1319 if (DeviceExtension
->IrpFlags
)
1321 IoRequestDpc(DeviceExtension
->DeviceObject
,
1322 DeviceExtension
->CurrentIrp
,
1330 // ScsiPortDpcForIsr
1337 // IN PDEVICE_OBJECT DpcDeviceObject
1339 // IN PVOID DpcContext
1342 ScsiPortDpcForIsr(IN PKDPC Dpc
,
1343 IN PDEVICE_OBJECT DpcDeviceObject
,
1345 IN PVOID DpcContext
)
1347 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1348 PIO_STACK_LOCATION IrpStack
;
1349 PSCSI_REQUEST_BLOCK Srb
;
1352 DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
1353 Dpc
, DpcDeviceObject
, DpcIrp
, DpcContext
);
1355 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DpcContext
;
1357 KeAcquireSpinLock(&DeviceExtension
->IrpLock
, &oldIrql
);
1358 if (DeviceExtension
->IrpFlags
)
1360 IrpStack
= IoGetCurrentIrpStackLocation(DeviceExtension
->CurrentIrp
);
1361 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
1363 if (DeviceExtension
->OriginalSrb
!= NULL
)
1365 DPRINT("Got sense data!\n");
1367 DPRINT("Valid: %x\n", DeviceExtension
->InternalSenseData
.Valid
);
1368 DPRINT("ErrorCode: %x\n", DeviceExtension
->InternalSenseData
.ErrorCode
);
1369 DPRINT("SenseKey: %x\n", DeviceExtension
->InternalSenseData
.SenseKey
);
1370 DPRINT("SenseCode: %x\n", DeviceExtension
->InternalSenseData
.AdditionalSenseCode
);
1372 /* Copy sense data */
1373 if (DeviceExtension
->OriginalSrb
->SenseInfoBufferLength
!= 0)
1375 RtlCopyMemory(DeviceExtension
->OriginalSrb
->SenseInfoBuffer
,
1376 &DeviceExtension
->InternalSenseData
,
1377 sizeof(SENSE_DATA
));
1378 DeviceExtension
->OriginalSrb
->SrbStatus
|= SRB_STATUS_AUTOSENSE_VALID
;
1381 /* Clear current sense data */
1382 RtlZeroMemory(&DeviceExtension
->InternalSenseData
, sizeof(SENSE_DATA
));
1384 IrpStack
->Parameters
.Scsi
.Srb
= DeviceExtension
->OriginalSrb
;
1385 DeviceExtension
->OriginalSrb
= NULL
;
1387 else if ((SRB_STATUS(Srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) &&
1388 (Srb
->ScsiStatus
== SCSISTAT_CHECK_CONDITION
))
1390 DPRINT("SCSIOP_REQUEST_SENSE required!\n");
1392 DeviceExtension
->OriginalSrb
= Srb
;
1393 IrpStack
->Parameters
.Scsi
.Srb
= ScsiPortInitSenseRequestSrb(DeviceExtension
,
1395 KeReleaseSpinLock(&DeviceExtension
->IrpLock
, oldIrql
);
1396 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
1397 ScsiPortStartPacket
,
1400 DPRINT("Synchronization failed!\n");
1402 DpcIrp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
1403 DpcIrp
->IoStatus
.Information
= 0;
1404 IoCompleteRequest(DpcIrp
,
1406 IoStartNextPacket(DpcDeviceObject
,
1413 DeviceExtension
->CurrentIrp
= NULL
;
1416 // DpcIrp->IoStatus.Information = 0;
1417 // DpcIrp->IoStatus.Status = STATUS_SUCCESS;
1419 if (DeviceExtension
->IrpFlags
& IRP_FLAG_COMPLETE
)
1421 DeviceExtension
->IrpFlags
&= ~IRP_FLAG_COMPLETE
;
1422 IoCompleteRequest(DpcIrp
, IO_NO_INCREMENT
);
1425 if (DeviceExtension
->IrpFlags
& IRP_FLAG_NEXT
)
1427 DeviceExtension
->IrpFlags
&= ~IRP_FLAG_NEXT
;
1428 KeReleaseSpinLock(&DeviceExtension
->IrpLock
, oldIrql
);
1429 IoStartNextPacket(DpcDeviceObject
, FALSE
);
1433 KeReleaseSpinLock(&DeviceExtension
->IrpLock
, oldIrql
);
1438 KeReleaseSpinLock(&DeviceExtension
->IrpLock
, oldIrql
);
1440 DPRINT("ScsiPortDpcForIsr() done\n");
1446 // This function handles timeouts and other time delayed processing
1451 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
1452 // IN PVOID Context the Controller extension for the
1453 // controller the device is on
1456 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
1459 DPRINT1("ScsiPortIoTimer()\n");
1463 static PSCSI_REQUEST_BLOCK
1464 ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
1465 PSCSI_REQUEST_BLOCK OriginalSrb
)
1467 PSCSI_REQUEST_BLOCK Srb
;
1470 Srb
= &DeviceExtension
->InternalSrb
;
1473 sizeof(SCSI_REQUEST_BLOCK
));
1475 Srb
->PathId
= OriginalSrb
->PathId
;
1476 Srb
->TargetId
= OriginalSrb
->TargetId
;
1477 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1478 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
);
1479 Srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
1481 Srb
->TimeOutValue
= 4;
1484 Srb
->DataBuffer
= &DeviceExtension
->InternalSenseData
;
1485 Srb
->DataTransferLength
= sizeof(SENSE_DATA
);
1487 Cdb
= (PCDB
)Srb
->Cdb
;
1488 Cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_REQUEST_SENSE
;
1489 Cdb
->CDB6INQUIRY
.AllocationLength
= sizeof(SENSE_DATA
);
1496 ScsiPortFreeSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
1498 DeviceExtension
->OriginalSrb
= NULL
;
1504 ScsiPortBuildDeviceMap(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
1506 OBJECT_ATTRIBUTES ObjectAttributes
;
1507 UNICODE_STRING KeyName
;
1508 WCHAR NameBuffer
[32];
1513 HANDLE ScsiTargetKey
;
1518 /* Open or create the 'Scsi' subkey */
1519 RtlInitUnicodeStringFromLiteral(&KeyName
,
1520 L
"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
1521 InitializeObjectAttributes(&ObjectAttributes
,
1526 Status
= NtCreateKey(&ScsiKey
,
1531 REG_OPTION_VOLATILE
,
1533 if (!NT_SUCCESS(Status
))
1536 /* Create new 'Scsi Port X' subkey */
1537 swprintf(NameBuffer
,
1539 DeviceExtension
->PortNumber
);
1540 RtlInitUnicodeString(&KeyName
,
1542 InitializeObjectAttributes(&ObjectAttributes
,
1547 Status
= NtCreateKey(&ScsiPortKey
,
1552 REG_OPTION_VOLATILE
,
1554 if (!NT_SUCCESS(Status
))
1560 /* Add port-specific values */
1562 /* 'DMA Enabled' (REG_DWORD) */
1563 DPRINT1("DMA Enabled = %s\n",
1564 (DeviceExtension
->PortCapabilities
->AdapterUsesPio
)?"TRUE":"FALSE");
1566 /* 'Driver' (REG_SZ) */
1568 /* 'Interrupt' (REG_DWORD) (NT4 only) */
1569 DPRINT1("Interrupt = %lx\n", DeviceExtension
->PortConfig
.BusInterruptLevel
);
1571 /* 'IOAddress' (REG_DWORD) (NT4 only) */
1572 DPRINT1("IOAddress = %lx\n",
1573 ScsiPortConvertPhysicalAddressToUlong(DeviceExtension
->PortConfig
.AccessRanges
[0].RangeStart
));
1576 /* Create 'Scsi Bus X' keys */
1577 for (BusNumber
= 0; BusNumber
< DeviceExtension
->PortConfig
.NumberOfBuses
; BusNumber
++)
1579 swprintf(NameBuffer
,
1581 DeviceExtension
->PortNumber
);
1582 RtlInitUnicodeString(&KeyName
,
1584 InitializeObjectAttributes(&ObjectAttributes
,
1589 Status
= NtCreateKey(&ScsiBusKey
,
1594 REG_OPTION_VOLATILE
,
1596 if (!NT_SUCCESS(Status
))
1598 NtClose(ScsiPortKey
);
1603 /* Create target keys */
1606 NtClose(ScsiBusKey
);
1609 NtClose(ScsiPortKey
);