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