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.20 2002/09/08 10:22:23 chorns 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 PIO_SCSI_CAPABILITIES PortCapabilities
;
83 PDEVICE_OBJECT DeviceObject
;
84 PCONTROLLER_OBJECT ControllerObject
;
86 PHW_STARTIO HwStartIo
;
87 PHW_INTERRUPT HwInterrupt
;
89 PSCSI_REQUEST_BLOCK OriginalSrb
;
90 SCSI_REQUEST_BLOCK InternalSrb
;
91 SENSE_DATA InternalSenseData
;
93 UCHAR MiniPortDeviceExtension
[1]; /* must be the last entry */
94 } SCSI_PORT_DEVICE_EXTENSION
, *PSCSI_PORT_DEVICE_EXTENSION
;
98 * SCSI_PORT_TIMER_STATES
101 * An enumeration containing the states in the timer DFA
106 #define IRP_FLAG_COMPLETE 0x00000001
107 #define IRP_FLAG_NEXT 0x00000002
110 /* GLOBALS *******************************************************************/
112 static NTSTATUS STDCALL
113 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
116 static NTSTATUS STDCALL
117 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
120 static NTSTATUS STDCALL
121 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
125 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
128 static IO_ALLOCATION_ACTION STDCALL
129 ScsiPortAllocateController(IN PDEVICE_OBJECT DeviceObject
,
131 IN PVOID MapRegisterBase
,
134 static BOOLEAN STDCALL
135 ScsiPortStartPacket(IN OUT PVOID Context
);
138 ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject
,
139 IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension
,
143 ScsiPortInquire(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
145 static BOOLEAN STDCALL
146 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
147 IN PVOID ServiceContext
);
150 ScsiPortDpcForIsr(IN PKDPC Dpc
,
151 IN PDEVICE_OBJECT DpcDeviceObject
,
153 IN PVOID DpcContext
);
156 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
159 static PSCSI_REQUEST_BLOCK
160 ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
161 PSCSI_REQUEST_BLOCK OriginalSrb
);
163 /* FUNCTIONS *****************************************************************/
165 /**********************************************************************
170 * This function initializes the driver.
177 * System allocated Driver Object for this driver.
180 * Name of registry driver service key.
187 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
188 IN PUNICODE_STRING RegistryPath
)
190 DPRINT("ScsiPort Driver %s\n", VERSION
);
191 return(STATUS_SUCCESS
);
195 /**********************************************************************
200 * Prints debugging messages.
207 * Debug level of the given message.
210 * Pointer to printf()-compatible format string.
213 Additional output data (see printf()).
220 ScsiDebugPrint(IN ULONG DebugPrintLevel
,
221 IN PCHAR DebugMessage
,
228 if (DebugPrintLevel
> InternalDebugLevel
)
232 va_start(ap
, DebugMessage
);
233 vsprintf(Buffer
, DebugMessage
, ap
);
241 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension
,
252 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address
)
254 return(Address
.u
.LowPart
);
259 ScsiPortFlushDma(IN PVOID HwDeviceExtension
)
266 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension
,
267 IN PVOID MappedAddress
)
274 ScsiPortGetBusData(IN PVOID DeviceExtension
,
275 IN ULONG BusDataType
,
276 IN ULONG SystemIoBusNumber
,
281 return(HalGetBusData(BusDataType
,
290 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension
,
291 IN INTERFACE_TYPE BusType
,
292 IN ULONG SystemIoBusNumber
,
293 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
294 IN ULONG NumberOfBytes
,
295 IN BOOLEAN InIoSpace
)
298 PHYSICAL_ADDRESS TranslatedAddress
;
299 PVOID VirtualAddress
;
303 AddressSpace
= (ULONG
)InIoSpace
;
305 if (!HalTranslateBusAddress(BusType
,
313 if (AddressSpace
!= 0)
314 return (PVOID
)TranslatedAddress
.u
.LowPart
;
316 VirtualAddress
= MmMapIoSpace(TranslatedAddress
,
320 Buffer
= ExAllocatePool(NonPagedPool
,0x20);
322 return VirtualAddress
;
324 return NULL
; /* ?? */
329 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension
,
338 SCSI_PHYSICAL_ADDRESS STDCALL
339 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension
,
340 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
341 IN PVOID VirtualAddress
,
348 PSCSI_REQUEST_BLOCK STDCALL
349 ScsiPortGetSrb(IN PVOID DeviceExtension
,
360 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension
,
361 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
362 IN ULONG NumberOfBytes
)
369 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension
,
370 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress
)
376 /**********************************************************************
381 * Initializes SCSI port driver specific data.
388 * Pointer to the miniport driver's driver object.
391 * Pointer to the miniport driver's registry path.
393 * HwInitializationData
394 * Pointer to port driver specific configuration data.
397 Miniport driver specific context.
404 ScsiPortInitialize(IN PVOID Argument1
,
406 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
409 PDRIVER_OBJECT DriverObject
= (PDRIVER_OBJECT
)Argument1
;
410 PUNICODE_STRING RegistryPath
= (PUNICODE_STRING
)Argument2
;
411 PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension
;
412 PCONFIGURATION_INFORMATION SystemConfig
;
413 PPORT_CONFIGURATION_INFORMATION PortConfig
;
419 PACCESS_RANGE AccessRanges
;
422 DPRINT("ScsiPortInitialize() called!\n");
424 if ((HwInitializationData
->HwInitialize
== NULL
) ||
425 (HwInitializationData
->HwStartIo
== NULL
) ||
426 (HwInitializationData
->HwInterrupt
== NULL
) ||
427 (HwInitializationData
->HwFindAdapter
== NULL
) ||
428 (HwInitializationData
->HwResetBus
== NULL
))
429 return(STATUS_INVALID_PARAMETER
);
431 DriverObject
->DriverStartIo
= ScsiPortStartIo
;
432 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ScsiPortCreateClose
;
433 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ScsiPortCreateClose
;
434 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ScsiPortDeviceControl
;
435 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = ScsiPortDispatchScsi
;
438 SystemConfig
= IoGetConfigurationInformation();
440 ExtensionSize
= sizeof(SCSI_PORT_DEVICE_EXTENSION
) +
441 HwInitializationData
->DeviceExtensionSize
;
442 PseudoDeviceExtension
= ExAllocatePool(PagedPool
,
444 RtlZeroMemory(PseudoDeviceExtension
,
446 PseudoDeviceExtension
->Length
= ExtensionSize
;
447 PseudoDeviceExtension
->MiniPortExtensionSize
= HwInitializationData
->DeviceExtensionSize
;
448 PseudoDeviceExtension
->HwStartIo
= HwInitializationData
->HwStartIo
;
449 PseudoDeviceExtension
->HwInterrupt
= HwInitializationData
->HwInterrupt
;
451 PortConfig
= &PseudoDeviceExtension
->PortConfig
;
453 PortConfig
->Length
= sizeof(PORT_CONFIGURATION_INFORMATION
);
454 PortConfig
->AdapterInterfaceType
= HwInitializationData
->AdapterInterfaceType
;
455 PortConfig
->InterruptMode
=
456 (PortConfig
->AdapterInterfaceType
== PCIBus
) ? LevelSensitive
: Latched
;
457 PortConfig
->AtdiskPrimaryClaimed
= SystemConfig
->AtDiskPrimaryAddressClaimed
;
458 PortConfig
->AtdiskSecondaryClaimed
= SystemConfig
->AtDiskSecondaryAddressClaimed
;
459 PortConfig
->NumberOfAccessRanges
= HwInitializationData
->NumberOfAccessRanges
;
461 PortConfig
->AccessRanges
=
462 ExAllocatePool(PagedPool
,
463 sizeof(ACCESS_RANGE
) * PortConfig
->NumberOfAccessRanges
);
466 PortConfig
->SystemIoBusNumber
= 0;
467 PortConfig
->SlotNumber
= 0;
469 MaxBus
= (PortConfig
->AdapterInterfaceType
== PCIBus
) ? 8 : 1;
471 DPRINT("MaxBus: %lu\n", MaxBus
);
475 DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig
->SystemIoBusNumber
);
477 // RtlZeroMemory(AccessRanges,
478 // sizeof(ACCESS_RANGE) * PortConfig->NumberOfAccessRanges);
480 RtlZeroMemory(PseudoDeviceExtension
->MiniPortDeviceExtension
,
481 PseudoDeviceExtension
->MiniPortExtensionSize
);
483 /* Note: HwFindAdapter is called once for each bus */
484 Result
= (HwInitializationData
->HwFindAdapter
)(&PseudoDeviceExtension
->MiniPortDeviceExtension
,
486 NULL
, /* BusInformation */
487 NULL
, /* ArgumentString */
488 &PseudoDeviceExtension
->PortConfig
,
490 DPRINT("HwFindAdapter() result: %lu\n", Result
);
492 if (Result
== SP_RETURN_FOUND
)
494 DPRINT("ScsiPortInitialize(): Found HBA!\n");
496 Status
= ScsiPortCreatePortDevice(DriverObject
,
497 PseudoDeviceExtension
,
498 SystemConfig
->ScsiPortCount
);
500 if (!NT_SUCCESS(Status
))
502 DbgPrint("ScsiPortCreatePortDevice() failed! (Status 0x%lX)\n", Status
);
504 ExFreePool(PortConfig
->AccessRanges
);
505 ExFreePool(PseudoDeviceExtension
);
510 /* Update the configuration info */
511 SystemConfig
->AtDiskPrimaryAddressClaimed
= PortConfig
->AtdiskPrimaryClaimed
;
512 SystemConfig
->AtDiskSecondaryAddressClaimed
= PortConfig
->AtdiskSecondaryClaimed
;
513 SystemConfig
->ScsiPortCount
++;
518 PortConfig
->SystemIoBusNumber
++;
519 PortConfig
->SlotNumber
= 0;
522 DPRINT("Bus: %lu MaxBus: %lu\n", PortConfig
->SystemIoBusNumber
, MaxBus
);
523 if (PortConfig
->SystemIoBusNumber
>= MaxBus
)
525 DPRINT("Scanned all buses!\n");
530 ExFreePool(PortConfig
->AccessRanges
);
531 ExFreePool(PseudoDeviceExtension
);
533 DPRINT("ScsiPortInitialize() done!\n");
535 return(STATUS_SUCCESS
);
540 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension
,
541 IN PSCSI_REQUEST_BLOCK Srb
,
542 IN ULONG LogicalAddress
,
550 ScsiPortLogError(IN PVOID HwDeviceExtension
,
551 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
563 ScsiPortMoveMemory(OUT PVOID Destination
,
567 RtlMoveMemory(Destination
,
574 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType
,
575 IN PVOID HwDeviceExtension
,
578 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
580 DPRINT("ScsiPortNotification() called\n");
582 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
583 SCSI_PORT_DEVICE_EXTENSION
,
584 MiniPortDeviceExtension
);
586 DPRINT("DeviceExtension %p\n", DeviceExtension
);
588 DPRINT("Initializing = %s\n", (DeviceExtension
->Initializing
)?"TRUE":"FALSE");
590 if (DeviceExtension
->Initializing
== TRUE
)
593 switch (NotificationType
)
595 case RequestComplete
:
596 DPRINT("Notify: RequestComplete\n");
597 DeviceExtension
->IrpFlags
|= IRP_FLAG_COMPLETE
;
601 DPRINT("Notify: NextRequest\n");
602 DeviceExtension
->IrpFlags
|= IRP_FLAG_NEXT
;
612 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension
,
613 IN ULONG BusDataType
,
614 IN ULONG SystemIoBusNumber
,
620 return(HalSetBusDataByOffset(BusDataType
,
630 ScsiPortValidateRange(IN PVOID HwDeviceExtension
,
631 IN INTERFACE_TYPE BusType
,
632 IN ULONG SystemIoBusNumber
,
633 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
634 IN ULONG NumberOfBytes
,
635 IN BOOLEAN InIoSpace
)
641 /* INTERNAL FUNCTIONS ********************************************************/
643 /**********************************************************************
645 * ScsiPortCreateClose
648 * Answer requests for Create/Close calls: a null operation.
655 * Pointer to a device object.
661 Additional output data (see printf()).
667 static NTSTATUS STDCALL
668 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
671 DPRINT("ScsiPortCreateClose()\n");
673 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
674 Irp
->IoStatus
.Information
= FILE_OPENED
;
676 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
678 return(STATUS_SUCCESS
);
682 /**********************************************************************
684 * ScsiPortDispatchScsi
687 * Answer requests for SCSI calls
693 * Standard dispatch arguments
699 static NTSTATUS STDCALL
700 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
703 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
704 PIO_STACK_LOCATION Stack
;
705 PSCSI_REQUEST_BLOCK Srb
;
706 NTSTATUS Status
= STATUS_SUCCESS
;
709 DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n",
712 DeviceExtension
= DeviceObject
->DeviceExtension
;
713 Stack
= IoGetCurrentIrpStackLocation(Irp
);
715 Srb
= Stack
->Parameters
.Scsi
.Srb
;
718 Status
= STATUS_UNSUCCESSFUL
;
720 Irp
->IoStatus
.Status
= Status
;
721 Irp
->IoStatus
.Information
= 0;
723 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
728 DPRINT("Srb: %p\n", Srb
);
729 DPRINT("Srb->Function: %lu\n", Srb
->Function
);
730 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb
->PathId
, Srb
->TargetId
, Srb
->Lun
);
732 switch (Srb
->Function
)
734 case SRB_FUNCTION_EXECUTE_SCSI
:
735 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
736 return(STATUS_PENDING
);
738 case SRB_FUNCTION_SHUTDOWN
:
739 case SRB_FUNCTION_FLUSH
:
740 if (DeviceExtension
->PortConfig
.CachesData
== TRUE
)
742 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
743 return(STATUS_PENDING
);
747 case SRB_FUNCTION_CLAIM_DEVICE
:
749 PSCSI_ADAPTER_BUS_INFO AdapterInfo
;
750 PSCSI_INQUIRY_DATA UnitInfo
;
751 PINQUIRYDATA InquiryData
;
753 DPRINT(" SRB_FUNCTION_CLAIM_DEVICE\n");
754 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb
->PathId
, Srb
->TargetId
, Srb
->Lun
);
756 Srb
->DataBuffer
= NULL
;
758 if (DeviceExtension
->PortBusInfo
!= NULL
)
760 AdapterInfo
= (PSCSI_ADAPTER_BUS_INFO
)DeviceExtension
->PortBusInfo
;
762 if (AdapterInfo
->BusData
[Srb
->PathId
].NumberOfLogicalUnits
== 0)
765 UnitInfo
= (PSCSI_INQUIRY_DATA
)((PUCHAR
)AdapterInfo
+
766 AdapterInfo
->BusData
[Srb
->PathId
].InquiryDataOffset
);
768 while (AdapterInfo
->BusData
[Srb
->PathId
].InquiryDataOffset
)
770 InquiryData
= (PINQUIRYDATA
)UnitInfo
->InquiryData
;
772 if ((UnitInfo
->TargetId
== Srb
->TargetId
) &&
773 (UnitInfo
->Lun
== Srb
->Lun
) &&
774 (UnitInfo
->DeviceClaimed
== FALSE
))
776 UnitInfo
->DeviceClaimed
= TRUE
;
777 DPRINT("Claimed device!\n");
779 /* FIXME: Hack!!!!! */
780 Srb
->DataBuffer
= DeviceObject
;
785 if (UnitInfo
->NextInquiryDataOffset
== 0)
788 UnitInfo
= (PSCSI_INQUIRY_DATA
)((PUCHAR
)AdapterInfo
+ UnitInfo
->NextInquiryDataOffset
);
794 case SRB_FUNCTION_RELEASE_DEVICE
:
796 PSCSI_ADAPTER_BUS_INFO AdapterInfo
;
797 PSCSI_INQUIRY_DATA UnitInfo
;
798 PINQUIRYDATA InquiryData
;
800 DPRINT(" SRB_FUNCTION_RELEASE_DEVICE\n");
801 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb
->PathId
, Srb
->TargetId
, Srb
->Lun
);
803 if (DeviceExtension
->PortBusInfo
!= NULL
)
805 AdapterInfo
= (PSCSI_ADAPTER_BUS_INFO
)DeviceExtension
->PortBusInfo
;
807 if (AdapterInfo
->BusData
[Srb
->PathId
].NumberOfLogicalUnits
== 0)
810 UnitInfo
= (PSCSI_INQUIRY_DATA
)((PUCHAR
)AdapterInfo
+
811 AdapterInfo
->BusData
[Srb
->PathId
].InquiryDataOffset
);
813 while (AdapterInfo
->BusData
[Srb
->PathId
].InquiryDataOffset
)
815 InquiryData
= (PINQUIRYDATA
)UnitInfo
->InquiryData
;
817 if ((UnitInfo
->TargetId
== Srb
->TargetId
) &&
818 (UnitInfo
->Lun
== Srb
->Lun
) &&
819 (UnitInfo
->DeviceClaimed
== TRUE
))
821 UnitInfo
->DeviceClaimed
= FALSE
;
822 DPRINT("Released device!\n");
826 if (UnitInfo
->NextInquiryDataOffset
== 0)
829 UnitInfo
= (PSCSI_INQUIRY_DATA
)((PUCHAR
)AdapterInfo
+ UnitInfo
->NextInquiryDataOffset
);
836 DPRINT1("SRB function not implemented (Function %lu)\n", Srb
->Function
);
837 Status
= STATUS_NOT_IMPLEMENTED
;
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 DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
890 *((PIO_SCSI_CAPABILITIES
*)Irp
->AssociatedIrp
.SystemBuffer
) =
891 DeviceExtension
->PortCapabilities
;
893 Irp
->IoStatus
.Information
= sizeof(PIO_SCSI_CAPABILITIES
);
897 case IOCTL_SCSI_GET_INQUIRY_DATA
:
899 DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
901 /* Copy inquiry data to the port device extension */
902 memcpy(Irp
->AssociatedIrp
.SystemBuffer
,
903 DeviceExtension
->PortBusInfo
,
904 DeviceExtension
->PortBusInfoSize
);
906 DPRINT("BufferSize: %lu\n", DeviceExtension
->PortBusInfoSize
);
907 Irp
->IoStatus
.Information
= DeviceExtension
->PortBusInfoSize
;
912 DPRINT1(" unknown ioctl code: 0x%lX\n",
913 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
917 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
919 return(STATUS_SUCCESS
);
924 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
927 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
928 PIO_STACK_LOCATION IrpStack
;
931 DPRINT("ScsiPortStartIo() called!\n");
933 DeviceExtension
= DeviceObject
->DeviceExtension
;
934 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
936 // FIXME: implement the supported functions
938 switch (IrpStack
->MajorFunction
)
943 PSCSI_REQUEST_BLOCK Srb
;
945 DPRINT("IRP_MJ_SCSI\n");
947 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
949 DPRINT("DeviceExtension %p\n", DeviceExtension
);
951 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
952 Irp
->IoStatus
.Information
= Srb
->DataTransferLength
;
954 DeviceExtension
->CurrentIrp
= Irp
;
956 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
960 DPRINT("Synchronization failed!\n");
962 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
963 Irp
->IoStatus
.Information
= 0;
964 IoCompleteRequest(Irp
,
966 IoStartNextPacket(DeviceObject
,
969 if (DeviceExtension
->IrpFlags
& IRP_FLAG_COMPLETE
)
971 DeviceExtension
->IrpFlags
&= ~IRP_FLAG_COMPLETE
;
972 IoCompleteRequest(Irp
,
976 if (DeviceExtension
->IrpFlags
& IRP_FLAG_NEXT
)
978 DeviceExtension
->IrpFlags
&= ~IRP_FLAG_NEXT
;
979 IoStartNextPacket(DeviceObject
,
986 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
987 Irp
->IoStatus
.Information
= 0;
988 IoCompleteRequest(Irp
,
990 IoStartNextPacket(DeviceObject
,
994 DPRINT("ScsiPortStartIo() done\n");
998 static BOOLEAN STDCALL
999 ScsiPortStartPacket(IN OUT PVOID Context
)
1001 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1002 PIO_STACK_LOCATION IrpStack
;
1003 PSCSI_REQUEST_BLOCK Srb
;
1005 DPRINT("ScsiPortStartPacket() called\n");
1007 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)Context
;
1009 IrpStack
= IoGetCurrentIrpStackLocation(DeviceExtension
->CurrentIrp
);
1010 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
1012 return(DeviceExtension
->HwStartIo(&DeviceExtension
->MiniPortDeviceExtension
,
1017 /**********************************************************************
1019 * ScsiPortCreatePortDevice
1022 * Creates and initializes a SCSI port device object.
1031 * PseudoDeviceExtension
1042 ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject
,
1043 IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension
,
1044 IN ULONG PortNumber
)
1046 PSCSI_PORT_DEVICE_EXTENSION PortDeviceExtension
;
1047 PIO_SCSI_CAPABILITIES PortCapabilities
;
1048 PDEVICE_OBJECT PortDeviceObject
;
1049 WCHAR NameBuffer
[80];
1050 UNICODE_STRING DeviceName
;
1051 WCHAR DosNameBuffer
[80];
1052 UNICODE_STRING DosDeviceName
;
1054 ULONG AccessRangeSize
;
1062 DPRINT("ScsiPortCreatePortDevice() called\n");
1065 MappedIrq
= HalGetInterruptVector(PseudoDeviceExtension
->PortConfig
.AdapterInterfaceType
,
1066 PseudoDeviceExtension
->PortConfig
.SystemIoBusNumber
,
1068 PseudoDeviceExtension
->PortConfig
.BusInterruptLevel
,
1073 /* Create a unicode device name */
1074 swprintf(NameBuffer
,
1075 L
"\\Device\\ScsiPort%lu",
1077 RtlInitUnicodeString(&DeviceName
,
1080 DPRINT("Creating device: %wZ\n", &DeviceName
);
1082 /* Create the port device */
1083 Status
= IoCreateDevice(DriverObject
,
1084 PseudoDeviceExtension
->Length
,
1086 FILE_DEVICE_CONTROLLER
,
1090 if (!NT_SUCCESS(Status
))
1092 DbgPrint("IoCreateDevice call failed! (Status 0x%lX)\n", Status
);
1096 DPRINT("Created device: %wZ\n", &DeviceName
);
1098 /* Set the buffering strategy here... */
1099 PortDeviceObject
->Flags
|= DO_DIRECT_IO
;
1100 PortDeviceObject
->AlignmentRequirement
= FILE_WORD_ALIGNMENT
;
1102 PortDeviceExtension
= PortDeviceObject
->DeviceExtension
;
1104 /* Copy pseudo device extension into the real device extension */
1105 memcpy(PortDeviceExtension
,
1106 PseudoDeviceExtension
,
1107 PseudoDeviceExtension
->Length
);
1109 /* Copy access ranges */
1111 sizeof(ACCESS_RANGE
) * PseudoDeviceExtension
->PortConfig
.NumberOfAccessRanges
;
1112 PortDeviceExtension
->PortConfig
.AccessRanges
= ExAllocatePool(NonPagedPool
,
1114 memcpy(PortDeviceExtension
->PortConfig
.AccessRanges
,
1115 PseudoDeviceExtension
->PortConfig
.AccessRanges
,
1118 PortDeviceExtension
->DeviceObject
= PortDeviceObject
;
1121 /* Initialize the spin lock in the controller extension */
1122 KeInitializeSpinLock(&PortDeviceExtension
->SpinLock
);
1124 /* Register an interrupt handler for this device */
1125 Status
= IoConnectInterrupt(&PortDeviceExtension
->Interrupt
,
1127 PortDeviceExtension
,
1128 &PortDeviceExtension
->SpinLock
,
1129 PortDeviceExtension
->PortConfig
.BusInterruptVector
, // MappedIrq,
1130 PortDeviceExtension
->PortConfig
.BusInterruptLevel
, // Dirql,
1132 PortDeviceExtension
->PortConfig
.InterruptMode
,
1136 if (!NT_SUCCESS(Status
))
1138 DbgPrint("Could not Connect Interrupt %d\n",
1139 PortDeviceExtension
->PortConfig
.BusInterruptVector
);
1143 /* Initialize the DPC object */
1144 IoInitializeDpcRequest(PortDeviceExtension
->DeviceObject
,
1147 /* Initialize the device timer */
1148 PortDeviceExtension
->TimerState
= IDETimerIdle
;
1149 PortDeviceExtension
->TimerCount
= 0;
1150 IoInitializeTimer(PortDeviceExtension
->DeviceObject
,
1152 PortDeviceExtension
);
1154 /* Initialize port capabilities */
1155 PortCapabilities
= ExAllocatePool(NonPagedPool
,
1156 sizeof(IO_SCSI_CAPABILITIES
));
1157 PortDeviceExtension
->PortCapabilities
= PortCapabilities
;
1158 PortCapabilities
->Length
= sizeof(IO_SCSI_CAPABILITIES
);
1159 PortCapabilities
->MaximumTransferLength
=
1160 PortDeviceExtension
->PortConfig
.MaximumTransferLength
;
1161 PortCapabilities
->MaximumPhysicalPages
=
1162 PortCapabilities
->MaximumTransferLength
/ PAGESIZE
;
1163 PortCapabilities
->SupportedAsynchronousEvents
= 0; /* FIXME */
1164 PortCapabilities
->AlignmentMask
=
1165 PortDeviceExtension
->PortConfig
.AlignmentMask
;
1166 PortCapabilities
->TaggedQueuing
=
1167 PortDeviceExtension
->PortConfig
.TaggedQueuing
;
1168 PortCapabilities
->AdapterScansDown
=
1169 PortDeviceExtension
->PortConfig
.AdapterScansDown
;
1170 PortCapabilities
->AdapterUsesPio
= TRUE
; /* FIXME */
1172 /* Initialize inquiry data */
1173 PortDeviceExtension
->PortBusInfoSize
= 0;
1174 PortDeviceExtension
->PortBusInfo
= NULL
;
1176 DPRINT("DeviceExtension %p\n", PortDeviceExtension
);
1177 ScsiPortInquire(PortDeviceExtension
);
1180 /* FIXME: Copy more configuration data? */
1182 /* Create the dos device link */
1183 swprintf(DosNameBuffer
,
1186 RtlInitUnicodeString(&DosDeviceName
,
1189 IoCreateSymbolicLink(&DosDeviceName
,
1192 DPRINT("ScsiPortCreatePortDevice() done\n");
1194 return(STATUS_SUCCESS
);
1199 ScsiPortInquire(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
1201 PSCSI_ADAPTER_BUS_INFO AdapterInfo
;
1202 PSCSI_INQUIRY_DATA UnitInfo
, PrevUnit
;
1203 SCSI_REQUEST_BLOCK Srb
;
1210 DPRINT("ScsiPortInquire() called\n");
1212 DeviceExtension
->Initializing
= TRUE
;
1214 /* Copy inquiry data to the port device extension */
1215 AdapterInfo
=(PSCSI_ADAPTER_BUS_INFO
)ExAllocatePool(NonPagedPool
, 4096);
1216 RtlZeroMemory(AdapterInfo
, 4096);
1217 AdapterInfo
->NumberOfBuses
= DeviceExtension
->PortConfig
.NumberOfBuses
;
1219 UnitInfo
= (PSCSI_INQUIRY_DATA
)
1220 ((PUCHAR
)AdapterInfo
+ sizeof(SCSI_ADAPTER_BUS_INFO
) +
1221 (sizeof(SCSI_BUS_DATA
) * (AdapterInfo
->NumberOfBuses
- 1)));
1224 sizeof(SCSI_REQUEST_BLOCK
));
1225 Srb
.DataBuffer
= ExAllocatePool(NonPagedPool
, 256);
1226 Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1227 Srb
.DataTransferLength
= 256;
1228 Srb
.Cdb
[0] = SCSIOP_INQUIRY
;
1230 for (Bus
= 0; Bus
< AdapterInfo
->NumberOfBuses
; Bus
++)
1234 AdapterInfo
->BusData
[Bus
].InitiatorBusId
= 0; /* ? */
1235 AdapterInfo
->BusData
[Bus
].InquiryDataOffset
=
1236 (ULONG
)((PUCHAR
)UnitInfo
- (PUCHAR
)AdapterInfo
);
1241 for (Target
= 0; Target
< DeviceExtension
->PortConfig
.MaximumNumberOfTargets
; Target
++)
1243 Srb
.TargetId
= Target
;
1245 Srb
.SrbStatus
= SRB_STATUS_SUCCESS
;
1247 Result
= DeviceExtension
->HwStartIo(&DeviceExtension
->MiniPortDeviceExtension
,
1249 DPRINT("Result: %s Srb.SrbStatus %lx\n", (Result
)?"True":"False", Srb
.SrbStatus
);
1251 if (Result
== TRUE
&& Srb
.SrbStatus
== SRB_STATUS_SUCCESS
)
1253 UnitInfo
->PathId
= Bus
;
1254 UnitInfo
->TargetId
= Target
;
1256 UnitInfo
->InquiryDataLength
= INQUIRYDATABUFFERSIZE
;
1257 memcpy(&UnitInfo
->InquiryData
,
1259 INQUIRYDATABUFFERSIZE
);
1260 if (PrevUnit
!= NULL
)
1261 PrevUnit
->NextInquiryDataOffset
= (ULONG
)((PUCHAR
)UnitInfo
-(PUCHAR
)AdapterInfo
);
1262 PrevUnit
= UnitInfo
;
1263 UnitInfo
= (PSCSI_INQUIRY_DATA
)((PUCHAR
)UnitInfo
+ sizeof(SCSI_INQUIRY_DATA
)+INQUIRYDATABUFFERSIZE
-1);
1267 DPRINT("UnitCount: %lu\n", UnitCount
);
1268 AdapterInfo
->BusData
[Bus
].NumberOfLogicalUnits
= UnitCount
;
1270 AdapterInfo
->BusData
[Bus
].InquiryDataOffset
= 0;
1272 DataSize
= (ULONG
)((PUCHAR
)UnitInfo
-(PUCHAR
)AdapterInfo
);
1274 ExFreePool(Srb
.DataBuffer
);
1276 DeviceExtension
->Initializing
= FALSE
;
1278 /* copy inquiry data to the port driver's device extension */
1279 DeviceExtension
->PortBusInfoSize
= DataSize
;
1280 DeviceExtension
->PortBusInfo
= ExAllocatePool(NonPagedPool
,
1282 RtlCopyMemory(DeviceExtension
->PortBusInfo
,
1286 ExFreePool(AdapterInfo
);
1288 DPRINT("ScsiPortInquire() done\n");
1292 static BOOLEAN STDCALL
1293 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
1294 IN PVOID ServiceContext
)
1296 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1299 DPRINT("ScsiPortIsr() called!\n");
1301 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)ServiceContext
;
1303 Result
= DeviceExtension
->HwInterrupt(&DeviceExtension
->MiniPortDeviceExtension
);
1304 if (Result
== FALSE
)
1309 if (DeviceExtension
->IrpFlags
)
1311 IoRequestDpc(DeviceExtension
->DeviceObject
,
1312 DeviceExtension
->CurrentIrp
,
1320 // ScsiPortDpcForIsr
1327 // IN PDEVICE_OBJECT DpcDeviceObject
1329 // IN PVOID DpcContext
1332 ScsiPortDpcForIsr(IN PKDPC Dpc
,
1333 IN PDEVICE_OBJECT DpcDeviceObject
,
1335 IN PVOID DpcContext
)
1337 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1338 PIO_STACK_LOCATION IrpStack
;
1339 PSCSI_REQUEST_BLOCK Srb
;
1341 DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
1342 Dpc
, DpcDeviceObject
, DpcIrp
, DpcContext
);
1344 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DpcContext
;
1346 IrpStack
= IoGetCurrentIrpStackLocation(DeviceExtension
->CurrentIrp
);
1347 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
1349 if (DeviceExtension
->OriginalSrb
!= NULL
)
1351 DPRINT("Got sense data!\n");
1353 DPRINT("Valid: %x\n", DeviceExtension
->InternalSenseData
.Valid
);
1354 DPRINT("ErrorCode: %x\n", DeviceExtension
->InternalSenseData
.ErrorCode
);
1355 DPRINT("SenseKey: %x\n", DeviceExtension
->InternalSenseData
.SenseKey
);
1356 DPRINT("SenseCode: %x\n", DeviceExtension
->InternalSenseData
.AdditionalSenseCode
);
1358 /* Copy sense data */
1359 if (DeviceExtension
->OriginalSrb
->SenseInfoBufferLength
!= 0)
1361 RtlCopyMemory(DeviceExtension
->OriginalSrb
->SenseInfoBuffer
,
1362 &DeviceExtension
->InternalSenseData
,
1363 sizeof(SENSE_DATA
));
1364 DeviceExtension
->OriginalSrb
->SrbStatus
|= SRB_STATUS_AUTOSENSE_VALID
;
1367 /* Clear current sense data */
1368 RtlZeroMemory(&DeviceExtension
->InternalSenseData
, sizeof(SENSE_DATA
));
1370 IrpStack
->Parameters
.Scsi
.Srb
= DeviceExtension
->OriginalSrb
;
1371 DeviceExtension
->OriginalSrb
= NULL
;
1373 else if ((SRB_STATUS(Srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) &&
1374 (Srb
->ScsiStatus
== SCSISTAT_CHECK_CONDITION
))
1376 DPRINT("SCSIOP_REQUEST_SENSE required!\n");
1378 DeviceExtension
->OriginalSrb
= Srb
;
1379 IrpStack
->Parameters
.Scsi
.Srb
= ScsiPortInitSenseRequestSrb(DeviceExtension
,
1382 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
1383 ScsiPortStartPacket
,
1386 DPRINT("Synchronization failed!\n");
1388 DpcIrp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
1389 DpcIrp
->IoStatus
.Information
= 0;
1390 IoCompleteRequest(DpcIrp
,
1392 IoStartNextPacket(DpcDeviceObject
,
1399 DeviceExtension
->CurrentIrp
= NULL
;
1402 // DpcIrp->IoStatus.Information = 0;
1403 // DpcIrp->IoStatus.Status = STATUS_SUCCESS;
1405 if (DeviceExtension
->IrpFlags
& IRP_FLAG_COMPLETE
)
1407 DeviceExtension
->IrpFlags
&= ~IRP_FLAG_COMPLETE
;
1408 IoCompleteRequest(DpcIrp
, IO_NO_INCREMENT
);
1411 if (DeviceExtension
->IrpFlags
& IRP_FLAG_NEXT
)
1413 DeviceExtension
->IrpFlags
&= ~IRP_FLAG_NEXT
;
1414 IoStartNextPacket(DpcDeviceObject
, FALSE
);
1417 DPRINT("ScsiPortDpcForIsr() done\n");
1423 // This function handles timeouts and other time delayed processing
1428 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
1429 // IN PVOID Context the Controller extension for the
1430 // controller the device is on
1433 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
1436 DPRINT1("ScsiPortIoTimer()\n");
1440 static PSCSI_REQUEST_BLOCK
1441 ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
1442 PSCSI_REQUEST_BLOCK OriginalSrb
)
1444 PSCSI_REQUEST_BLOCK Srb
;
1447 Srb
= &DeviceExtension
->InternalSrb
;
1450 sizeof(SCSI_REQUEST_BLOCK
));
1452 Srb
->PathId
= OriginalSrb
->PathId
;
1453 Srb
->TargetId
= OriginalSrb
->TargetId
;
1454 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1455 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
);
1456 Srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
1458 Srb
->TimeOutValue
= 4;
1461 Srb
->DataBuffer
= &DeviceExtension
->InternalSenseData
;
1462 Srb
->DataTransferLength
= sizeof(SENSE_DATA
);
1464 Cdb
= (PCDB
)Srb
->Cdb
;
1465 Cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_REQUEST_SENSE
;
1466 Cdb
->CDB6INQUIRY
.AllocationLength
= sizeof(SENSE_DATA
);
1473 ScsiPortFreeSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
1475 DeviceExtension
->OriginalSrb
= NULL
;