Author: fireball
Date: Wed Mar 28 01:15:09 2007
New Revision: 26189
URL: 
http://svn.reactos.org/svn/reactos?rev=26189&view=rev
Log:
- Rewrite bus scanning / inquiry handling (was BSODing).
- Change a way LUN extensions are stored inside DeviceExtension.
Modified:
    trunk/reactos/drivers/storage/scsiport-new/scsiport.c
    trunk/reactos/drivers/storage/scsiport-new/scsiport_int.h
Modified: trunk/reactos/drivers/storage/scsiport-new/scsiport.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/storage/scsiport-n…
==============================================================================
--- trunk/reactos/drivers/storage/scsiport-new/scsiport.c (original)
+++ trunk/reactos/drivers/storage/scsiport-new/scsiport.c Wed Mar 28 01:15:09 2007
@@ -80,13 +80,7 @@
 static PSCSI_PORT_LUN_EXTENSION
-SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
-                        IN UCHAR PathId,
-                        IN UCHAR TargetId,
-                        IN UCHAR Lun);
-
-static VOID
-SpiRemoveLunExtension (IN PSCSI_PORT_LUN_EXTENSION LunExtension);
+SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
 static PSCSI_PORT_LUN_EXTENSION
 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
@@ -96,14 +90,14 @@
 static NTSTATUS
 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject,
-               IN OUT PSCSI_REQUEST_BLOCK Srb);
+               IN PSCSI_LUN_INFO LunInfo);
 static VOID
 SpiScanAdapter (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
-static ULONG
+static NTSTATUS
 SpiGetInquiryData (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
-                  OUT PSCSI_ADAPTER_BUS_INFO AdapterBusInfo);
+                  IN PIRP Irp);
 static BOOLEAN STDCALL
 ScsiPortIsr(IN PKINTERRUPT Interrupt,
@@ -246,7 +240,7 @@
   PSCSI_PORT_DEVICE_BASE DeviceBase;
   PLIST_ENTRY Entry;
-  DPRINT("ScsiPortFreeDeviceBase() called\n");
+  //DPRINT("ScsiPortFreeDeviceBase() called\n");
   DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
                                      SCSI_PORT_DEVICE_EXTENSION,
@@ -311,7 +305,7 @@
   ULONG AddressSpace;
   PVOID MappedAddress;
-  DPRINT ("ScsiPortGetDeviceBase() called\n");
+  //DPRINT ("ScsiPortGetDeviceBase() called\n");
   AddressSpace = (ULONG)InIoSpace;
   if (HalTranslateBusAddress(BusType,
@@ -359,6 +353,8 @@
                       IN UCHAR TargetId,
                       IN UCHAR Lun)
 {
+    UNIMPLEMENTED;
+#if 0
   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
   PSCSI_PORT_LUN_EXTENSION LunExtension;
   PLIST_ENTRY Entry;
@@ -386,7 +382,7 @@
       Entry = Entry->Flink;
     }
-
+#endif
   return NULL;
 }
@@ -748,9 +744,6 @@
       /* Initialize the device base list */
       InitializeListHead (&DeviceExtension->DeviceBaseListHead);
-      /* Initialize LUN-Extension list */
-      InitializeListHead (&DeviceExtension->LunExtensionListHead);
-
       /* Initialize the spin lock in the controller extension */
       KeInitializeSpinLock (&DeviceExtension->IrpLock);
       KeInitializeSpinLock (&DeviceExtension->SpinLock);
@@ -791,7 +784,7 @@
 //  PortConfig->DmaSpeed =
 //  PortConfig->AlignmentMask =
       PortConfig->NumberOfAccessRanges =
HwInitializationData->NumberOfAccessRanges;
-//  PortConfig->NumberOfBuses =
+    PortConfig->NumberOfBuses = MaxBus;
       for (i = 0; i < SCSI_MAXIMUM_BUSES; i++)
        PortConfig->InitiatorBusId[i] = 255;
@@ -916,6 +909,26 @@
            PortConfig->AdapterScansDown;
          PortCapabilities->AdapterUsesPio = TRUE; /* FIXME */
+          /* Initialize bus scanning information */
+          DeviceExtension->BusesConfig = ExAllocatePool(PagedPool,
+              sizeof(PSCSI_BUS_SCAN_INFO) *
DeviceExtension->PortConfig->NumberOfBuses
+              + sizeof(ULONG));
+
+          if (!DeviceExtension->BusesConfig)
+          {
+              DPRINT1("Out of resources!\n");
+              Status = STATUS_INSUFFICIENT_RESOURCES;
+              goto ByeBye;
+          }
+
+          /* Zero it */
+          RtlZeroMemory(DeviceExtension->BusesConfig,
+              sizeof(PSCSI_BUS_SCAN_INFO) *
DeviceExtension->PortConfig->NumberOfBuses
+              + sizeof(ULONG));
+
+          /* Store number of buses there */
+          DeviceExtension->BusesConfig->NumberOfBuses =
DeviceExtension->PortConfig->NumberOfBuses;
+
          /* Scan the adapter for devices */
          SpiScanAdapter (DeviceExtension);
@@ -1552,10 +1565,7 @@
          DPRINT("  IOCTL_SCSI_GET_INQUIRY_DATA\n");
          /* Copy inquiry data to the port device extension */
-         Irp->IoStatus.Information =
-           SpiGetInquiryData(DeviceExtension,
-                             Irp->AssociatedIrp.SystemBuffer);
-         DPRINT("Inquiry data size: %lu\n", Irp->IoStatus.Information);
+         Irp->IoStatus.Status = SpiGetInquiryData(DeviceExtension, Irp);
        }
        break;
@@ -1723,64 +1733,41 @@
 static PSCSI_PORT_LUN_EXTENSION
-SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
-                        IN UCHAR PathId,
-                        IN UCHAR TargetId,
-                        IN UCHAR Lun)
-{
-  PSCSI_PORT_LUN_EXTENSION LunExtension;
-  ULONG LunExtensionSize;
-
-  DPRINT("SpiAllocateLunExtension (%p %u %u %u)\n",
-        DeviceExtension, PathId, TargetId, Lun);
-
-  LunExtensionSize =
-    sizeof(SCSI_PORT_LUN_EXTENSION) + DeviceExtension->LunExtensionSize;
-  DPRINT("LunExtensionSize %lu\n", LunExtensionSize);
-
-  LunExtension = ExAllocatePool(NonPagedPool,
-                               LunExtensionSize);
-  if (LunExtension == NULL)
-    {
-      return NULL;
-    }
-
-  RtlZeroMemory(LunExtension,
-               LunExtensionSize);
-
-  InsertTailList(&DeviceExtension->LunExtensionListHead,
-                &LunExtension->List);
-
-  LunExtension->PathId = PathId;
-  LunExtension->TargetId = TargetId;
-  LunExtension->Lun = Lun;
-
-  KeInitializeDeviceQueue (&LunExtension->DeviceQueue);
-
-  return LunExtension;
-}
-
-
-static VOID
-SpiRemoveLunExtension (IN PSCSI_PORT_LUN_EXTENSION LunExtension)
-{
-  DPRINT("SpiRemoveLunExtension(%p) called\n",
-        LunExtension);
-
-  if (LunExtension == NULL)
-    return;
-
-  RemoveEntryList (&LunExtension->List);
-
-
-  /* Release LUN extersion data */
-
-
-  ExFreePool (LunExtension);
-
-  return;
-}
-
+SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
+{
+    PSCSI_PORT_LUN_EXTENSION LunExtension;
+    ULONG LunExtensionSize;
+
+    DPRINT("SpiAllocateLunExtension (%p)\n",
+        DeviceExtension);
+
+    /* Round LunExtensionSize first to the sizeof LONGLONG */
+    LunExtensionSize = (DeviceExtension->LunExtensionSize +
+        sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1);
+
+    LunExtensionSize += sizeof(SCSI_PORT_LUN_EXTENSION);
+    DPRINT("LunExtensionSize %lu\n", LunExtensionSize);
+
+    LunExtension = ExAllocatePool(NonPagedPool, LunExtensionSize);
+    if (LunExtension == NULL)
+    {
+        DPRINT1("Out of resources!\n");
+        return NULL;
+    }
+
+    /* Zero everything */
+    RtlZeroMemory(LunExtension, LunExtensionSize);
+
+    /* Initialize a list of requests */
+    InitializeListHead(&LunExtension->SrbInfo.Requests);
+
+    /* TODO: Initialize other fields */
+
+    /* Initialize request queue */
+    KeInitializeDeviceQueue (&LunExtension->DeviceQueue);
+
+    return LunExtension;
+}
 static PSCSI_PORT_LUN_EXTENSION
 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
@@ -1788,248 +1775,519 @@
                    IN UCHAR TargetId,
                    IN UCHAR Lun)
 {
-  PSCSI_PORT_LUN_EXTENSION LunExtension;
-  PLIST_ENTRY Entry;
-
-  DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
-        DeviceExtension, PathId, TargetId, Lun);
-
-  if (IsListEmpty(&DeviceExtension->LunExtensionListHead))
+    PSCSI_PORT_LUN_EXTENSION LunExtension;
+
+    DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
+        DeviceExtension, PathId, TargetId, Lun);
+
+    /* Get appropriate list */
+    LunExtension = DeviceExtension->LunExtensionList[(TargetId + Lun) % LUS_NUMBER];
+
+    /* Iterate it until we find what we need */
+    while (!LunExtension)
+    {
+        if (LunExtension->TargetId == TargetId &&
+            LunExtension->Lun == Lun &&
+            LunExtension->PathId == PathId)
+        {
+            /* All matches, return */
+            return LunExtension;
+        }
+
+        /* Advance to the next item */
+        LunExtension = LunExtension->Next;
+    }
+
+    /* We did not find anything */
+    DPRINT("Nothing found\n");
     return NULL;
-
-  Entry = DeviceExtension->LunExtensionListHead.Flink;
-  while (Entry != &DeviceExtension->LunExtensionListHead)
-    {
-      LunExtension = CONTAINING_RECORD(Entry,
-                                      SCSI_PORT_LUN_EXTENSION,
-                                      List);
-      if (LunExtension->PathId == PathId &&
-         LunExtension->TargetId == TargetId &&
-         LunExtension->Lun == Lun)
-       {
-         return LunExtension;
-       }
-
-      Entry = Entry->Flink;
-    }
-
-  return NULL;
 }
 static NTSTATUS
 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject,
-               IN OUT PSCSI_REQUEST_BLOCK Srb)
-{
-  IO_STATUS_BLOCK IoStatusBlock;
-  PIO_STACK_LOCATION IrpStack;
-  PKEVENT Event;
-  PIRP Irp;
-  NTSTATUS Status;
-
-  DPRINT ("SpiSendInquiry() called\n");
-
-  Event = ExAllocatePool (NonPagedPool,
-                         sizeof(KEVENT));
-  if (Event == NULL)
-    return STATUS_INSUFFICIENT_RESOURCES;
-
-  KeInitializeEvent (Event,
-                    NotificationEvent,
-                    FALSE);
-
-  Irp = IoBuildDeviceIoControlRequest (IOCTL_SCSI_EXECUTE_OUT,
-                                      DeviceObject,
-                                      NULL,
-                                      0,
-                                      Srb->DataBuffer,
-                                      Srb->DataTransferLength,
-                                      TRUE,
-                                      Event,
-                                      &IoStatusBlock);
-  if (Irp == NULL)
-    {
-      DPRINT("IoBuildDeviceIoControlRequest() failed\n");
-      ExFreePool (Event);
-      return STATUS_INSUFFICIENT_RESOURCES;
-    }
-
-  /* Attach Srb to the Irp */
-  IrpStack = IoGetNextIrpStackLocation (Irp);
-  IrpStack->Parameters.Scsi.Srb = Srb;
-  Srb->OriginalRequest = Irp;
-
-  /* Call the driver */
-  Status = IoCallDriver (DeviceObject,
-                        Irp);
-  if (Status == STATUS_PENDING)
-    {
-      KeWaitForSingleObject (Event,
-                            Suspended,
-                            KernelMode,
-                            FALSE,
-                            NULL);
-      Status = IoStatusBlock.Status;
-    }
-
-  ExFreePool (Event);
-
-  return Status;
-}
-
-
+               IN PSCSI_LUN_INFO LunInfo)
+{
+    IO_STATUS_BLOCK IoStatusBlock;
+    PIO_STACK_LOCATION IrpStack;
+    KEVENT Event;
+    PIRP Irp;
+    NTSTATUS Status;
+    PINQUIRYDATA InquiryBuffer;
+    PSENSE_DATA SenseBuffer;
+    BOOLEAN KeepTrying = TRUE;
+    ULONG RetryCount = 0;
+    SCSI_REQUEST_BLOCK Srb;
+    PCDB Cdb;
+
+    DPRINT ("SpiSendInquiry() called\n");
+
+    InquiryBuffer = ExAllocatePool (NonPagedPool, INQUIRYDATABUFFERSIZE);
+    if (InquiryBuffer == NULL)
+        return STATUS_INSUFFICIENT_RESOURCES;
+
+    SenseBuffer = ExAllocatePool (NonPagedPool, SENSE_BUFFER_SIZE);
+    if (SenseBuffer == NULL)
+        return STATUS_INSUFFICIENT_RESOURCES;
+
+    while (KeepTrying)
+    {
+        /* Initialize event for waiting */
+        KeInitializeEvent(&Event,
+                          NotificationEvent,
+                          FALSE);
+
+        /* Create an IRP */
+        Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_IN,
+            DeviceObject,
+            NULL,
+            0,
+            InquiryBuffer,
+            INQUIRYDATABUFFERSIZE,
+            TRUE,
+            &Event,
+            &IoStatusBlock);
+        if (Irp == NULL)
+        {
+            DPRINT("IoBuildDeviceIoControlRequest() failed\n");
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        /* Prepare SRB */
+        RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
+
+        Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
+        Srb.OriginalRequest = Irp;
+        Srb.PathId = LunInfo->PathId;
+        Srb.TargetId = LunInfo->TargetId;
+        Srb.Lun = LunInfo->Lun;
+        Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
+        Srb.SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
+        Srb.TimeOutValue = 4;
+        Srb.CdbLength = 6;
+
+        Srb.SenseInfoBuffer = SenseBuffer;
+        Srb.SenseInfoBufferLength = SENSE_BUFFER_SIZE;
+
+        Srb.DataBuffer = InquiryBuffer;
+        Srb.DataTransferLength = INQUIRYDATABUFFERSIZE;
+
+        /* Attach Srb to the Irp */
+        IrpStack = IoGetNextIrpStackLocation (Irp);
+        IrpStack->Parameters.Scsi.Srb = &Srb;
+
+        /* Fill in CDB */
+        Cdb = (PCDB)Srb.Cdb;
+        Cdb->CDB6INQUIRY.LogicalUnitNumber = LunInfo->Lun;
+        Cdb->CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE;
+
+        /* Call the driver */
+        Status = IoCallDriver(DeviceObject, Irp);
+
+        /* Wait for it to complete */
+        if (Status == STATUS_PENDING)
+        {
+            KeWaitForSingleObject(&Event,
+                Executive,
+                KernelMode,
+                FALSE,
+                NULL);
+            Status = IoStatusBlock.Status;
+        }
+
+        if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_SUCCESS)
+        {
+            /* All fine, copy data over */
+            RtlCopyMemory(LunInfo->InquiryData,
+                          InquiryBuffer,
+                          INQUIRYDATABUFFERSIZE);
+
+            Status = STATUS_SUCCESS;
+        }
+        else
+        {
+            /* Check if queue is frozen */
+            if (Srb.SrbStatus & SRB_STATUS_QUEUE_FROZEN)
+            {
+                /* Something weird happeend */
+                ASSERT(FALSE);
+            }
+
+            /* Check if data overrun happened */
+            if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN)
+            {
+                /* TODO: Implement */
+                ASSERT(FALSE);
+            }
+            else if ((Srb.SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
+                SenseBuffer->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST)
+            {
+                /* LUN is not valid, but some device responds there.
+                   Mark it as invalid anyway */
+
+                Status = STATUS_INVALID_DEVICE_REQUEST;
+            }
+            else
+            {
+                /* Retry a couple of times if no timeout happened */
+                if ((RetryCount < 2) &&
+                    (SRB_STATUS(Srb.SrbStatus) != SRB_STATUS_NO_DEVICE) &&
+                    (SRB_STATUS(Srb.SrbStatus) != SRB_STATUS_SELECTION_TIMEOUT))
+                {
+                    RetryCount++;
+                    KeepTrying = TRUE;
+                }
+                else
+                {
+                    /* That's all, go to exit */
+                    KeepTrying = FALSE;
+
+                    /* Set status according to SRB status */
+                    if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_BAD_FUNCTION ||
+                        SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_BAD_SRB_BLOCK_LENGTH)
+                    {
+                          Status = STATUS_INVALID_DEVICE_REQUEST;
+                    }
+                    else
+                    {
+                        Status = STATUS_IO_DEVICE_ERROR;
+                    }
+                }
+            }
+        }
+    }
+
+    /* Free buffers */
+    ExFreePool(InquiryBuffer);
+    ExFreePool(SenseBuffer);
+
+    return Status;
+}
+
+
+/* Scans all SCSI buses */
 static VOID
-SpiScanAdapter (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
-{
-  PSCSI_PORT_LUN_EXTENSION LunExtension;
-  SCSI_REQUEST_BLOCK Srb;
-  PCDB Cdb;
-  ULONG Bus;
-  ULONG Target;
-  ULONG Lun;
-  NTSTATUS Status;
-
-  DPRINT ("SpiScanAdapter() called\n");
-
-  RtlZeroMemory(&Srb,
-               sizeof(SCSI_REQUEST_BLOCK));
-  Srb.SrbFlags = SRB_FLAGS_DATA_IN;
-  Srb.DataBuffer = ExAllocatePool(NonPagedPool, 256);
-  Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
-  Srb.DataTransferLength = 255; //256;
-  Srb.CdbLength = 6;
-
-  Cdb = (PCDB) &Srb.Cdb;
-
-  Cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
-  Cdb->CDB6INQUIRY.AllocationLength = 255;
-
-  for (Bus = 0; Bus < DeviceExtension->PortConfig->NumberOfBuses; Bus++)
-    {
-      Srb.PathId = Bus;
-
-      for (Target = 0; Target <
DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
-       {
-         Srb.TargetId = Target;
-
-         for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
-           {
-             Srb.Lun = Lun;
-             Srb.SrbStatus = SRB_STATUS_SUCCESS;
-
-             Cdb->CDB6INQUIRY.LogicalUnitNumber = Lun;
-
-             LunExtension = SpiAllocateLunExtension (DeviceExtension,
-                                                     Bus,
-                                                     Target,
-                                                     Lun);
-             if (LunExtension == NULL)
-               {
-                 DPRINT("Failed to allocate the LUN extension!\n");
-                 ExFreePool(Srb.DataBuffer);
-                 return;
-               }
-
-             Status = SpiSendInquiry (DeviceExtension->DeviceObject,
-                                      &Srb);
-             DPRINT ("Status %lx  Srb.SrbStatus %x\n", Status, Srb.SrbStatus);
-
-             if (NT_SUCCESS(Status) &&
-                 (Srb.SrbStatus == SRB_STATUS_SUCCESS ||
-                  Srb.SrbStatus == SRB_STATUS_DATA_OVERRUN) &&
-                 ((PINQUIRYDATA)Srb.DataBuffer)->DeviceTypeQualifier == 0)
-               {
-                 /* Copy inquiry data */
-                 RtlCopyMemory (&LunExtension->InquiryData,
-                                Srb.DataBuffer,
-                                sizeof(INQUIRYDATA));
-               }
-             else
-               {
-                 SpiRemoveLunExtension (LunExtension);
-               }
-           }
-       }
-    }
-
-  ExFreePool(Srb.DataBuffer);
-
-  DPRINT ("SpiScanAdapter() done\n");
-}
-
-
-static ULONG
+SpiScanAdapter(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
+{
+    PSCSI_PORT_LUN_EXTENSION LunExtension;
+    ULONG Bus;
+    ULONG Target;
+    ULONG Lun;
+    PSCSI_BUS_SCAN_INFO BusScanInfo;
+    PSCSI_LUN_INFO LastLunInfo, LunInfo, LunInfoExists;
+    BOOLEAN DeviceExists;
+    ULONG Hint;
+    NTSTATUS Status;
+    ULONG DevicesFound;
+
+    DPRINT ("SpiScanAdapter() called\n");
+
+    /* Scan all buses */
+    for (Bus = 0; Bus < DeviceExtension->PortConfig->NumberOfBuses; Bus++)
+    {
+        DevicesFound = 0;
+
+        /* Get pointer to the scan information */
+        BusScanInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus];
+
+        if (BusScanInfo)
+        {
+            /* Find the last LUN info in the list */
+            LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
+            LastLunInfo = LunInfo;
+
+            while (LunInfo != NULL)
+            {
+                LastLunInfo = LunInfo;
+                LunInfo = LunInfo->Next;
+            }
+        }
+        else
+        {
+            /* We need to allocate this buffer */
+            BusScanInfo = ExAllocatePool(NonPagedPool, sizeof(SCSI_BUS_SCAN_INFO));
+
+            if (!BusScanInfo)
+            {
+                DPRINT1("Out of resources!\n");
+                return;
+            }
+
+            /* Fill this struct (length and bus ids for now) */
+            BusScanInfo->Length = sizeof(SCSI_BUS_SCAN_INFO);
+            BusScanInfo->LogicalUnitsCount = 0;
+            BusScanInfo->BusIdentifier =
DeviceExtension->PortConfig->InitiatorBusId[Bus];
+            BusScanInfo->LunInfo = NULL;
+
+            /* Set pointer to the last LUN info to NULL */
+            LastLunInfo = NULL;
+        }
+
+        /* Create LUN information structure */
+        LunInfo = ExAllocatePool(PagedPool, sizeof(SCSI_LUN_INFO));
+
+        if (LunInfo == NULL)
+        {
+            DPRINT1("Out of resources!\n");
+            return;
+        }
+
+        RtlZeroMemory(LunInfo, sizeof(SCSI_LUN_INFO));
+
+        /* Create LunExtension */
+        LunExtension = SpiAllocateLunExtension (DeviceExtension);
+
+        /* And send INQUIRY to every target */
+        for (Target = 0; Target <
DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
+        {
+            /* TODO: Support scan bottom-up */
+
+            /* Skip if it's the same address */
+            if (Target == BusScanInfo->BusIdentifier)
+                continue;
+
+            /* Try to find an existing device here */
+            DeviceExists = FALSE;
+            LunInfoExists = BusScanInfo->LunInfo;
+
+            /* Find matching address on this bus */
+            while (LunInfoExists)
+            {
+                if (LunInfoExists->TargetId == Target)
+                {
+                    DeviceExists = TRUE;
+                    break;
+                }
+
+                /* Advance to the next one */
+                LunInfoExists = LunInfoExists->Next;
+            }
+
+            /* No need to bother rescanning, since we already did that before */
+            if (DeviceExists)
+                continue;
+
+            /* Scan all logical units */
+            for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
+            {
+                if (!LunExtension)
+                    break;
+
+                /* Add extension to the list */
+                Hint = (Target + Lun) % LUS_NUMBER;
+                LunExtension->Next = DeviceExtension->LunExtensionList[Hint];
+                DeviceExtension->LunExtensionList[Hint] = LunExtension;
+
+                /* Fill Path, Target, Lun fields */
+                LunExtension->PathId = LunInfo->PathId = Bus;
+                LunExtension->TargetId = LunInfo->TargetId = Target;
+                LunExtension->Lun = LunInfo->Lun = Lun;
+
+                /* Set flag to prevent race conditions */
+                LunExtension->Flags |= SCSI_PORT_SCAN_IN_PROGRESS;
+
+                /* Zero LU extension contents */
+                if (DeviceExtension->LunExtensionSize)
+                {
+                    RtlZeroMemory(LunExtension + 1,
+                                  DeviceExtension->LunExtensionSize);
+                }
+
+                /* Finally send the inquiry command */
+                Status = SpiSendInquiry(DeviceExtension->DeviceObject, LunInfo);
+
+                if (NT_SUCCESS(Status))
+                {
+                    /* Let's see if we really found a device */
+                    PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData;
+
+                    /* Check if this device is unsupported */
+                    if (InquiryData->DeviceTypeQualifier ==
DEVICE_QUALIFIER_NOT_SUPPORTED)
+                    {
+                        DeviceExtension->LunExtensionList[Hint] =
+                            DeviceExtension->LunExtensionList[Hint]->Next;
+
+                        continue;
+                    }
+
+                    /* Clear the "in scan" flag */
+                    LunExtension->Flags &= ~SCSI_PORT_SCAN_IN_PROGRESS;
+
+                    DPRINT("SpiScanAdapter(): Found device of type %d at bus %d tid
%d lun %d\n",
+                        InquiryData->DeviceType, Bus, Target, Lun);
+
+                    /* Add this info to the linked list */
+                    LunInfo->Next = NULL;
+                    if (LastLunInfo)
+                        LastLunInfo->Next = LunInfo;
+                    else
+                        BusScanInfo->LunInfo = LunInfo;
+
+                    /* Store the last LUN info */
+                    LastLunInfo = LunInfo;
+
+                    /* Store DeviceObject */
+                    LunInfo->DeviceObject = DeviceExtension->DeviceObject;
+
+                    /* Allocate another buffer */
+                    LunInfo = ExAllocatePool(PagedPool, sizeof(SCSI_LUN_INFO));
+
+                    if (!LunInfo)
+                    {
+                        DPRINT1("Out of resources!\n");
+                        break;
+                    }
+
+                    RtlZeroMemory(LunInfo, sizeof(SCSI_LUN_INFO));
+
+                    /* Create a new LU extension */
+                    LunExtension = SpiAllocateLunExtension(DeviceExtension);
+
+                    DevicesFound++;
+                }
+                else
+                {
+                    /* Remove this LUN from the list */
+                    DeviceExtension->LunExtensionList[Hint] =
+                        DeviceExtension->LunExtensionList[Hint]->Next;
+
+                    /* Decide whether we are continuing or not */
+                    if (Status == STATUS_INVALID_DEVICE_REQUEST)
+                        continue;
+                    else
+                        break;
+                }
+            }
+        }
+
+        /* Free allocated buffers */
+        if (LunExtension)
+            ExFreePool(LunExtension);
+
+        if (LunInfo)
+            ExFreePool(LunInfo);
+
+        /* Sum what we found */
+        BusScanInfo->LogicalUnitsCount += DevicesFound;
+    }
+
+    DPRINT ("SpiScanAdapter() done\n");
+}
+
+
+static NTSTATUS
 SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
-                 OUT PSCSI_ADAPTER_BUS_INFO AdapterBusInfo)
-{
-  PSCSI_PORT_LUN_EXTENSION LunExtension;
-  PSCSI_INQUIRY_DATA UnitInfo, PrevUnit;
-  ULONG Bus;
-  ULONG Target;
-  ULONG Lun;
-  ULONG UnitCount;
-
-  DPRINT("SpiGetInquiryData() called\n");
-
-  /* Copy inquiry data to the port device extension */
-  AdapterBusInfo->NumberOfBuses = DeviceExtension->PortConfig->NumberOfBuses;
-
-  UnitInfo = (PSCSI_INQUIRY_DATA)
-       ((PUCHAR)AdapterBusInfo + sizeof(SCSI_ADAPTER_BUS_INFO) +
-        (sizeof(SCSI_BUS_DATA) * (AdapterBusInfo->NumberOfBuses - 1)));
-
-  for (Bus = 0; Bus < AdapterBusInfo->NumberOfBuses; Bus++)
-    {
-      AdapterBusInfo->BusData[Bus].InitiatorBusId =
-       DeviceExtension->PortConfig->InitiatorBusId[Bus];
-      AdapterBusInfo->BusData[Bus].InquiryDataOffset =
-       (ULONG)((PUCHAR)UnitInfo - (PUCHAR)AdapterBusInfo);
-
-      PrevUnit = NULL;
-      UnitCount = 0;
-
-      for (Target = 0; Target <
DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
-       {
-         for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
-           {
-             LunExtension = SpiGetLunExtension(DeviceExtension,
-                                               Bus,
-                                               Target,
-                                               Lun);
-             if (LunExtension != NULL)
-               {
-                 DPRINT("(Bus %lu Target %lu Lun %lu)\n",
-                        Bus, Target, Lun);
-
-                 UnitInfo->PathId = Bus;
-                 UnitInfo->TargetId = Target;
-                 UnitInfo->Lun = Lun;
-                 UnitInfo->InquiryDataLength = INQUIRYDATABUFFERSIZE;
-                 RtlCopyMemory (&UnitInfo->InquiryData,
-                                &LunExtension->InquiryData,
-                                INQUIRYDATABUFFERSIZE);
-                 if (PrevUnit != NULL)
-                   {
-                     PrevUnit->NextInquiryDataOffset =
-                       (ULONG)((ULONG_PTR)UnitInfo-(ULONG_PTR)AdapterBusInfo);
-                   }
-                 PrevUnit = UnitInfo;
-                 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)UnitInfo +
sizeof(SCSI_INQUIRY_DATA)+INQUIRYDATABUFFERSIZE-1);
-                 UnitCount++;
-               }
-           }
-       }
-      DPRINT("UnitCount: %lu\n", UnitCount);
-      AdapterBusInfo->BusData[Bus].NumberOfLogicalUnits = UnitCount;
-      if (UnitCount == 0)
-       {
-         AdapterBusInfo->BusData[Bus].InquiryDataOffset = 0;
-       }
-    }
-
-  DPRINT("Data size: %lu\n", (ULONG)UnitInfo - (ULONG)AdapterBusInfo);
-
-  return (ULONG)((PUCHAR)UnitInfo-(PUCHAR)AdapterBusInfo);
+                 PIRP Irp)
+{
+    ULONG InquiryDataSize;
+    PSCSI_LUN_INFO LunInfo;
+    ULONG BusCount, LunCount, Length;
+    PIO_STACK_LOCATION IrpStack;
+    PSCSI_ADAPTER_BUS_INFO AdapterBusInfo;
+    PSCSI_INQUIRY_DATA InquiryData;
+    PSCSI_BUS_DATA BusData;
+    ULONG Bus;
+    PUCHAR Buffer;
+
+    DPRINT("SpiGetInquiryData() called\n");
+
+    /* Get pointer to the buffer */
+    IrpStack = IoGetCurrentIrpStackLocation(Irp);
+    Buffer = Irp->AssociatedIrp.SystemBuffer;
+
+    /* Initialize bus and LUN counters */
+    BusCount = DeviceExtension->BusesConfig->NumberOfBuses;
+    LunCount = 0;
+
+    /* Calculate total number of LUNs */
+    for (Bus = 0; Bus < BusCount; Bus++)
+        LunCount +=
DeviceExtension->BusesConfig->BusScanInfo[Bus]->LogicalUnitsCount;
+
+    /* Calculate size of inquiry data, rounding up to sizeof(ULONG) */
+    InquiryDataSize =
+        ((sizeof(SCSI_INQUIRY_DATA) - 1 + INQUIRYDATABUFFERSIZE +
+        sizeof(ULONG) - 1) & ~(sizeof(ULONG) - 1));
+
+    /* Calculate data size */
+    Length = sizeof(SCSI_ADAPTER_BUS_INFO) + (BusCount - 1) *
+        sizeof(SCSI_BUS_DATA);
+
+    Length += InquiryDataSize * LunCount;
+
+    /* Check, if all data is going to fit into provided buffer */
+    if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < Length)
+    {
+        Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+        return STATUS_BUFFER_TOO_SMALL;
+    }
+
+    /* Store data size in the IRP */
+    Irp->IoStatus.Information = Length;
+
+    DPRINT("Data size: %lu\n", Length);
+
+    AdapterBusInfo = (PSCSI_ADAPTER_BUS_INFO)Buffer;
+
+    AdapterBusInfo->NumberOfBuses = (UCHAR)BusCount;
+
+    /* Point InquiryData to the corresponding place inside Buffer */
+    InquiryData = (PSCSI_INQUIRY_DATA)(Buffer + sizeof(SCSI_ADAPTER_BUS_INFO) +
+        (BusCount - 1) * sizeof(SCSI_BUS_DATA));
+
+    /* Loop each bus */
+    for (Bus = 0; Bus < BusCount; Bus++)
+    {
+        BusData = &AdapterBusInfo->BusData[Bus];
+
+        /* Calculate and save an offset of the inquiry data */
+        BusData->InquiryDataOffset = (PUCHAR)InquiryData - Buffer;
+
+        /* Get a pointer to the LUN information structure */
+        LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
+
+        /* Store Initiator Bus Id */
+        BusData->InitiatorBusId =
+            DeviceExtension->BusesConfig->BusScanInfo[Bus]->BusIdentifier;
+
+        /* Store LUN count */
+        BusData->NumberOfLogicalUnits =
+            DeviceExtension->BusesConfig->BusScanInfo[Bus]->LogicalUnitsCount;
+
+        /* Loop all LUNs */
+        while (LunInfo != NULL)
+        {
+            DPRINT("(Bus %lu Target %lu Lun %lu)\n",
+                Bus, LunInfo->TargetId, LunInfo->Lun);
+
+            /* Fill InquiryData with values */
+            InquiryData->PathId = LunInfo->PathId;
+            InquiryData->TargetId = LunInfo->TargetId;
+            InquiryData->Lun = LunInfo->Lun;
+            InquiryData->InquiryDataLength = INQUIRYDATABUFFERSIZE;
+            InquiryData->DeviceClaimed = LunInfo->DeviceClaimed;
+            InquiryData->NextInquiryDataOffset =
+                (PUCHAR)InquiryData + InquiryDataSize - Buffer;
+
+            /* Copy data in it */
+            RtlCopyMemory(InquiryData->InquiryData,
+                          LunInfo->InquiryData,
+                          INQUIRYDATABUFFERSIZE);
+
+            /* Move to the next LUN */
+            LunInfo = LunInfo->Next;
+            InquiryData = (PSCSI_INQUIRY_DATA) ((PCHAR)InquiryData + InquiryDataSize);
+        }
+
+        /* Either mark the end, or set offset to 0 */
+        if (BusData->NumberOfLogicalUnits != 0)
+            ((PSCSI_INQUIRY_DATA) ((PCHAR) InquiryData -
InquiryDataSize))->NextInquiryDataOffset = 0;
+        else
+            BusData->InquiryDataOffset = 0;
+    }
+
+    /* Finish with success */
+    Irp->IoStatus.Status = STATUS_SUCCESS;
+    return STATUS_SUCCESS;
 }
Modified: trunk/reactos/drivers/storage/scsiport-new/scsiport_int.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/storage/scsiport-n…
==============================================================================
--- trunk/reactos/drivers/storage/scsiport-new/scsiport_int.h (original)
+++ trunk/reactos/drivers/storage/scsiport-new/scsiport_int.h Wed Mar 28 01:15:09 2007
@@ -15,6 +15,12 @@
 #endif
 #define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) +
((D)<<24))
+
+/* Defines how many logical unit arrays will be in a device extension */
+#define LUS_NUMBER 8
+
+/* Flags */
+#define SCSI_PORT_SCAN_IN_PROGRESS 0x8000
 typedef enum _SCSI_PORT_TIMER_STATES
 {
@@ -35,14 +41,20 @@
   ULONG SystemIoBusNumber;
 } SCSI_PORT_DEVICE_BASE, *PSCSI_PORT_DEVICE_BASE;
+typedef struct _SCSI_REQUEST_BLOCK_INFO
+{
+    LIST_ENTRY Requests;
+} SCSI_REQUEST_BLOCK_INFO, *PSCSI_REQUEST_BLOCK_INFO;
 typedef struct _SCSI_PORT_LUN_EXTENSION
 {
-  LIST_ENTRY List;
-
   UCHAR PathId;
   UCHAR TargetId;
   UCHAR Lun;
+
+  ULONG Flags;
+
+  struct _SCSI_PORT_LUN_EXTENSION *Next;
   BOOLEAN DeviceClaimed;
   PDEVICE_OBJECT DeviceObject;
@@ -51,11 +63,39 @@
   KDEVICE_QUEUE DeviceQueue;
+  SCSI_REQUEST_BLOCK_INFO SrbInfo;
+
   /* More data? */
   UCHAR MiniportLunExtension[1]; /* must be the last entry */
 } SCSI_PORT_LUN_EXTENSION, *PSCSI_PORT_LUN_EXTENSION;
+/* Structures for inquiries support */
+
+typedef struct _SCSI_LUN_INFO
+{
+    UCHAR PathId;
+    UCHAR TargetId;
+    UCHAR Lun;
+    BOOLEAN DeviceClaimed;
+    PVOID DeviceObject;
+    struct _SCSI_LUN_INFO *Next;
+    UCHAR InquiryData[INQUIRYDATABUFFERSIZE];
+} SCSI_LUN_INFO, *PSCSI_LUN_INFO;
+
+typedef struct _SCSI_BUS_SCAN_INFO
+{
+    USHORT Length;
+    UCHAR LogicalUnitsCount;
+    UCHAR BusIdentifier;
+    PSCSI_LUN_INFO LunInfo;
+} SCSI_BUS_SCAN_INFO, *PSCSI_BUS_SCAN_INFO;
+
+typedef struct _BUSES_CONFIGURATION_INFORMATION
+{
+    UCHAR NumberOfBuses;
+    PSCSI_BUS_SCAN_INFO BusScanInfo[1];
+} BUSES_CONFIGURATION_INFORMATION, *PBUSES_CONFIGURATION_INFORMATION;
 /*
  * SCSI_PORT_DEVICE_EXTENSION
@@ -70,6 +110,7 @@
   ULONG Length;
   ULONG MiniPortExtensionSize;
   PPORT_CONFIGURATION_INFORMATION PortConfig;
+  PBUSES_CONFIGURATION_INFORMATION BusesConfig;
   ULONG PortNumber;
   KSPIN_LOCK IrpLock;
@@ -84,7 +125,7 @@
   LIST_ENTRY DeviceBaseListHead;
   ULONG LunExtensionSize;
-  LIST_ENTRY LunExtensionListHead;
+  PSCSI_PORT_LUN_EXTENSION LunExtensionList[LUS_NUMBER];
   ULONG SrbExtensionSize;