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.34 2003/09/05 11:48:03 ekohl Exp $
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * FILE: services/storage/scsiport/scsiport.c
24 * PURPOSE: SCSI port driver
25 * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
28 /* INCLUDES *****************************************************************/
30 #include <ddk/ntddk.h>
33 #include <ddk/ntddscsi.h>
39 #define VERSION "0.0.1"
41 #include "scsiport_int.h"
43 /* TYPES *********************************************************************/
45 #define IRP_FLAG_COMPLETE 0x00000001
46 #define IRP_FLAG_NEXT 0x00000002
49 /* GLOBALS *******************************************************************/
51 static NTSTATUS STDCALL
52 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
55 static NTSTATUS STDCALL
56 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
59 static NTSTATUS STDCALL
60 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
64 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
67 static IO_ALLOCATION_ACTION STDCALL
68 ScsiPortAllocateController(IN PDEVICE_OBJECT DeviceObject
,
70 IN PVOID MapRegisterBase
,
73 static BOOLEAN STDCALL
74 ScsiPortStartPacket(IN OUT PVOID Context
);
77 ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject
,
78 IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension
,
80 IN OUT PSCSI_PORT_DEVICE_EXTENSION
*RealDeviceExtension
);
82 static PSCSI_PORT_LUN_EXTENSION
83 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
88 static PSCSI_PORT_LUN_EXTENSION
89 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
95 ScsiPortInquire(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
);
98 SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
99 OUT PSCSI_ADAPTER_BUS_INFO AdapterBusInfo
);
101 static BOOLEAN STDCALL
102 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
103 IN PVOID ServiceContext
);
106 ScsiPortDpcForIsr(IN PKDPC Dpc
,
107 IN PDEVICE_OBJECT DpcDeviceObject
,
109 IN PVOID DpcContext
);
112 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
115 static PSCSI_REQUEST_BLOCK
116 ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
117 PSCSI_REQUEST_BLOCK OriginalSrb
);
120 ScsiPortBuildDeviceMap(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
121 PUNICODE_STRING RegistryPath
);
124 /* FUNCTIONS *****************************************************************/
126 /**********************************************************************
131 * This function initializes the driver.
138 * System allocated Driver Object for this driver.
141 * Name of registry driver service key.
148 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
149 IN PUNICODE_STRING RegistryPath
)
151 DPRINT("ScsiPort Driver %s\n", VERSION
);
152 return(STATUS_SUCCESS
);
156 /**********************************************************************
161 * Prints debugging messages.
168 * Debug level of the given message.
171 * Pointer to printf()-compatible format string.
174 Additional output data (see printf()).
183 ScsiDebugPrint(IN ULONG DebugPrintLevel
,
184 IN PCHAR DebugMessage
,
191 if (DebugPrintLevel
> InternalDebugLevel
)
195 va_start(ap
, DebugMessage
);
196 vsprintf(Buffer
, DebugMessage
, ap
);
207 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension
,
213 DPRINT("ScsiPortCompleteRequest()\n");
222 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address
)
224 DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
225 return(Address
.u
.LowPart
);
233 ScsiPortFlushDma(IN PVOID HwDeviceExtension
)
235 DPRINT("ScsiPortFlushDma()\n");
244 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension
,
245 IN PVOID MappedAddress
)
247 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
248 PSCSI_PORT_DEVICE_BASE DeviceBase
;
251 DPRINT("ScsiPortFreeDeviceBase() called\n");
253 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
254 SCSI_PORT_DEVICE_EXTENSION
,
255 MiniPortDeviceExtension
);
256 if (IsListEmpty(&DeviceExtension
->DeviceBaseListHead
))
259 Entry
= DeviceExtension
->DeviceBaseListHead
.Flink
;
260 while (Entry
!= &DeviceExtension
->DeviceBaseListHead
)
262 DeviceBase
= CONTAINING_RECORD(Entry
,
263 SCSI_PORT_DEVICE_BASE
,
265 if (DeviceBase
->MappedAddress
== MappedAddress
)
267 MmUnmapIoSpace(DeviceBase
->MappedAddress
,
268 DeviceBase
->NumberOfBytes
);
269 RemoveEntryList(Entry
);
270 ExFreePool(DeviceBase
);
275 Entry
= Entry
->Flink
;
284 ScsiPortGetBusData(IN PVOID DeviceExtension
,
285 IN ULONG BusDataType
,
286 IN ULONG SystemIoBusNumber
,
291 return(HalGetBusData(BusDataType
,
303 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension
,
304 IN INTERFACE_TYPE BusType
,
305 IN ULONG SystemIoBusNumber
,
306 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
307 IN ULONG NumberOfBytes
,
308 IN BOOLEAN InIoSpace
)
310 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
311 PHYSICAL_ADDRESS TranslatedAddress
;
312 PSCSI_PORT_DEVICE_BASE DeviceBase
;
316 DPRINT("ScsiPortGetDeviceBase() called\n");
318 AddressSpace
= (ULONG
)InIoSpace
;
319 if (HalTranslateBusAddress(BusType
,
323 &TranslatedAddress
) == FALSE
)
327 if (AddressSpace
!= 0)
328 return((PVOID
)TranslatedAddress
.u
.LowPart
);
330 MappedAddress
= MmMapIoSpace(TranslatedAddress
,
334 DeviceBase
= ExAllocatePool(NonPagedPool
,
335 sizeof(SCSI_PORT_DEVICE_BASE
));
336 if (DeviceBase
== NULL
)
337 return(MappedAddress
);
339 DeviceBase
->MappedAddress
= MappedAddress
;
340 DeviceBase
->NumberOfBytes
= NumberOfBytes
;
341 DeviceBase
->IoAddress
= IoAddress
;
342 DeviceBase
->SystemIoBusNumber
= SystemIoBusNumber
;
344 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
345 SCSI_PORT_DEVICE_EXTENSION
,
346 MiniPortDeviceExtension
);
348 InsertHeadList(&DeviceExtension
->DeviceBaseListHead
,
351 return(MappedAddress
);
359 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension
,
364 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
365 PSCSI_PORT_LUN_EXTENSION LunExtension
;
368 DPRINT("ScsiPortGetLogicalUnit() called\n");
370 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
371 SCSI_PORT_DEVICE_EXTENSION
,
372 MiniPortDeviceExtension
);
373 if (IsListEmpty(&DeviceExtension
->LunExtensionListHead
))
376 Entry
= DeviceExtension
->LunExtensionListHead
.Flink
;
377 while (Entry
!= &DeviceExtension
->LunExtensionListHead
)
379 LunExtension
= CONTAINING_RECORD(Entry
,
380 SCSI_PORT_LUN_EXTENSION
,
382 if (LunExtension
->PathId
== PathId
&&
383 LunExtension
->TargetId
== TargetId
&&
384 LunExtension
->Lun
== Lun
)
386 return (PVOID
)&LunExtension
->MiniportLunExtension
;
389 Entry
= Entry
->Flink
;
399 SCSI_PHYSICAL_ADDRESS STDCALL
400 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension
,
401 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
402 IN PVOID VirtualAddress
,
405 DPRINT1("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
406 HwDeviceExtension
, Srb
, VirtualAddress
, Length
);
414 PSCSI_REQUEST_BLOCK STDCALL
415 ScsiPortGetSrb(IN PVOID DeviceExtension
,
421 DPRINT("ScsiPortGetSrb()\n");
430 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension
,
431 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
432 IN ULONG NumberOfBytes
)
434 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
435 DEVICE_DESCRIPTION DeviceDescription
;
437 DPRINT1("ScsiPortGetUncachedExtension(%p %p %lu)\n",
438 HwDeviceExtension
, ConfigInfo
, NumberOfBytes
);
440 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
441 SCSI_PORT_DEVICE_EXTENSION
,
442 MiniPortDeviceExtension
);
444 /* Check for allocated common DMA buffer */
445 if (DeviceExtension
->VirtualAddress
!= NULL
)
447 DPRINT1("The HBA has already got a common DMA buffer!\n");
451 /* Check for DMA adapter object */
452 if (DeviceExtension
->AdapterObject
== NULL
)
454 /* Initialize DMA adapter description */
455 RtlZeroMemory(&DeviceDescription
,
456 sizeof(DEVICE_DESCRIPTION
));
457 DeviceDescription
.Version
= DEVICE_DESCRIPTION_VERSION1
;
458 DeviceDescription
.Master
= ConfigInfo
->Master
;
459 DeviceDescription
.ScatterGather
= ConfigInfo
->ScatterGather
;
460 DeviceDescription
.DemandMode
= ConfigInfo
->DemandMode
;
461 DeviceDescription
.Dma32BitAddresses
= ConfigInfo
->Dma32BitAddresses
;
462 DeviceDescription
.BusNumber
= ConfigInfo
->SystemIoBusNumber
;
463 DeviceDescription
.DmaChannel
= ConfigInfo
->DmaChannel
;
464 DeviceDescription
.InterfaceType
= ConfigInfo
->AdapterInterfaceType
;
465 DeviceDescription
.DmaWidth
= ConfigInfo
->DmaWidth
;
466 DeviceDescription
.DmaSpeed
= ConfigInfo
->DmaSpeed
;
467 DeviceDescription
.MaximumLength
= ConfigInfo
->MaximumTransferLength
;
468 DeviceDescription
.DmaPort
= ConfigInfo
->DmaPort
;
470 /* Get a DMA adapter object */
471 DeviceExtension
->AdapterObject
= HalGetAdapter(&DeviceDescription
,
472 &DeviceExtension
->MapRegisterCount
);
473 if (DeviceExtension
->AdapterObject
== NULL
)
475 DPRINT1("HalGetAdapter() failed\n");
480 /* Allocate a common DMA buffer */
481 DeviceExtension
->CommonBufferLength
= NumberOfBytes
;
482 DeviceExtension
->VirtualAddress
=
483 HalAllocateCommonBuffer(DeviceExtension
->AdapterObject
,
484 DeviceExtension
->CommonBufferLength
,
485 &DeviceExtension
->PhysicalAddress
,
487 if (DeviceExtension
->VirtualAddress
== NULL
)
489 DPRINT1("HalAllocateCommonBuffer() failed!\n");
490 DeviceExtension
->CommonBufferLength
= 0;
494 return DeviceExtension
->VirtualAddress
;
502 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension
,
503 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress
)
505 DPRINT("ScsiPortGetVirtualAddress()\n");
510 /**********************************************************************
515 * Initializes SCSI port driver specific data.
522 * Pointer to the miniport driver's driver object.
525 * Pointer to the miniport driver's registry path.
527 * HwInitializationData
528 * Pointer to port driver specific configuration data.
531 Miniport driver specific context.
540 ScsiPortInitialize(IN PVOID Argument1
,
542 IN
struct _HW_INITIALIZATION_DATA
*HwInitializationData
,
545 PDRIVER_OBJECT DriverObject
= (PDRIVER_OBJECT
)Argument1
;
546 PUNICODE_STRING RegistryPath
= (PUNICODE_STRING
)Argument2
;
547 PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension
;
548 PSCSI_PORT_DEVICE_EXTENSION RealDeviceExtension
;
549 PCONFIGURATION_INFORMATION SystemConfig
;
550 PPORT_CONFIGURATION_INFORMATION PortConfig
;
556 PACCESS_RANGE AccessRanges
;
559 DPRINT("ScsiPortInitialize() called!\n");
561 if ((HwInitializationData
->HwInitialize
== NULL
) ||
562 (HwInitializationData
->HwStartIo
== NULL
) ||
563 (HwInitializationData
->HwInterrupt
== NULL
) ||
564 (HwInitializationData
->HwFindAdapter
== NULL
) ||
565 (HwInitializationData
->HwResetBus
== NULL
))
566 return(STATUS_INVALID_PARAMETER
);
568 DriverObject
->DriverStartIo
= ScsiPortStartIo
;
569 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = (PDRIVER_DISPATCH
)ScsiPortCreateClose
;
570 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = (PDRIVER_DISPATCH
)ScsiPortCreateClose
;
571 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = (PDRIVER_DISPATCH
)ScsiPortDeviceControl
;
572 DriverObject
->MajorFunction
[IRP_MJ_SCSI
] = (PDRIVER_DISPATCH
)ScsiPortDispatchScsi
;
575 SystemConfig
= IoGetConfigurationInformation();
577 ExtensionSize
= sizeof(SCSI_PORT_DEVICE_EXTENSION
) +
578 HwInitializationData
->DeviceExtensionSize
;
579 PseudoDeviceExtension
= ExAllocatePool(PagedPool
,
581 RtlZeroMemory(PseudoDeviceExtension
,
583 PseudoDeviceExtension
->Length
= ExtensionSize
;
584 PseudoDeviceExtension
->MiniPortExtensionSize
= HwInitializationData
->DeviceExtensionSize
;
585 PseudoDeviceExtension
->LunExtensionSize
= HwInitializationData
->SpecificLuExtensionSize
;
586 PseudoDeviceExtension
->HwStartIo
= HwInitializationData
->HwStartIo
;
587 PseudoDeviceExtension
->HwInterrupt
= HwInitializationData
->HwInterrupt
;
589 PortConfig
= &PseudoDeviceExtension
->PortConfig
;
591 PortConfig
->Length
= sizeof(PORT_CONFIGURATION_INFORMATION
);
592 PortConfig
->AdapterInterfaceType
= HwInitializationData
->AdapterInterfaceType
;
593 PortConfig
->InterruptMode
=
594 (PortConfig
->AdapterInterfaceType
== PCIBus
) ? LevelSensitive
: Latched
;
595 PortConfig
->AtdiskPrimaryClaimed
= SystemConfig
->AtDiskPrimaryAddressClaimed
;
596 PortConfig
->AtdiskSecondaryClaimed
= SystemConfig
->AtDiskSecondaryAddressClaimed
;
597 PortConfig
->NumberOfAccessRanges
= HwInitializationData
->NumberOfAccessRanges
;
599 PortConfig
->AccessRanges
=
600 ExAllocatePool(PagedPool
,
601 sizeof(ACCESS_RANGE
) * PortConfig
->NumberOfAccessRanges
);
603 for (i
= 0; i
< SCSI_MAXIMUM_BUSES
; i
++)
604 PortConfig
->InitiatorBusId
[i
] = 255;
606 PortConfig
->SystemIoBusNumber
= 0;
607 PortConfig
->SlotNumber
= 0;
609 MaxBus
= (PortConfig
->AdapterInterfaceType
== PCIBus
) ? 8 : 1;
611 DPRINT("MaxBus: %lu\n", MaxBus
);
615 DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig
->SystemIoBusNumber
);
617 InitializeListHead(&PseudoDeviceExtension
->DeviceBaseListHead
);
619 // RtlZeroMemory(AccessRanges,
620 // sizeof(ACCESS_RANGE) * PortConfig->NumberOfAccessRanges);
622 RtlZeroMemory(PseudoDeviceExtension
->MiniPortDeviceExtension
,
623 PseudoDeviceExtension
->MiniPortExtensionSize
);
625 /* Note: HwFindAdapter is called once for each bus */
626 Result
= (HwInitializationData
->HwFindAdapter
)(&PseudoDeviceExtension
->MiniPortDeviceExtension
,
628 NULL
, /* BusInformation */
629 NULL
, /* ArgumentString */
630 &PseudoDeviceExtension
->PortConfig
,
632 DPRINT("HwFindAdapter() result: %lu\n", Result
);
634 if (Result
== SP_RETURN_FOUND
)
636 DPRINT("ScsiPortInitialize(): Found HBA!\n");
638 Status
= ScsiPortCreatePortDevice(DriverObject
,
639 PseudoDeviceExtension
,
640 SystemConfig
->ScsiPortCount
,
641 &RealDeviceExtension
);
643 if (!NT_SUCCESS(Status
))
645 DbgPrint("ScsiPortCreatePortDevice() failed! (Status 0x%lX)\n", Status
);
647 ExFreePool(PortConfig
->AccessRanges
);
648 ExFreePool(PseudoDeviceExtension
);
653 /* Get inquiry data */
654 ScsiPortInquire(RealDeviceExtension
);
656 /* Build the registry device map */
657 ScsiPortBuildDeviceMap(RealDeviceExtension
,
658 (PUNICODE_STRING
)Argument2
);
660 /* Update the configuration info */
661 SystemConfig
->AtDiskPrimaryAddressClaimed
= PortConfig
->AtdiskPrimaryClaimed
;
662 SystemConfig
->AtDiskSecondaryAddressClaimed
= PortConfig
->AtdiskSecondaryClaimed
;
663 SystemConfig
->ScsiPortCount
++;
668 PortConfig
->SystemIoBusNumber
++;
669 PortConfig
->SlotNumber
= 0;
672 DPRINT("Bus: %lu MaxBus: %lu\n", PortConfig
->SystemIoBusNumber
, MaxBus
);
673 if (PortConfig
->SystemIoBusNumber
>= MaxBus
)
675 DPRINT("Scanned all buses!\n");
680 ExFreePool(PortConfig
->AccessRanges
);
681 ExFreePool(PseudoDeviceExtension
);
683 DPRINT("ScsiPortInitialize() done!\n");
685 return(STATUS_SUCCESS
);
693 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension
,
694 IN PSCSI_REQUEST_BLOCK Srb
,
695 IN ULONG LogicalAddress
,
698 DPRINT("ScsiPortIoMapTransfer()\n");
707 ScsiPortLogError(IN PVOID HwDeviceExtension
,
708 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL
,
715 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
717 DPRINT("ScsiPortLogError() called\n");
719 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
720 SCSI_PORT_DEVICE_EXTENSION
,
721 MiniPortDeviceExtension
);
724 DPRINT("ScsiPortLogError() done\n");
732 ScsiPortMoveMemory(OUT PVOID Destination
,
736 RtlMoveMemory(Destination
,
746 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType
,
747 IN PVOID HwDeviceExtension
,
750 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
752 DPRINT("ScsiPortNotification() called\n");
754 DeviceExtension
= CONTAINING_RECORD(HwDeviceExtension
,
755 SCSI_PORT_DEVICE_EXTENSION
,
756 MiniPortDeviceExtension
);
758 DPRINT("DeviceExtension %p\n", DeviceExtension
);
760 DPRINT("Initializing = %s\n", (DeviceExtension
->Initializing
)?"TRUE":"FALSE");
762 if (DeviceExtension
->Initializing
== TRUE
)
765 switch (NotificationType
)
767 case RequestComplete
:
768 DPRINT("Notify: RequestComplete\n");
769 DeviceExtension
->IrpFlags
|= IRP_FLAG_COMPLETE
;
773 DPRINT("Notify: NextRequest\n");
774 DeviceExtension
->IrpFlags
|= IRP_FLAG_NEXT
;
787 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension
,
788 IN ULONG BusDataType
,
789 IN ULONG SystemIoBusNumber
,
795 DPRINT("ScsiPortSetBusDataByOffset()\n");
796 return(HalSetBusDataByOffset(BusDataType
,
809 ScsiPortValidateRange(IN PVOID HwDeviceExtension
,
810 IN INTERFACE_TYPE BusType
,
811 IN ULONG SystemIoBusNumber
,
812 IN SCSI_PHYSICAL_ADDRESS IoAddress
,
813 IN ULONG NumberOfBytes
,
814 IN BOOLEAN InIoSpace
)
816 DPRINT("ScsiPortValidateRange()\n");
821 /* INTERNAL FUNCTIONS ********************************************************/
823 /**********************************************************************
825 * ScsiPortCreateClose
828 * Answer requests for Create/Close calls: a null operation.
835 * Pointer to a device object.
841 Additional output data (see printf()).
847 static NTSTATUS STDCALL
848 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject
,
851 DPRINT("ScsiPortCreateClose()\n");
853 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
854 Irp
->IoStatus
.Information
= FILE_OPENED
;
856 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
858 return(STATUS_SUCCESS
);
862 /**********************************************************************
864 * ScsiPortDispatchScsi
867 * Answer requests for SCSI calls
873 * Standard dispatch arguments
879 static NTSTATUS STDCALL
880 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject
,
883 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
884 PIO_STACK_LOCATION Stack
;
885 PSCSI_REQUEST_BLOCK Srb
;
886 NTSTATUS Status
= STATUS_SUCCESS
;
889 DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n",
892 DeviceExtension
= DeviceObject
->DeviceExtension
;
893 Stack
= IoGetCurrentIrpStackLocation(Irp
);
895 Srb
= Stack
->Parameters
.Scsi
.Srb
;
898 Status
= STATUS_UNSUCCESSFUL
;
900 Irp
->IoStatus
.Status
= Status
;
901 Irp
->IoStatus
.Information
= 0;
903 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
908 DPRINT("Srb: %p\n", Srb
);
909 DPRINT("Srb->Function: %lu\n", Srb
->Function
);
910 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb
->PathId
, Srb
->TargetId
, Srb
->Lun
);
912 switch (Srb
->Function
)
914 case SRB_FUNCTION_EXECUTE_SCSI
:
915 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
916 return(STATUS_PENDING
);
918 case SRB_FUNCTION_SHUTDOWN
:
919 case SRB_FUNCTION_FLUSH
:
920 if (DeviceExtension
->PortConfig
.CachesData
== TRUE
)
922 IoStartPacket(DeviceObject
, Irp
, NULL
, NULL
);
923 return(STATUS_PENDING
);
927 case SRB_FUNCTION_CLAIM_DEVICE
:
929 PSCSI_PORT_LUN_EXTENSION LunExtension
;
931 DPRINT(" SRB_FUNCTION_CLAIM_DEVICE\n");
932 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb
->PathId
, Srb
->TargetId
, Srb
->Lun
);
934 LunExtension
= SpiGetLunExtension(DeviceExtension
,
938 if (LunExtension
!= NULL
)
940 /* Reference device object and keep the pointer */
941 ObReferenceObject(DeviceObject
);
942 LunExtension
->DeviceObject
= DeviceObject
;
943 LunExtension
->DeviceClaimed
= TRUE
;
944 Srb
->DataBuffer
= DeviceObject
;
948 Srb
->DataBuffer
= NULL
;
953 case SRB_FUNCTION_RELEASE_DEVICE
:
955 PSCSI_PORT_LUN_EXTENSION LunExtension
;
957 DPRINT(" SRB_FUNCTION_RELEASE_DEVICE\n");
958 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb
->PathId
, Srb
->TargetId
, Srb
->Lun
);
960 LunExtension
= SpiGetLunExtension(DeviceExtension
,
964 if (LunExtension
!= NULL
)
966 /* Dereference device object */
967 ObDereferenceObject(LunExtension
->DeviceObject
);
968 LunExtension
->DeviceObject
= NULL
;
969 LunExtension
->DeviceClaimed
= FALSE
;
975 DPRINT1("SRB function not implemented (Function %lu)\n", Srb
->Function
);
976 Status
= STATUS_NOT_IMPLEMENTED
;
980 Irp
->IoStatus
.Status
= Status
;
981 Irp
->IoStatus
.Information
= DataSize
;
983 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
989 /**********************************************************************
991 * ScsiPortDeviceControl
994 * Answer requests for device control calls
1000 * Standard dispatch arguments
1006 static NTSTATUS STDCALL
1007 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject
,
1010 PIO_STACK_LOCATION Stack
;
1011 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1013 DPRINT("ScsiPortDeviceControl()\n");
1015 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1016 Irp
->IoStatus
.Information
= 0;
1019 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1020 DeviceExtension
= DeviceObject
->DeviceExtension
;
1022 switch (Stack
->Parameters
.DeviceIoControl
.IoControlCode
)
1024 case IOCTL_SCSI_GET_DUMP_POINTERS
:
1026 PDUMP_POINTERS DumpPointers
;
1027 DPRINT(" IOCTL_SCSI_GET_DUMP_POINTERS\n");
1028 DumpPointers
= (PDUMP_POINTERS
)Irp
->AssociatedIrp
.SystemBuffer
;
1029 DumpPointers
->DeviceObject
= DeviceObject
;
1031 Irp
->IoStatus
.Information
= sizeof(DUMP_POINTERS
);
1035 case IOCTL_SCSI_GET_CAPABILITIES
:
1037 DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
1039 *((PIO_SCSI_CAPABILITIES
*)Irp
->AssociatedIrp
.SystemBuffer
) =
1040 DeviceExtension
->PortCapabilities
;
1042 Irp
->IoStatus
.Information
= sizeof(PIO_SCSI_CAPABILITIES
);
1046 case IOCTL_SCSI_GET_INQUIRY_DATA
:
1048 DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
1050 /* Copy inquiry data to the port device extension */
1051 Irp
->IoStatus
.Information
=
1052 SpiGetInquiryData(DeviceExtension
,
1053 Irp
->AssociatedIrp
.SystemBuffer
);
1054 DPRINT("Inquiry data size: %lu\n", Irp
->IoStatus
.Information
);
1059 DPRINT1(" unknown ioctl code: 0x%lX\n",
1060 Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
1064 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1066 return(STATUS_SUCCESS
);
1071 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject
,
1074 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1075 PIO_STACK_LOCATION IrpStack
;
1078 DPRINT("ScsiPortStartIo() called!\n");
1080 DeviceExtension
= DeviceObject
->DeviceExtension
;
1081 IrpStack
= IoGetCurrentIrpStackLocation(Irp
);
1083 // FIXME: implement the supported functions
1085 switch (IrpStack
->MajorFunction
)
1090 PSCSI_REQUEST_BLOCK Srb
;
1093 DPRINT("IRP_MJ_SCSI\n");
1095 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
1097 DPRINT("DeviceExtension %p\n", DeviceExtension
);
1099 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1100 Irp
->IoStatus
.Information
= Srb
->DataTransferLength
;
1102 DeviceExtension
->CurrentIrp
= Irp
;
1104 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
1105 ScsiPortStartPacket
,
1108 DPRINT("Synchronization failed!\n");
1110 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
1111 Irp
->IoStatus
.Information
= 0;
1112 IoCompleteRequest(Irp
,
1114 IoStartNextPacket(DeviceObject
,
1117 KeAcquireSpinLock(&DeviceExtension
->IrpLock
, &oldIrql
);
1118 if (DeviceExtension
->IrpFlags
& IRP_FLAG_COMPLETE
)
1120 DeviceExtension
->IrpFlags
&= ~IRP_FLAG_COMPLETE
;
1121 IoCompleteRequest(Irp
,
1125 if (DeviceExtension
->IrpFlags
& IRP_FLAG_NEXT
)
1127 DeviceExtension
->IrpFlags
&= ~IRP_FLAG_NEXT
;
1128 KeReleaseSpinLock(&DeviceExtension
->IrpLock
, oldIrql
);
1129 IoStartNextPacket(DeviceObject
,
1134 KeReleaseSpinLock(&DeviceExtension
->IrpLock
, oldIrql
);
1140 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
1141 Irp
->IoStatus
.Information
= 0;
1142 IoCompleteRequest(Irp
,
1144 IoStartNextPacket(DeviceObject
,
1148 DPRINT("ScsiPortStartIo() done\n");
1152 static BOOLEAN STDCALL
1153 ScsiPortStartPacket(IN OUT PVOID Context
)
1155 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1156 PIO_STACK_LOCATION IrpStack
;
1157 PSCSI_REQUEST_BLOCK Srb
;
1159 DPRINT("ScsiPortStartPacket() called\n");
1161 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)Context
;
1163 IrpStack
= IoGetCurrentIrpStackLocation(DeviceExtension
->CurrentIrp
);
1164 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
1166 return(DeviceExtension
->HwStartIo(&DeviceExtension
->MiniPortDeviceExtension
,
1171 /**********************************************************************
1173 * ScsiPortCreatePortDevice
1176 * Creates and initializes a SCSI port device object.
1185 * PseudoDeviceExtension
1196 ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject
,
1197 IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension
,
1198 IN ULONG PortNumber
,
1199 IN OUT PSCSI_PORT_DEVICE_EXTENSION
*RealDeviceExtension
)
1201 PSCSI_PORT_DEVICE_EXTENSION PortDeviceExtension
;
1202 PIO_SCSI_CAPABILITIES PortCapabilities
;
1203 PDEVICE_OBJECT PortDeviceObject
;
1204 WCHAR NameBuffer
[80];
1205 UNICODE_STRING DeviceName
;
1206 WCHAR DosNameBuffer
[80];
1207 UNICODE_STRING DosDeviceName
;
1209 ULONG AccessRangeSize
;
1214 DPRINT("ScsiPortCreatePortDevice() called\n");
1216 *RealDeviceExtension
= NULL
;
1218 MappedIrq
= HalGetInterruptVector(PseudoDeviceExtension
->PortConfig
.AdapterInterfaceType
,
1219 PseudoDeviceExtension
->PortConfig
.SystemIoBusNumber
,
1220 PseudoDeviceExtension
->PortConfig
.BusInterruptLevel
,
1221 PseudoDeviceExtension
->PortConfig
.BusInterruptVector
,
1225 /* Create a unicode device name */
1226 swprintf(NameBuffer
,
1227 L
"\\Device\\ScsiPort%lu",
1229 RtlInitUnicodeString(&DeviceName
,
1232 DPRINT("Creating device: %wZ\n", &DeviceName
);
1234 /* Create the port device */
1235 Status
= IoCreateDevice(DriverObject
,
1236 PseudoDeviceExtension
->Length
,
1238 FILE_DEVICE_CONTROLLER
,
1242 if (!NT_SUCCESS(Status
))
1244 DbgPrint("IoCreateDevice call failed! (Status 0x%lX)\n", Status
);
1248 DPRINT("Created device: %wZ\n", &DeviceName
);
1250 /* Set the buffering strategy here... */
1251 PortDeviceObject
->Flags
|= DO_DIRECT_IO
;
1252 PortDeviceObject
->AlignmentRequirement
= FILE_WORD_ALIGNMENT
;
1254 PortDeviceExtension
= PortDeviceObject
->DeviceExtension
;
1256 /* Copy pseudo device extension into the real device extension */
1257 memcpy(PortDeviceExtension
,
1258 PseudoDeviceExtension
,
1259 PseudoDeviceExtension
->Length
);
1261 /* Copy access ranges */
1263 sizeof(ACCESS_RANGE
) * PseudoDeviceExtension
->PortConfig
.NumberOfAccessRanges
;
1264 PortDeviceExtension
->PortConfig
.AccessRanges
= ExAllocatePool(NonPagedPool
,
1266 memcpy(PortDeviceExtension
->PortConfig
.AccessRanges
,
1267 PseudoDeviceExtension
->PortConfig
.AccessRanges
,
1270 /* Copy device base list */
1271 if (IsListEmpty(&PseudoDeviceExtension
->DeviceBaseListHead
))
1273 InitializeListHead(&PortDeviceExtension
->DeviceBaseListHead
);
1277 PseudoDeviceExtension
->DeviceBaseListHead
.Flink
=
1278 PortDeviceExtension
->DeviceBaseListHead
.Flink
;
1279 PseudoDeviceExtension
->DeviceBaseListHead
.Blink
=
1280 PortDeviceExtension
->DeviceBaseListHead
.Blink
;
1281 PortDeviceExtension
->DeviceBaseListHead
.Blink
->Flink
=
1282 &PortDeviceExtension
->DeviceBaseListHead
;
1283 PortDeviceExtension
->DeviceBaseListHead
.Flink
->Blink
=
1284 &PortDeviceExtension
->DeviceBaseListHead
;
1287 PortDeviceExtension
->DeviceObject
= PortDeviceObject
;
1288 PortDeviceExtension
->PortNumber
= PortNumber
;
1290 /* Initialize the spin lock in the controller extension */
1291 KeInitializeSpinLock(&PortDeviceExtension
->IrpLock
);
1292 KeInitializeSpinLock(&PortDeviceExtension
->SpinLock
);
1294 /* Register an interrupt handler for this device */
1295 Status
= IoConnectInterrupt(&PortDeviceExtension
->Interrupt
,
1297 PortDeviceExtension
,
1298 &PortDeviceExtension
->SpinLock
,
1302 PortDeviceExtension
->PortConfig
.InterruptMode
,
1306 if (!NT_SUCCESS(Status
))
1308 DbgPrint("Could not Connect Interrupt %d\n",
1309 PortDeviceExtension
->PortConfig
.BusInterruptVector
);
1310 IoDeleteDevice(PortDeviceObject
);
1314 /* Initialize the DPC object */
1315 IoInitializeDpcRequest(PortDeviceExtension
->DeviceObject
,
1318 /* Initialize the device timer */
1319 PortDeviceExtension
->TimerState
= IDETimerIdle
;
1320 PortDeviceExtension
->TimerCount
= 0;
1321 IoInitializeTimer(PortDeviceExtension
->DeviceObject
,
1323 PortDeviceExtension
);
1325 /* Initialize port capabilities */
1326 PortCapabilities
= ExAllocatePool(NonPagedPool
,
1327 sizeof(IO_SCSI_CAPABILITIES
));
1328 PortDeviceExtension
->PortCapabilities
= PortCapabilities
;
1329 PortCapabilities
->Length
= sizeof(IO_SCSI_CAPABILITIES
);
1330 PortCapabilities
->MaximumTransferLength
=
1331 PortDeviceExtension
->PortConfig
.MaximumTransferLength
;
1332 PortCapabilities
->MaximumPhysicalPages
=
1333 PortCapabilities
->MaximumTransferLength
/ PAGE_SIZE
;
1334 PortCapabilities
->SupportedAsynchronousEvents
= 0; /* FIXME */
1335 PortCapabilities
->AlignmentMask
=
1336 PortDeviceExtension
->PortConfig
.AlignmentMask
;
1337 PortCapabilities
->TaggedQueuing
=
1338 PortDeviceExtension
->PortConfig
.TaggedQueuing
;
1339 PortCapabilities
->AdapterScansDown
=
1340 PortDeviceExtension
->PortConfig
.AdapterScansDown
;
1341 PortCapabilities
->AdapterUsesPio
= TRUE
; /* FIXME */
1343 /* Initialize LUN-Extension list */
1344 InitializeListHead(&PortDeviceExtension
->LunExtensionListHead
);
1346 DPRINT("DeviceExtension %p\n", PortDeviceExtension
);
1348 /* FIXME: Copy more configuration data? */
1351 /* Create the dos device link */
1352 swprintf(DosNameBuffer
,
1355 RtlInitUnicodeString(&DosDeviceName
,
1358 IoCreateSymbolicLink(&DosDeviceName
,
1361 *RealDeviceExtension
= PortDeviceExtension
;
1363 DPRINT("ScsiPortCreatePortDevice() done\n");
1365 return(STATUS_SUCCESS
);
1369 static PSCSI_PORT_LUN_EXTENSION
1370 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
1375 PSCSI_PORT_LUN_EXTENSION LunExtension
;
1376 ULONG LunExtensionSize
;
1378 DPRINT("SpiAllocateLunExtension (%p %u %u %u)\n",
1379 DeviceExtension
, PathId
, TargetId
, Lun
);
1382 sizeof(SCSI_PORT_LUN_EXTENSION
) + DeviceExtension
->LunExtensionSize
;
1383 DPRINT("LunExtensionSize %lu\n", LunExtensionSize
);
1385 LunExtension
= ExAllocatePool(NonPagedPool
,
1387 if (LunExtension
== NULL
)
1392 RtlZeroMemory(LunExtension
,
1395 InsertTailList(&DeviceExtension
->LunExtensionListHead
,
1396 &LunExtension
->List
);
1398 LunExtension
->PathId
= PathId
;
1399 LunExtension
->TargetId
= TargetId
;
1400 LunExtension
->Lun
= Lun
;
1402 return LunExtension
;
1406 static PSCSI_PORT_LUN_EXTENSION
1407 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
1412 PSCSI_PORT_LUN_EXTENSION LunExtension
;
1415 DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
1416 DeviceExtension
, PathId
, TargetId
, Lun
);
1418 if (IsListEmpty(&DeviceExtension
->LunExtensionListHead
))
1421 Entry
= DeviceExtension
->LunExtensionListHead
.Flink
;
1422 while (Entry
!= &DeviceExtension
->LunExtensionListHead
)
1424 LunExtension
= CONTAINING_RECORD(Entry
,
1425 SCSI_PORT_LUN_EXTENSION
,
1427 if (LunExtension
->PathId
== PathId
&&
1428 LunExtension
->TargetId
== TargetId
&&
1429 LunExtension
->Lun
== Lun
)
1431 return LunExtension
;
1434 Entry
= Entry
->Flink
;
1442 ScsiPortInquire(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
1444 PSCSI_PORT_LUN_EXTENSION LunExtension
;
1445 SCSI_REQUEST_BLOCK Srb
;
1451 DPRINT("ScsiPortInquire() called\n");
1453 DeviceExtension
->Initializing
= TRUE
;
1456 sizeof(SCSI_REQUEST_BLOCK
));
1457 Srb
.DataBuffer
= ExAllocatePool(NonPagedPool
, 256);
1458 Srb
.Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1459 Srb
.DataTransferLength
= 256;
1460 Srb
.Cdb
[0] = SCSIOP_INQUIRY
;
1462 for (Bus
= 0; Bus
< DeviceExtension
->PortConfig
.NumberOfBuses
; Bus
++)
1466 for (Target
= 0; Target
< DeviceExtension
->PortConfig
.MaximumNumberOfTargets
; Target
++)
1468 Srb
.TargetId
= Target
;
1470 for (Lun
= 0; Lun
< SCSI_MAXIMUM_LOGICAL_UNITS
; Lun
++)
1473 Srb
.SrbStatus
= SRB_STATUS_SUCCESS
;
1475 Result
= DeviceExtension
->HwStartIo(&DeviceExtension
->MiniPortDeviceExtension
,
1477 DPRINT("Result: %s Srb.SrbStatus %lx\n", (Result
)?"True":"False", Srb
.SrbStatus
);
1479 if (Result
== TRUE
&& Srb
.SrbStatus
== SRB_STATUS_SUCCESS
)
1481 LunExtension
= SpiAllocateLunExtension(DeviceExtension
,
1485 if (LunExtension
!= NULL
)
1487 /* Copy inquiry data */
1488 memcpy(&LunExtension
->InquiryData
,
1490 sizeof(INQUIRYDATA
));
1497 ExFreePool(Srb
.DataBuffer
);
1499 DeviceExtension
->Initializing
= FALSE
;
1501 DPRINT("ScsiPortInquire() done\n");
1506 SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
1507 OUT PSCSI_ADAPTER_BUS_INFO AdapterBusInfo
)
1509 PSCSI_PORT_LUN_EXTENSION LunExtension
;
1510 PSCSI_INQUIRY_DATA UnitInfo
, PrevUnit
;
1516 DPRINT("SpiGetInquiryData() called\n");
1518 /* Copy inquiry data to the port device extension */
1519 AdapterBusInfo
->NumberOfBuses
= DeviceExtension
->PortConfig
.NumberOfBuses
;
1521 UnitInfo
= (PSCSI_INQUIRY_DATA
)
1522 ((PUCHAR
)AdapterBusInfo
+ sizeof(SCSI_ADAPTER_BUS_INFO
) +
1523 (sizeof(SCSI_BUS_DATA
) * (AdapterBusInfo
->NumberOfBuses
- 1)));
1525 for (Bus
= 0; Bus
< AdapterBusInfo
->NumberOfBuses
; Bus
++)
1527 AdapterBusInfo
->BusData
[Bus
].InitiatorBusId
=
1528 DeviceExtension
->PortConfig
.InitiatorBusId
[Bus
];
1529 AdapterBusInfo
->BusData
[Bus
].InquiryDataOffset
=
1530 (ULONG
)((PUCHAR
)UnitInfo
- (PUCHAR
)AdapterBusInfo
);
1535 for (Target
= 0; Target
< DeviceExtension
->PortConfig
.MaximumNumberOfTargets
; Target
++)
1537 for (Lun
= 0; Lun
< SCSI_MAXIMUM_LOGICAL_UNITS
; Lun
++)
1539 LunExtension
= SpiGetLunExtension(DeviceExtension
,
1543 if (LunExtension
!= NULL
)
1545 DPRINT("(Bus %lu Target %lu Lun %lu)\n",
1548 UnitInfo
->PathId
= Bus
;
1549 UnitInfo
->TargetId
= Target
;
1550 UnitInfo
->Lun
= Lun
;
1551 UnitInfo
->InquiryDataLength
= INQUIRYDATABUFFERSIZE
;
1552 memcpy(&UnitInfo
->InquiryData
,
1553 &LunExtension
->InquiryData
,
1554 INQUIRYDATABUFFERSIZE
);
1555 if (PrevUnit
!= NULL
)
1556 PrevUnit
->NextInquiryDataOffset
= (ULONG
)((PUCHAR
)UnitInfo
-(PUCHAR
)AdapterBusInfo
);
1557 PrevUnit
= UnitInfo
;
1558 UnitInfo
= (PSCSI_INQUIRY_DATA
)((PUCHAR
)UnitInfo
+ sizeof(SCSI_INQUIRY_DATA
)+INQUIRYDATABUFFERSIZE
-1);
1563 DPRINT("UnitCount: %lu\n", UnitCount
);
1564 AdapterBusInfo
->BusData
[Bus
].NumberOfLogicalUnits
= UnitCount
;
1566 AdapterBusInfo
->BusData
[Bus
].InquiryDataOffset
= 0;
1569 DPRINT("Data size: %lu\n", (ULONG
)UnitInfo
- (ULONG
)AdapterBusInfo
);
1571 return (ULONG
)((PUCHAR
)UnitInfo
-(PUCHAR
)AdapterBusInfo
);
1575 static BOOLEAN STDCALL
1576 ScsiPortIsr(IN PKINTERRUPT Interrupt
,
1577 IN PVOID ServiceContext
)
1579 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1582 DPRINT("ScsiPortIsr() called!\n");
1584 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)ServiceContext
;
1586 Result
= DeviceExtension
->HwInterrupt(&DeviceExtension
->MiniPortDeviceExtension
);
1587 if (Result
== FALSE
)
1592 if (DeviceExtension
->IrpFlags
)
1594 IoRequestDpc(DeviceExtension
->DeviceObject
,
1595 DeviceExtension
->CurrentIrp
,
1603 // ScsiPortDpcForIsr
1610 // IN PDEVICE_OBJECT DpcDeviceObject
1612 // IN PVOID DpcContext
1615 ScsiPortDpcForIsr(IN PKDPC Dpc
,
1616 IN PDEVICE_OBJECT DpcDeviceObject
,
1618 IN PVOID DpcContext
)
1620 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
;
1621 PIO_STACK_LOCATION IrpStack
;
1622 PSCSI_REQUEST_BLOCK Srb
;
1625 DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
1626 Dpc
, DpcDeviceObject
, DpcIrp
, DpcContext
);
1628 DeviceExtension
= (PSCSI_PORT_DEVICE_EXTENSION
)DpcContext
;
1630 KeAcquireSpinLock(&DeviceExtension
->IrpLock
, &oldIrql
);
1631 if (DeviceExtension
->IrpFlags
)
1633 IrpStack
= IoGetCurrentIrpStackLocation(DeviceExtension
->CurrentIrp
);
1634 Srb
= IrpStack
->Parameters
.Scsi
.Srb
;
1636 if (DeviceExtension
->OriginalSrb
!= NULL
)
1638 DPRINT("Got sense data!\n");
1640 DPRINT("Valid: %x\n", DeviceExtension
->InternalSenseData
.Valid
);
1641 DPRINT("ErrorCode: %x\n", DeviceExtension
->InternalSenseData
.ErrorCode
);
1642 DPRINT("SenseKey: %x\n", DeviceExtension
->InternalSenseData
.SenseKey
);
1643 DPRINT("SenseCode: %x\n", DeviceExtension
->InternalSenseData
.AdditionalSenseCode
);
1645 /* Copy sense data */
1646 if (DeviceExtension
->OriginalSrb
->SenseInfoBufferLength
!= 0)
1648 RtlCopyMemory(DeviceExtension
->OriginalSrb
->SenseInfoBuffer
,
1649 &DeviceExtension
->InternalSenseData
,
1650 sizeof(SENSE_DATA
));
1651 DeviceExtension
->OriginalSrb
->SrbStatus
|= SRB_STATUS_AUTOSENSE_VALID
;
1654 /* Clear current sense data */
1655 RtlZeroMemory(&DeviceExtension
->InternalSenseData
, sizeof(SENSE_DATA
));
1657 IrpStack
->Parameters
.Scsi
.Srb
= DeviceExtension
->OriginalSrb
;
1658 DeviceExtension
->OriginalSrb
= NULL
;
1660 else if ((SRB_STATUS(Srb
->SrbStatus
) != SRB_STATUS_SUCCESS
) &&
1661 (Srb
->ScsiStatus
== SCSISTAT_CHECK_CONDITION
))
1663 DPRINT("SCSIOP_REQUEST_SENSE required!\n");
1665 DeviceExtension
->OriginalSrb
= Srb
;
1666 IrpStack
->Parameters
.Scsi
.Srb
= ScsiPortInitSenseRequestSrb(DeviceExtension
,
1668 KeReleaseSpinLock(&DeviceExtension
->IrpLock
, oldIrql
);
1669 if (!KeSynchronizeExecution(DeviceExtension
->Interrupt
,
1670 ScsiPortStartPacket
,
1673 DPRINT1("Synchronization failed!\n");
1675 DpcIrp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
1676 DpcIrp
->IoStatus
.Information
= 0;
1677 IoCompleteRequest(DpcIrp
,
1679 IoStartNextPacket(DpcDeviceObject
,
1686 DeviceExtension
->CurrentIrp
= NULL
;
1689 // DpcIrp->IoStatus.Information = 0;
1690 // DpcIrp->IoStatus.Status = STATUS_SUCCESS;
1692 if (DeviceExtension
->IrpFlags
& IRP_FLAG_COMPLETE
)
1694 DeviceExtension
->IrpFlags
&= ~IRP_FLAG_COMPLETE
;
1695 IoCompleteRequest(DpcIrp
, IO_NO_INCREMENT
);
1698 if (DeviceExtension
->IrpFlags
& IRP_FLAG_NEXT
)
1700 DeviceExtension
->IrpFlags
&= ~IRP_FLAG_NEXT
;
1701 KeReleaseSpinLock(&DeviceExtension
->IrpLock
, oldIrql
);
1702 IoStartNextPacket(DpcDeviceObject
, FALSE
);
1706 KeReleaseSpinLock(&DeviceExtension
->IrpLock
, oldIrql
);
1711 KeReleaseSpinLock(&DeviceExtension
->IrpLock
, oldIrql
);
1714 DPRINT("ScsiPortDpcForIsr() done\n");
1720 // This function handles timeouts and other time delayed processing
1725 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
1726 // IN PVOID Context the Controller extension for the
1727 // controller the device is on
1730 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject
,
1733 DPRINT1("ScsiPortIoTimer()\n");
1737 static PSCSI_REQUEST_BLOCK
1738 ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
1739 PSCSI_REQUEST_BLOCK OriginalSrb
)
1741 PSCSI_REQUEST_BLOCK Srb
;
1744 Srb
= &DeviceExtension
->InternalSrb
;
1747 sizeof(SCSI_REQUEST_BLOCK
));
1749 Srb
->PathId
= OriginalSrb
->PathId
;
1750 Srb
->TargetId
= OriginalSrb
->TargetId
;
1751 Srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
1752 Srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
);
1753 Srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
1755 Srb
->TimeOutValue
= 4;
1758 Srb
->DataBuffer
= &DeviceExtension
->InternalSenseData
;
1759 Srb
->DataTransferLength
= sizeof(SENSE_DATA
);
1761 Cdb
= (PCDB
)Srb
->Cdb
;
1762 Cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_REQUEST_SENSE
;
1763 Cdb
->CDB6INQUIRY
.AllocationLength
= sizeof(SENSE_DATA
);
1770 ScsiPortFreeSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
)
1772 DeviceExtension
->OriginalSrb
= NULL
;
1776 /**********************************************************************
1778 * ScsiPortBuildDeviceMap
1781 * Builds the registry device map of all device which are attached
1782 * to the given SCSI HBA port. The device map is located at:
1783 * \Registry\Machine\DeviceMap\Scsi
1793 * Name of registry driver service key.
1800 ScsiPortBuildDeviceMap(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension
,
1801 PUNICODE_STRING RegistryPath
)
1803 PSCSI_PORT_LUN_EXTENSION LunExtension
;
1804 OBJECT_ATTRIBUTES ObjectAttributes
;
1805 UNICODE_STRING KeyName
;
1806 UNICODE_STRING ValueName
;
1807 WCHAR NameBuffer
[64];
1812 HANDLE ScsiInitiatorKey
;
1813 HANDLE ScsiTargetKey
;
1817 ULONG CurrentTarget
;
1824 DPRINT("ScsiPortBuildDeviceMap() called\n");
1826 if (DeviceExtension
== NULL
|| RegistryPath
== NULL
)
1828 DPRINT1("Invalid parameter\n");
1829 return(STATUS_INVALID_PARAMETER
);
1832 /* Open or create the 'Scsi' subkey */
1833 RtlInitUnicodeStringFromLiteral(&KeyName
,
1834 L
"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
1835 InitializeObjectAttributes(&ObjectAttributes
,
1837 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
1840 Status
= ZwCreateKey(&ScsiKey
,
1845 REG_OPTION_VOLATILE
,
1847 if (!NT_SUCCESS(Status
))
1849 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
1853 /* Create new 'Scsi Port X' subkey */
1854 DPRINT("Scsi Port %lu\n",
1855 DeviceExtension
->PortNumber
);
1857 swprintf(NameBuffer
,
1859 DeviceExtension
->PortNumber
);
1860 RtlInitUnicodeString(&KeyName
,
1862 InitializeObjectAttributes(&ObjectAttributes
,
1867 Status
= ZwCreateKey(&ScsiPortKey
,
1872 REG_OPTION_VOLATILE
,
1875 if (!NT_SUCCESS(Status
))
1877 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
1882 * Create port-specific values
1885 /* Set 'DMA Enabled' (REG_DWORD) value */
1886 UlongData
= (ULONG
)!DeviceExtension
->PortCapabilities
->AdapterUsesPio
;
1887 DPRINT(" DMA Enabled = %s\n", (UlongData
) ? "TRUE" : "FALSE");
1888 RtlInitUnicodeString(&ValueName
,
1890 Status
= ZwSetValueKey(ScsiPortKey
,
1896 if (!NT_SUCCESS(Status
))
1898 DPRINT("ZwSetValueKey('DMA Enabled') failed (Status %lx)\n", Status
);
1899 ZwClose(ScsiPortKey
);
1903 /* Set 'Driver' (REG_SZ) value */
1904 DriverName
= wcsrchr(RegistryPath
->Buffer
, L
'\\') + 1;
1905 RtlInitUnicodeString(&ValueName
,
1907 Status
= ZwSetValueKey(ScsiPortKey
,
1912 (wcslen(DriverName
) + 1) * sizeof(WCHAR
));
1913 if (!NT_SUCCESS(Status
))
1915 DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status
);
1916 ZwClose(ScsiPortKey
);
1920 /* Set 'Interrupt' (REG_DWORD) value (NT4 only) */
1921 UlongData
= (ULONG
)DeviceExtension
->PortConfig
.BusInterruptLevel
;
1922 DPRINT(" Interrupt = %lu\n", UlongData
);
1923 RtlInitUnicodeString(&ValueName
,
1925 Status
= ZwSetValueKey(ScsiPortKey
,
1931 if (!NT_SUCCESS(Status
))
1933 DPRINT("ZwSetValueKey('Interrupt') failed (Status %lx)\n", Status
);
1934 ZwClose(ScsiPortKey
);
1938 /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
1939 UlongData
= ScsiPortConvertPhysicalAddressToUlong(DeviceExtension
->PortConfig
.AccessRanges
[0].RangeStart
);
1940 DPRINT(" IOAddress = %lx\n", UlongData
);
1941 RtlInitUnicodeString(&ValueName
,
1943 Status
= ZwSetValueKey(ScsiPortKey
,
1949 if (!NT_SUCCESS(Status
))
1951 DPRINT("ZwSetValueKey('IOAddress') failed (Status %lx)\n", Status
);
1952 ZwClose(ScsiPortKey
);
1956 /* Enumerate buses */
1957 for (BusNumber
= 0; BusNumber
< DeviceExtension
->PortConfig
.NumberOfBuses
; BusNumber
++)
1959 /* Create 'Scsi Bus X' key */
1960 DPRINT(" Scsi Bus %lu\n", BusNumber
);
1961 swprintf(NameBuffer
,
1964 RtlInitUnicodeString(&KeyName
,
1966 InitializeObjectAttributes(&ObjectAttributes
,
1971 Status
= ZwCreateKey(&ScsiBusKey
,
1976 REG_OPTION_VOLATILE
,
1978 if (!NT_SUCCESS(Status
))
1980 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
1981 ZwClose(ScsiPortKey
);
1985 /* Create 'Initiator Id X' key */
1986 DPRINT(" Initiator Id %u\n",
1987 DeviceExtension
->PortConfig
.InitiatorBusId
[BusNumber
]);
1988 swprintf(NameBuffer
,
1990 DeviceExtension
->PortConfig
.InitiatorBusId
[BusNumber
]);
1991 RtlInitUnicodeString(&KeyName
,
1993 InitializeObjectAttributes(&ObjectAttributes
,
1998 Status
= ZwCreateKey(&ScsiInitiatorKey
,
2003 REG_OPTION_VOLATILE
,
2005 if (!NT_SUCCESS(Status
))
2007 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
2008 ZwClose(ScsiBusKey
);
2009 ZwClose(ScsiPortKey
);
2013 /* FIXME: Are there any initiator values (??) */
2015 ZwClose(ScsiInitiatorKey
);
2018 /* Enumerate targets */
2019 CurrentTarget
= (ULONG
)-1;
2020 ScsiTargetKey
= NULL
;
2021 for (Target
= 0; Target
< DeviceExtension
->PortConfig
.MaximumNumberOfTargets
; Target
++)
2023 for (Lun
= 0; Lun
< SCSI_MAXIMUM_LOGICAL_UNITS
; Lun
++)
2025 LunExtension
= SpiGetLunExtension(DeviceExtension
,
2029 if (LunExtension
!= NULL
)
2031 if (Target
!= CurrentTarget
)
2033 /* Close old target key */
2034 if (ScsiTargetKey
!= NULL
)
2036 ZwClose(ScsiTargetKey
);
2037 ScsiTargetKey
= NULL
;
2040 /* Create 'Target Id X' key */
2041 DPRINT(" Target Id %lu\n", Target
);
2042 swprintf(NameBuffer
,
2045 RtlInitUnicodeString(&KeyName
,
2047 InitializeObjectAttributes(&ObjectAttributes
,
2052 Status
= ZwCreateKey(&ScsiTargetKey
,
2057 REG_OPTION_VOLATILE
,
2059 if (!NT_SUCCESS(Status
))
2061 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
2062 ZwClose(ScsiBusKey
);
2063 ZwClose(ScsiPortKey
);
2067 CurrentTarget
= Target
;
2070 /* Create 'Logical Unit Id X' key */
2071 DPRINT(" Logical Unit Id %lu\n", Lun
);
2072 swprintf(NameBuffer
,
2073 L
"Logical Unit Id %lu",
2075 RtlInitUnicodeString(&KeyName
,
2077 InitializeObjectAttributes(&ObjectAttributes
,
2082 Status
= ZwCreateKey(&ScsiLunKey
,
2087 REG_OPTION_VOLATILE
,
2089 if (!NT_SUCCESS(Status
))
2091 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status
);
2092 ZwClose(ScsiTargetKey
);
2093 ZwClose(ScsiBusKey
);
2094 ZwClose(ScsiPortKey
);
2098 /* Set 'Identifier' (REG_SZ) value */
2099 swprintf(NameBuffer
,
2101 LunExtension
->InquiryData
.VendorId
,
2102 LunExtension
->InquiryData
.ProductId
,
2103 LunExtension
->InquiryData
.ProductRevisionLevel
);
2104 DPRINT(" Identifier = '%S'\n", NameBuffer
);
2105 RtlInitUnicodeString(&ValueName
,
2107 Status
= ZwSetValueKey(ScsiLunKey
,
2112 (wcslen(NameBuffer
) + 1) * sizeof(WCHAR
));
2113 if (!NT_SUCCESS(Status
))
2115 DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", Status
);
2116 ZwClose(ScsiLunKey
);
2117 ZwClose(ScsiTargetKey
);
2118 ZwClose(ScsiBusKey
);
2119 ZwClose(ScsiPortKey
);
2123 /* Set 'Type' (REG_SZ) value */
2124 switch (LunExtension
->InquiryData
.DeviceType
)
2127 TypeName
= L
"DiskPeripheral";
2130 TypeName
= L
"TapePeripheral";
2133 TypeName
= L
"PrinterPeripheral";
2136 TypeName
= L
"WormPeripheral";
2139 TypeName
= L
"CdRomPeripheral";
2142 TypeName
= L
"ScannerPeripheral";
2145 TypeName
= L
"OpticalDiskPeripheral";
2148 TypeName
= L
"MediumChangerPeripheral";
2151 TypeName
= L
"CommunicationPeripheral";
2154 TypeName
= L
"OtherPeripheral";
2157 DPRINT(" Type = '%S'\n", TypeName
);
2158 RtlInitUnicodeString(&ValueName
,
2160 Status
= ZwSetValueKey(ScsiLunKey
,
2165 (wcslen(TypeName
) + 1) * sizeof(WCHAR
));
2166 if (!NT_SUCCESS(Status
))
2168 DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status
);
2169 ZwClose(ScsiLunKey
);
2170 ZwClose(ScsiTargetKey
);
2171 ZwClose(ScsiBusKey
);
2172 ZwClose(ScsiPortKey
);
2176 ZwClose(ScsiLunKey
);
2180 /* Close old target key */
2181 if (ScsiTargetKey
!= NULL
)
2183 ZwClose(ScsiTargetKey
);
2184 ScsiTargetKey
= NULL
;
2188 ZwClose(ScsiBusKey
);
2191 ZwClose(ScsiPortKey
);
2193 DPRINT("ScsiPortBuildDeviceMap() done\n");