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.17 2002/07/15 18:25:17 hbirr 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
;
710 DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n",
713 DeviceExtension
= DeviceObject
->DeviceExtension
;
714 Stack
= IoGetCurrentIrpStackLocation(Irp
);
717 switch(Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
719 case IOCTL_SCSI_EXECUTE_IN
:
721 DPRINT(" IOCTL_SCSI_EXECUTE_IN\n");
725 case IOCTL_SCSI_EXECUTE_OUT
:
727 DPRINT(" IOCTL_SCSI_EXECUTE_OUT\n");
731 case IOCTL_SCSI_EXECUTE_NONE
:
733 DPRINT(" IOCTL_SCSI_EXECUTE_NONE\n");
738 Srb
= Stack
->Parameters
.Scsi
.Srb
;
742 Status
= STATUS_UNSUCCESSFUL
;
745 Irp
->IoStatus
.Status
= Status
;
746 Irp
->IoStatus
.Information
= 0;
748 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
753 DPRINT("Srb: %p\n", Srb
);
754 DPRINT("Srb->Function: %lu\n", Srb
->Function
);
755 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb
->PathId
, Srb
->TargetId
, Srb
->Lun
);
757 switch (Srb
->Function
)
759 case SRB_FUNCTION_EXECUTE_SCSI
:
760 DPRINT(" SRB_FUNCTION_EXECUTE_SCSI\n");
761 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
762 DPRINT("Returning STATUS_PENDING\n");
763 return(STATUS_PENDING
);
765 case SRB_FUNCTION_CLAIM_DEVICE
:
767 PSCSI_ADAPTER_BUS_INFO AdapterInfo
;
768 PSCSI_INQUIRY_DATA UnitInfo
;
769 PINQUIRYDATA InquiryData
;
771 DPRINT(" SRB_FUNCTION_CLAIM_DEVICE\n");
772 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb
->PathId
, Srb
->TargetId
, Srb
->Lun
);
774 Srb
->DataBuffer
= NULL
;
776 if (DeviceExtension
->PortBusInfo
!= NULL
)
778 AdapterInfo
= (PSCSI_ADAPTER_BUS_INFO
)DeviceExtension
->PortBusInfo
;
780 if (AdapterInfo
->BusData
[Srb
->PathId
].NumberOfLogicalUnits
== 0)
783 UnitInfo
= (PSCSI_INQUIRY_DATA
)((PUCHAR
)AdapterInfo
+
784 AdapterInfo
->BusData
[Srb
->PathId
].InquiryDataOffset
);
786 while (AdapterInfo
->BusData
[Srb
->PathId
].InquiryDataOffset
)
788 InquiryData
= (PINQUIRYDATA
)UnitInfo
->InquiryData
;
790 if ((UnitInfo
->TargetId
== Srb
->TargetId
) &&
791 (UnitInfo
->Lun
== Srb
->Lun
) &&
792 (UnitInfo
->DeviceClaimed
== FALSE
))
794 UnitInfo
->DeviceClaimed
= TRUE
;
795 DPRINT("Claimed device!\n");
797 /* FIXME: Hack!!!!! */
798 Srb
->DataBuffer
= DeviceObject
;
803 if (UnitInfo
->NextInquiryDataOffset
== 0)
806 UnitInfo
= (PSCSI_INQUIRY_DATA
)((PUCHAR
)AdapterInfo
+ UnitInfo
->NextInquiryDataOffset
);
812 case SRB_FUNCTION_RELEASE_DEVICE
:
814 PSCSI_ADAPTER_BUS_INFO AdapterInfo
;
815 PSCSI_INQUIRY_DATA UnitInfo
;
816 PINQUIRYDATA InquiryData
;
818 DPRINT(" SRB_FUNCTION_RELEASE_DEVICE\n");
819 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb
->PathId
, Srb
->TargetId
, Srb
->Lun
);
821 if (DeviceExtension
->PortBusInfo
!= NULL
)
823 AdapterInfo
= (PSCSI_ADAPTER_BUS_INFO
)DeviceExtension
->PortBusInfo
;
825 if (AdapterInfo
->BusData
[Srb
->PathId
].NumberOfLogicalUnits
== 0)
828 UnitInfo
= (PSCSI_INQUIRY_DATA
)((PUCHAR
)AdapterInfo
+
829 AdapterInfo
->BusData
[Srb
->PathId
].InquiryDataOffset
);
831 while (AdapterInfo
->BusData
[Srb
->PathId
].InquiryDataOffset
)
833 InquiryData
= (PINQUIRYDATA
)UnitInfo
->InquiryData
;
835 if ((UnitInfo
->TargetId
== Srb
->TargetId
) &&
836 (UnitInfo
->Lun
== Srb
->Lun
) &&
837 (UnitInfo
->DeviceClaimed
== TRUE
))
839 UnitInfo
->DeviceClaimed
= FALSE
;
840 DPRINT("Released device!\n");
844 if (UnitInfo
->NextInquiryDataOffset
== 0)
847 UnitInfo
= (PSCSI_INQUIRY_DATA
)((PUCHAR
)AdapterInfo
+ UnitInfo
->NextInquiryDataOffset
);
854 Irp
->IoStatus
.Status
= Status
;
855 Irp
->IoStatus
.Information
= DataSize
;
857 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
863 /**********************************************************************
865 * ScsiPortDeviceControl
868 * Answer requests for device control calls
874 * Standard dispatch arguments
880 static NTSTATUS STDCALL
881 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
884 PIO_STACK_LOCATION Stack
;
885 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
887 DPRINT("ScsiPortDeviceControl()\n");
889 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
890 Irp
->IoStatus
.Information
= 0;
893 Stack
= IoGetCurrentIrpStackLocation(Irp
);
894 DeviceExtension
= DeviceObject
->DeviceExtension
;
896 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
899 case IOCTL_SCSI_GET_CAPABILITIES
:
901 DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
903 *((PIO_SCSI_CAPABILITIES
*)Irp
->AssociatedIrp
.SystemBuffer
) =
904 DeviceExtension
->PortCapabilities
;
906 Irp
->IoStatus
.Information
= sizeof(PIO_SCSI_CAPABILITIES
);
910 case IOCTL_SCSI_GET_INQUIRY_DATA
:
912 DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
914 /* Copy inquiry data to the port device extension */
915 memcpy(Irp
->AssociatedIrp
.SystemBuffer
,
916 DeviceExtension
->PortBusInfo
,
917 DeviceExtension
->PortBusInfoSize
);
919 DPRINT("BufferSize: %lu\n", DeviceExtension
->PortBusInfoSize
);
920 Irp
->IoStatus
.Information
= DeviceExtension
->PortBusInfoSize
;
925 DPRINT1(" unknown ioctl code: 0x%lX\n",
926 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
930 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
932 return(STATUS_SUCCESS
);
937 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
940 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
941 PIO_STACK_LOCATION IrpStack
;
944 DPRINT("ScsiPortStartIo() called!\n");
946 DeviceExtension
= DeviceObject
->DeviceExtension
;
947 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
949 // FIXME: implement the supported functions
951 switch (IrpStack
->MajorFunction
)
956 PSCSI_REQUEST_BLOCK Srb
;
958 DPRINT("IRP_MJ_SCSI\n");
960 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
962 DPRINT("DeviceExtension %p\n", DeviceExtension
);
964 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
965 Irp
->IoStatus
.Information
= Srb
->DataTransferLength
;
967 DeviceExtension
->CurrentIrp
= Irp
;
969 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
973 DPRINT("Synchronization failed!\n");
975 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
976 Irp
->IoStatus
.Information
= 0;
977 IoCompleteRequest(Irp
,
979 IoStartNextPacket(DeviceObject
,
982 if (DeviceExtension
->IrpFlags
& IRP_FLAG_COMPLETE
)
984 DeviceExtension
->IrpFlags
&= ~IRP_FLAG_COMPLETE
;
985 IoCompleteRequest(Irp
,
989 if (DeviceExtension
->IrpFlags
& IRP_FLAG_NEXT
)
991 DeviceExtension
->IrpFlags
&= ~IRP_FLAG_NEXT
;
992 IoStartNextPacket(DeviceObject
,
999 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
1000 Irp
->IoStatus
.Information
= 0;
1001 IoCompleteRequest(Irp
,
1003 IoStartNextPacket(DeviceObject
,
1007 DPRINT("ScsiPortStartIo() done\n");
1011 static BOOLEAN STDCALL
1012 ScsiPortStartPacket(IN OUT PVOID Context
)
1014 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1015 PIO_STACK_LOCATION IrpStack
;
1016 PSCSI_REQUEST_BLOCK Srb
;
1018 DPRINT("ScsiPortStartPacket() called\n");
1020 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)Context
;
1022 IrpStack
= IoGetCurrentIrpStackLocation(DeviceExtension
->CurrentIrp
);
1023 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
1025 return(DeviceExtension
->HwStartIo(&DeviceExtension
->MiniPortDeviceExtension
,
1030 /**********************************************************************
1032 * ScsiPortCreatePortDevice
1035 * Creates and initializes a SCSI port device object.
1044 * PseudoDeviceExtension
1055 ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject
,
1056 IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension
,
1057 IN ULONG PortNumber
)
1059 PSCSI_PORT_DEVICE_EXTENSION PortDeviceExtension
;
1060 PIO_SCSI_CAPABILITIES PortCapabilities
;
1061 PDEVICE_OBJECT PortDeviceObject
;
1062 WCHAR NameBuffer
[80];
1063 UNICODE_STRING DeviceName
;
1064 WCHAR DosNameBuffer
[80];
1065 UNICODE_STRING DosDeviceName
;
1067 ULONG AccessRangeSize
;
1075 DPRINT("ScsiPortCreatePortDevice() called\n");
1078 MappedIrq
= HalGetInterruptVector(PseudoDeviceExtension
->PortConfig
.AdapterInterfaceType
,
1079 PseudoDeviceExtension
->PortConfig
.SystemIoBusNumber
,
1081 PseudoDeviceExtension
->PortConfig
.BusInterruptLevel
,
1086 /* Create a unicode device name */
1087 swprintf(NameBuffer
,
1088 L
"\\Device\\ScsiPort%lu",
1090 RtlInitUnicodeString(&DeviceName
,
1093 DPRINT("Creating device: %wZ\n", &DeviceName
);
1095 /* Create the port device */
1096 Status
= IoCreateDevice(DriverObject
,
1097 PseudoDeviceExtension
->Length
,
1099 FILE_DEVICE_CONTROLLER
,
1103 if (!NT_SUCCESS(Status
))
1105 DbgPrint("IoCreateDevice call failed! (Status 0x%lX)\n", Status
);
1109 DPRINT("Created device: %wZ\n", &DeviceName
);
1111 /* Set the buffering strategy here... */
1112 PortDeviceObject
->Flags
|= DO_DIRECT_IO
;
1113 PortDeviceObject
->AlignmentRequirement
= FILE_WORD_ALIGNMENT
;
1115 PortDeviceExtension
= PortDeviceObject
->DeviceExtension
;
1117 /* Copy pseudo device extension into the real device extension */
1118 memcpy(PortDeviceExtension
,
1119 PseudoDeviceExtension
,
1120 PseudoDeviceExtension
->Length
);
1122 /* Copy access ranges */
1124 sizeof(ACCESS_RANGE
) * PseudoDeviceExtension
->PortConfig
.NumberOfAccessRanges
;
1125 PortDeviceExtension
->PortConfig
.AccessRanges
= ExAllocatePool(NonPagedPool
,
1127 memcpy(PortDeviceExtension
->PortConfig
.AccessRanges
,
1128 PseudoDeviceExtension
->PortConfig
.AccessRanges
,
1131 PortDeviceExtension
->DeviceObject
= PortDeviceObject
;
1134 /* Initialize the spin lock in the controller extension */
1135 KeInitializeSpinLock(&PortDeviceExtension
->SpinLock
);
1137 /* Register an interrupt handler for this device */
1138 Status
= IoConnectInterrupt(&PortDeviceExtension
->Interrupt
,
1140 PortDeviceExtension
,
1141 &PortDeviceExtension
->SpinLock
,
1142 PortDeviceExtension
->PortConfig
.BusInterruptVector
, // MappedIrq,
1143 PortDeviceExtension
->PortConfig
.BusInterruptLevel
, // Dirql,
1145 PortDeviceExtension
->PortConfig
.InterruptMode
,
1149 if (!NT_SUCCESS(Status
))
1151 DbgPrint("Could not Connect Interrupt %d\n",
1152 PortDeviceExtension
->PortConfig
.BusInterruptVector
);
1156 /* Initialize the DPC object */
1157 IoInitializeDpcRequest(PortDeviceExtension
->DeviceObject
,
1160 /* Initialize the device timer */
1161 PortDeviceExtension
->TimerState
= IDETimerIdle
;
1162 PortDeviceExtension
->TimerCount
= 0;
1163 IoInitializeTimer(PortDeviceExtension
->DeviceObject
,
1165 PortDeviceExtension
);
1167 /* Initialize port capabilities */
1168 PortCapabilities
= ExAllocatePool(NonPagedPool
,
1169 sizeof(IO_SCSI_CAPABILITIES
));
1170 PortDeviceExtension
->PortCapabilities
= PortCapabilities
;
1171 PortCapabilities
->Length
= sizeof(IO_SCSI_CAPABILITIES
);
1172 PortCapabilities
->MaximumTransferLength
=
1173 PortDeviceExtension
->PortConfig
.MaximumTransferLength
;
1174 PortCapabilities
->MaximumPhysicalPages
=
1175 PortCapabilities
->MaximumTransferLength
/ PAGESIZE
;
1176 PortCapabilities
->SupportedAsynchronousEvents
= 0; /* FIXME */
1177 PortCapabilities
->AlignmentMask
=
1178 PortDeviceExtension
->PortConfig
.AlignmentMask
;
1179 PortCapabilities
->TaggedQueuing
=
1180 PortDeviceExtension
->PortConfig
.TaggedQueuing
;
1181 PortCapabilities
->AdapterScansDown
=
1182 PortDeviceExtension
->PortConfig
.AdapterScansDown
;
1183 PortCapabilities
->AdapterUsesPio
= TRUE
; /* FIXME */
1185 /* Initialize inquiry data */
1186 PortDeviceExtension
->PortBusInfoSize
= 0;
1187 PortDeviceExtension
->PortBusInfo
= NULL
;
1189 DPRINT("DeviceExtension %p\n", PortDeviceExtension
);
1190 ScsiPortInquire(PortDeviceExtension
);
1193 /* FIXME: Copy more configuration data? */
1195 /* Create the dos device link */
1196 swprintf(DosNameBuffer
,
1199 RtlInitUnicodeString(&DosDeviceName
,
1202 IoCreateSymbolicLink(&DosDeviceName
,
1205 DPRINT("ScsiPortCreatePortDevice() done\n");
1207 return(STATUS_SUCCESS
);
1212 ScsiPortInquire(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
1214 PSCSI_ADAPTER_BUS_INFO AdapterInfo
;
1215 PSCSI_INQUIRY_DATA UnitInfo
, PrevUnit
;
1216 SCSI_REQUEST_BLOCK Srb
;
1223 DPRINT("ScsiPortInquire() called\n");
1225 DeviceExtension
->Initializing
= TRUE
;
1227 /* Copy inquiry data to the port device extension */
1228 AdapterInfo
=(PSCSI_ADAPTER_BUS_INFO
)ExAllocatePool(NonPagedPool
, 4096);
1229 RtlZeroMemory(AdapterInfo
, 4096);
1230 AdapterInfo
->NumberOfBuses
= DeviceExtension
->PortConfig
.NumberOfBuses
;
1232 UnitInfo
= (PSCSI_INQUIRY_DATA
)
1233 ((PUCHAR
)AdapterInfo
+ sizeof(SCSI_ADAPTER_BUS_INFO
) +
1234 (sizeof(SCSI_BUS_DATA
) * (AdapterInfo
->NumberOfBuses
- 1)));
1237 sizeof(SCSI_REQUEST_BLOCK
));
1238 Srb
.DataBuffer
= ExAllocatePool(NonPagedPool
, 256);
1239 Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1240 Srb
.DataTransferLength
= 256;
1241 Srb
.Cdb
[0] = SCSIOP_INQUIRY
;
1243 for (Bus
= 0; Bus
< AdapterInfo
->NumberOfBuses
; Bus
++)
1247 AdapterInfo
->BusData
[Bus
].InitiatorBusId
= 0; /* ? */
1248 AdapterInfo
->BusData
[Bus
].InquiryDataOffset
=
1249 (ULONG
)((PUCHAR
)UnitInfo
- (PUCHAR
)AdapterInfo
);
1254 for (Target
= 0; Target
< DeviceExtension
->PortConfig
.MaximumNumberOfTargets
; Target
++)
1256 Srb
.TargetId
= Target
;
1258 Srb
.SrbStatus
= SRB_STATUS_SUCCESS
;
1260 Result
= DeviceExtension
->HwStartIo(&DeviceExtension
->MiniPortDeviceExtension
,
1262 DPRINT("Result: %s Srb.SrbStatus %lx\n", (Result
)?"True":"False", Srb
.SrbStatus
);
1264 if (Result
== TRUE
&& Srb
.SrbStatus
== SRB_STATUS_SUCCESS
)
1266 UnitInfo
->PathId
= Bus
;
1267 UnitInfo
->TargetId
= Target
;
1269 UnitInfo
->InquiryDataLength
= INQUIRYDATABUFFERSIZE
;
1270 memcpy(&UnitInfo
->InquiryData
,
1272 INQUIRYDATABUFFERSIZE
);
1273 if (PrevUnit
!= NULL
)
1274 PrevUnit
->NextInquiryDataOffset
= (ULONG
)((PUCHAR
)UnitInfo
-(PUCHAR
)AdapterInfo
);
1275 PrevUnit
= UnitInfo
;
1276 UnitInfo
= (PSCSI_INQUIRY_DATA
)((PUCHAR
)UnitInfo
+ sizeof(SCSI_INQUIRY_DATA
)+INQUIRYDATABUFFERSIZE
-1);
1280 DPRINT("UnitCount: %lu\n", UnitCount
);
1281 AdapterInfo
->BusData
[Bus
].NumberOfLogicalUnits
= UnitCount
;
1283 AdapterInfo
->BusData
[Bus
].InquiryDataOffset
= 0;
1285 DataSize
= (ULONG
)((PUCHAR
)UnitInfo
-(PUCHAR
)AdapterInfo
);
1287 ExFreePool(Srb
.DataBuffer
);
1289 DeviceExtension
->Initializing
= FALSE
;
1291 /* copy inquiry data to the port driver's device extension */
1292 DeviceExtension
->PortBusInfoSize
= DataSize
;
1293 DeviceExtension
->PortBusInfo
= ExAllocatePool(NonPagedPool
,
1295 RtlCopyMemory(DeviceExtension
->PortBusInfo
,
1299 ExFreePool(AdapterInfo
);
1301 DPRINT("ScsiPortInquire() done\n");
1305 static BOOLEAN STDCALL
1306 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
1307 IN PVOID ServiceContext
)
1309 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1312 DPRINT("ScsiPortIsr() called!\n");
1314 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)ServiceContext
;
1316 Result
= DeviceExtension
->HwInterrupt(&DeviceExtension
->MiniPortDeviceExtension
);
1317 if (Result
== FALSE
)
1322 if (DeviceExtension
->IrpFlags
)
1324 IoRequestDpc(DeviceExtension
->DeviceObject
,
1325 DeviceExtension
->CurrentIrp
,
1333 // ScsiPortDpcForIsr
1340 // IN PDEVICE_OBJECT DpcDeviceObject
1342 // IN PVOID DpcContext
1345 ScsiPortDpcForIsr(IN PKDPC Dpc
,
1346 IN PDEVICE_OBJECT DpcDeviceObject
,
1348 IN PVOID DpcContext
)
1350 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1351 PIO_STACK_LOCATION IrpStack
;
1352 PSCSI_REQUEST_BLOCK Srb
;
1354 DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
1355 Dpc
, DpcDeviceObject
, DpcIrp
, DpcContext
);
1357 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DpcContext
;
1359 IrpStack
= IoGetCurrentIrpStackLocation(DeviceExtension
->CurrentIrp
);
1360 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
1362 if (DeviceExtension
->OriginalSrb
!= NULL
)
1364 DPRINT("Got sense data!\n");
1366 DPRINT("Valid: %x\n", DeviceExtension
->InternalSenseData
.Valid
);
1367 DPRINT("ErrorCode: %x\n", DeviceExtension
->InternalSenseData
.ErrorCode
);
1368 DPRINT("SenseKey: %x\n", DeviceExtension
->InternalSenseData
.SenseKey
);
1369 DPRINT("SenseCode: %x\n", DeviceExtension
->InternalSenseData
.AdditionalSenseCode
);
1371 /* Copy sense data */
1372 if (DeviceExtension
->OriginalSrb
->SenseInfoBufferLength
!= 0)
1374 RtlCopyMemory(DeviceExtension
->OriginalSrb
->SenseInfoBuffer
,
1375 &DeviceExtension
->InternalSenseData
,
1376 sizeof(SENSE_DATA
));
1377 DeviceExtension
->OriginalSrb
->SrbStatus
|= SRB_STATUS_AUTOSENSE_VALID
;
1380 /* Clear current sense data */
1381 RtlZeroMemory(&DeviceExtension
->InternalSenseData
, sizeof(SENSE_DATA
));
1383 IrpStack
->Parameters
.Scsi
.Srb
= DeviceExtension
->OriginalSrb
;
1384 DeviceExtension
->OriginalSrb
= NULL
;
1386 else if ((SRB_STATUS(Srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) &&
1387 (Srb
->ScsiStatus
== SCSISTAT_CHECK_CONDITION
))
1389 DPRINT("SCSIOP_REQUEST_SENSE required!\n");
1391 DeviceExtension
->OriginalSrb
= Srb
;
1392 IrpStack
->Parameters
.Scsi
.Srb
= ScsiPortInitSenseRequestSrb(DeviceExtension
,
1395 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
1396 ScsiPortStartPacket
,
1399 DPRINT("Synchronization failed!\n");
1401 DpcIrp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
1402 DpcIrp
->IoStatus
.Information
= 0;
1403 IoCompleteRequest(DpcIrp
,
1405 IoStartNextPacket(DpcDeviceObject
,
1412 DeviceExtension
->CurrentIrp
= NULL
;
1415 // DpcIrp->IoStatus.Information = 0;
1416 // DpcIrp->IoStatus.Status = STATUS_SUCCESS;
1418 if (DeviceExtension
->IrpFlags
& IRP_FLAG_COMPLETE
)
1420 DeviceExtension
->IrpFlags
&= ~IRP_FLAG_COMPLETE
;
1421 IoCompleteRequest(DpcIrp
, IO_NO_INCREMENT
);
1424 if (DeviceExtension
->IrpFlags
& IRP_FLAG_NEXT
)
1426 DeviceExtension
->IrpFlags
&= ~IRP_FLAG_NEXT
;
1427 IoStartNextPacket(DpcDeviceObject
, FALSE
);
1430 DPRINT("ScsiPortDpcForIsr() done\n");
1436 // This function handles timeouts and other time delayed processing
1441 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
1442 // IN PVOID Context the Controller extension for the
1443 // controller the device is on
1446 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
1449 DPRINT1("ScsiPortIoTimer()\n");
1453 static PSCSI_REQUEST_BLOCK
1454 ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
1455 PSCSI_REQUEST_BLOCK OriginalSrb
)
1457 PSCSI_REQUEST_BLOCK Srb
;
1460 Srb
= &DeviceExtension
->InternalSrb
;
1463 sizeof(SCSI_REQUEST_BLOCK
));
1465 Srb
->PathId
= OriginalSrb
->PathId
;
1466 Srb
->TargetId
= OriginalSrb
->TargetId
;
1467 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1468 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
);
1469 Srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
1471 Srb
->TimeOutValue
= 4;
1474 Srb
->DataBuffer
= &DeviceExtension
->InternalSenseData
;
1475 Srb
->DataTransferLength
= sizeof(SENSE_DATA
);
1477 Cdb
= (PCDB
)Srb
->Cdb
;
1478 Cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_REQUEST_SENSE
;
1479 Cdb
->CDB6INQUIRY
.AllocationLength
= sizeof(SENSE_DATA
);
1486 ScsiPortFreeSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
1488 DeviceExtension
->OriginalSrb
= NULL
;