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"
41 #include "scsiport_int.h"
43 //#define USE_DEVICE_QUEUES
45 /* TYPES *********************************************************************/
47 #define IRP_FLAG_COMPLETE 0x00000001
48 #define IRP_FLAG_NEXT 0x00000002
49 #define IRP_FLAG_NEXT_LU 0x00000004
52 /* GLOBALS *******************************************************************/
54 static NTSTATUS STDCALL
55 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
58 static NTSTATUS STDCALL
59 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
62 static NTSTATUS STDCALL
63 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
67 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
70 static IO_ALLOCATION_ACTION STDCALL
71 ScsiPortAllocateController(IN PDEVICE_OBJECT DeviceObject,
73 IN PVOID MapRegisterBase,
76 static BOOLEAN STDCALL
77 ScsiPortStartPacket(IN OUT PVOID Context);
80 ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject,
81 IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension,
83 IN OUT PSCSI_PORT_DEVICE_EXTENSION *RealDeviceExtension);
85 static PSCSI_PORT_LUN_EXTENSION
86 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
91 static PSCSI_PORT_LUN_EXTENSION
92 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
98 SpiInquirePort (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
101 SpiGetInquiryData (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
102 OUT PSCSI_ADAPTER_BUS_INFO AdapterBusInfo);
104 static BOOLEAN STDCALL
105 ScsiPortIsr(IN PKINTERRUPT Interrupt,
106 IN PVOID ServiceContext);
109 ScsiPortDpcForIsr(IN PKDPC Dpc,
110 IN PDEVICE_OBJECT DpcDeviceObject,
112 IN PVOID DpcContext);
115 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
118 static PSCSI_REQUEST_BLOCK
119 ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
120 PSCSI_REQUEST_BLOCK OriginalSrb);
123 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
124 PUNICODE_STRING RegistryPath);
127 /* FUNCTIONS *****************************************************************/
129 /**********************************************************************
134 * This function initializes the driver.
141 * System allocated Driver Object for this driver.
144 * Name of registry driver service key.
151 DriverEntry(IN PDRIVER_OBJECT DriverObject,
152 IN PUNICODE_STRING RegistryPath)
154 DPRINT("ScsiPort Driver %s\n", VERSION);
155 return(STATUS_SUCCESS);
159 /**********************************************************************
164 * Prints debugging messages.
171 * Debug level of the given message.
174 * Pointer to printf()-compatible format string.
177 Additional output data (see printf()).
186 ScsiDebugPrint(IN ULONG DebugPrintLevel,
187 IN PCHAR DebugMessage,
194 if (DebugPrintLevel > InternalDebugLevel)
198 va_start(ap, DebugMessage);
199 vsprintf(Buffer, DebugMessage, ap);
210 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension,
216 DPRINT("ScsiPortCompleteRequest()\n");
225 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address)
227 DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
228 return(Address.u.LowPart);
236 ScsiPortFlushDma(IN PVOID HwDeviceExtension)
238 DPRINT("ScsiPortFlushDma()\n");
247 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension,
248 IN PVOID MappedAddress)
250 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
251 PSCSI_PORT_DEVICE_BASE DeviceBase;
254 DPRINT("ScsiPortFreeDeviceBase() called\n");
256 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
257 SCSI_PORT_DEVICE_EXTENSION,
258 MiniPortDeviceExtension);
259 if (IsListEmpty(&DeviceExtension->DeviceBaseListHead))
262 Entry = DeviceExtension->DeviceBaseListHead.Flink;
263 while (Entry != &DeviceExtension->DeviceBaseListHead)
265 DeviceBase = CONTAINING_RECORD(Entry,
266 SCSI_PORT_DEVICE_BASE,
268 if (DeviceBase->MappedAddress == MappedAddress)
270 MmUnmapIoSpace(DeviceBase->MappedAddress,
271 DeviceBase->NumberOfBytes);
272 RemoveEntryList(Entry);
273 ExFreePool(DeviceBase);
278 Entry = Entry->Flink;
287 ScsiPortGetBusData(IN PVOID DeviceExtension,
288 IN ULONG BusDataType,
289 IN ULONG SystemIoBusNumber,
294 return(HalGetBusData(BusDataType,
306 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension,
307 IN INTERFACE_TYPE BusType,
308 IN ULONG SystemIoBusNumber,
309 IN SCSI_PHYSICAL_ADDRESS IoAddress,
310 IN ULONG NumberOfBytes,
311 IN BOOLEAN InIoSpace)
313 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
314 PHYSICAL_ADDRESS TranslatedAddress;
315 PSCSI_PORT_DEVICE_BASE DeviceBase;
319 DPRINT("ScsiPortGetDeviceBase() called\n");
321 AddressSpace = (ULONG)InIoSpace;
322 if (HalTranslateBusAddress(BusType,
326 &TranslatedAddress) == FALSE)
330 if (AddressSpace != 0)
331 return((PVOID)TranslatedAddress.u.LowPart);
333 MappedAddress = MmMapIoSpace(TranslatedAddress,
337 DeviceBase = ExAllocatePool(NonPagedPool,
338 sizeof(SCSI_PORT_DEVICE_BASE));
339 if (DeviceBase == NULL)
340 return(MappedAddress);
342 DeviceBase->MappedAddress = MappedAddress;
343 DeviceBase->NumberOfBytes = NumberOfBytes;
344 DeviceBase->IoAddress = IoAddress;
345 DeviceBase->SystemIoBusNumber = SystemIoBusNumber;
347 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
348 SCSI_PORT_DEVICE_EXTENSION,
349 MiniPortDeviceExtension);
351 InsertHeadList(&DeviceExtension->DeviceBaseListHead,
354 return(MappedAddress);
362 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension,
367 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
368 PSCSI_PORT_LUN_EXTENSION LunExtension;
371 DPRINT("ScsiPortGetLogicalUnit() called\n");
373 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
374 SCSI_PORT_DEVICE_EXTENSION,
375 MiniPortDeviceExtension);
376 if (IsListEmpty(&DeviceExtension->LunExtensionListHead))
379 Entry = DeviceExtension->LunExtensionListHead.Flink;
380 while (Entry != &DeviceExtension->LunExtensionListHead)
382 LunExtension = CONTAINING_RECORD(Entry,
383 SCSI_PORT_LUN_EXTENSION,
385 if (LunExtension->PathId == PathId &&
386 LunExtension->TargetId == TargetId &&
387 LunExtension->Lun == Lun)
389 return (PVOID)&LunExtension->MiniportLunExtension;
392 Entry = Entry->Flink;
402 SCSI_PHYSICAL_ADDRESS STDCALL
403 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension,
404 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
405 IN PVOID VirtualAddress,
408 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
409 SCSI_PHYSICAL_ADDRESS PhysicalAddress;
410 ULONG BufferLength = 0;
413 DPRINT1("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
414 HwDeviceExtension, Srb, VirtualAddress, Length);
416 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
417 SCSI_PORT_DEVICE_EXTENSION,
418 MiniPortDeviceExtension);
424 if ((ULONG_PTR)DeviceExtension->VirtualAddress > (ULONG_PTR)VirtualAddress)
426 PhysicalAddress.QuadPart = 0ULL;
427 return PhysicalAddress;
430 Offset = (ULONG_PTR)VirtualAddress - (ULONG_PTR)DeviceExtension->VirtualAddress;
431 if (Offset >= DeviceExtension->CommonBufferLength)
433 PhysicalAddress.QuadPart = 0ULL;
434 return PhysicalAddress;
437 PhysicalAddress.QuadPart =
438 DeviceExtension->PhysicalAddress.QuadPart + (ULONGLONG)Offset;
439 BufferLength = DeviceExtension->CommonBufferLength - Offset;
444 DPRINT1("Srb != NULL is not implemented yet!\n");
448 *Length = BufferLength;
450 return PhysicalAddress;
457 PSCSI_REQUEST_BLOCK STDCALL
458 ScsiPortGetSrb(IN PVOID DeviceExtension,
464 DPRINT("ScsiPortGetSrb()\n");
473 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension,
474 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
475 IN ULONG NumberOfBytes)
477 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
478 DEVICE_DESCRIPTION DeviceDescription;
480 DPRINT1("ScsiPortGetUncachedExtension(%p %p %lu)\n",
481 HwDeviceExtension, ConfigInfo, NumberOfBytes);
483 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
484 SCSI_PORT_DEVICE_EXTENSION,
485 MiniPortDeviceExtension);
487 /* Check for allocated common DMA buffer */
488 if (DeviceExtension->VirtualAddress != NULL)
490 DPRINT1("The HBA has already got a common DMA buffer!\n");
494 /* Check for DMA adapter object */
495 if (DeviceExtension->AdapterObject == NULL)
497 /* Initialize DMA adapter description */
498 RtlZeroMemory(&DeviceDescription,
499 sizeof(DEVICE_DESCRIPTION));
500 DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
501 DeviceDescription.Master = ConfigInfo->Master;
502 DeviceDescription.ScatterGather = ConfigInfo->ScatterGather;
503 DeviceDescription.DemandMode = ConfigInfo->DemandMode;
504 DeviceDescription.Dma32BitAddresses = ConfigInfo->Dma32BitAddresses;
505 DeviceDescription.BusNumber = ConfigInfo->SystemIoBusNumber;
506 DeviceDescription.DmaChannel = ConfigInfo->DmaChannel;
507 DeviceDescription.InterfaceType = ConfigInfo->AdapterInterfaceType;
508 DeviceDescription.DmaWidth = ConfigInfo->DmaWidth;
509 DeviceDescription.DmaSpeed = ConfigInfo->DmaSpeed;
510 DeviceDescription.MaximumLength = ConfigInfo->MaximumTransferLength;
511 DeviceDescription.DmaPort = ConfigInfo->DmaPort;
513 /* Get a DMA adapter object */
514 DeviceExtension->AdapterObject = HalGetAdapter(&DeviceDescription,
515 &DeviceExtension->MapRegisterCount);
516 if (DeviceExtension->AdapterObject == NULL)
518 DPRINT1("HalGetAdapter() failed\n");
523 /* Allocate a common DMA buffer */
524 DeviceExtension->CommonBufferLength = NumberOfBytes;
525 DeviceExtension->VirtualAddress =
526 HalAllocateCommonBuffer(DeviceExtension->AdapterObject,
527 DeviceExtension->CommonBufferLength,
528 &DeviceExtension->PhysicalAddress,
530 if (DeviceExtension->VirtualAddress == NULL)
532 DPRINT1("HalAllocateCommonBuffer() failed!\n");
533 DeviceExtension->CommonBufferLength = 0;
537 return DeviceExtension->VirtualAddress;
545 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension,
546 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress)
548 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
551 DPRINT("ScsiPortGetVirtualAddress(%p %I64x)\n",
552 HwDeviceExtension, PhysicalAddress.QuadPart);
554 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
555 SCSI_PORT_DEVICE_EXTENSION,
556 MiniPortDeviceExtension);
558 if (DeviceExtension->PhysicalAddress.QuadPart > PhysicalAddress.QuadPart)
561 Offset = (ULONG)(PhysicalAddress.QuadPart - DeviceExtension->PhysicalAddress.QuadPart);
562 if (Offset >= DeviceExtension->CommonBufferLength)
565 return (PVOID)((ULONG_PTR)DeviceExtension->VirtualAddress + Offset);
569 /**********************************************************************
574 * Initializes SCSI port driver specific data.
581 * Pointer to the miniport driver's driver object.
584 * Pointer to the miniport driver's registry path.
586 * HwInitializationData
587 * Pointer to port driver specific configuration data.
590 Miniport driver specific context.
599 ScsiPortInitialize(IN PVOID Argument1,
601 IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
604 PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Argument1;
605 PUNICODE_STRING RegistryPath = (PUNICODE_STRING)Argument2;
606 PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension;
607 PSCSI_PORT_DEVICE_EXTENSION RealDeviceExtension;
608 PCONFIGURATION_INFORMATION SystemConfig;
609 PPORT_CONFIGURATION_INFORMATION PortConfig;
615 PACCESS_RANGE AccessRanges;
618 DPRINT("ScsiPortInitialize() called!\n");
620 if ((HwInitializationData->HwInitialize == NULL) ||
621 (HwInitializationData->HwStartIo == NULL) ||
622 (HwInitializationData->HwInterrupt == NULL) ||
623 (HwInitializationData->HwFindAdapter == NULL) ||
624 (HwInitializationData->HwResetBus == NULL))
625 return(STATUS_INVALID_PARAMETER);
627 DriverObject->DriverStartIo = ScsiPortStartIo;
628 DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH)ScsiPortCreateClose;
629 DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH)ScsiPortCreateClose;
630 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH)ScsiPortDeviceControl;
631 DriverObject->MajorFunction[IRP_MJ_SCSI] = (PDRIVER_DISPATCH)ScsiPortDispatchScsi;
634 SystemConfig = IoGetConfigurationInformation();
636 ExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) +
637 HwInitializationData->DeviceExtensionSize;
638 PseudoDeviceExtension = ExAllocatePool(PagedPool,
640 RtlZeroMemory(PseudoDeviceExtension,
642 PseudoDeviceExtension->Length = ExtensionSize;
643 PseudoDeviceExtension->MiniPortExtensionSize = HwInitializationData->DeviceExtensionSize;
644 PseudoDeviceExtension->LunExtensionSize = HwInitializationData->SpecificLuExtensionSize;
645 PseudoDeviceExtension->HwStartIo = HwInitializationData->HwStartIo;
646 PseudoDeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
648 PortConfig = &PseudoDeviceExtension->PortConfig;
650 PortConfig->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
651 PortConfig->AdapterInterfaceType = HwInitializationData->AdapterInterfaceType;
652 PortConfig->InterruptMode =
653 (PortConfig->AdapterInterfaceType == PCIBus) ? LevelSensitive : Latched;
654 PortConfig->AtdiskPrimaryClaimed = SystemConfig->AtDiskPrimaryAddressClaimed;
655 PortConfig->AtdiskSecondaryClaimed = SystemConfig->AtDiskSecondaryAddressClaimed;
656 PortConfig->NumberOfAccessRanges = HwInitializationData->NumberOfAccessRanges;
658 PortConfig->AccessRanges =
659 ExAllocatePool(PagedPool,
660 sizeof(ACCESS_RANGE) * PortConfig->NumberOfAccessRanges);
662 for (i = 0; i < SCSI_MAXIMUM_BUSES; i++)
663 PortConfig->InitiatorBusId[i] = 255;
665 PortConfig->SystemIoBusNumber = 0;
666 PortConfig->SlotNumber = 0;
668 MaxBus = (PortConfig->AdapterInterfaceType == PCIBus) ? 8 : 1;
670 DPRINT("MaxBus: %lu\n", MaxBus);
674 DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber);
676 InitializeListHead(&PseudoDeviceExtension->DeviceBaseListHead);
678 // RtlZeroMemory(AccessRanges,
679 // sizeof(ACCESS_RANGE) * PortConfig->NumberOfAccessRanges);
681 PseudoDeviceExtension->AdapterObject = NULL;
682 PseudoDeviceExtension->MapRegisterCount = 0;
683 PseudoDeviceExtension->PhysicalAddress.QuadPart = 0ULL;
684 PseudoDeviceExtension->VirtualAddress = NULL;
685 PseudoDeviceExtension->CommonBufferLength = 0;
687 RtlZeroMemory(PseudoDeviceExtension->MiniPortDeviceExtension,
688 PseudoDeviceExtension->MiniPortExtensionSize);
690 /* Note: HwFindAdapter is called once for each bus */
691 Result = (HwInitializationData->HwFindAdapter)(&PseudoDeviceExtension->MiniPortDeviceExtension,
693 NULL, /* BusInformation */
694 NULL, /* ArgumentString */
695 &PseudoDeviceExtension->PortConfig,
697 DPRINT("HwFindAdapter() result: %lu\n", Result);
699 if (Result == SP_RETURN_FOUND)
701 DPRINT("ScsiPortInitialize(): Found HBA!\n");
703 Status = ScsiPortCreatePortDevice(DriverObject,
704 PseudoDeviceExtension,
705 SystemConfig->ScsiPortCount,
706 &RealDeviceExtension);
708 if (!NT_SUCCESS(Status))
710 DbgPrint("ScsiPortCreatePortDevice() failed! (Status 0x%lX)\n", Status);
712 ExFreePool(PortConfig->AccessRanges);
713 ExFreePool(PseudoDeviceExtension);
718 /* Get inquiry data */
719 SpiInquirePort (RealDeviceExtension);
721 /* Build the registry device map */
722 SpiBuildDeviceMap (RealDeviceExtension,
723 (PUNICODE_STRING)Argument2);
725 /* Update the configuration info */
726 SystemConfig->AtDiskPrimaryAddressClaimed = PortConfig->AtdiskPrimaryClaimed;
727 SystemConfig->AtDiskSecondaryAddressClaimed = PortConfig->AtdiskSecondaryClaimed;
728 SystemConfig->ScsiPortCount++;
733 PortConfig->SystemIoBusNumber++;
734 PortConfig->SlotNumber = 0;
737 DPRINT("Bus: %lu MaxBus: %lu\n", PortConfig->SystemIoBusNumber, MaxBus);
738 if (PortConfig->SystemIoBusNumber >= MaxBus)
740 DPRINT("Scanned all buses!\n");
745 ExFreePool(PortConfig->AccessRanges);
746 ExFreePool(PseudoDeviceExtension);
748 DPRINT("ScsiPortInitialize() done!\n");
750 return(STATUS_SUCCESS);
758 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension,
759 IN PSCSI_REQUEST_BLOCK Srb,
760 IN ULONG LogicalAddress,
763 DPRINT("ScsiPortIoMapTransfer()\n");
772 ScsiPortLogError(IN PVOID HwDeviceExtension,
773 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
780 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
782 DPRINT("ScsiPortLogError() called\n");
784 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
785 SCSI_PORT_DEVICE_EXTENSION,
786 MiniPortDeviceExtension);
789 DPRINT("ScsiPortLogError() done\n");
797 ScsiPortMoveMemory(OUT PVOID Destination,
801 RtlMoveMemory(Destination,
811 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType,
812 IN PVOID HwDeviceExtension,
815 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
818 DPRINT("ScsiPortNotification() called\n");
820 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
821 SCSI_PORT_DEVICE_EXTENSION,
822 MiniPortDeviceExtension);
824 DPRINT("DeviceExtension %p\n", DeviceExtension);
826 DPRINT("Initializing = %s\n", (DeviceExtension->Initializing)?"TRUE":"FALSE");
828 if (DeviceExtension->Initializing == TRUE)
831 va_start(ap, HwDeviceExtension);
833 switch (NotificationType)
835 case RequestComplete:
837 PSCSI_REQUEST_BLOCK Srb;
839 Srb = (PSCSI_REQUEST_BLOCK) va_arg (ap, PSCSI_REQUEST_BLOCK);
841 DPRINT("Notify: RequestComplete (Srb %p)\n", Srb);
842 DeviceExtension->IrpFlags |= IRP_FLAG_COMPLETE;
847 DPRINT("Notify: NextRequest\n");
848 DeviceExtension->IrpFlags |= IRP_FLAG_NEXT;
857 PathId = (UCHAR) va_arg (ap, int);
858 TargetId = (UCHAR) va_arg (ap, int);
859 Lun = (UCHAR) va_arg (ap, int);
861 DPRINT1 ("Notify: NextLuRequest(PathId %u TargetId %u Lun %u)\n",
862 PathId, TargetId, Lun);
863 /* FIXME: Implement it! */
865 // DeviceExtension->IrpFlags |= IRP_FLAG_NEXT_LU;
871 DPRINT1("Notify: ResetDetected\n");
876 DPRINT1 ("Unsupported notification %lu\n", NotificationType);
888 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension,
889 IN ULONG BusDataType,
890 IN ULONG SystemIoBusNumber,
896 DPRINT("ScsiPortSetBusDataByOffset()\n");
897 return(HalSetBusDataByOffset(BusDataType,
910 ScsiPortValidateRange(IN PVOID HwDeviceExtension,
911 IN INTERFACE_TYPE BusType,
912 IN ULONG SystemIoBusNumber,
913 IN SCSI_PHYSICAL_ADDRESS IoAddress,
914 IN ULONG NumberOfBytes,
915 IN BOOLEAN InIoSpace)
917 DPRINT("ScsiPortValidateRange()\n");
922 /* INTERNAL FUNCTIONS ********************************************************/
924 /**********************************************************************
926 * ScsiPortCreateClose
929 * Answer requests for Create/Close calls: a null operation.
936 * Pointer to a device object.
942 Additional output data (see printf()).
948 static NTSTATUS STDCALL
949 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
952 DPRINT("ScsiPortCreateClose()\n");
954 Irp->IoStatus.Status = STATUS_SUCCESS;
955 Irp->IoStatus.Information = FILE_OPENED;
957 IoCompleteRequest(Irp, IO_NO_INCREMENT);
959 return(STATUS_SUCCESS);
963 /**********************************************************************
965 * ScsiPortDispatchScsi
968 * Answer requests for SCSI calls
974 * Standard dispatch arguments
980 static NTSTATUS STDCALL
981 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
984 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
985 PSCSI_PORT_LUN_EXTENSION LunExtension;
986 PIO_STACK_LOCATION Stack;
987 PSCSI_REQUEST_BLOCK Srb;
988 NTSTATUS Status = STATUS_SUCCESS;
991 DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n",
994 DeviceExtension = DeviceObject->DeviceExtension;
995 Stack = IoGetCurrentIrpStackLocation(Irp);
997 Srb = Stack->Parameters.Scsi.Srb;
1000 Status = STATUS_UNSUCCESSFUL;
1002 Irp->IoStatus.Status = Status;
1003 Irp->IoStatus.Information = 0;
1005 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1010 DPRINT("Srb: %p\n", Srb);
1011 DPRINT("Srb->Function: %lu\n", Srb->Function);
1012 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
1014 LunExtension = SpiGetLunExtension(DeviceExtension,
1018 if (LunExtension == NULL)
1020 Status = STATUS_NO_SUCH_DEVICE;
1022 Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
1023 Irp->IoStatus.Status = Status;
1024 Irp->IoStatus.Information = 0;
1026 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1031 switch (Srb->Function)
1033 case SRB_FUNCTION_EXECUTE_SCSI:
1034 case SRB_FUNCTION_IO_CONTROL:
1035 #ifdef USE_DEVICE_QUEUES
1036 if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
1038 IoStartPacket (DeviceObject, Irp, NULL, NULL);
1044 KeRaiseIrql (DISPATCH_LEVEL,
1047 if (!KeInsertByKeyDeviceQueue (&LunExtension->DeviceQueue,
1048 &Irp->Tail.Overlay.DeviceQueueEntry,
1051 Srb->SrbStatus = SRB_STATUS_SUCCESS;
1052 IoStartPacket (DeviceObject, Irp, NULL, NULL);
1055 KeLowerIrql (oldIrql);
1058 IoStartPacket (DeviceObject, Irp, NULL, NULL);
1060 return(STATUS_PENDING);
1062 case SRB_FUNCTION_SHUTDOWN:
1063 case SRB_FUNCTION_FLUSH:
1064 if (DeviceExtension->PortConfig.CachesData == TRUE)
1066 IoStartPacket(DeviceObject, Irp, NULL, NULL);
1067 return(STATUS_PENDING);
1071 case SRB_FUNCTION_CLAIM_DEVICE:
1072 DPRINT(" SRB_FUNCTION_CLAIM_DEVICE\n");
1074 /* Reference device object and keep the pointer */
1075 ObReferenceObject(DeviceObject);
1076 LunExtension->DeviceObject = DeviceObject;
1077 LunExtension->DeviceClaimed = TRUE;
1078 Srb->DataBuffer = DeviceObject;
1081 case SRB_FUNCTION_RELEASE_DEVICE:
1083 PSCSI_PORT_LUN_EXTENSION LunExtension;
1085 DPRINT(" SRB_FUNCTION_RELEASE_DEVICE\n");
1086 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
1088 LunExtension = SpiGetLunExtension(DeviceExtension,
1092 if (LunExtension != NULL)
1094 /* Dereference device object */
1095 ObDereferenceObject(LunExtension->DeviceObject);
1096 LunExtension->DeviceObject = NULL;
1097 LunExtension->DeviceClaimed = FALSE;
1103 DPRINT1("SRB function not implemented (Function %lu)\n", Srb->Function);
1104 Status = STATUS_NOT_IMPLEMENTED;
1108 Irp->IoStatus.Status = Status;
1109 Irp->IoStatus.Information = DataSize;
1111 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1117 /**********************************************************************
1119 * ScsiPortDeviceControl
1122 * Answer requests for device control calls
1128 * Standard dispatch arguments
1134 static NTSTATUS STDCALL
1135 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
1138 PIO_STACK_LOCATION Stack;
1139 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1141 DPRINT("ScsiPortDeviceControl()\n");
1143 Irp->IoStatus.Status = STATUS_SUCCESS;
1144 Irp->IoStatus.Information = 0;
1147 Stack = IoGetCurrentIrpStackLocation(Irp);
1148 DeviceExtension = DeviceObject->DeviceExtension;
1150 switch (Stack->Parameters.DeviceIoControl.IoControlCode)
1152 case IOCTL_SCSI_GET_DUMP_POINTERS:
1154 PDUMP_POINTERS DumpPointers;
1155 DPRINT(" IOCTL_SCSI_GET_DUMP_POINTERS\n");
1156 DumpPointers = (PDUMP_POINTERS)Irp->AssociatedIrp.SystemBuffer;
1157 DumpPointers->DeviceObject = DeviceObject;
1159 Irp->IoStatus.Information = sizeof(DUMP_POINTERS);
1163 case IOCTL_SCSI_GET_CAPABILITIES:
1165 DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
1167 *((PIO_SCSI_CAPABILITIES *)Irp->AssociatedIrp.SystemBuffer) =
1168 DeviceExtension->PortCapabilities;
1170 Irp->IoStatus.Information = sizeof(PIO_SCSI_CAPABILITIES);
1174 case IOCTL_SCSI_GET_INQUIRY_DATA:
1176 DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
1178 /* Copy inquiry data to the port device extension */
1179 Irp->IoStatus.Information =
1180 SpiGetInquiryData(DeviceExtension,
1181 Irp->AssociatedIrp.SystemBuffer);
1182 DPRINT("Inquiry data size: %lu\n", Irp->IoStatus.Information);
1187 DPRINT1(" unknown ioctl code: 0x%lX\n",
1188 Stack->Parameters.DeviceIoControl.IoControlCode);
1192 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1194 return(STATUS_SUCCESS);
1199 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
1202 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1203 PSCSI_PORT_LUN_EXTENSION LunExtension;
1204 PIO_STACK_LOCATION IrpStack;
1205 PSCSI_REQUEST_BLOCK Srb;
1209 DPRINT("ScsiPortStartIo() called!\n");
1211 DeviceExtension = DeviceObject->DeviceExtension;
1212 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1214 DPRINT("DeviceExtension %p\n", DeviceExtension);
1216 if (IrpStack->MajorFunction != IRP_MJ_SCSI)
1218 DPRINT("No IRP_MJ_SCSI!\n");
1219 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
1220 Irp->IoStatus.Information = 0;
1221 IoCompleteRequest (Irp,
1223 IoStartNextPacket (DeviceObject,
1228 Srb = IrpStack->Parameters.Scsi.Srb;
1230 LunExtension = SpiGetLunExtension(DeviceExtension,
1234 if (LunExtension == NULL)
1236 DPRINT("No IRP_MJ_SCSI!\n");
1237 Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
1238 Irp->IoStatus.Information = 0;
1239 IoCompleteRequest (Irp,
1241 IoStartNextPacket (DeviceObject,
1246 Irp->IoStatus.Status = STATUS_SUCCESS;
1247 Irp->IoStatus.Information = Srb->DataTransferLength;
1249 DeviceExtension->CurrentIrp = Irp;
1251 if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
1252 ScsiPortStartPacket,
1255 DPRINT("Synchronization failed!\n");
1257 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
1258 Irp->IoStatus.Information = 0;
1259 IoCompleteRequest(Irp,
1261 IoStartNextPacket(DeviceObject,
1265 KeAcquireSpinLock(&DeviceExtension->IrpLock, &oldIrql);
1266 if (DeviceExtension->IrpFlags & IRP_FLAG_COMPLETE)
1268 DeviceExtension->IrpFlags &= ~IRP_FLAG_COMPLETE;
1269 IoCompleteRequest(Irp,
1273 if (DeviceExtension->IrpFlags & IRP_FLAG_NEXT)
1275 DeviceExtension->IrpFlags &= ~IRP_FLAG_NEXT;
1276 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1277 IoStartNextPacket(DeviceObject,
1282 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1285 DPRINT("ScsiPortStartIo() done\n");
1289 static BOOLEAN STDCALL
1290 ScsiPortStartPacket(IN OUT PVOID Context)
1292 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1293 PIO_STACK_LOCATION IrpStack;
1294 PSCSI_REQUEST_BLOCK Srb;
1296 DPRINT("ScsiPortStartPacket() called\n");
1298 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)Context;
1300 IrpStack = IoGetCurrentIrpStackLocation(DeviceExtension->CurrentIrp);
1301 Srb = IrpStack->Parameters.Scsi.Srb;
1303 return(DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
1308 /**********************************************************************
1310 * ScsiPortCreatePortDevice
1313 * Creates and initializes a SCSI port device object.
1322 * PseudoDeviceExtension
1333 ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject,
1334 IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension,
1335 IN ULONG PortNumber,
1336 IN OUT PSCSI_PORT_DEVICE_EXTENSION *RealDeviceExtension)
1338 PSCSI_PORT_DEVICE_EXTENSION PortDeviceExtension;
1339 PIO_SCSI_CAPABILITIES PortCapabilities;
1340 PDEVICE_OBJECT PortDeviceObject;
1341 WCHAR NameBuffer[80];
1342 UNICODE_STRING DeviceName;
1343 WCHAR DosNameBuffer[80];
1344 UNICODE_STRING DosDeviceName;
1346 ULONG AccessRangeSize;
1351 DPRINT("ScsiPortCreatePortDevice() called\n");
1353 *RealDeviceExtension = NULL;
1355 MappedIrq = HalGetInterruptVector(PseudoDeviceExtension->PortConfig.AdapterInterfaceType,
1356 PseudoDeviceExtension->PortConfig.SystemIoBusNumber,
1357 PseudoDeviceExtension->PortConfig.BusInterruptLevel,
1358 PseudoDeviceExtension->PortConfig.BusInterruptVector,
1362 /* Create a unicode device name */
1363 swprintf(NameBuffer,
1364 L"\\Device\\ScsiPort%lu",
1366 RtlInitUnicodeString(&DeviceName,
1369 DPRINT("Creating device: %wZ\n", &DeviceName);
1371 /* Create the port device */
1372 Status = IoCreateDevice(DriverObject,
1373 PseudoDeviceExtension->Length,
1375 FILE_DEVICE_CONTROLLER,
1379 if (!NT_SUCCESS(Status))
1381 DbgPrint("IoCreateDevice call failed! (Status 0x%lX)\n", Status);
1385 DPRINT("Created device: %wZ\n", &DeviceName);
1387 /* Set the buffering strategy here... */
1388 PortDeviceObject->Flags |= DO_DIRECT_IO;
1389 PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
1391 PortDeviceExtension = PortDeviceObject->DeviceExtension;
1393 /* Copy pseudo device extension into the real device extension */
1394 memcpy(PortDeviceExtension,
1395 PseudoDeviceExtension,
1396 PseudoDeviceExtension->Length);
1398 /* Copy access ranges */
1400 sizeof(ACCESS_RANGE) * PseudoDeviceExtension->PortConfig.NumberOfAccessRanges;
1401 PortDeviceExtension->PortConfig.AccessRanges = ExAllocatePool(NonPagedPool,
1403 memcpy(PortDeviceExtension->PortConfig.AccessRanges,
1404 PseudoDeviceExtension->PortConfig.AccessRanges,
1407 /* Copy device base list */
1408 if (IsListEmpty(&PseudoDeviceExtension->DeviceBaseListHead))
1410 InitializeListHead(&PortDeviceExtension->DeviceBaseListHead);
1414 PseudoDeviceExtension->DeviceBaseListHead.Flink =
1415 PortDeviceExtension->DeviceBaseListHead.Flink;
1416 PseudoDeviceExtension->DeviceBaseListHead.Blink =
1417 PortDeviceExtension->DeviceBaseListHead.Blink;
1418 PortDeviceExtension->DeviceBaseListHead.Blink->Flink =
1419 &PortDeviceExtension->DeviceBaseListHead;
1420 PortDeviceExtension->DeviceBaseListHead.Flink->Blink =
1421 &PortDeviceExtension->DeviceBaseListHead;
1424 PortDeviceExtension->DeviceObject = PortDeviceObject;
1425 PortDeviceExtension->PortNumber = PortNumber;
1427 /* Initialize the spin lock in the controller extension */
1428 KeInitializeSpinLock(&PortDeviceExtension->IrpLock);
1429 KeInitializeSpinLock(&PortDeviceExtension->SpinLock);
1431 /* Register an interrupt handler for this device */
1432 Status = IoConnectInterrupt(&PortDeviceExtension->Interrupt,
1434 PortDeviceExtension,
1435 &PortDeviceExtension->SpinLock,
1439 PortDeviceExtension->PortConfig.InterruptMode,
1443 if (!NT_SUCCESS(Status))
1445 DbgPrint("Could not Connect Interrupt %d\n",
1446 PortDeviceExtension->PortConfig.BusInterruptVector);
1447 IoDeleteDevice(PortDeviceObject);
1451 /* Initialize the DPC object */
1452 IoInitializeDpcRequest(PortDeviceExtension->DeviceObject,
1455 /* Initialize the device timer */
1456 PortDeviceExtension->TimerState = IDETimerIdle;
1457 PortDeviceExtension->TimerCount = 0;
1458 IoInitializeTimer(PortDeviceExtension->DeviceObject,
1460 PortDeviceExtension);
1462 /* Initialize port capabilities */
1463 PortCapabilities = ExAllocatePool(NonPagedPool,
1464 sizeof(IO_SCSI_CAPABILITIES));
1465 PortDeviceExtension->PortCapabilities = PortCapabilities;
1466 PortCapabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
1467 PortCapabilities->MaximumTransferLength =
1468 PortDeviceExtension->PortConfig.MaximumTransferLength;
1469 PortCapabilities->MaximumPhysicalPages =
1470 PortCapabilities->MaximumTransferLength / PAGE_SIZE;
1471 PortCapabilities->SupportedAsynchronousEvents = 0; /* FIXME */
1472 PortCapabilities->AlignmentMask =
1473 PortDeviceExtension->PortConfig.AlignmentMask;
1474 PortCapabilities->TaggedQueuing =
1475 PortDeviceExtension->PortConfig.TaggedQueuing;
1476 PortCapabilities->AdapterScansDown =
1477 PortDeviceExtension->PortConfig.AdapterScansDown;
1478 PortCapabilities->AdapterUsesPio = TRUE; /* FIXME */
1480 /* Initialize LUN-Extension list */
1481 InitializeListHead(&PortDeviceExtension->LunExtensionListHead);
1483 DPRINT("DeviceExtension %p\n", PortDeviceExtension);
1485 /* FIXME: Copy more configuration data? */
1488 /* Create the dos device link */
1489 swprintf(DosNameBuffer,
1492 RtlInitUnicodeString(&DosDeviceName,
1495 IoCreateSymbolicLink(&DosDeviceName,
1498 *RealDeviceExtension = PortDeviceExtension;
1500 DPRINT("ScsiPortCreatePortDevice() done\n");
1502 return(STATUS_SUCCESS);
1506 static PSCSI_PORT_LUN_EXTENSION
1507 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1512 PSCSI_PORT_LUN_EXTENSION LunExtension;
1513 ULONG LunExtensionSize;
1515 DPRINT("SpiAllocateLunExtension (%p %u %u %u)\n",
1516 DeviceExtension, PathId, TargetId, Lun);
1519 sizeof(SCSI_PORT_LUN_EXTENSION) + DeviceExtension->LunExtensionSize;
1520 DPRINT("LunExtensionSize %lu\n", LunExtensionSize);
1522 LunExtension = ExAllocatePool(NonPagedPool,
1524 if (LunExtension == NULL)
1529 RtlZeroMemory(LunExtension,
1532 InsertTailList(&DeviceExtension->LunExtensionListHead,
1533 &LunExtension->List);
1535 LunExtension->PathId = PathId;
1536 LunExtension->TargetId = TargetId;
1537 LunExtension->Lun = Lun;
1539 KeInitializeDeviceQueue (&LunExtension->DeviceQueue);
1541 return LunExtension;
1545 static PSCSI_PORT_LUN_EXTENSION
1546 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1551 PSCSI_PORT_LUN_EXTENSION LunExtension;
1554 DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
1555 DeviceExtension, PathId, TargetId, Lun);
1557 if (IsListEmpty(&DeviceExtension->LunExtensionListHead))
1560 Entry = DeviceExtension->LunExtensionListHead.Flink;
1561 while (Entry != &DeviceExtension->LunExtensionListHead)
1563 LunExtension = CONTAINING_RECORD(Entry,
1564 SCSI_PORT_LUN_EXTENSION,
1566 if (LunExtension->PathId == PathId &&
1567 LunExtension->TargetId == TargetId &&
1568 LunExtension->Lun == Lun)
1570 return LunExtension;
1573 Entry = Entry->Flink;
1581 SpiInquirePort(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
1583 PSCSI_PORT_LUN_EXTENSION LunExtension;
1584 SCSI_REQUEST_BLOCK Srb;
1590 DPRINT("SpiInquirePort() called\n");
1592 DeviceExtension->Initializing = TRUE;
1595 sizeof(SCSI_REQUEST_BLOCK));
1596 Srb.SrbFlags = SRB_FLAGS_DATA_IN;
1597 Srb.DataBuffer = ExAllocatePool(NonPagedPool, 256);
1598 Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
1599 Srb.DataTransferLength = 256;
1600 Srb.Cdb[0] = SCSIOP_INQUIRY;
1602 for (Bus = 0; Bus < DeviceExtension->PortConfig.NumberOfBuses; Bus++)
1606 for (Target = 0; Target < DeviceExtension->PortConfig.MaximumNumberOfTargets; Target++)
1608 Srb.TargetId = Target;
1610 for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
1613 Srb.SrbStatus = SRB_STATUS_SUCCESS;
1615 Result = DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
1617 DPRINT("Result %s Srb.SrbStatus %lx\n", (Result) ? "TRUE" : "FALSE", Srb.SrbStatus);
1619 if (Result == TRUE && Srb.SrbStatus == SRB_STATUS_SUCCESS)
1621 LunExtension = SpiAllocateLunExtension(DeviceExtension,
1625 if (LunExtension != NULL)
1627 /* Copy inquiry data */
1628 memcpy(&LunExtension->InquiryData,
1630 sizeof(INQUIRYDATA));
1637 ExFreePool(Srb.DataBuffer);
1639 DeviceExtension->Initializing = FALSE;
1641 DPRINT("SpiInquirePort() done\n");
1646 SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1647 OUT PSCSI_ADAPTER_BUS_INFO AdapterBusInfo)
1649 PSCSI_PORT_LUN_EXTENSION LunExtension;
1650 PSCSI_INQUIRY_DATA UnitInfo, PrevUnit;
1656 DPRINT("SpiGetInquiryData() called\n");
1658 /* Copy inquiry data to the port device extension */
1659 AdapterBusInfo->NumberOfBuses = DeviceExtension->PortConfig.NumberOfBuses;
1661 UnitInfo = (PSCSI_INQUIRY_DATA)
1662 ((PUCHAR)AdapterBusInfo + sizeof(SCSI_ADAPTER_BUS_INFO) +
1663 (sizeof(SCSI_BUS_DATA) * (AdapterBusInfo->NumberOfBuses - 1)));
1665 for (Bus = 0; Bus < AdapterBusInfo->NumberOfBuses; Bus++)
1667 AdapterBusInfo->BusData[Bus].InitiatorBusId =
1668 DeviceExtension->PortConfig.InitiatorBusId[Bus];
1669 AdapterBusInfo->BusData[Bus].InquiryDataOffset =
1670 (ULONG)((PUCHAR)UnitInfo - (PUCHAR)AdapterBusInfo);
1675 for (Target = 0; Target < DeviceExtension->PortConfig.MaximumNumberOfTargets; Target++)
1677 for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
1679 LunExtension = SpiGetLunExtension(DeviceExtension,
1683 if (LunExtension != NULL)
1685 DPRINT("(Bus %lu Target %lu Lun %lu)\n",
1688 UnitInfo->PathId = Bus;
1689 UnitInfo->TargetId = Target;
1690 UnitInfo->Lun = Lun;
1691 UnitInfo->InquiryDataLength = INQUIRYDATABUFFERSIZE;
1692 memcpy(&UnitInfo->InquiryData,
1693 &LunExtension->InquiryData,
1694 INQUIRYDATABUFFERSIZE);
1695 if (PrevUnit != NULL)
1696 PrevUnit->NextInquiryDataOffset = (ULONG)((PUCHAR)UnitInfo-(PUCHAR)AdapterBusInfo);
1697 PrevUnit = UnitInfo;
1698 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)UnitInfo + sizeof(SCSI_INQUIRY_DATA)+INQUIRYDATABUFFERSIZE-1);
1703 DPRINT("UnitCount: %lu\n", UnitCount);
1704 AdapterBusInfo->BusData[Bus].NumberOfLogicalUnits = UnitCount;
1706 AdapterBusInfo->BusData[Bus].InquiryDataOffset = 0;
1709 DPRINT("Data size: %lu\n", (ULONG)UnitInfo - (ULONG)AdapterBusInfo);
1711 return (ULONG)((PUCHAR)UnitInfo-(PUCHAR)AdapterBusInfo);
1715 static BOOLEAN STDCALL
1716 ScsiPortIsr(IN PKINTERRUPT Interrupt,
1717 IN PVOID ServiceContext)
1719 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1722 DPRINT("ScsiPortIsr() called!\n");
1724 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext;
1726 Result = DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension);
1727 if (Result == FALSE)
1732 if (DeviceExtension->IrpFlags)
1734 IoRequestDpc(DeviceExtension->DeviceObject,
1735 DeviceExtension->CurrentIrp,
1743 // ScsiPortDpcForIsr
1750 // IN PDEVICE_OBJECT DpcDeviceObject
1752 // IN PVOID DpcContext
1755 ScsiPortDpcForIsr(IN PKDPC Dpc,
1756 IN PDEVICE_OBJECT DpcDeviceObject,
1758 IN PVOID DpcContext)
1760 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1761 PIO_STACK_LOCATION IrpStack;
1762 PSCSI_REQUEST_BLOCK Srb;
1765 DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
1766 Dpc, DpcDeviceObject, DpcIrp, DpcContext);
1768 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DpcContext;
1770 KeAcquireSpinLock(&DeviceExtension->IrpLock, &oldIrql);
1771 if (DeviceExtension->IrpFlags)
1773 IrpStack = IoGetCurrentIrpStackLocation(DeviceExtension->CurrentIrp);
1774 Srb = IrpStack->Parameters.Scsi.Srb;
1776 if (DeviceExtension->OriginalSrb != NULL)
1778 DPRINT("Got sense data!\n");
1780 DPRINT("Valid: %x\n", DeviceExtension->InternalSenseData.Valid);
1781 DPRINT("ErrorCode: %x\n", DeviceExtension->InternalSenseData.ErrorCode);
1782 DPRINT("SenseKey: %x\n", DeviceExtension->InternalSenseData.SenseKey);
1783 DPRINT("SenseCode: %x\n", DeviceExtension->InternalSenseData.AdditionalSenseCode);
1785 /* Copy sense data */
1786 if (DeviceExtension->OriginalSrb->SenseInfoBufferLength != 0)
1788 RtlCopyMemory(DeviceExtension->OriginalSrb->SenseInfoBuffer,
1789 &DeviceExtension->InternalSenseData,
1790 sizeof(SENSE_DATA));
1791 DeviceExtension->OriginalSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
1794 /* Clear current sense data */
1795 RtlZeroMemory(&DeviceExtension->InternalSenseData, sizeof(SENSE_DATA));
1797 IrpStack->Parameters.Scsi.Srb = DeviceExtension->OriginalSrb;
1798 DeviceExtension->OriginalSrb = NULL;
1800 else if ((SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) &&
1801 (Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION))
1803 DPRINT("SCSIOP_REQUEST_SENSE required!\n");
1805 DeviceExtension->OriginalSrb = Srb;
1806 IrpStack->Parameters.Scsi.Srb = ScsiPortInitSenseRequestSrb(DeviceExtension,
1808 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1809 if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
1810 ScsiPortStartPacket,
1813 DPRINT1("Synchronization failed!\n");
1815 DpcIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
1816 DpcIrp->IoStatus.Information = 0;
1817 IoCompleteRequest(DpcIrp,
1819 IoStartNextPacket(DpcDeviceObject,
1826 DeviceExtension->CurrentIrp = NULL;
1828 // DpcIrp->IoStatus.Information = 0;
1829 // DpcIrp->IoStatus.Status = STATUS_SUCCESS;
1831 if (DeviceExtension->IrpFlags & IRP_FLAG_COMPLETE)
1833 DeviceExtension->IrpFlags &= ~IRP_FLAG_COMPLETE;
1834 IoCompleteRequest(DpcIrp, IO_NO_INCREMENT);
1837 if (DeviceExtension->IrpFlags & IRP_FLAG_NEXT)
1839 DeviceExtension->IrpFlags &= ~IRP_FLAG_NEXT;
1840 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1841 IoStartNextPacket(DpcDeviceObject, FALSE);
1845 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1850 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1853 DPRINT("ScsiPortDpcForIsr() done\n");
1859 // This function handles timeouts and other time delayed processing
1864 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
1865 // IN PVOID Context the Controller extension for the
1866 // controller the device is on
1869 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
1872 DPRINT1("ScsiPortIoTimer()\n");
1876 static PSCSI_REQUEST_BLOCK
1877 ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1878 PSCSI_REQUEST_BLOCK OriginalSrb)
1880 PSCSI_REQUEST_BLOCK Srb;
1883 Srb = &DeviceExtension->InternalSrb;
1886 sizeof(SCSI_REQUEST_BLOCK));
1888 Srb->PathId = OriginalSrb->PathId;
1889 Srb->TargetId = OriginalSrb->TargetId;
1890 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1891 Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
1892 Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
1894 Srb->TimeOutValue = 4;
1897 Srb->DataBuffer = &DeviceExtension->InternalSenseData;
1898 Srb->DataTransferLength = sizeof(SENSE_DATA);
1900 Cdb = (PCDB)Srb->Cdb;
1901 Cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE;
1902 Cdb->CDB6INQUIRY.AllocationLength = sizeof(SENSE_DATA);
1909 ScsiPortFreeSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
1911 DeviceExtension->OriginalSrb = NULL;
1915 /**********************************************************************
1920 * Builds the registry device map of all device which are attached
1921 * to the given SCSI HBA port. The device map is located at:
1922 * \Registry\Machine\DeviceMap\Scsi
1932 * Name of registry driver service key.
1939 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1940 PUNICODE_STRING RegistryPath)
1942 PSCSI_PORT_LUN_EXTENSION LunExtension;
1943 OBJECT_ATTRIBUTES ObjectAttributes;
1944 UNICODE_STRING KeyName;
1945 UNICODE_STRING ValueName;
1946 WCHAR NameBuffer[64];
1949 HANDLE ScsiPortKey = NULL;
1950 HANDLE ScsiBusKey = NULL;
1951 HANDLE ScsiInitiatorKey = NULL;
1952 HANDLE ScsiTargetKey = NULL;
1953 HANDLE ScsiLunKey = NULL;
1956 ULONG CurrentTarget;
1963 DPRINT("SpiBuildDeviceMap() called\n");
1965 if (DeviceExtension == NULL || RegistryPath == NULL)
1967 DPRINT1("Invalid parameter\n");
1968 return(STATUS_INVALID_PARAMETER);
1971 /* Open or create the 'Scsi' subkey */
1972 RtlInitUnicodeStringFromLiteral(&KeyName,
1973 L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
1974 InitializeObjectAttributes(&ObjectAttributes,
1976 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
1979 Status = ZwCreateKey(&ScsiKey,
1984 REG_OPTION_VOLATILE,
1986 if (!NT_SUCCESS(Status))
1988 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
1992 /* Create new 'Scsi Port X' subkey */
1993 DPRINT("Scsi Port %lu\n",
1994 DeviceExtension->PortNumber);
1996 swprintf(NameBuffer,
1998 DeviceExtension->PortNumber);
1999 RtlInitUnicodeString(&KeyName,
2001 InitializeObjectAttributes(&ObjectAttributes,
2006 Status = ZwCreateKey(&ScsiPortKey,
2011 REG_OPTION_VOLATILE,
2014 if (!NT_SUCCESS(Status))
2016 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
2021 * Create port-specific values
2024 /* Set 'DMA Enabled' (REG_DWORD) value */
2025 UlongData = (ULONG)!DeviceExtension->PortCapabilities->AdapterUsesPio;
2026 DPRINT(" DMA Enabled = %s\n", (UlongData) ? "TRUE" : "FALSE");
2027 RtlInitUnicodeString(&ValueName,
2029 Status = ZwSetValueKey(ScsiPortKey,
2035 if (!NT_SUCCESS(Status))
2037 DPRINT("ZwSetValueKey('DMA Enabled') failed (Status %lx)\n", Status);
2038 ZwClose(ScsiPortKey);
2042 /* Set 'Driver' (REG_SZ) value */
2043 DriverName = wcsrchr(RegistryPath->Buffer, L'\\') + 1;
2044 RtlInitUnicodeString(&ValueName,
2046 Status = ZwSetValueKey(ScsiPortKey,
2051 (wcslen(DriverName) + 1) * sizeof(WCHAR));
2052 if (!NT_SUCCESS(Status))
2054 DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status);
2055 ZwClose(ScsiPortKey);
2059 /* Set 'Interrupt' (REG_DWORD) value (NT4 only) */
2060 UlongData = (ULONG)DeviceExtension->PortConfig.BusInterruptLevel;
2061 DPRINT(" Interrupt = %lu\n", UlongData);
2062 RtlInitUnicodeString(&ValueName,
2064 Status = ZwSetValueKey(ScsiPortKey,
2070 if (!NT_SUCCESS(Status))
2072 DPRINT("ZwSetValueKey('Interrupt') failed (Status %lx)\n", Status);
2073 ZwClose(ScsiPortKey);
2077 /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
2078 UlongData = ScsiPortConvertPhysicalAddressToUlong(DeviceExtension->PortConfig.AccessRanges[0].RangeStart);
2079 DPRINT(" IOAddress = %lx\n", UlongData);
2080 RtlInitUnicodeString(&ValueName,
2082 Status = ZwSetValueKey(ScsiPortKey,
2088 if (!NT_SUCCESS(Status))
2090 DPRINT("ZwSetValueKey('IOAddress') failed (Status %lx)\n", Status);
2091 ZwClose(ScsiPortKey);
2095 /* Enumerate buses */
2096 for (BusNumber = 0; BusNumber < DeviceExtension->PortConfig.NumberOfBuses; BusNumber++)
2098 /* Create 'Scsi Bus X' key */
2099 DPRINT(" Scsi Bus %lu\n", BusNumber);
2100 swprintf(NameBuffer,
2103 RtlInitUnicodeString(&KeyName,
2105 InitializeObjectAttributes(&ObjectAttributes,
2110 Status = ZwCreateKey(&ScsiBusKey,
2115 REG_OPTION_VOLATILE,
2117 if (!NT_SUCCESS(Status))
2119 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
2123 /* Create 'Initiator Id X' key */
2124 DPRINT(" Initiator Id %u\n",
2125 DeviceExtension->PortConfig.InitiatorBusId[BusNumber]);
2126 swprintf(NameBuffer,
2128 DeviceExtension->PortConfig.InitiatorBusId[BusNumber]);
2129 RtlInitUnicodeString(&KeyName,
2131 InitializeObjectAttributes(&ObjectAttributes,
2136 Status = ZwCreateKey(&ScsiInitiatorKey,
2141 REG_OPTION_VOLATILE,
2143 if (!NT_SUCCESS(Status))
2145 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
2149 /* FIXME: Are there any initiator values (??) */
2151 ZwClose(ScsiInitiatorKey);
2152 ScsiInitiatorKey = NULL;
2155 /* Enumerate targets */
2156 CurrentTarget = (ULONG)-1;
2157 ScsiTargetKey = NULL;
2158 for (Target = 0; Target < DeviceExtension->PortConfig.MaximumNumberOfTargets; Target++)
2160 for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
2162 LunExtension = SpiGetLunExtension(DeviceExtension,
2166 if (LunExtension != NULL)
2168 if (Target != CurrentTarget)
2170 /* Close old target key */
2171 if (ScsiTargetKey != NULL)
2173 ZwClose(ScsiTargetKey);
2174 ScsiTargetKey = NULL;
2177 /* Create 'Target Id X' key */
2178 DPRINT(" Target Id %lu\n", Target);
2179 swprintf(NameBuffer,
2182 RtlInitUnicodeString(&KeyName,
2184 InitializeObjectAttributes(&ObjectAttributes,
2189 Status = ZwCreateKey(&ScsiTargetKey,
2194 REG_OPTION_VOLATILE,
2196 if (!NT_SUCCESS(Status))
2198 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
2202 CurrentTarget = Target;
2205 /* Create 'Logical Unit Id X' key */
2206 DPRINT(" Logical Unit Id %lu\n", Lun);
2207 swprintf(NameBuffer,
2208 L"Logical Unit Id %lu",
2210 RtlInitUnicodeString(&KeyName,
2212 InitializeObjectAttributes(&ObjectAttributes,
2217 Status = ZwCreateKey(&ScsiLunKey,
2222 REG_OPTION_VOLATILE,
2224 if (!NT_SUCCESS(Status))
2226 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
2230 /* Set 'Identifier' (REG_SZ) value */
2231 swprintf(NameBuffer,
2233 LunExtension->InquiryData.VendorId,
2234 LunExtension->InquiryData.ProductId,
2235 LunExtension->InquiryData.ProductRevisionLevel);
2236 DPRINT(" Identifier = '%S'\n", NameBuffer);
2237 RtlInitUnicodeString(&ValueName,
2239 Status = ZwSetValueKey(ScsiLunKey,
2244 (wcslen(NameBuffer) + 1) * sizeof(WCHAR));
2245 if (!NT_SUCCESS(Status))
2247 DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", Status);
2251 /* Set 'Type' (REG_SZ) value */
2252 switch (LunExtension->InquiryData.DeviceType)
2255 TypeName = L"DiskPeripheral";
2258 TypeName = L"TapePeripheral";
2261 TypeName = L"PrinterPeripheral";
2264 TypeName = L"WormPeripheral";
2267 TypeName = L"CdRomPeripheral";
2270 TypeName = L"ScannerPeripheral";
2273 TypeName = L"OpticalDiskPeripheral";
2276 TypeName = L"MediumChangerPeripheral";
2279 TypeName = L"CommunicationPeripheral";
2282 TypeName = L"OtherPeripheral";
2285 DPRINT(" Type = '%S'\n", TypeName);
2286 RtlInitUnicodeString(&ValueName,
2288 Status = ZwSetValueKey(ScsiLunKey,
2293 (wcslen(TypeName) + 1) * sizeof(WCHAR));
2294 if (!NT_SUCCESS(Status))
2296 DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status);
2300 ZwClose(ScsiLunKey);
2305 /* Close old target key */
2306 if (ScsiTargetKey != NULL)
2308 ZwClose(ScsiTargetKey);
2309 ScsiTargetKey = NULL;
2313 ZwClose(ScsiBusKey);
2318 if (ScsiLunKey != NULL)
2319 ZwClose (ScsiLunKey);
2321 if (ScsiInitiatorKey != NULL)
2322 ZwClose (ScsiInitiatorKey);
2324 if (ScsiTargetKey != NULL)
2325 ZwClose (ScsiTargetKey);
2327 if (ScsiBusKey != NULL)
2328 ZwClose (ScsiBusKey);
2330 if (ScsiPortKey != NULL)
2331 ZwClose (ScsiPortKey);
2333 DPRINT("SpiBuildDeviceMap() done\n");