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 * SCSI_PORT_TIMER_STATES
48 * An enumeration containing the states in the timer DFA
50 typedef enum _SCSI_PORT_TIMER_STATES
54 IDETimerResetWaitForBusyNegate,
55 IDETimerResetWaitForDrdyAssert
56 } SCSI_PORT_TIMER_STATES;
59 typedef struct _SCSI_PORT_DEVICE_BASE
65 SCSI_PHYSICAL_ADDRESS IoAddress;
66 ULONG SystemIoBusNumber;
67 } SCSI_PORT_DEVICE_BASE, *PSCSI_PORT_DEVICE_BASE;
71 * SCSI_PORT_DEVICE_EXTENSION
74 * First part of the port objects device extension. The second
75 * part is the miniport-specific device extension.
78 typedef struct _SCSI_PORT_DEVICE_EXTENSION
81 ULONG MiniPortExtensionSize;
82 PORT_CONFIGURATION_INFORMATION PortConfig;
87 PKINTERRUPT Interrupt;
91 SCSI_PORT_TIMER_STATES TimerState;
96 LIST_ENTRY DeviceBaseListHead;
98 ULONG PortBusInfoSize;
99 PSCSI_ADAPTER_BUS_INFO PortBusInfo;
101 PIO_SCSI_CAPABILITIES PortCapabilities;
103 PDEVICE_OBJECT DeviceObject;
104 PCONTROLLER_OBJECT ControllerObject;
106 PHW_STARTIO HwStartIo;
107 PHW_INTERRUPT HwInterrupt;
109 PSCSI_REQUEST_BLOCK OriginalSrb;
110 SCSI_REQUEST_BLOCK InternalSrb;
111 SENSE_DATA InternalSenseData;
113 UCHAR MiniPortDeviceExtension[1]; /* must be the last entry */
114 } SCSI_PORT_DEVICE_EXTENSION, *PSCSI_PORT_DEVICE_EXTENSION;
117 #define IRP_FLAG_COMPLETE 0x00000001
118 #define IRP_FLAG_NEXT 0x00000002
121 /* GLOBALS *******************************************************************/
123 static NTSTATUS STDCALL
124 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
127 static NTSTATUS STDCALL
128 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
131 static NTSTATUS STDCALL
132 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
136 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
139 static IO_ALLOCATION_ACTION STDCALL
140 ScsiPortAllocateController(IN PDEVICE_OBJECT DeviceObject,
142 IN PVOID MapRegisterBase,
145 static BOOLEAN STDCALL
146 ScsiPortStartPacket(IN OUT PVOID Context);
149 ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject,
150 IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension,
152 IN OUT PSCSI_PORT_DEVICE_EXTENSION *RealDeviceExtension);
155 ScsiPortInquire(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
157 static BOOLEAN STDCALL
158 ScsiPortIsr(IN PKINTERRUPT Interrupt,
159 IN PVOID ServiceContext);
162 ScsiPortDpcForIsr(IN PKDPC Dpc,
163 IN PDEVICE_OBJECT DpcDeviceObject,
165 IN PVOID DpcContext);
168 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
171 static PSCSI_REQUEST_BLOCK
172 ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
173 PSCSI_REQUEST_BLOCK OriginalSrb);
176 ScsiPortBuildDeviceMap(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
177 PUNICODE_STRING RegistryPath);
180 /* FUNCTIONS *****************************************************************/
182 /**********************************************************************
187 * This function initializes the driver.
194 * System allocated Driver Object for this driver.
197 * Name of registry driver service key.
204 DriverEntry(IN PDRIVER_OBJECT DriverObject,
205 IN PUNICODE_STRING RegistryPath)
207 DPRINT("ScsiPort Driver %s\n", VERSION);
208 return(STATUS_SUCCESS);
212 /**********************************************************************
217 * Prints debugging messages.
224 * Debug level of the given message.
227 * Pointer to printf()-compatible format string.
230 Additional output data (see printf()).
237 ScsiDebugPrint(IN ULONG DebugPrintLevel,
238 IN PCHAR DebugMessage,
245 if (DebugPrintLevel > InternalDebugLevel)
249 va_start(ap, DebugMessage);
250 vsprintf(Buffer, DebugMessage, ap);
258 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension,
264 DPRINT("ScsiPortCompleteRequest()\n");
270 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address)
272 DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
273 return(Address.u.LowPart);
278 ScsiPortFlushDma(IN PVOID HwDeviceExtension)
280 DPRINT("ScsiPortFlushDma()\n");
286 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension,
287 IN PVOID MappedAddress)
289 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
290 PSCSI_PORT_DEVICE_BASE DeviceBase;
293 DPRINT("ScsiPortFreeDeviceBase() called\n");
295 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
296 SCSI_PORT_DEVICE_EXTENSION,
297 MiniPortDeviceExtension);
298 if (IsListEmpty(&DeviceExtension->DeviceBaseListHead))
301 Entry = DeviceExtension->DeviceBaseListHead.Flink;
302 while (Entry != &DeviceExtension->DeviceBaseListHead)
304 DeviceBase = CONTAINING_RECORD(Entry,
305 SCSI_PORT_DEVICE_BASE,
307 if (DeviceBase->MappedAddress == MappedAddress)
309 MmUnmapIoSpace(DeviceBase->MappedAddress,
310 DeviceBase->NumberOfBytes);
311 RemoveEntryList(Entry);
312 ExFreePool(DeviceBase);
317 Entry = Entry->Flink;
323 ScsiPortGetBusData(IN PVOID DeviceExtension,
324 IN ULONG BusDataType,
325 IN ULONG SystemIoBusNumber,
330 return(HalGetBusData(BusDataType,
339 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension,
340 IN INTERFACE_TYPE BusType,
341 IN ULONG SystemIoBusNumber,
342 IN SCSI_PHYSICAL_ADDRESS IoAddress,
343 IN ULONG NumberOfBytes,
344 IN BOOLEAN InIoSpace)
346 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
347 PHYSICAL_ADDRESS TranslatedAddress;
348 PSCSI_PORT_DEVICE_BASE DeviceBase;
352 DPRINT("ScsiPortGetDeviceBase() called\n");
354 AddressSpace = (ULONG)InIoSpace;
355 if (HalTranslateBusAddress(BusType,
359 &TranslatedAddress) == FALSE)
363 if (AddressSpace != 0)
364 return((PVOID)TranslatedAddress.u.LowPart);
366 MappedAddress = MmMapIoSpace(TranslatedAddress,
370 DeviceBase = ExAllocatePool(NonPagedPool,
371 sizeof(SCSI_PORT_DEVICE_BASE));
372 if (DeviceBase == NULL)
373 return(MappedAddress);
375 DeviceBase->MappedAddress = MappedAddress;
376 DeviceBase->NumberOfBytes = NumberOfBytes;
377 DeviceBase->IoAddress = IoAddress;
378 DeviceBase->SystemIoBusNumber = SystemIoBusNumber;
380 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
381 SCSI_PORT_DEVICE_EXTENSION,
382 MiniPortDeviceExtension);
384 InsertHeadList(&DeviceExtension->DeviceBaseListHead,
387 return(MappedAddress);
392 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension,
397 DPRINT("ScsiPortGetLogicalUnit()\n");
402 SCSI_PHYSICAL_ADDRESS STDCALL
403 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension,
404 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
405 IN PVOID VirtualAddress,
408 DPRINT("ScsiPortGetPhysicalAddress()\n");
413 PSCSI_REQUEST_BLOCK STDCALL
414 ScsiPortGetSrb(IN PVOID DeviceExtension,
420 DPRINT("ScsiPortGetSrb()\n");
426 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension,
427 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
428 IN ULONG NumberOfBytes)
430 DPRINT("ScsiPortGetUncachedExtension()\n");
436 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension,
437 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress)
439 DPRINT("ScsiPortGetVirtualAddress()\n");
444 /**********************************************************************
449 * Initializes SCSI port driver specific data.
456 * Pointer to the miniport driver's driver object.
459 * Pointer to the miniport driver's registry path.
461 * HwInitializationData
462 * Pointer to port driver specific configuration data.
465 Miniport driver specific context.
472 ScsiPortInitialize(IN PVOID Argument1,
474 IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
477 PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Argument1;
478 PUNICODE_STRING RegistryPath = (PUNICODE_STRING)Argument2;
479 PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension;
480 PSCSI_PORT_DEVICE_EXTENSION RealDeviceExtension;
481 PCONFIGURATION_INFORMATION SystemConfig;
482 PPORT_CONFIGURATION_INFORMATION PortConfig;
488 PACCESS_RANGE AccessRanges;
491 DPRINT("ScsiPortInitialize() called!\n");
493 if ((HwInitializationData->HwInitialize == NULL) ||
494 (HwInitializationData->HwStartIo == NULL) ||
495 (HwInitializationData->HwInterrupt == NULL) ||
496 (HwInitializationData->HwFindAdapter == NULL) ||
497 (HwInitializationData->HwResetBus == NULL))
498 return(STATUS_INVALID_PARAMETER);
500 DriverObject->DriverStartIo = ScsiPortStartIo;
501 DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiPortCreateClose;
502 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiPortCreateClose;
503 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiPortDeviceControl;
504 DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiPortDispatchScsi;
507 SystemConfig = IoGetConfigurationInformation();
509 ExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) +
510 HwInitializationData->DeviceExtensionSize;
511 PseudoDeviceExtension = ExAllocatePool(PagedPool,
513 RtlZeroMemory(PseudoDeviceExtension,
515 PseudoDeviceExtension->Length = ExtensionSize;
516 PseudoDeviceExtension->MiniPortExtensionSize = HwInitializationData->DeviceExtensionSize;
517 PseudoDeviceExtension->HwStartIo = HwInitializationData->HwStartIo;
518 PseudoDeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
520 PortConfig = &PseudoDeviceExtension->PortConfig;
522 PortConfig->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
523 PortConfig->AdapterInterfaceType = HwInitializationData->AdapterInterfaceType;
524 PortConfig->InterruptMode =
525 (PortConfig->AdapterInterfaceType == PCIBus) ? LevelSensitive : Latched;
526 PortConfig->AtdiskPrimaryClaimed = SystemConfig->AtDiskPrimaryAddressClaimed;
527 PortConfig->AtdiskSecondaryClaimed = SystemConfig->AtDiskSecondaryAddressClaimed;
528 PortConfig->NumberOfAccessRanges = HwInitializationData->NumberOfAccessRanges;
530 PortConfig->AccessRanges =
531 ExAllocatePool(PagedPool,
532 sizeof(ACCESS_RANGE) * PortConfig->NumberOfAccessRanges);
534 for (i = 0; i < SCSI_MAXIMUM_BUSES; i++)
535 PortConfig->InitiatorBusId[i] = 255;
537 PortConfig->SystemIoBusNumber = 0;
538 PortConfig->SlotNumber = 0;
540 MaxBus = (PortConfig->AdapterInterfaceType == PCIBus) ? 8 : 1;
542 DPRINT("MaxBus: %lu\n", MaxBus);
546 DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber);
548 InitializeListHead(&PseudoDeviceExtension->DeviceBaseListHead);
550 // RtlZeroMemory(AccessRanges,
551 // sizeof(ACCESS_RANGE) * PortConfig->NumberOfAccessRanges);
553 RtlZeroMemory(PseudoDeviceExtension->MiniPortDeviceExtension,
554 PseudoDeviceExtension->MiniPortExtensionSize);
556 /* Note: HwFindAdapter is called once for each bus */
557 Result = (HwInitializationData->HwFindAdapter)(&PseudoDeviceExtension->MiniPortDeviceExtension,
559 NULL, /* BusInformation */
560 NULL, /* ArgumentString */
561 &PseudoDeviceExtension->PortConfig,
563 DPRINT("HwFindAdapter() result: %lu\n", Result);
565 if (Result == SP_RETURN_FOUND)
567 DPRINT("ScsiPortInitialize(): Found HBA!\n");
569 Status = ScsiPortCreatePortDevice(DriverObject,
570 PseudoDeviceExtension,
571 SystemConfig->ScsiPortCount,
572 &RealDeviceExtension);
574 if (!NT_SUCCESS(Status))
576 DbgPrint("ScsiPortCreatePortDevice() failed! (Status 0x%lX)\n", Status);
578 ExFreePool(PortConfig->AccessRanges);
579 ExFreePool(PseudoDeviceExtension);
584 /* Build the registry device map */
585 ScsiPortBuildDeviceMap(RealDeviceExtension,
586 (PUNICODE_STRING)Argument2);
588 /* Update the configuration info */
589 SystemConfig->AtDiskPrimaryAddressClaimed = PortConfig->AtdiskPrimaryClaimed;
590 SystemConfig->AtDiskSecondaryAddressClaimed = PortConfig->AtdiskSecondaryClaimed;
591 SystemConfig->ScsiPortCount++;
596 PortConfig->SystemIoBusNumber++;
597 PortConfig->SlotNumber = 0;
600 DPRINT("Bus: %lu MaxBus: %lu\n", PortConfig->SystemIoBusNumber, MaxBus);
601 if (PortConfig->SystemIoBusNumber >= MaxBus)
603 DPRINT("Scanned all buses!\n");
608 ExFreePool(PortConfig->AccessRanges);
609 ExFreePool(PseudoDeviceExtension);
611 DPRINT("ScsiPortInitialize() done!\n");
613 return(STATUS_SUCCESS);
618 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension,
619 IN PSCSI_REQUEST_BLOCK Srb,
620 IN ULONG LogicalAddress,
623 DPRINT("ScsiPortIoMapTransfer()\n");
629 ScsiPortLogError(IN PVOID HwDeviceExtension,
630 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
637 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
639 DPRINT("ScsiPortLogError() called\n");
641 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
642 SCSI_PORT_DEVICE_EXTENSION,
643 MiniPortDeviceExtension);
646 DPRINT("ScsiPortLogError() done\n");
651 ScsiPortMoveMemory(OUT PVOID Destination,
655 RtlMoveMemory(Destination,
662 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType,
663 IN PVOID HwDeviceExtension,
666 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
668 DPRINT("ScsiPortNotification() called\n");
670 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
671 SCSI_PORT_DEVICE_EXTENSION,
672 MiniPortDeviceExtension);
674 DPRINT("DeviceExtension %p\n", DeviceExtension);
676 DPRINT("Initializing = %s\n", (DeviceExtension->Initializing)?"TRUE":"FALSE");
678 if (DeviceExtension->Initializing == TRUE)
681 switch (NotificationType)
683 case RequestComplete:
684 DPRINT("Notify: RequestComplete\n");
685 DeviceExtension->IrpFlags |= IRP_FLAG_COMPLETE;
689 DPRINT("Notify: NextRequest\n");
690 DeviceExtension->IrpFlags |= IRP_FLAG_NEXT;
700 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension,
701 IN ULONG BusDataType,
702 IN ULONG SystemIoBusNumber,
708 DPRINT("ScsiPortSetBusDataByOffset()\n");
709 return(HalSetBusDataByOffset(BusDataType,
719 ScsiPortValidateRange(IN PVOID HwDeviceExtension,
720 IN INTERFACE_TYPE BusType,
721 IN ULONG SystemIoBusNumber,
722 IN SCSI_PHYSICAL_ADDRESS IoAddress,
723 IN ULONG NumberOfBytes,
724 IN BOOLEAN InIoSpace)
726 DPRINT("ScsiPortValidateRange()\n");
731 /* INTERNAL FUNCTIONS ********************************************************/
733 /**********************************************************************
735 * ScsiPortCreateClose
738 * Answer requests for Create/Close calls: a null operation.
745 * Pointer to a device object.
751 Additional output data (see printf()).
757 static NTSTATUS STDCALL
758 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
761 DPRINT("ScsiPortCreateClose()\n");
763 Irp->IoStatus.Status = STATUS_SUCCESS;
764 Irp->IoStatus.Information = FILE_OPENED;
766 IoCompleteRequest(Irp, IO_NO_INCREMENT);
768 return(STATUS_SUCCESS);
772 /**********************************************************************
774 * ScsiPortDispatchScsi
777 * Answer requests for SCSI calls
783 * Standard dispatch arguments
789 static NTSTATUS STDCALL
790 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
793 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
794 PIO_STACK_LOCATION Stack;
795 PSCSI_REQUEST_BLOCK Srb;
796 NTSTATUS Status = STATUS_SUCCESS;
799 DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n",
802 DeviceExtension = DeviceObject->DeviceExtension;
803 Stack = IoGetCurrentIrpStackLocation(Irp);
805 Srb = Stack->Parameters.Scsi.Srb;
808 Status = STATUS_UNSUCCESSFUL;
810 Irp->IoStatus.Status = Status;
811 Irp->IoStatus.Information = 0;
813 IoCompleteRequest(Irp, IO_NO_INCREMENT);
818 DPRINT("Srb: %p\n", Srb);
819 DPRINT("Srb->Function: %lu\n", Srb->Function);
820 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
822 switch (Srb->Function)
824 case SRB_FUNCTION_EXECUTE_SCSI:
825 IoStartPacket(DeviceObject, Irp, NULL, NULL);
826 return(STATUS_PENDING);
828 case SRB_FUNCTION_SHUTDOWN:
829 case SRB_FUNCTION_FLUSH:
830 if (DeviceExtension->PortConfig.CachesData == TRUE)
832 IoStartPacket(DeviceObject, Irp, NULL, NULL);
833 return(STATUS_PENDING);
837 case SRB_FUNCTION_CLAIM_DEVICE:
839 PSCSI_ADAPTER_BUS_INFO AdapterInfo;
840 PSCSI_INQUIRY_DATA UnitInfo;
841 PINQUIRYDATA InquiryData;
843 DPRINT(" SRB_FUNCTION_CLAIM_DEVICE\n");
844 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
846 Srb->DataBuffer = NULL;
848 if (DeviceExtension->PortBusInfo != NULL)
850 AdapterInfo = (PSCSI_ADAPTER_BUS_INFO)DeviceExtension->PortBusInfo;
852 if (AdapterInfo->BusData[Srb->PathId].NumberOfLogicalUnits == 0)
855 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo +
856 AdapterInfo->BusData[Srb->PathId].InquiryDataOffset);
858 while (AdapterInfo->BusData[Srb->PathId].InquiryDataOffset)
860 InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
862 if ((UnitInfo->TargetId == Srb->TargetId) &&
863 (UnitInfo->Lun == Srb->Lun) &&
864 (UnitInfo->DeviceClaimed == FALSE))
866 UnitInfo->DeviceClaimed = TRUE;
867 DPRINT("Claimed device!\n");
869 /* FIXME: Hack!!!!! */
870 Srb->DataBuffer = DeviceObject;
875 if (UnitInfo->NextInquiryDataOffset == 0)
878 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo + UnitInfo->NextInquiryDataOffset);
884 case SRB_FUNCTION_RELEASE_DEVICE:
886 PSCSI_ADAPTER_BUS_INFO AdapterInfo;
887 PSCSI_INQUIRY_DATA UnitInfo;
888 PINQUIRYDATA InquiryData;
890 DPRINT(" SRB_FUNCTION_RELEASE_DEVICE\n");
891 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
893 if (DeviceExtension->PortBusInfo != NULL)
895 AdapterInfo = (PSCSI_ADAPTER_BUS_INFO)DeviceExtension->PortBusInfo;
897 if (AdapterInfo->BusData[Srb->PathId].NumberOfLogicalUnits == 0)
900 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo +
901 AdapterInfo->BusData[Srb->PathId].InquiryDataOffset);
903 while (AdapterInfo->BusData[Srb->PathId].InquiryDataOffset)
905 InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
907 if ((UnitInfo->TargetId == Srb->TargetId) &&
908 (UnitInfo->Lun == Srb->Lun) &&
909 (UnitInfo->DeviceClaimed == TRUE))
911 UnitInfo->DeviceClaimed = FALSE;
912 DPRINT("Released device!\n");
916 if (UnitInfo->NextInquiryDataOffset == 0)
919 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo + UnitInfo->NextInquiryDataOffset);
926 DPRINT1("SRB function not implemented (Function %lu)\n", Srb->Function);
927 Status = STATUS_NOT_IMPLEMENTED;
931 Irp->IoStatus.Status = Status;
932 Irp->IoStatus.Information = DataSize;
934 IoCompleteRequest(Irp, IO_NO_INCREMENT);
940 /**********************************************************************
942 * ScsiPortDeviceControl
945 * Answer requests for device control calls
951 * Standard dispatch arguments
957 static NTSTATUS STDCALL
958 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
961 PIO_STACK_LOCATION Stack;
962 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
964 DPRINT("ScsiPortDeviceControl()\n");
966 Irp->IoStatus.Status = STATUS_SUCCESS;
967 Irp->IoStatus.Information = 0;
970 Stack = IoGetCurrentIrpStackLocation(Irp);
971 DeviceExtension = DeviceObject->DeviceExtension;
973 switch (Stack->Parameters.DeviceIoControl.IoControlCode)
976 case IOCTL_SCSI_GET_CAPABILITIES:
978 DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
980 *((PIO_SCSI_CAPABILITIES *)Irp->AssociatedIrp.SystemBuffer) =
981 DeviceExtension->PortCapabilities;
983 Irp->IoStatus.Information = sizeof(PIO_SCSI_CAPABILITIES);
987 case IOCTL_SCSI_GET_INQUIRY_DATA:
989 DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
991 /* Copy inquiry data to the port device extension */
992 memcpy(Irp->AssociatedIrp.SystemBuffer,
993 DeviceExtension->PortBusInfo,
994 DeviceExtension->PortBusInfoSize);
996 DPRINT("BufferSize: %lu\n", DeviceExtension->PortBusInfoSize);
997 Irp->IoStatus.Information = DeviceExtension->PortBusInfoSize;
1002 DPRINT1(" unknown ioctl code: 0x%lX\n",
1003 Stack->Parameters.DeviceIoControl.IoControlCode);
1007 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1009 return(STATUS_SUCCESS);
1014 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
1017 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1018 PIO_STACK_LOCATION IrpStack;
1021 DPRINT("ScsiPortStartIo() called!\n");
1023 DeviceExtension = DeviceObject->DeviceExtension;
1024 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1026 // FIXME: implement the supported functions
1028 switch (IrpStack->MajorFunction)
1033 PSCSI_REQUEST_BLOCK Srb;
1036 DPRINT("IRP_MJ_SCSI\n");
1038 Srb = IrpStack->Parameters.Scsi.Srb;
1040 DPRINT("DeviceExtension %p\n", DeviceExtension);
1042 Irp->IoStatus.Status = STATUS_SUCCESS;
1043 Irp->IoStatus.Information = Srb->DataTransferLength;
1045 DeviceExtension->CurrentIrp = Irp;
1047 if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
1048 ScsiPortStartPacket,
1051 DPRINT("Synchronization failed!\n");
1053 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
1054 Irp->IoStatus.Information = 0;
1055 IoCompleteRequest(Irp,
1057 IoStartNextPacket(DeviceObject,
1060 KeAcquireSpinLock(&DeviceExtension->IrpLock, &oldIrql);
1061 if (DeviceExtension->IrpFlags & IRP_FLAG_COMPLETE)
1063 DeviceExtension->IrpFlags &= ~IRP_FLAG_COMPLETE;
1064 IoCompleteRequest(Irp,
1068 if (DeviceExtension->IrpFlags & IRP_FLAG_NEXT)
1070 DeviceExtension->IrpFlags &= ~IRP_FLAG_NEXT;
1071 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1072 IoStartNextPacket(DeviceObject,
1077 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1083 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
1084 Irp->IoStatus.Information = 0;
1085 IoCompleteRequest(Irp,
1087 IoStartNextPacket(DeviceObject,
1091 DPRINT("ScsiPortStartIo() done\n");
1095 static BOOLEAN STDCALL
1096 ScsiPortStartPacket(IN OUT PVOID Context)
1098 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1099 PIO_STACK_LOCATION IrpStack;
1100 PSCSI_REQUEST_BLOCK Srb;
1102 DPRINT("ScsiPortStartPacket() called\n");
1104 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)Context;
1106 IrpStack = IoGetCurrentIrpStackLocation(DeviceExtension->CurrentIrp);
1107 Srb = IrpStack->Parameters.Scsi.Srb;
1109 return(DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
1114 /**********************************************************************
1116 * ScsiPortCreatePortDevice
1119 * Creates and initializes a SCSI port device object.
1128 * PseudoDeviceExtension
1139 ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject,
1140 IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension,
1141 IN ULONG PortNumber,
1142 IN OUT PSCSI_PORT_DEVICE_EXTENSION *RealDeviceExtension)
1144 PSCSI_PORT_DEVICE_EXTENSION PortDeviceExtension;
1145 PIO_SCSI_CAPABILITIES PortCapabilities;
1146 PDEVICE_OBJECT PortDeviceObject;
1147 WCHAR NameBuffer[80];
1148 UNICODE_STRING DeviceName;
1149 WCHAR DosNameBuffer[80];
1150 UNICODE_STRING DosDeviceName;
1152 ULONG AccessRangeSize;
1157 DPRINT("ScsiPortCreatePortDevice() called\n");
1159 *RealDeviceExtension = NULL;
1161 MappedIrq = HalGetInterruptVector(PseudoDeviceExtension->PortConfig.AdapterInterfaceType,
1162 PseudoDeviceExtension->PortConfig.SystemIoBusNumber,
1163 PseudoDeviceExtension->PortConfig.BusInterruptLevel,
1164 PseudoDeviceExtension->PortConfig.BusInterruptVector,
1168 /* Create a unicode device name */
1169 swprintf(NameBuffer,
1170 L"\\Device\\ScsiPort%lu",
1172 RtlInitUnicodeString(&DeviceName,
1175 DPRINT("Creating device: %wZ\n", &DeviceName);
1177 /* Create the port device */
1178 Status = IoCreateDevice(DriverObject,
1179 PseudoDeviceExtension->Length,
1181 FILE_DEVICE_CONTROLLER,
1185 if (!NT_SUCCESS(Status))
1187 DbgPrint("IoCreateDevice call failed! (Status 0x%lX)\n", Status);
1191 DPRINT("Created device: %wZ\n", &DeviceName);
1193 /* Set the buffering strategy here... */
1194 PortDeviceObject->Flags |= DO_DIRECT_IO;
1195 PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
1197 PortDeviceExtension = PortDeviceObject->DeviceExtension;
1199 /* Copy pseudo device extension into the real device extension */
1200 memcpy(PortDeviceExtension,
1201 PseudoDeviceExtension,
1202 PseudoDeviceExtension->Length);
1204 /* Copy access ranges */
1206 sizeof(ACCESS_RANGE) * PseudoDeviceExtension->PortConfig.NumberOfAccessRanges;
1207 PortDeviceExtension->PortConfig.AccessRanges = ExAllocatePool(NonPagedPool,
1209 memcpy(PortDeviceExtension->PortConfig.AccessRanges,
1210 PseudoDeviceExtension->PortConfig.AccessRanges,
1213 /* Copy device base list */
1214 if (IsListEmpty(&PseudoDeviceExtension->DeviceBaseListHead))
1216 InitializeListHead(&PortDeviceExtension->DeviceBaseListHead);
1220 PseudoDeviceExtension->DeviceBaseListHead.Flink =
1221 PortDeviceExtension->DeviceBaseListHead.Flink;
1222 PseudoDeviceExtension->DeviceBaseListHead.Blink =
1223 PortDeviceExtension->DeviceBaseListHead.Blink;
1224 PortDeviceExtension->DeviceBaseListHead.Blink->Flink =
1225 &PortDeviceExtension->DeviceBaseListHead;
1226 PortDeviceExtension->DeviceBaseListHead.Flink->Blink =
1227 &PortDeviceExtension->DeviceBaseListHead;
1230 PortDeviceExtension->DeviceObject = PortDeviceObject;
1231 PortDeviceExtension->PortNumber = PortNumber;
1233 /* Initialize the spin lock in the controller extension */
1234 KeInitializeSpinLock(&PortDeviceExtension->IrpLock);
1235 KeInitializeSpinLock(&PortDeviceExtension->SpinLock);
1237 /* Register an interrupt handler for this device */
1238 Status = IoConnectInterrupt(&PortDeviceExtension->Interrupt,
1240 PortDeviceExtension,
1241 &PortDeviceExtension->SpinLock,
1245 PortDeviceExtension->PortConfig.InterruptMode,
1249 if (!NT_SUCCESS(Status))
1251 DbgPrint("Could not Connect Interrupt %d\n",
1252 PortDeviceExtension->PortConfig.BusInterruptVector);
1256 /* Initialize the DPC object */
1257 IoInitializeDpcRequest(PortDeviceExtension->DeviceObject,
1260 /* Initialize the device timer */
1261 PortDeviceExtension->TimerState = IDETimerIdle;
1262 PortDeviceExtension->TimerCount = 0;
1263 IoInitializeTimer(PortDeviceExtension->DeviceObject,
1265 PortDeviceExtension);
1267 /* Initialize port capabilities */
1268 PortCapabilities = ExAllocatePool(NonPagedPool,
1269 sizeof(IO_SCSI_CAPABILITIES));
1270 PortDeviceExtension->PortCapabilities = PortCapabilities;
1271 PortCapabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
1272 PortCapabilities->MaximumTransferLength =
1273 PortDeviceExtension->PortConfig.MaximumTransferLength;
1274 PortCapabilities->MaximumPhysicalPages =
1275 PortCapabilities->MaximumTransferLength / PAGE_SIZE;
1276 PortCapabilities->SupportedAsynchronousEvents = 0; /* FIXME */
1277 PortCapabilities->AlignmentMask =
1278 PortDeviceExtension->PortConfig.AlignmentMask;
1279 PortCapabilities->TaggedQueuing =
1280 PortDeviceExtension->PortConfig.TaggedQueuing;
1281 PortCapabilities->AdapterScansDown =
1282 PortDeviceExtension->PortConfig.AdapterScansDown;
1283 PortCapabilities->AdapterUsesPio = TRUE; /* FIXME */
1285 /* Initialize inquiry data */
1286 PortDeviceExtension->PortBusInfoSize = 0;
1287 PortDeviceExtension->PortBusInfo = NULL;
1289 DPRINT("DeviceExtension %p\n", PortDeviceExtension);
1290 ScsiPortInquire(PortDeviceExtension);
1293 /* FIXME: Copy more configuration data? */
1296 /* Create the dos device link */
1297 swprintf(DosNameBuffer,
1300 RtlInitUnicodeString(&DosDeviceName,
1303 IoCreateSymbolicLink(&DosDeviceName,
1306 *RealDeviceExtension = PortDeviceExtension;
1308 DPRINT("ScsiPortCreatePortDevice() done\n");
1310 return(STATUS_SUCCESS);
1315 ScsiPortInquire(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
1317 PSCSI_ADAPTER_BUS_INFO AdapterInfo;
1318 PSCSI_INQUIRY_DATA UnitInfo, PrevUnit;
1319 SCSI_REQUEST_BLOCK Srb;
1326 DPRINT("ScsiPortInquire() called\n");
1328 DeviceExtension->Initializing = TRUE;
1330 /* Copy inquiry data to the port device extension */
1331 AdapterInfo =(PSCSI_ADAPTER_BUS_INFO)ExAllocatePool(NonPagedPool, 4096);
1332 RtlZeroMemory(AdapterInfo, 4096);
1333 AdapterInfo->NumberOfBuses = DeviceExtension->PortConfig.NumberOfBuses;
1335 UnitInfo = (PSCSI_INQUIRY_DATA)
1336 ((PUCHAR)AdapterInfo + sizeof(SCSI_ADAPTER_BUS_INFO) +
1337 (sizeof(SCSI_BUS_DATA) * (AdapterInfo->NumberOfBuses - 1)));
1340 sizeof(SCSI_REQUEST_BLOCK));
1341 Srb.DataBuffer = ExAllocatePool(NonPagedPool, 256);
1342 Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
1343 Srb.DataTransferLength = 256;
1344 Srb.Cdb[0] = SCSIOP_INQUIRY;
1346 for (Bus = 0; Bus < AdapterInfo->NumberOfBuses; Bus++)
1350 AdapterInfo->BusData[Bus].InitiatorBusId =
1351 DeviceExtension->PortConfig.InitiatorBusId[Bus];
1352 AdapterInfo->BusData[Bus].InquiryDataOffset =
1353 (ULONG)((PUCHAR)UnitInfo - (PUCHAR)AdapterInfo);
1358 for (Target = 0; Target < DeviceExtension->PortConfig.MaximumNumberOfTargets; Target++)
1360 Srb.TargetId = Target;
1362 Srb.SrbStatus = SRB_STATUS_SUCCESS;
1364 Result = DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
1366 DPRINT("Result: %s Srb.SrbStatus %lx\n", (Result)?"True":"False", Srb.SrbStatus);
1368 if (Result == TRUE && Srb.SrbStatus == SRB_STATUS_SUCCESS)
1370 UnitInfo->PathId = Bus;
1371 UnitInfo->TargetId = Target;
1373 UnitInfo->InquiryDataLength = INQUIRYDATABUFFERSIZE;
1374 memcpy(&UnitInfo->InquiryData,
1376 INQUIRYDATABUFFERSIZE);
1377 if (PrevUnit != NULL)
1378 PrevUnit->NextInquiryDataOffset = (ULONG)((PUCHAR)UnitInfo-(PUCHAR)AdapterInfo);
1379 PrevUnit = UnitInfo;
1380 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)UnitInfo + sizeof(SCSI_INQUIRY_DATA)+INQUIRYDATABUFFERSIZE-1);
1384 DPRINT("UnitCount: %lu\n", UnitCount);
1385 AdapterInfo->BusData[Bus].NumberOfLogicalUnits = UnitCount;
1387 AdapterInfo->BusData[Bus].InquiryDataOffset = 0;
1389 DataSize = (ULONG)((PUCHAR)UnitInfo-(PUCHAR)AdapterInfo);
1391 ExFreePool(Srb.DataBuffer);
1393 DeviceExtension->Initializing = FALSE;
1395 /* copy inquiry data to the port driver's device extension */
1396 DeviceExtension->PortBusInfoSize = DataSize;
1397 DeviceExtension->PortBusInfo = ExAllocatePool(NonPagedPool,
1399 RtlCopyMemory(DeviceExtension->PortBusInfo,
1403 ExFreePool(AdapterInfo);
1405 DPRINT("ScsiPortInquire() done\n");
1409 static BOOLEAN STDCALL
1410 ScsiPortIsr(IN PKINTERRUPT Interrupt,
1411 IN PVOID ServiceContext)
1413 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1416 DPRINT("ScsiPortIsr() called!\n");
1418 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext;
1420 Result = DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension);
1421 if (Result == FALSE)
1426 if (DeviceExtension->IrpFlags)
1428 IoRequestDpc(DeviceExtension->DeviceObject,
1429 DeviceExtension->CurrentIrp,
1437 // ScsiPortDpcForIsr
1444 // IN PDEVICE_OBJECT DpcDeviceObject
1446 // IN PVOID DpcContext
1449 ScsiPortDpcForIsr(IN PKDPC Dpc,
1450 IN PDEVICE_OBJECT DpcDeviceObject,
1452 IN PVOID DpcContext)
1454 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1455 PIO_STACK_LOCATION IrpStack;
1456 PSCSI_REQUEST_BLOCK Srb;
1459 DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
1460 Dpc, DpcDeviceObject, DpcIrp, DpcContext);
1462 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DpcContext;
1464 KeAcquireSpinLock(&DeviceExtension->IrpLock, &oldIrql);
1465 if (DeviceExtension->IrpFlags)
1467 IrpStack = IoGetCurrentIrpStackLocation(DeviceExtension->CurrentIrp);
1468 Srb = IrpStack->Parameters.Scsi.Srb;
1470 if (DeviceExtension->OriginalSrb != NULL)
1472 DPRINT("Got sense data!\n");
1474 DPRINT("Valid: %x\n", DeviceExtension->InternalSenseData.Valid);
1475 DPRINT("ErrorCode: %x\n", DeviceExtension->InternalSenseData.ErrorCode);
1476 DPRINT("SenseKey: %x\n", DeviceExtension->InternalSenseData.SenseKey);
1477 DPRINT("SenseCode: %x\n", DeviceExtension->InternalSenseData.AdditionalSenseCode);
1479 /* Copy sense data */
1480 if (DeviceExtension->OriginalSrb->SenseInfoBufferLength != 0)
1482 RtlCopyMemory(DeviceExtension->OriginalSrb->SenseInfoBuffer,
1483 &DeviceExtension->InternalSenseData,
1484 sizeof(SENSE_DATA));
1485 DeviceExtension->OriginalSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
1488 /* Clear current sense data */
1489 RtlZeroMemory(&DeviceExtension->InternalSenseData, sizeof(SENSE_DATA));
1491 IrpStack->Parameters.Scsi.Srb = DeviceExtension->OriginalSrb;
1492 DeviceExtension->OriginalSrb = NULL;
1494 else if ((SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) &&
1495 (Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION))
1497 DPRINT("SCSIOP_REQUEST_SENSE required!\n");
1499 DeviceExtension->OriginalSrb = Srb;
1500 IrpStack->Parameters.Scsi.Srb = ScsiPortInitSenseRequestSrb(DeviceExtension,
1502 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1503 if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
1504 ScsiPortStartPacket,
1507 DPRINT("Synchronization failed!\n");
1509 DpcIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
1510 DpcIrp->IoStatus.Information = 0;
1511 IoCompleteRequest(DpcIrp,
1513 IoStartNextPacket(DpcDeviceObject,
1520 DeviceExtension->CurrentIrp = NULL;
1523 // DpcIrp->IoStatus.Information = 0;
1524 // DpcIrp->IoStatus.Status = STATUS_SUCCESS;
1526 if (DeviceExtension->IrpFlags & IRP_FLAG_COMPLETE)
1528 DeviceExtension->IrpFlags &= ~IRP_FLAG_COMPLETE;
1529 IoCompleteRequest(DpcIrp, IO_NO_INCREMENT);
1532 if (DeviceExtension->IrpFlags & IRP_FLAG_NEXT)
1534 DeviceExtension->IrpFlags &= ~IRP_FLAG_NEXT;
1535 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1536 IoStartNextPacket(DpcDeviceObject, FALSE);
1540 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1545 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1547 DPRINT("ScsiPortDpcForIsr() done\n");
1553 // This function handles timeouts and other time delayed processing
1558 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
1559 // IN PVOID Context the Controller extension for the
1560 // controller the device is on
1563 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
1566 DPRINT1("ScsiPortIoTimer()\n");
1570 static PSCSI_REQUEST_BLOCK
1571 ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1572 PSCSI_REQUEST_BLOCK OriginalSrb)
1574 PSCSI_REQUEST_BLOCK Srb;
1577 Srb = &DeviceExtension->InternalSrb;
1580 sizeof(SCSI_REQUEST_BLOCK));
1582 Srb->PathId = OriginalSrb->PathId;
1583 Srb->TargetId = OriginalSrb->TargetId;
1584 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1585 Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
1586 Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
1588 Srb->TimeOutValue = 4;
1591 Srb->DataBuffer = &DeviceExtension->InternalSenseData;
1592 Srb->DataTransferLength = sizeof(SENSE_DATA);
1594 Cdb = (PCDB)Srb->Cdb;
1595 Cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE;
1596 Cdb->CDB6INQUIRY.AllocationLength = sizeof(SENSE_DATA);
1603 ScsiPortFreeSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
1605 DeviceExtension->OriginalSrb = NULL;
1609 /**********************************************************************
1611 * ScsiPortBuildDeviceMap
1614 * Builds the registry device map of all device which are attached
1615 * to the given SCSI HBA port. The device map is located at:
1616 * \Registry\Machine\DeviceMap\Scsi
1626 * Name of registry driver service key.
1633 ScsiPortBuildDeviceMap(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1634 PUNICODE_STRING RegistryPath)
1636 OBJECT_ATTRIBUTES ObjectAttributes;
1637 UNICODE_STRING KeyName;
1638 UNICODE_STRING ValueName;
1639 WCHAR NameBuffer[64];
1644 HANDLE ScsiInitiatorKey;
1645 HANDLE ScsiTargetKey;
1648 UCHAR CurrentTarget;
1649 PSCSI_ADAPTER_BUS_INFO AdapterInfo;
1650 PSCSI_INQUIRY_DATA UnitInfo;
1651 PINQUIRYDATA InquiryData;
1657 DPRINT("ScsiPortBuildDeviceMap() called\n");
1659 if (DeviceExtension == NULL || RegistryPath == NULL)
1661 DPRINT1("Invalid parameter\n");
1662 return(STATUS_INVALID_PARAMETER);
1665 /* Open or create the 'Scsi' subkey */
1666 RtlInitUnicodeStringFromLiteral(&KeyName,
1667 L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
1668 InitializeObjectAttributes(&ObjectAttributes,
1670 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
1673 Status = ZwCreateKey(&ScsiKey,
1678 REG_OPTION_VOLATILE,
1680 if (!NT_SUCCESS(Status))
1682 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
1686 /* Create new 'Scsi Port X' subkey */
1687 DPRINT("Scsi Port %lu\n",
1688 DeviceExtension->PortNumber);
1690 swprintf(NameBuffer,
1692 DeviceExtension->PortNumber);
1693 RtlInitUnicodeString(&KeyName,
1695 InitializeObjectAttributes(&ObjectAttributes,
1700 Status = ZwCreateKey(&ScsiPortKey,
1705 REG_OPTION_VOLATILE,
1708 if (!NT_SUCCESS(Status))
1710 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
1715 * Create port-specific values
1718 /* Set 'DMA Enabled' (REG_DWORD) value */
1719 UlongData = (ULONG)!DeviceExtension->PortCapabilities->AdapterUsesPio;
1720 DPRINT(" DMA Enabled = %s\n", (UlongData) ? "TRUE" : "FALSE");
1721 RtlInitUnicodeString(&ValueName,
1723 Status = ZwSetValueKey(ScsiPortKey,
1729 if (!NT_SUCCESS(Status))
1731 DPRINT("ZwSetValueKey('DMA Enabled') failed (Status %lx)\n", Status);
1732 ZwClose(ScsiPortKey);
1736 /* Set 'Driver' (REG_SZ) value */
1737 DriverName = wcsrchr(RegistryPath->Buffer, L'\\') + 1;
1738 RtlInitUnicodeString(&ValueName,
1740 Status = ZwSetValueKey(ScsiPortKey,
1745 (wcslen(DriverName) + 1) * sizeof(WCHAR));
1746 if (!NT_SUCCESS(Status))
1748 DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status);
1749 ZwClose(ScsiPortKey);
1753 /* Set 'Interrupt' (REG_DWORD) value (NT4 only) */
1754 UlongData = (ULONG)DeviceExtension->PortConfig.BusInterruptLevel;
1755 DPRINT(" Interrupt = %lu\n", UlongData);
1756 RtlInitUnicodeString(&ValueName,
1758 Status = ZwSetValueKey(ScsiPortKey,
1764 if (!NT_SUCCESS(Status))
1766 DPRINT("ZwSetValueKey('Interrupt') failed (Status %lx)\n", Status);
1767 ZwClose(ScsiPortKey);
1771 /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
1772 UlongData = ScsiPortConvertPhysicalAddressToUlong(DeviceExtension->PortConfig.AccessRanges[0].RangeStart);
1773 DPRINT(" IOAddress = %lx\n", UlongData);
1774 RtlInitUnicodeString(&ValueName,
1776 Status = ZwSetValueKey(ScsiPortKey,
1782 if (!NT_SUCCESS(Status))
1784 DPRINT("ZwSetValueKey('IOAddress') failed (Status %lx)\n", Status);
1785 ZwClose(ScsiPortKey);
1789 /* Enumerate buses */
1790 for (BusNumber = 0; BusNumber < DeviceExtension->PortConfig.NumberOfBuses; BusNumber++)
1792 /* Create 'Scsi Bus X' key */
1793 DPRINT(" Scsi Bus %lu\n", BusNumber);
1794 swprintf(NameBuffer,
1797 RtlInitUnicodeString(&KeyName,
1799 InitializeObjectAttributes(&ObjectAttributes,
1804 Status = ZwCreateKey(&ScsiBusKey,
1809 REG_OPTION_VOLATILE,
1811 if (!NT_SUCCESS(Status))
1813 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
1814 ZwClose(ScsiPortKey);
1818 /* Create 'Initiator Id X' key */
1819 DPRINT(" Initiator Id %u\n",
1820 DeviceExtension->PortConfig.InitiatorBusId[BusNumber]);
1821 swprintf(NameBuffer,
1823 DeviceExtension->PortConfig.InitiatorBusId[BusNumber]);
1824 RtlInitUnicodeString(&KeyName,
1826 InitializeObjectAttributes(&ObjectAttributes,
1831 Status = ZwCreateKey(&ScsiInitiatorKey,
1836 REG_OPTION_VOLATILE,
1838 if (!NT_SUCCESS(Status))
1840 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
1841 ZwClose(ScsiBusKey);
1842 ZwClose(ScsiPortKey);
1846 /* FIXME: Are there any initiator values (??) */
1848 ZwClose(ScsiInitiatorKey);
1851 /* Enumerate targets */
1852 CurrentTarget = (UCHAR)-1;
1853 ScsiTargetKey = NULL;
1854 AdapterInfo = (PSCSI_ADAPTER_BUS_INFO)DeviceExtension->PortBusInfo;
1855 if (AdapterInfo->BusData[BusNumber].NumberOfLogicalUnits != 0)
1857 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo +
1858 AdapterInfo->BusData[BusNumber].InquiryDataOffset);
1860 while (AdapterInfo->BusData[BusNumber].InquiryDataOffset)
1862 if (UnitInfo->TargetId != CurrentTarget)
1864 /* Close old target key */
1865 if (ScsiTargetKey != NULL)
1867 ZwClose(ScsiTargetKey);
1868 ScsiTargetKey = NULL;
1871 /* Create 'Target Id X' key */
1872 DPRINT(" Target Id %u\n",
1873 UnitInfo->TargetId);
1874 swprintf(NameBuffer,
1876 UnitInfo->TargetId);
1877 RtlInitUnicodeString(&KeyName,
1879 InitializeObjectAttributes(&ObjectAttributes,
1884 Status = ZwCreateKey(&ScsiTargetKey,
1889 REG_OPTION_VOLATILE,
1891 if (!NT_SUCCESS(Status))
1893 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
1894 ZwClose(ScsiBusKey);
1895 ZwClose(ScsiPortKey);
1899 CurrentTarget = UnitInfo->TargetId;
1902 /* Create 'Logical Unit Id X' key */
1903 DPRINT(" Logical Unit Id %u\n",
1905 swprintf(NameBuffer,
1906 L"Logical Unit Id %u",
1908 RtlInitUnicodeString(&KeyName,
1910 InitializeObjectAttributes(&ObjectAttributes,
1915 Status = ZwCreateKey(&ScsiLunKey,
1920 REG_OPTION_VOLATILE,
1922 if (!NT_SUCCESS(Status))
1924 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
1925 ZwClose(ScsiTargetKey);
1926 ZwClose(ScsiBusKey);
1927 ZwClose(ScsiPortKey);
1931 /* Set values for logical unit */
1932 InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
1934 /* Set 'Identifier' (REG_SZ) value */
1935 swprintf(NameBuffer,
1937 InquiryData->VendorId,
1938 InquiryData->ProductId,
1939 InquiryData->ProductRevisionLevel);
1940 DPRINT(" Identifier = '%S'\n",
1942 RtlInitUnicodeString(&ValueName,
1944 Status = ZwSetValueKey(ScsiLunKey,
1949 (wcslen(NameBuffer) + 1) * sizeof(WCHAR));
1950 if (!NT_SUCCESS(Status))
1952 DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", Status);
1953 ZwClose(ScsiLunKey);
1954 ZwClose(ScsiTargetKey);
1955 ZwClose(ScsiBusKey);
1956 ZwClose(ScsiPortKey);
1960 /* Set 'Type' (REG_SZ) value */
1961 switch (InquiryData->DeviceType)
1964 TypeName = L"DiskPeripheral";
1967 TypeName = L"TapePeripheral";
1970 TypeName = L"PrinterPeripheral";
1973 TypeName = L"WormPeripheral";
1976 TypeName = L"CdRomPeripheral";
1979 TypeName = L"ScannerPeripheral";
1982 TypeName = L"OpticalDiskPeripheral";
1985 TypeName = L"MediumChangerPeripheral";
1988 TypeName = L"CommunicationPeripheral";
1991 TypeName = L"OtherPeripheral";
1994 DPRINT(" Type = '%S'\n", TypeName);
1995 RtlInitUnicodeString(&ValueName,
1997 Status = ZwSetValueKey(ScsiLunKey,
2002 (wcslen(TypeName) + 1) * sizeof(WCHAR));
2003 if (!NT_SUCCESS(Status))
2005 DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status);
2006 ZwClose(ScsiLunKey);
2007 ZwClose(ScsiTargetKey);
2008 ZwClose(ScsiBusKey);
2009 ZwClose(ScsiPortKey);
2013 ZwClose(ScsiLunKey);
2015 if (UnitInfo->NextInquiryDataOffset == 0)
2018 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo +
2019 UnitInfo->NextInquiryDataOffset);
2022 /* Close old target key */
2023 if (ScsiTargetKey != NULL)
2025 ZwClose(ScsiTargetKey);
2026 ScsiTargetKey = NULL;
2030 ZwClose(ScsiBusKey);
2033 ZwClose(ScsiPortKey);
2035 DPRINT("ScsiPortBuildDeviceMap() done\n");