ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

scsiport.c
Go to the documentation of this file.
00001 /*
00002  *  ReactOS kernel
00003  *  Copyright (C) 2001, 2002 ReactOS Team
00004  *
00005  *  This program is free software; you can redistribute it and/or modify
00006  *  it under the terms of the GNU General Public License as published by
00007  *  the Free Software Foundation; either version 2 of the License, or
00008  *  (at your option) any later version.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License along
00016  *  with this program; if not, write to the Free Software Foundation, Inc.,
00017  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00018  */
00019 /*
00020  * COPYRIGHT:       See COPYING in the top level directory
00021  * PROJECT:         ReactOS Storage Stack
00022  * FILE:            drivers/storage/scsiport/scsiport.c
00023  * PURPOSE:         SCSI port driver
00024  * PROGRAMMER:      Eric Kohl
00025  *                  Aleksey Bragin (aleksey reactos org)
00026  */
00027 
00028 /* INCLUDES *****************************************************************/
00029 
00030 #include "precomp.h"
00031 
00032 #ifndef NDEBUG
00033 #define NDEBUG
00034 #endif
00035 #include <debug.h>
00036 
00037 ULONG InternalDebugLevel = 0x00;
00038 
00039 #undef ScsiPortMoveMemory
00040 
00041 /* TYPES *********************************************************************/
00042 
00043 /* GLOBALS *******************************************************************/
00044 
00045 static BOOLEAN
00046 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject,
00047                     IN PDEVICE_OBJECT DeviceObject,
00048                     IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
00049                     IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,
00050                     IN PUNICODE_STRING RegistryPath,
00051                     IN ULONG BusNumber,
00052                     IN OUT PPCI_SLOT_NUMBER NextSlotNumber);
00053 
00054 static NTSTATUS NTAPI
00055 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
00056             IN PIRP Irp);
00057 
00058 static DRIVER_DISPATCH ScsiPortDispatchScsi;
00059 static NTSTATUS NTAPI
00060 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
00061              IN PIRP Irp);
00062 
00063 static NTSTATUS NTAPI
00064 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
00065               IN PIRP Irp);
00066 
00067 static DRIVER_STARTIO ScsiPortStartIo;
00068 static VOID NTAPI
00069 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
00070         IN PIRP Irp);
00071 
00072 static BOOLEAN NTAPI
00073 ScsiPortStartPacket(IN OUT PVOID Context);
00074 
00075 IO_ALLOCATION_ACTION
00076 NTAPI
00077 SpiAdapterControl(PDEVICE_OBJECT DeviceObject, PIRP Irp,
00078                   PVOID MapRegisterBase, PVOID Context);
00079 
00080 static PSCSI_PORT_LUN_EXTENSION
00081 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
00082 
00083 static PSCSI_PORT_LUN_EXTENSION
00084 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
00085             IN UCHAR PathId,
00086             IN UCHAR TargetId,
00087             IN UCHAR Lun);
00088 
00089 static PSCSI_REQUEST_BLOCK_INFO
00090 SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
00091                          PSCSI_PORT_LUN_EXTENSION LunExtension,
00092                          PSCSI_REQUEST_BLOCK Srb);
00093 
00094 static NTSTATUS
00095 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject,
00096         IN PSCSI_LUN_INFO LunInfo);
00097 
00098 static VOID
00099 SpiScanAdapter (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
00100 
00101 static NTSTATUS
00102 SpiGetInquiryData (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
00103            IN PIRP Irp);
00104 
00105 static PSCSI_REQUEST_BLOCK_INFO
00106 SpiGetSrbData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
00107               IN UCHAR PathId,
00108               IN UCHAR TargetId,
00109               IN UCHAR Lun,
00110               IN UCHAR QueueTag);
00111 
00112 static BOOLEAN NTAPI
00113 ScsiPortIsr(IN PKINTERRUPT Interrupt,
00114         IN PVOID ServiceContext);
00115 
00116 static VOID NTAPI
00117 ScsiPortDpcForIsr(IN PKDPC Dpc,
00118           IN PDEVICE_OBJECT DpcDeviceObject,
00119           IN PIRP DpcIrp,
00120           IN PVOID DpcContext);
00121 
00122 static VOID NTAPI
00123 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
00124         PVOID Context);
00125 
00126 IO_ALLOCATION_ACTION
00127 NTAPI
00128 ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject,
00129                                IN PIRP Irp,
00130                                IN PVOID MapRegisterBase,
00131                                IN PVOID Context);
00132 
00133 static NTSTATUS
00134 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
00135            PUNICODE_STRING RegistryPath);
00136 
00137 static NTSTATUS
00138 SpiStatusSrbToNt(UCHAR SrbStatus);
00139 
00140 static VOID
00141 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
00142                     IN PSCSI_REQUEST_BLOCK Srb);
00143 
00144 static IO_COMPLETION_ROUTINE SpiCompletionRoutine;
00145 NTSTATUS NTAPI
00146 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject,
00147                      PIRP Irp,
00148                      PVOID Context);
00149 
00150 static VOID
00151 NTAPI
00152 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
00153                            IN PSCSI_REQUEST_BLOCK_INFO SrbInfo,
00154                            OUT PBOOLEAN NeedToCallStartIo);
00155 
00156 VOID NTAPI
00157 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
00158                          IN PSCSI_PORT_LUN_EXTENSION LunExtension);
00159 
00160 VOID NTAPI
00161 SpiMiniportTimerDpc(IN struct _KDPC *Dpc,
00162                     IN PVOID DeviceObject,
00163                     IN PVOID SystemArgument1,
00164                     IN PVOID SystemArgument2);
00165 
00166 static NTSTATUS
00167 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
00168                     PHW_INITIALIZATION_DATA HwInitData,
00169                     PCONFIGURATION_INFO InternalConfigInfo,
00170                     PPORT_CONFIGURATION_INFORMATION ConfigInfo,
00171                     BOOLEAN FirstCall);
00172 
00173 NTSTATUS NTAPI
00174 SpQueryDeviceCallout(IN PVOID  Context,
00175                      IN PUNICODE_STRING  PathName,
00176                      IN INTERFACE_TYPE  BusType,
00177                      IN ULONG  BusNumber,
00178                      IN PKEY_VALUE_FULL_INFORMATION  *BusInformation,
00179                      IN CONFIGURATION_TYPE  ControllerType,
00180                      IN ULONG  ControllerNumber,
00181                      IN PKEY_VALUE_FULL_INFORMATION  *ControllerInformation,
00182                      IN CONFIGURATION_TYPE  PeripheralType,
00183                      IN ULONG  PeripheralNumber,
00184                      IN PKEY_VALUE_FULL_INFORMATION  *PeripheralInformation);
00185 
00186 static VOID
00187 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
00188                    IN HANDLE Key,
00189                    IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
00190                    IN PCONFIGURATION_INFO InternalConfigInfo,
00191                    IN PUCHAR Buffer);
00192 
00193 static VOID
00194 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData,
00195                     IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor,
00196                     IN PPORT_CONFIGURATION_INFORMATION PortConfig);
00197 
00198 static PCM_RESOURCE_LIST
00199 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
00200                     PPORT_CONFIGURATION_INFORMATION PortConfig);
00201 
00202 static VOID
00203 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
00204 
00205 static NTSTATUS
00206 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
00207                        PIRP Irp);
00208 
00209 static NTSTATUS
00210 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, ULONG NonCachedSize);
00211 
00212 NTHALAPI ULONG NTAPI HalGetBusData(BUS_DATA_TYPE, ULONG, ULONG, PVOID, ULONG);
00213 NTHALAPI ULONG NTAPI HalGetInterruptVector(INTERFACE_TYPE, ULONG, ULONG, ULONG, PKIRQL, PKAFFINITY);
00214 NTHALAPI NTSTATUS NTAPI HalAssignSlotResources(PUNICODE_STRING, PUNICODE_STRING, PDRIVER_OBJECT, PDEVICE_OBJECT, INTERFACE_TYPE, ULONG, ULONG, PCM_RESOURCE_LIST *);
00215 
00216 /* FUNCTIONS *****************************************************************/
00217 
00218 /**********************************************************************
00219  * NAME                         EXPORTED
00220  *  DriverEntry
00221  *
00222  * DESCRIPTION
00223  *  This function initializes the driver.
00224  *
00225  * RUN LEVEL
00226  *  PASSIVE_LEVEL
00227  *
00228  * ARGUMENTS
00229  *  DriverObject
00230  *      System allocated Driver Object for this driver.
00231  *
00232  *  RegistryPath
00233  *      Name of registry driver service key.
00234  *
00235  * RETURN VALUE
00236  *  Status.
00237  */
00238 
00239 NTSTATUS NTAPI
00240 DriverEntry(IN PDRIVER_OBJECT DriverObject,
00241         IN PUNICODE_STRING RegistryPath)
00242 {
00243     DPRINT("ScsiPort Driver %s\n", VERSION);
00244     return(STATUS_SUCCESS);
00245 }
00246 
00247 
00248 /**********************************************************************
00249  * NAME                         EXPORTED
00250  *  ScsiDebugPrint
00251  *
00252  * DESCRIPTION
00253  *  Prints debugging messages.
00254  *
00255  * RUN LEVEL
00256  *  PASSIVE_LEVEL
00257  *
00258  * ARGUMENTS
00259  *  DebugPrintLevel
00260  *      Debug level of the given message.
00261  *
00262  *  DebugMessage
00263  *      Pointer to printf()-compatible format string.
00264  *
00265  *  ...
00266         Additional output data (see printf()).
00267  *
00268  * RETURN VALUE
00269  *  None.
00270  *
00271  * @implemented
00272  */
00273 
00274 VOID
00275 ScsiDebugPrint(IN ULONG DebugPrintLevel,
00276            IN PCHAR DebugMessage,
00277            ...)
00278 {
00279     char Buffer[256];
00280     va_list ap;
00281 
00282     if (DebugPrintLevel > InternalDebugLevel)
00283         return;
00284 
00285     va_start(ap, DebugMessage);
00286     vsprintf(Buffer, DebugMessage, ap);
00287     va_end(ap);
00288 
00289     DbgPrint(Buffer);
00290 }
00291 
00292 /* An internal helper function for ScsiPortCompleteRequest */
00293 VOID
00294 NTAPI
00295 SpiCompleteRequest(IN PVOID HwDeviceExtension,
00296                    IN PSCSI_REQUEST_BLOCK_INFO SrbInfo,
00297                    IN UCHAR SrbStatus)
00298 {
00299     PSCSI_REQUEST_BLOCK Srb;
00300 
00301     /* Get current SRB */
00302     Srb = SrbInfo->Srb;
00303 
00304     /* Return if there is no SRB or it is not active */
00305     if (!Srb || !(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE)) return;
00306 
00307     /* Set status */
00308     Srb->SrbStatus = SrbStatus;
00309 
00310     /* Set data transfered to 0 */
00311     Srb->DataTransferLength = 0;
00312 
00313     /* Notify */
00314     ScsiPortNotification(RequestComplete,
00315                          HwDeviceExtension,
00316                          Srb);
00317 }
00318 
00319 /*
00320  * @unimplemented
00321  */
00322 VOID NTAPI
00323 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension,
00324                         IN UCHAR PathId,
00325                         IN UCHAR TargetId,
00326                         IN UCHAR Lun,
00327                         IN UCHAR SrbStatus)
00328 {
00329     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
00330     PSCSI_PORT_LUN_EXTENSION LunExtension;
00331     PSCSI_REQUEST_BLOCK_INFO SrbInfo;
00332     PLIST_ENTRY ListEntry;
00333     ULONG BusNumber;
00334     ULONG Target;
00335 
00336     DPRINT("ScsiPortCompleteRequest() called\n");
00337 
00338     DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
00339                                         SCSI_PORT_DEVICE_EXTENSION,
00340                                         MiniPortDeviceExtension);
00341 
00342     /* Go through all buses */
00343     for (BusNumber = 0; BusNumber < 8; BusNumber++)
00344     {
00345         /* Go through all targets */
00346         for (Target = 0; Target < DeviceExtension->MaxTargedIds; Target++)
00347         {
00348             /* Get logical unit list head */
00349             LunExtension = DeviceExtension->LunExtensionList[Target % 8];
00350 
00351             /* Go through all logical units */
00352             while (LunExtension)
00353             {
00354                 /* Now match what caller asked with what we are at now */
00355                 if ((PathId == SP_UNTAGGED || PathId == LunExtension->PathId) &&
00356                     (TargetId == SP_UNTAGGED || TargetId == LunExtension->TargetId) &&
00357                     (Lun == SP_UNTAGGED || Lun == LunExtension->Lun))
00358                 {
00359                     /* Yes, that's what caller asked for. Complete abort requests */
00360                     if (LunExtension->CompletedAbortRequests)
00361                     {
00362                         /* TODO: Save SrbStatus in this request */
00363                         DPRINT1("Completing abort request without setting SrbStatus!\n");
00364 
00365                         /* Issue a notification request */
00366                         ScsiPortNotification(RequestComplete,
00367                                              HwDeviceExtension,
00368                                              LunExtension->CompletedAbortRequests);
00369                     }
00370 
00371                     /* Complete the request using our helper */
00372                     SpiCompleteRequest(HwDeviceExtension,
00373                                        &LunExtension->SrbInfo,
00374                                        SrbStatus);
00375 
00376                     /* Go through the queue and complete everything there too */
00377                     ListEntry = LunExtension->SrbInfo.Requests.Flink;
00378                     while (ListEntry != &LunExtension->SrbInfo.Requests)
00379                     {
00380                         /* Get the actual SRB info entry */
00381                         SrbInfo = CONTAINING_RECORD(ListEntry,
00382                                                     SCSI_REQUEST_BLOCK_INFO,
00383                                                     Requests);
00384 
00385                         /* Complete it */
00386                         SpiCompleteRequest(HwDeviceExtension,
00387                                            SrbInfo,
00388                                            SrbStatus);
00389 
00390                         /* Advance to the next request in queue */
00391                         ListEntry = SrbInfo->Requests.Flink;
00392                     }
00393                 }
00394 
00395                 /* Advance to the next one */
00396                 LunExtension = LunExtension->Next;
00397             }
00398         }
00399     }
00400 }
00401 
00402 /*
00403  * @unimplemented
00404  */
00405 VOID NTAPI
00406 ScsiPortFlushDma(IN PVOID HwDeviceExtension)
00407 {
00408   DPRINT("ScsiPortFlushDma()\n");
00409   UNIMPLEMENTED;
00410 }
00411 
00412 
00413 /*
00414  * @implemented
00415  */
00416 VOID NTAPI
00417 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension,
00418                IN PVOID MappedAddress)
00419 {
00420     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
00421     PMAPPED_ADDRESS NextMa, LastMa;
00422 
00423     //DPRINT("ScsiPortFreeDeviceBase() called\n");
00424 
00425     DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
00426                                         SCSI_PORT_DEVICE_EXTENSION,
00427                                         MiniPortDeviceExtension);
00428 
00429     /* Initialize our pointers */
00430     NextMa = DeviceExtension->MappedAddressList;
00431     LastMa = NextMa;
00432 
00433     while (NextMa)
00434     {
00435         if (NextMa->MappedAddress == MappedAddress)
00436         {
00437             /* Unmap it first */
00438             MmUnmapIoSpace(MappedAddress, NextMa->NumberOfBytes);
00439 
00440             /* Remove it from the list */
00441             if (NextMa == DeviceExtension->MappedAddressList)
00442             {
00443                 /* Remove the first entry */
00444                 DeviceExtension->MappedAddressList = NextMa->NextMappedAddress;
00445             }
00446             else
00447             {
00448                 LastMa->NextMappedAddress = NextMa->NextMappedAddress;
00449             }
00450 
00451             /* Free the resources and quit */
00452             ExFreePool(NextMa);
00453 
00454             return;
00455         }
00456         else
00457         {
00458             LastMa = NextMa;
00459             NextMa = NextMa->NextMappedAddress;
00460         }
00461     }
00462 }
00463 
00464 
00465 /*
00466  * @implemented
00467  */
00468 ULONG NTAPI
00469 ScsiPortGetBusData(IN PVOID DeviceExtension,
00470            IN ULONG BusDataType,
00471            IN ULONG SystemIoBusNumber,
00472            IN ULONG SlotNumber,
00473            IN PVOID Buffer,
00474            IN ULONG Length)
00475 {
00476     DPRINT("ScsiPortGetBusData()\n");
00477 
00478     if (Length)
00479     {
00480         /* If Length is non-zero, just forward the call to
00481         HalGetBusData() function */
00482         return HalGetBusData(BusDataType,
00483                              SystemIoBusNumber,
00484                              SlotNumber,
00485                              Buffer,
00486                              Length);
00487     }
00488 
00489     /* We have a more complex case here */
00490     UNIMPLEMENTED;
00491     return 0;
00492 }
00493 
00494 /*
00495  * @implemented
00496  */
00497 ULONG NTAPI
00498 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension,
00499                            IN ULONG BusDataType,
00500                            IN ULONG SystemIoBusNumber,
00501                            IN ULONG SlotNumber,
00502                            IN PVOID Buffer,
00503                            IN ULONG Offset,
00504                            IN ULONG Length)
00505 {
00506     DPRINT("ScsiPortSetBusDataByOffset()\n");
00507     return HalSetBusDataByOffset(BusDataType,
00508                                  SystemIoBusNumber,
00509                                  SlotNumber,
00510                                  Buffer,
00511                                  Offset,
00512                                  Length);
00513 }
00514 
00515 /*
00516  * @implemented
00517  */
00518 PVOID NTAPI
00519 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension,
00520               IN INTERFACE_TYPE BusType,
00521               IN ULONG SystemIoBusNumber,
00522               IN SCSI_PHYSICAL_ADDRESS IoAddress,
00523               IN ULONG NumberOfBytes,
00524               IN BOOLEAN InIoSpace)
00525 {
00526     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
00527     PHYSICAL_ADDRESS TranslatedAddress;
00528     PMAPPED_ADDRESS DeviceBase;
00529     ULONG AddressSpace;
00530     PVOID MappedAddress;
00531 
00532     //DPRINT ("ScsiPortGetDeviceBase() called\n");
00533 
00534     DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
00535                                         SCSI_PORT_DEVICE_EXTENSION,
00536                                         MiniPortDeviceExtension);
00537 
00538     AddressSpace = (ULONG)InIoSpace;
00539     if (HalTranslateBusAddress(BusType,
00540                                SystemIoBusNumber,
00541                                IoAddress,
00542                                &AddressSpace,
00543                                &TranslatedAddress) == FALSE)
00544     {
00545         return NULL;
00546     }
00547 
00548     /* i/o space */
00549     if (AddressSpace != 0)
00550         return((PVOID)(ULONG_PTR)TranslatedAddress.QuadPart);
00551 
00552     MappedAddress = MmMapIoSpace(TranslatedAddress,
00553                                  NumberOfBytes,
00554                                  FALSE);
00555 
00556     DeviceBase = ExAllocatePoolWithTag(NonPagedPool,
00557                                 sizeof(MAPPED_ADDRESS), TAG_SCSIPORT);
00558 
00559     if (DeviceBase == NULL)
00560         return MappedAddress;
00561 
00562     DeviceBase->MappedAddress = MappedAddress;
00563     DeviceBase->NumberOfBytes = NumberOfBytes;
00564     DeviceBase->IoAddress = IoAddress;
00565     DeviceBase->BusNumber = SystemIoBusNumber;
00566 
00567     /* Link it to the Device Extension list */
00568     DeviceBase->NextMappedAddress = DeviceExtension->MappedAddressList;
00569     DeviceExtension->MappedAddressList = DeviceBase;
00570 
00571     return MappedAddress;
00572 }
00573 
00574 /*
00575  * @unimplemented
00576  */
00577 PVOID NTAPI
00578 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension,
00579                IN UCHAR PathId,
00580                IN UCHAR TargetId,
00581                IN UCHAR Lun)
00582 {
00583     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
00584     PSCSI_PORT_LUN_EXTENSION LunExtension;
00585 
00586     DPRINT("ScsiPortGetLogicalUnit() called\n");
00587 
00588     DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
00589                                         SCSI_PORT_DEVICE_EXTENSION,
00590                                         MiniPortDeviceExtension);
00591 
00592     /* Check the extension size */
00593     if (!DeviceExtension->LunExtensionSize)
00594     {
00595         /* They didn't want one */
00596         return NULL;
00597     }
00598 
00599     LunExtension = SpiGetLunExtension(DeviceExtension,
00600                                       PathId,
00601                                       TargetId,
00602                                       Lun);
00603     /* Check that the logical unit exists */
00604     if (!LunExtension)
00605     {
00606         /* Nope, return NULL */
00607         return NULL;
00608     }
00609 
00610     /* Return the logical unit miniport extension */
00611     return (LunExtension + 1);
00612 }
00613 
00614 
00615 /*
00616  * @implemented
00617  */
00618 SCSI_PHYSICAL_ADDRESS NTAPI
00619 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension,
00620                            IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
00621                            IN PVOID VirtualAddress,
00622                            OUT ULONG *Length)
00623 {
00624     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
00625     SCSI_PHYSICAL_ADDRESS PhysicalAddress;
00626     ULONG BufferLength = 0;
00627     ULONG Offset;
00628     PSCSI_SG_ADDRESS SGList;
00629     PSCSI_REQUEST_BLOCK_INFO SrbInfo;
00630 
00631     DPRINT("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
00632         HwDeviceExtension, Srb, VirtualAddress, Length);
00633 
00634     DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
00635                                         SCSI_PORT_DEVICE_EXTENSION,
00636                                         MiniPortDeviceExtension);
00637 
00638     if (Srb == NULL || Srb->SenseInfoBuffer == VirtualAddress)
00639     {
00640         /* Simply look it up in the allocated common buffer */
00641         Offset = (PUCHAR)VirtualAddress - (PUCHAR)DeviceExtension->SrbExtensionBuffer;
00642 
00643         BufferLength = DeviceExtension->CommonBufferLength - Offset;
00644         PhysicalAddress.QuadPart = DeviceExtension->PhysicalAddress.QuadPart + Offset;
00645     }
00646     else if (DeviceExtension->MapRegisters)
00647     {
00648         /* Scatter-gather list must be used */
00649         SrbInfo = SpiGetSrbData(DeviceExtension,
00650                                Srb->PathId,
00651                                Srb->TargetId,
00652                                Srb->Lun,
00653                                Srb->QueueTag);
00654 
00655         SGList = SrbInfo->ScatterGather;
00656 
00657         /* Find needed item in the SG list */
00658         Offset = (PCHAR)VirtualAddress - (PCHAR)Srb->DataBuffer;
00659         while (Offset >= SGList->Length)
00660         {
00661             Offset -= SGList->Length;
00662             SGList++;
00663         }
00664 
00665         /* We're done, store length and physical address */
00666         BufferLength = SGList->Length - Offset;
00667         PhysicalAddress.QuadPart = SGList->PhysicalAddress.QuadPart + Offset;
00668     }
00669     else
00670     {
00671         /* Nothing */
00672         *Length = 0;
00673         PhysicalAddress.QuadPart = (LONGLONG)(SP_UNINITIALIZED_VALUE);
00674     }
00675 
00676     *Length = BufferLength;
00677     return PhysicalAddress;
00678 }
00679 
00680 
00681 /*
00682  * @unimplemented
00683  */
00684 PSCSI_REQUEST_BLOCK NTAPI
00685 ScsiPortGetSrb(IN PVOID DeviceExtension,
00686            IN UCHAR PathId,
00687            IN UCHAR TargetId,
00688            IN UCHAR Lun,
00689            IN LONG QueueTag)
00690 {
00691   DPRINT1("ScsiPortGetSrb() unimplemented\n");
00692   UNIMPLEMENTED;
00693   return NULL;
00694 }
00695 
00696 
00697 /*
00698  * @implemented
00699  */
00700 PVOID NTAPI
00701 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension,
00702                  IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
00703                  IN ULONG NumberOfBytes)
00704 {
00705     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
00706     DEVICE_DESCRIPTION DeviceDescription;
00707     ULONG MapRegistersCount;
00708     NTSTATUS Status;
00709 
00710     DPRINT("ScsiPortGetUncachedExtension(%p %p %lu)\n",
00711         HwDeviceExtension, ConfigInfo, NumberOfBytes);
00712 
00713     DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
00714                                         SCSI_PORT_DEVICE_EXTENSION,
00715                                         MiniPortDeviceExtension);
00716 
00717     /* Check for allocated common DMA buffer */
00718     if (DeviceExtension->SrbExtensionBuffer != NULL)
00719     {
00720         DPRINT1("The HBA has already got a common DMA buffer!\n");
00721         return NULL;
00722     }
00723 
00724     /* Check for DMA adapter object */
00725     if (DeviceExtension->AdapterObject == NULL)
00726     {
00727         /* Initialize DMA adapter description */
00728         RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
00729 
00730         DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
00731         DeviceDescription.Master = ConfigInfo->Master;
00732         DeviceDescription.ScatterGather = ConfigInfo->ScatterGather;
00733         DeviceDescription.DemandMode = ConfigInfo->DemandMode;
00734         DeviceDescription.Dma32BitAddresses = ConfigInfo->Dma32BitAddresses;
00735         DeviceDescription.BusNumber = ConfigInfo->SystemIoBusNumber;
00736         DeviceDescription.DmaChannel = ConfigInfo->DmaChannel;
00737         DeviceDescription.InterfaceType = ConfigInfo->AdapterInterfaceType;
00738         DeviceDescription.DmaWidth = ConfigInfo->DmaWidth;
00739         DeviceDescription.DmaSpeed = ConfigInfo->DmaSpeed;
00740         DeviceDescription.MaximumLength = ConfigInfo->MaximumTransferLength;
00741         DeviceDescription.DmaPort = ConfigInfo->DmaPort;
00742 
00743         /* Get a DMA adapter object */
00744         DeviceExtension->AdapterObject =
00745             HalGetAdapter(&DeviceDescription, &MapRegistersCount);
00746 
00747         /* Fail in case of error */
00748         if (DeviceExtension->AdapterObject == NULL)
00749         {
00750             DPRINT1("HalGetAdapter() failed\n");
00751             return NULL;
00752         }
00753 
00754         /* Set number of physical breaks */
00755         if (ConfigInfo->NumberOfPhysicalBreaks != 0 &&
00756             MapRegistersCount > ConfigInfo->NumberOfPhysicalBreaks)
00757         {
00758             DeviceExtension->PortCapabilities.MaximumPhysicalPages =
00759                 ConfigInfo->NumberOfPhysicalBreaks;
00760         }
00761         else
00762         {
00763             DeviceExtension->PortCapabilities.MaximumPhysicalPages = MapRegistersCount;
00764         }
00765     }
00766 
00767     /* Update auto request sense feature */
00768     DeviceExtension->SupportsAutoSense = ConfigInfo->AutoRequestSense;
00769 
00770     /* Update Srb extension size */
00771     if (DeviceExtension->SrbExtensionSize != ConfigInfo->SrbExtensionSize)
00772         DeviceExtension->SrbExtensionSize = ConfigInfo->SrbExtensionSize;
00773 
00774     /* Update Srb extension alloc flag */
00775     if (ConfigInfo->AutoRequestSense || DeviceExtension->SrbExtensionSize)
00776         DeviceExtension->NeedSrbExtensionAlloc = TRUE;
00777 
00778     /* Allocate a common DMA buffer */
00779     Status = SpiAllocateCommonBuffer(DeviceExtension, NumberOfBytes);
00780 
00781     if (!NT_SUCCESS(Status))
00782     {
00783         DPRINT1("SpiAllocateCommonBuffer() failed with Status = 0x%08X!\n", Status);
00784         return NULL;
00785     }
00786 
00787     return DeviceExtension->NonCachedExtension;
00788 }
00789 
00790 static NTSTATUS
00791 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, ULONG NonCachedSize)
00792 {
00793     PVOID *SrbExtension, CommonBuffer;
00794     ULONG CommonBufferLength, BufSize;
00795 
00796     /* If size is 0, set it to 16 */
00797     if (!DeviceExtension->SrbExtensionSize)
00798         DeviceExtension->SrbExtensionSize = 16;
00799 
00800     /* Calculate size */
00801     BufSize = DeviceExtension->SrbExtensionSize;
00802 
00803     /* Add autosense data size if needed */
00804     if (DeviceExtension->SupportsAutoSense)
00805         BufSize += sizeof(SENSE_DATA);
00806 
00807 
00808     /* Round it */
00809     BufSize = (BufSize + sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1);
00810 
00811     /* Sum up into the total common buffer length, and round it to page size */
00812     CommonBufferLength =
00813         ROUND_TO_PAGES(NonCachedSize + BufSize * DeviceExtension->RequestsNumber);
00814 
00815     /* Allocate it */
00816     if (!DeviceExtension->AdapterObject)
00817     {
00818         /* From nonpaged pool if there is no DMA */
00819         CommonBuffer = ExAllocatePoolWithTag(NonPagedPool, CommonBufferLength, TAG_SCSIPORT);
00820     }
00821     else
00822     {
00823         /* Perform a full request since we have a DMA adapter*/
00824         CommonBuffer = HalAllocateCommonBuffer(DeviceExtension->AdapterObject,
00825             CommonBufferLength,
00826             &DeviceExtension->PhysicalAddress,
00827             FALSE );
00828     }
00829 
00830     /* Fail in case of error */
00831     if (!CommonBuffer)
00832         return STATUS_INSUFFICIENT_RESOURCES;
00833 
00834     /* Zero it */
00835     RtlZeroMemory(CommonBuffer, CommonBufferLength);
00836 
00837     /* Store its size in Device Extension */
00838     DeviceExtension->CommonBufferLength = CommonBufferLength;
00839 
00840     /* SrbExtension buffer is located at the beginning of the buffer */
00841     DeviceExtension->SrbExtensionBuffer = CommonBuffer;
00842 
00843     /* Non-cached extension buffer is located at the end of
00844        the common buffer */
00845     if (NonCachedSize)
00846     {
00847         CommonBufferLength -=  NonCachedSize;
00848         DeviceExtension->NonCachedExtension = (PUCHAR)CommonBuffer + CommonBufferLength;
00849     }
00850     else
00851     {
00852         DeviceExtension->NonCachedExtension = NULL;
00853     }
00854 
00855     if (DeviceExtension->NeedSrbExtensionAlloc)
00856     {
00857         /* Look up how many SRB data structures we need */
00858         DeviceExtension->SrbDataCount = CommonBufferLength / BufSize;
00859 
00860         /* Initialize the free SRB extensions list */
00861         SrbExtension = (PVOID *)CommonBuffer;
00862         DeviceExtension->FreeSrbExtensions = SrbExtension;
00863 
00864         /* Fill the remainding pointers (if we have more than 1 SRB) */
00865         while (CommonBufferLength >= 2 * BufSize)
00866         {
00867             *SrbExtension = (PVOID*)((PCHAR)SrbExtension + BufSize);
00868             SrbExtension = *SrbExtension;
00869 
00870             CommonBufferLength -= BufSize;
00871         }
00872     }
00873 
00874     return STATUS_SUCCESS;
00875 }
00876 
00877 
00878 
00879 /*
00880  * @implemented
00881  */
00882 PVOID NTAPI
00883 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension,
00884                           IN SCSI_PHYSICAL_ADDRESS PhysicalAddress)
00885 {
00886     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
00887     ULONG Offset;
00888 
00889     DPRINT("ScsiPortGetVirtualAddress(%p %I64x)\n",
00890         HwDeviceExtension, PhysicalAddress.QuadPart);
00891 
00892     DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
00893                                         SCSI_PORT_DEVICE_EXTENSION,
00894                                         MiniPortDeviceExtension);
00895 
00896     if (DeviceExtension->PhysicalAddress.QuadPart > PhysicalAddress.QuadPart)
00897         return NULL;
00898 
00899     Offset = (ULONG)(PhysicalAddress.QuadPart - DeviceExtension->PhysicalAddress.QuadPart);
00900 
00901     if (Offset >= DeviceExtension->CommonBufferLength)
00902         return NULL;
00903 
00904     return (PVOID)((ULONG_PTR)DeviceExtension->SrbExtensionBuffer + Offset);
00905 }
00906 
00907 static VOID
00908 SpiInitOpenKeys(PCONFIGURATION_INFO ConfigInfo, PUNICODE_STRING RegistryPath)
00909 {
00910     OBJECT_ATTRIBUTES ObjectAttributes;
00911     UNICODE_STRING KeyName;
00912     NTSTATUS Status;
00913 
00914     /* Open the service key */
00915     InitializeObjectAttributes(&ObjectAttributes,
00916                                RegistryPath,
00917                                OBJ_CASE_INSENSITIVE,
00918                                NULL,
00919                                NULL);
00920 
00921     Status = ZwOpenKey(&ConfigInfo->ServiceKey,
00922                        KEY_READ,
00923                        &ObjectAttributes);
00924 
00925     if (!NT_SUCCESS(Status))
00926     {
00927         DPRINT("Unable to open driver's registry key %wZ, status 0x%08x\n", RegistryPath, Status);
00928         ConfigInfo->ServiceKey = NULL;
00929     }
00930 
00931     /* If we could open driver's service key, then proceed to the Parameters key */
00932     if (ConfigInfo->ServiceKey != NULL)
00933     {
00934         RtlInitUnicodeString(&KeyName, L"Parameters");
00935         InitializeObjectAttributes(&ObjectAttributes,
00936                                    &KeyName,
00937                                    OBJ_CASE_INSENSITIVE,
00938                                    ConfigInfo->ServiceKey,
00939                                    (PSECURITY_DESCRIPTOR) NULL);
00940 
00941         /* Try to open it */
00942         Status = ZwOpenKey(&ConfigInfo->DeviceKey,
00943                            KEY_READ,
00944                            &ObjectAttributes);
00945 
00946         if (NT_SUCCESS(Status))
00947         {
00948             /* Yes, Parameters key exist, and it must be used instead of
00949                the Service key */
00950             ZwClose(ConfigInfo->ServiceKey);
00951             ConfigInfo->ServiceKey = ConfigInfo->DeviceKey;
00952             ConfigInfo->DeviceKey = NULL;
00953         }
00954     }
00955 
00956     if (ConfigInfo->ServiceKey != NULL)
00957     {
00958         /* Open the Device key */
00959         RtlInitUnicodeString(&KeyName, L"Device");
00960         InitializeObjectAttributes(&ObjectAttributes,
00961                                    &KeyName,
00962                                    OBJ_CASE_INSENSITIVE,
00963                                    ConfigInfo->ServiceKey,
00964                                    NULL);
00965 
00966         /* We don't check for failure here - not needed */
00967         ZwOpenKey(&ConfigInfo->DeviceKey,
00968                   KEY_READ,
00969                   &ObjectAttributes);
00970     }
00971 }
00972 
00973 
00974 /**********************************************************************
00975  * NAME                         EXPORTED
00976  *  ScsiPortInitialize
00977  *
00978  * DESCRIPTION
00979  *  Initializes SCSI port driver specific data.
00980  *
00981  * RUN LEVEL
00982  *  PASSIVE_LEVEL
00983  *
00984  * ARGUMENTS
00985  *  Argument1
00986  *      Pointer to the miniport driver's driver object.
00987  *
00988  *  Argument2
00989  *      Pointer to the miniport driver's registry path.
00990  *
00991  *  HwInitializationData
00992  *      Pointer to port driver specific configuration data.
00993  *
00994  *  HwContext
00995         Miniport driver specific context.
00996  *
00997  * RETURN VALUE
00998  *  Status.
00999  *
01000  * @implemented
01001  */
01002 
01003 ULONG NTAPI
01004 ScsiPortInitialize(IN PVOID Argument1,
01005            IN PVOID Argument2,
01006            IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
01007            IN PVOID HwContext)
01008 {
01009     PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Argument1;
01010     PUNICODE_STRING RegistryPath = (PUNICODE_STRING)Argument2;
01011     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = NULL;
01012     PCONFIGURATION_INFORMATION SystemConfig;
01013     PPORT_CONFIGURATION_INFORMATION PortConfig;
01014     PORT_CONFIGURATION_INFORMATION InitialPortConfig;
01015     CONFIGURATION_INFO ConfigInfo;
01016     ULONG DeviceExtensionSize;
01017     ULONG PortConfigSize;
01018     BOOLEAN Again;
01019     BOOLEAN DeviceFound = FALSE;
01020     BOOLEAN FirstConfigCall = TRUE;
01021     ULONG Result;
01022     NTSTATUS Status;
01023     ULONG MaxBus;
01024     ULONG BusNumber = 0;
01025     PCI_SLOT_NUMBER SlotNumber;
01026 
01027     PDEVICE_OBJECT PortDeviceObject;
01028     WCHAR NameBuffer[80];
01029     UNICODE_STRING DeviceName;
01030     WCHAR DosNameBuffer[80];
01031     UNICODE_STRING DosDeviceName;
01032     PIO_SCSI_CAPABILITIES PortCapabilities;
01033 
01034     KIRQL OldIrql;
01035     PCM_RESOURCE_LIST ResourceList;
01036     BOOLEAN Conflict;
01037 
01038 
01039     DPRINT ("ScsiPortInitialize() called!\n");
01040 
01041     /* Check params for validity */
01042     if ((HwInitializationData->HwInitialize == NULL) ||
01043         (HwInitializationData->HwStartIo == NULL) ||
01044         (HwInitializationData->HwInterrupt == NULL) ||
01045         (HwInitializationData->HwFindAdapter == NULL) ||
01046         (HwInitializationData->HwResetBus == NULL))
01047     {
01048         return STATUS_INVALID_PARAMETER;
01049     }
01050 
01051     /* Set handlers */
01052     DriverObject->DriverStartIo = ScsiPortStartIo;
01053     DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiPortCreateClose;
01054     DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiPortCreateClose;
01055     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiPortDeviceControl;
01056     DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiPortDispatchScsi;
01057 
01058     /* Obtain configuration information */
01059     SystemConfig = IoGetConfigurationInformation();
01060 
01061     /* Zero the internal configuration info structure */
01062     RtlZeroMemory(&ConfigInfo, sizeof(CONFIGURATION_INFO));
01063 
01064     /* Zero starting slot number */
01065     SlotNumber.u.AsULONG = 0;
01066 
01067     /* Allocate space for access ranges */
01068     if (HwInitializationData->NumberOfAccessRanges)
01069     {
01070         ConfigInfo.AccessRanges =
01071             ExAllocatePoolWithTag(PagedPool,
01072             HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE), TAG_SCSIPORT);
01073 
01074         /* Fail if failed */
01075         if (ConfigInfo.AccessRanges == NULL)
01076             return STATUS_INSUFFICIENT_RESOURCES;
01077     }
01078 
01079     /* Open registry keys */
01080     SpiInitOpenKeys(&ConfigInfo, (PUNICODE_STRING)Argument2);
01081 
01082     /* Last adapter number = not known */
01083     ConfigInfo.LastAdapterNumber = SP_UNINITIALIZED_VALUE;
01084 
01085     /* Calculate sizes of DeviceExtension and PortConfig */
01086     DeviceExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) +
01087         HwInitializationData->DeviceExtensionSize;
01088 
01089     MaxBus = (HwInitializationData->AdapterInterfaceType == PCIBus) ? 8 : 1;
01090     DPRINT("MaxBus: %lu\n", MaxBus);
01091 
01092     while (TRUE)
01093     {
01094         /* Create a unicode device name */
01095         swprintf(NameBuffer,
01096                  L"\\Device\\ScsiPort%lu",
01097                  SystemConfig->ScsiPortCount);
01098         RtlInitUnicodeString(&DeviceName, NameBuffer);
01099 
01100         DPRINT("Creating device: %wZ\n", &DeviceName);
01101 
01102         /* Create the port device */
01103         Status = IoCreateDevice(DriverObject,
01104                                 DeviceExtensionSize,
01105                                 &DeviceName,
01106                                 FILE_DEVICE_CONTROLLER,
01107                                 0,
01108                                 FALSE,
01109                                 &PortDeviceObject);
01110 
01111         if (!NT_SUCCESS(Status))
01112         {
01113             DPRINT1("IoCreateDevice call failed! (Status 0x%lX)\n", Status);
01114             PortDeviceObject = NULL;
01115             break;
01116         }
01117 
01118         DPRINT ("Created device: %wZ (%p)\n", &DeviceName, PortDeviceObject);
01119 
01120         /* Set the buffering strategy here... */
01121         PortDeviceObject->Flags |= DO_DIRECT_IO;
01122         PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT; /* FIXME: Is this really needed? */
01123 
01124         /* Fill Device Extension */
01125         DeviceExtension = PortDeviceObject->DeviceExtension;
01126         RtlZeroMemory(DeviceExtension, DeviceExtensionSize);
01127         DeviceExtension->Length = DeviceExtensionSize;
01128         DeviceExtension->DeviceObject = PortDeviceObject;
01129         DeviceExtension->PortNumber = SystemConfig->ScsiPortCount;
01130 
01131         /* Driver's routines... */
01132         DeviceExtension->HwInitialize = HwInitializationData->HwInitialize;
01133         DeviceExtension->HwStartIo = HwInitializationData->HwStartIo;
01134         DeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
01135         DeviceExtension->HwResetBus = HwInitializationData->HwResetBus;
01136         DeviceExtension->HwDmaStarted = HwInitializationData->HwDmaStarted;
01137 
01138         /* Extensions sizes */
01139         DeviceExtension->MiniPortExtensionSize = HwInitializationData->DeviceExtensionSize;
01140         DeviceExtension->LunExtensionSize = HwInitializationData->SpecificLuExtensionSize;
01141         DeviceExtension->SrbExtensionSize = HwInitializationData->SrbExtensionSize;
01142 
01143         /* Round Srb extension size to the quadword */
01144         DeviceExtension->SrbExtensionSize =
01145             ~(sizeof(LONGLONG) - 1) & (DeviceExtension->SrbExtensionSize +
01146             sizeof(LONGLONG) - 1);
01147 
01148         /* Fill some numbers (bus count, lun count, etc) */
01149         DeviceExtension->MaxLunCount = SCSI_MAXIMUM_LOGICAL_UNITS;
01150         DeviceExtension->RequestsNumber = 16;
01151 
01152         /* Initialize the spin lock in the controller extension */
01153         KeInitializeSpinLock(&DeviceExtension->IrqLock);
01154         KeInitializeSpinLock(&DeviceExtension->SpinLock);
01155 
01156         /* Initialize the DPC object */
01157         IoInitializeDpcRequest(PortDeviceObject,
01158                                ScsiPortDpcForIsr);
01159 
01160         /* Initialize the device timer */
01161         DeviceExtension->TimerCount = -1;
01162         IoInitializeTimer(PortDeviceObject,
01163                           ScsiPortIoTimer,
01164                           DeviceExtension);
01165 
01166         /* Initialize miniport timer */
01167         KeInitializeTimer(&DeviceExtension->MiniportTimer);
01168         KeInitializeDpc(&DeviceExtension->MiniportTimerDpc,
01169                         SpiMiniportTimerDpc,
01170                         PortDeviceObject);
01171 
01172 CreatePortConfig:
01173 
01174         Status = SpiCreatePortConfig(DeviceExtension,
01175                                      HwInitializationData,
01176                                      &ConfigInfo,
01177                                      &InitialPortConfig,
01178                                      FirstConfigCall);
01179 
01180         if (!NT_SUCCESS(Status))
01181         {
01182             DPRINT("SpiCreatePortConfig() failed with Status 0x%08X\n", Status);
01183             break;
01184         }
01185 
01186         /* Allocate and initialize port configuration info */
01187         PortConfigSize = (sizeof(PORT_CONFIGURATION_INFORMATION) +
01188                           HwInitializationData->NumberOfAccessRanges *
01189                           sizeof(ACCESS_RANGE) + 7) & ~7;
01190         DeviceExtension->PortConfig = ExAllocatePoolWithTag(NonPagedPool, PortConfigSize, TAG_SCSIPORT);
01191 
01192         /* Fail if failed */
01193         if (DeviceExtension->PortConfig == NULL)
01194         {
01195             Status = STATUS_INSUFFICIENT_RESOURCES;
01196             break;
01197         }
01198 
01199         PortConfig = DeviceExtension->PortConfig;
01200 
01201         /* Copy information here */
01202         RtlCopyMemory(PortConfig,
01203                       &InitialPortConfig,
01204                       sizeof(PORT_CONFIGURATION_INFORMATION));
01205 
01206 
01207         /* Copy extension sizes into the PortConfig */
01208         PortConfig->SpecificLuExtensionSize = DeviceExtension->LunExtensionSize;
01209         PortConfig->SrbExtensionSize = DeviceExtension->SrbExtensionSize;
01210 
01211         /* Initialize Access ranges */
01212         if (HwInitializationData->NumberOfAccessRanges != 0)
01213         {
01214             PortConfig->AccessRanges = (PVOID)(PortConfig+1);
01215 
01216             /* Align to LONGLONG */
01217             PortConfig->AccessRanges = (PVOID)((ULONG_PTR)(PortConfig->AccessRanges) + 7);
01218             PortConfig->AccessRanges = (PVOID)((ULONG_PTR)(PortConfig->AccessRanges) & ~7);
01219 
01220             /* Copy the data */
01221             RtlCopyMemory(PortConfig->AccessRanges,
01222                           ConfigInfo.AccessRanges,
01223                           HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE));
01224         }
01225 
01226       /* Search for matching PCI device */
01227       if ((HwInitializationData->AdapterInterfaceType == PCIBus) &&
01228           (HwInitializationData->VendorIdLength > 0) &&
01229           (HwInitializationData->VendorId != NULL) &&
01230           (HwInitializationData->DeviceIdLength > 0) &&
01231           (HwInitializationData->DeviceId != NULL))
01232       {
01233           PortConfig->BusInterruptLevel = 0;
01234 
01235           /* Get PCI device data */
01236           DPRINT("VendorId '%.*s'  DeviceId '%.*s'\n",
01237                  HwInitializationData->VendorIdLength,
01238                  HwInitializationData->VendorId,
01239                  HwInitializationData->DeviceIdLength,
01240                  HwInitializationData->DeviceId);
01241 
01242           if (!SpiGetPciConfigData(DriverObject,
01243                                    PortDeviceObject,
01244                                    HwInitializationData,
01245                                    PortConfig,
01246                                    RegistryPath,
01247                                    ConfigInfo.BusNumber,
01248                                    &SlotNumber))
01249           {
01250               /* Continue to the next bus, nothing here */
01251               ConfigInfo.BusNumber++;
01252               DeviceExtension->PortConfig = NULL;
01253               ExFreePool(PortConfig);
01254               Again = FALSE;
01255               goto CreatePortConfig;
01256           }
01257 
01258           if (!PortConfig->BusInterruptLevel)
01259           {
01260               /* Bypass this slot, because no interrupt was assigned */
01261               DeviceExtension->PortConfig = NULL;
01262               ExFreePool(PortConfig);
01263               goto CreatePortConfig;
01264           }
01265       }
01266       else
01267       {
01268           DPRINT("Non-pci bus\n");
01269       }
01270 
01271       /* Note: HwFindAdapter is called once for each bus */
01272       Again = FALSE;
01273       DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber);
01274       Result = (HwInitializationData->HwFindAdapter)(&DeviceExtension->MiniPortDeviceExtension,
01275                                                      HwContext,
01276                                                      0,  /* BusInformation */
01277                                                      ConfigInfo.Parameter, /* ArgumentString */
01278                                                      PortConfig,
01279                                                      &Again);
01280 
01281       DPRINT("HwFindAdapter() Result: %lu  Again: %s\n",
01282              Result, (Again) ? "True" : "False");
01283 
01284       /* Free MapRegisterBase, it's not needed anymore */
01285       if (DeviceExtension->MapRegisterBase != NULL)
01286       {
01287           ExFreePool(DeviceExtension->MapRegisterBase);
01288           DeviceExtension->MapRegisterBase = NULL;
01289       }
01290 
01291       /* If result is nothing good... */
01292       if (Result != SP_RETURN_FOUND)
01293       {
01294           DPRINT("HwFindAdapter() Result: %lu\n", Result);
01295 
01296           if (Result == SP_RETURN_NOT_FOUND)
01297           {
01298               /* We can continue on the next bus */
01299               ConfigInfo.BusNumber++;
01300               Again = FALSE;
01301 
01302               DeviceExtension->PortConfig = NULL;
01303               ExFreePool(PortConfig);
01304               goto CreatePortConfig;
01305           }
01306 
01307           /* Otherwise, break */
01308           Status = STATUS_INTERNAL_ERROR;
01309           break;
01310       }
01311 
01312       DPRINT("ScsiPortInitialize(): Found HBA! (%x), adapter Id %d\n",
01313           PortConfig->BusInterruptVector, PortConfig->InitiatorBusId[0]);
01314 
01315       /* If the SRB extension size was updated */
01316       if (!DeviceExtension->NonCachedExtension &&
01317           (PortConfig->SrbExtensionSize != DeviceExtension->SrbExtensionSize))
01318       {
01319           /* Set it (rounding to LONGLONG again) */
01320           DeviceExtension->SrbExtensionSize =
01321               (PortConfig->SrbExtensionSize +
01322                sizeof(LONGLONG)) & ~(sizeof(LONGLONG) - 1);
01323       }
01324 
01325       /* The same with LUN extension size */
01326       if (PortConfig->SpecificLuExtensionSize != DeviceExtension->LunExtensionSize)
01327           DeviceExtension->LunExtensionSize = PortConfig->SpecificLuExtensionSize;
01328 
01329 
01330       if (!((HwInitializationData->AdapterInterfaceType == PCIBus) &&
01331           (HwInitializationData->VendorIdLength > 0) &&
01332           (HwInitializationData->VendorId != NULL) &&
01333           (HwInitializationData->DeviceIdLength > 0) &&
01334           (HwInitializationData->DeviceId != NULL)))
01335       {
01336           /* Construct a resource list */
01337           ResourceList = SpiConfigToResource(DeviceExtension,
01338                                              PortConfig);
01339 
01340           if (ResourceList)
01341           {
01342               UNICODE_STRING UnicodeString;
01343               RtlInitUnicodeString(&UnicodeString, L"ScsiAdapter");
01344               DPRINT("Reporting resources\n");
01345               Status = IoReportResourceUsage(&UnicodeString,
01346                                              DriverObject,
01347                                              NULL,
01348                                              0,
01349                                              PortDeviceObject,
01350                                              ResourceList,
01351                                              FIELD_OFFSET(CM_RESOURCE_LIST,
01352                                                  List[0].PartialResourceList.PartialDescriptors) +
01353                                                  ResourceList->List[0].PartialResourceList.Count
01354                                                  * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
01355                                              FALSE,
01356                                              &Conflict);
01357               ExFreePool(ResourceList);
01358 
01359               /* In case of a failure or a conflict, break */
01360               if (Conflict || (!NT_SUCCESS(Status)))
01361               {
01362                   if (Conflict)
01363                       Status = STATUS_CONFLICTING_ADDRESSES;
01364                   break;
01365               }
01366             }
01367       }
01368 
01369       /* Reset the Conflict var */
01370       Conflict = FALSE;
01371 
01372       /* Copy all stuff which we ever need from PortConfig to the DeviceExtension */
01373       if (PortConfig->MaximumNumberOfTargets > SCSI_MAXIMUM_TARGETS_PER_BUS)
01374           DeviceExtension->MaxTargedIds = SCSI_MAXIMUM_TARGETS_PER_BUS;
01375       else
01376           DeviceExtension->MaxTargedIds = PortConfig->MaximumNumberOfTargets;
01377 
01378       DeviceExtension->BusNum = PortConfig->NumberOfBuses;
01379       DeviceExtension->CachesData = PortConfig->CachesData;
01380       DeviceExtension->ReceiveEvent = PortConfig->ReceiveEvent;
01381       DeviceExtension->SupportsTaggedQueuing = PortConfig->TaggedQueuing;
01382       DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu;
01383 
01384       /* If something was disabled via registry - apply it */
01385       if (ConfigInfo.DisableMultipleLun)
01386           DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu = FALSE;
01387 
01388       if (ConfigInfo.DisableTaggedQueueing)
01389           DeviceExtension->SupportsTaggedQueuing = PortConfig->MultipleRequestPerLu = FALSE;
01390 
01391       /* Check if we need to alloc SRB data */
01392       if (DeviceExtension->SupportsTaggedQueuing ||
01393           DeviceExtension->MultipleReqsPerLun)
01394       {
01395           DeviceExtension->NeedSrbDataAlloc = TRUE;
01396       }
01397       else
01398       {
01399           DeviceExtension->NeedSrbDataAlloc = FALSE;
01400       }
01401 
01402       /* Get a pointer to the port capabilities */
01403       PortCapabilities = &DeviceExtension->PortCapabilities;
01404 
01405       /* Copy one field there */
01406       DeviceExtension->MapBuffers = PortConfig->MapBuffers;
01407       PortCapabilities->AdapterUsesPio = PortConfig->MapBuffers;
01408 
01409       if (DeviceExtension->AdapterObject == NULL &&
01410           (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE || PortConfig->Master))
01411       {
01412           DPRINT1("DMA is not supported yet\n");
01413           ASSERT(FALSE);
01414       }
01415 
01416       if (DeviceExtension->SrbExtensionBuffer == NULL &&
01417           (DeviceExtension->SrbExtensionSize != 0  ||
01418           PortConfig->AutoRequestSense))
01419       {
01420           DeviceExtension->SupportsAutoSense = PortConfig->AutoRequestSense;
01421           DeviceExtension->NeedSrbExtensionAlloc = TRUE;
01422 
01423           /* Allocate common buffer */
01424           Status = SpiAllocateCommonBuffer(DeviceExtension, 0);
01425 
01426           /* Check for failure */
01427           if (!NT_SUCCESS(Status))
01428               break;
01429       }
01430 
01431       /* Allocate SrbData, if needed */
01432       if (DeviceExtension->NeedSrbDataAlloc)
01433       {
01434           ULONG Count;
01435           PSCSI_REQUEST_BLOCK_INFO SrbData;
01436 
01437           if (DeviceExtension->SrbDataCount != 0)
01438               Count = DeviceExtension->SrbDataCount;
01439           else
01440               Count = DeviceExtension->RequestsNumber * 2;
01441 
01442           /* Allocate the data */
01443           SrbData = ExAllocatePoolWithTag(NonPagedPool, Count * sizeof(SCSI_REQUEST_BLOCK_INFO), TAG_SCSIPORT);
01444           if (SrbData == NULL)
01445               return STATUS_INSUFFICIENT_RESOURCES;
01446 
01447           RtlZeroMemory(SrbData, Count * sizeof(SCSI_REQUEST_BLOCK_INFO));
01448 
01449           DeviceExtension->SrbInfo = SrbData;
01450           DeviceExtension->FreeSrbInfo = SrbData;
01451           DeviceExtension->SrbDataCount = Count;
01452 
01453           /* Link it to the list */
01454           while (Count > 0)
01455           {
01456               SrbData->Requests.Flink = (PLIST_ENTRY)(SrbData + 1);
01457               SrbData++;
01458               Count--;
01459           }
01460 
01461           /* Mark the last entry of the list */
01462           SrbData--;
01463           SrbData->Requests.Flink = NULL;
01464       }
01465 
01466       /* Initialize port capabilities */
01467       PortCapabilities = &DeviceExtension->PortCapabilities;
01468       PortCapabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
01469       PortCapabilities->MaximumTransferLength = PortConfig->MaximumTransferLength;
01470 
01471       if (PortConfig->ReceiveEvent)
01472           PortCapabilities->SupportedAsynchronousEvents |= SRBEV_SCSI_ASYNC_NOTIFICATION;
01473 
01474       PortCapabilities->TaggedQueuing = DeviceExtension->SupportsTaggedQueuing;
01475       PortCapabilities->AdapterScansDown = PortConfig->AdapterScansDown;
01476 
01477       if (PortConfig->AlignmentMask > PortDeviceObject->AlignmentRequirement)
01478           PortDeviceObject->AlignmentRequirement = PortConfig->AlignmentMask;
01479 
01480       PortCapabilities->AlignmentMask = PortDeviceObject->AlignmentRequirement;
01481 
01482       if (PortCapabilities->MaximumPhysicalPages == 0)
01483       {
01484           PortCapabilities->MaximumPhysicalPages =
01485               BYTES_TO_PAGES(PortCapabilities->MaximumTransferLength);
01486 
01487           /* Apply miniport's limits */
01488           if (PortConfig->NumberOfPhysicalBreaks < PortCapabilities->MaximumPhysicalPages)
01489           {
01490               PortCapabilities->MaximumPhysicalPages = PortConfig->NumberOfPhysicalBreaks;
01491           }
01492       }
01493 
01494       /* Deal with interrupts */
01495       if (DeviceExtension->HwInterrupt == NULL ||
01496           (PortConfig->BusInterruptLevel == 0 && PortConfig->BusInterruptVector == 0))
01497       {
01498           /* No interrupts */
01499           DeviceExtension->InterruptCount = 0;
01500 
01501           DPRINT1("Interrupt Count: 0\n");
01502 
01503           UNIMPLEMENTED;
01504 
01505           /* This code path will ALWAYS crash so stop it now */
01506           while(TRUE);
01507       }
01508       else
01509       {
01510           BOOLEAN InterruptShareable;
01511           KINTERRUPT_MODE InterruptMode[2];
01512           ULONG InterruptVector[2], i, MappedIrq[2];
01513           KIRQL Dirql[2], MaxDirql;
01514           KAFFINITY Affinity[2];
01515 
01516           DeviceExtension->InterruptLevel[0] = PortConfig->BusInterruptLevel;
01517           DeviceExtension->InterruptLevel[1] = PortConfig->BusInterruptLevel2;
01518 
01519           InterruptVector[0] = PortConfig->BusInterruptVector;
01520           InterruptVector[1] = PortConfig->BusInterruptVector2;
01521 
01522           InterruptMode[0] = PortConfig->InterruptMode;
01523           InterruptMode[1] = PortConfig->InterruptMode2;
01524 
01525           DeviceExtension->InterruptCount = (PortConfig->BusInterruptLevel2 != 0 || PortConfig->BusInterruptVector2 != 0) ? 2 : 1;
01526 
01527           for (i = 0; i < DeviceExtension->InterruptCount; i++)
01528           {
01529               /* Register an interrupt handler for this device */
01530               MappedIrq[i] = HalGetInterruptVector(PortConfig->AdapterInterfaceType,
01531                                                    PortConfig->SystemIoBusNumber,
01532                                                    DeviceExtension->InterruptLevel[i],
01533                                                    InterruptVector[i],
01534                                                    &Dirql[i],
01535                                                    &Affinity[i]);
01536           }
01537 
01538           if (DeviceExtension->InterruptCount == 1 || Dirql[0] > Dirql[1])
01539               MaxDirql = Dirql[0];
01540           else
01541               MaxDirql = Dirql[1];
01542 
01543           for (i = 0; i < DeviceExtension->InterruptCount; i++)
01544           {
01545               /* Determing IRQ sharability as usual */
01546               if (PortConfig->AdapterInterfaceType == MicroChannel ||
01547                   InterruptMode[i] == LevelSensitive)
01548               {
01549                   InterruptShareable = TRUE;
01550               }
01551               else
01552               {
01553                   InterruptShareable = FALSE;
01554               }
01555 
01556               Status = IoConnectInterrupt(&DeviceExtension->Interrupt[i],
01557                                           (PKSERVICE_ROUTINE)ScsiPortIsr,
01558                                           DeviceExtension,
01559                                           &DeviceExtension->IrqLock,
01560                                           MappedIrq[i],
01561                                           Dirql[i],
01562                                           MaxDirql,
01563                                           InterruptMode[i],
01564                                           InterruptShareable,
01565                                           Affinity[i],
01566                                           FALSE);
01567 
01568               if (!(NT_SUCCESS(Status)))
01569               {
01570                   DPRINT1("Could not connect interrupt %d\n",
01571                           InterruptVector[i]);
01572                   DeviceExtension->Interrupt[i] = NULL;
01573                   break;
01574               }
01575           }
01576 
01577           if (!NT_SUCCESS(Status))
01578               break;
01579       }
01580 
01581       /* Save IoAddress (from access ranges) */
01582       if (HwInitializationData->NumberOfAccessRanges != 0)
01583       {
01584           DeviceExtension->IoAddress =
01585               ((*(PortConfig->AccessRanges))[0]).RangeStart.LowPart;
01586 
01587           DPRINT("Io Address %x\n", DeviceExtension->IoAddress);
01588       }
01589 
01590       /* Set flag that it's allowed to disconnect during this command */
01591       DeviceExtension->Flags |= SCSI_PORT_DISCONNECT_ALLOWED;
01592 
01593       /* Initialize counter of active requests (-1 means there are none) */
01594       DeviceExtension->ActiveRequestCounter = -1;
01595 
01596       /* Analyze what we have about DMA */
01597       if (DeviceExtension->AdapterObject != NULL &&
01598           PortConfig->Master &&
01599           PortConfig->NeedPhysicalAddresses)
01600       {
01601           DeviceExtension->MapRegisters = TRUE;
01602       }
01603       else
01604       {
01605           DeviceExtension->MapRegisters = FALSE;
01606       }
01607 
01608       /* Call HwInitialize at DISPATCH_LEVEL */
01609       KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
01610 
01611       if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0],
01612                                   DeviceExtension->HwInitialize,
01613                                   DeviceExtension->MiniPortDeviceExtension))
01614       {
01615           DPRINT1("HwInitialize() failed!\n");
01616           KeLowerIrql(OldIrql);
01617           Status = STATUS_ADAPTER_HARDWARE_ERROR;
01618           break;
01619       }
01620 
01621       /* Check if a notification is needed */
01622       if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
01623       {
01624           /* Call DPC right away, because we're already at DISPATCH_LEVEL */
01625           ScsiPortDpcForIsr(NULL,
01626                             DeviceExtension->DeviceObject,
01627                             NULL,
01628                             NULL);
01629       }
01630 
01631       /* Lower irql back to what it was */
01632       KeLowerIrql(OldIrql);
01633 
01634       /* Start our timer */
01635       IoStartTimer(PortDeviceObject);
01636 
01637       /* Initialize bus scanning information */
01638       DeviceExtension->BusesConfig = ExAllocatePoolWithTag(PagedPool,
01639           sizeof(PVOID) * DeviceExtension->PortConfig->NumberOfBuses
01640           + sizeof(ULONG), TAG_SCSIPORT);
01641 
01642       if (!DeviceExtension->BusesConfig)
01643       {
01644           DPRINT1("Out of resources!\n");
01645           Status = STATUS_INSUFFICIENT_RESOURCES;
01646           break;
01647       }
01648 
01649       /* Zero it */
01650       RtlZeroMemory(DeviceExtension->BusesConfig,
01651           sizeof(PVOID) * DeviceExtension->PortConfig->NumberOfBuses
01652           + sizeof(ULONG));
01653 
01654       /* Store number of buses there */
01655       DeviceExtension->BusesConfig->NumberOfBuses = (UCHAR)DeviceExtension->BusNum;
01656 
01657       /* Scan the adapter for devices */
01658       SpiScanAdapter(DeviceExtension);
01659 
01660       /* Build the registry device map */
01661       SpiBuildDeviceMap(DeviceExtension,
01662                        (PUNICODE_STRING)Argument2);
01663 
01664       /* Create the dos device link */
01665       swprintf(DosNameBuffer,
01666                L"\\??\\Scsi%lu:",
01667               SystemConfig->ScsiPortCount);
01668       RtlInitUnicodeString(&DosDeviceName, DosNameBuffer);
01669       IoCreateSymbolicLink(&DosDeviceName, &DeviceName);
01670 
01671       /* Increase the port count */
01672       SystemConfig->ScsiPortCount++;
01673       FirstConfigCall = FALSE;
01674 
01675       /* Increase adapter number and bus number respectively */
01676       ConfigInfo.AdapterNumber++;
01677 
01678       if (!Again)
01679           ConfigInfo.BusNumber++;
01680 
01681       DPRINT("Bus: %lu  MaxBus: %lu\n", BusNumber, MaxBus);
01682 
01683       DeviceFound = TRUE;
01684     }
01685 
01686     /* Clean up the mess */
01687     SpiCleanupAfterInit(DeviceExtension);
01688 
01689     /* Close registry keys */
01690     if (ConfigInfo.ServiceKey != NULL)
01691         ZwClose(ConfigInfo.ServiceKey);
01692 
01693     if (ConfigInfo.DeviceKey != NULL)
01694         ZwClose(ConfigInfo.DeviceKey);
01695 
01696     if (ConfigInfo.BusKey != NULL)
01697         ZwClose(ConfigInfo.BusKey);
01698 
01699     if (ConfigInfo.AccessRanges != NULL)
01700         ExFreePool(ConfigInfo.AccessRanges);
01701 
01702     if (ConfigInfo.Parameter != NULL)
01703         ExFreePool(ConfigInfo.Parameter);
01704 
01705     DPRINT("ScsiPortInitialize() done, Status = 0x%08X, DeviceFound = %d!\n",
01706         Status, DeviceFound);
01707 
01708     return (DeviceFound == FALSE) ? Status : STATUS_SUCCESS;
01709 }
01710 
01711 static VOID
01712 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
01713 {
01714     PSCSI_LUN_INFO LunInfo;
01715     PVOID Ptr;
01716     ULONG Bus, Lun;
01717 
01718     /* Check if we have something to clean up */
01719     if (DeviceExtension == NULL)
01720         return;
01721 
01722     /* Stop the timer */
01723     IoStopTimer(DeviceExtension->DeviceObject);
01724 
01725     /* Disconnect the interrupts */
01726     while (DeviceExtension->InterruptCount)
01727     {
01728         if (DeviceExtension->Interrupt[--DeviceExtension->InterruptCount])
01729             IoDisconnectInterrupt(DeviceExtension->Interrupt[DeviceExtension->InterruptCount]);
01730     }
01731 
01732     /* Delete ConfigInfo */
01733     if (DeviceExtension->BusesConfig)
01734     {
01735         for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
01736         {
01737             if (!DeviceExtension->BusesConfig->BusScanInfo[Bus])
01738                 continue;
01739 
01740             LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
01741 
01742             while (LunInfo)
01743             {
01744                 /* Free current, but save pointer to the next one */
01745                 Ptr = LunInfo->Next;
01746                 ExFreePool(LunInfo);
01747                 LunInfo = Ptr;
01748             }
01749 
01750             ExFreePool(DeviceExtension->BusesConfig->BusScanInfo[Bus]);
01751         }
01752 
01753         ExFreePool(DeviceExtension->BusesConfig);
01754     }
01755 
01756     /* Free PortConfig */
01757     if (DeviceExtension->PortConfig)
01758         ExFreePool(DeviceExtension->PortConfig);
01759 
01760     /* Free LUNs*/
01761     for(Lun = 0; Lun < LUS_NUMBER; Lun++)
01762     {
01763         while (DeviceExtension->LunExtensionList[Lun])
01764         {
01765             Ptr = DeviceExtension->LunExtensionList[Lun];
01766             DeviceExtension->LunExtensionList[Lun] = DeviceExtension->LunExtensionList[Lun]->Next;
01767 
01768             ExFreePool(Ptr);
01769         }
01770     }
01771 
01772     /* Free common buffer (if it exists) */
01773     if (DeviceExtension->SrbExtensionBuffer != NULL &&
01774         DeviceExtension->CommonBufferLength != 0)
01775     {
01776             if (!DeviceExtension->AdapterObject)
01777             {
01778                 ExFreePool(DeviceExtension->SrbExtensionBuffer);
01779             }
01780             else
01781             {
01782                 HalFreeCommonBuffer(DeviceExtension->AdapterObject,
01783                                     DeviceExtension->CommonBufferLength,
01784                                     DeviceExtension->PhysicalAddress,
01785                                     DeviceExtension->SrbExtensionBuffer,
01786                                     FALSE);
01787             }
01788     }
01789 
01790     /* Free SRB info */
01791     if (DeviceExtension->SrbInfo != NULL)
01792         ExFreePool(DeviceExtension->SrbInfo);
01793 
01794     /* Unmap mapped addresses */
01795     while (DeviceExtension->MappedAddressList != NULL)
01796     {
01797         MmUnmapIoSpace(DeviceExtension->MappedAddressList->MappedAddress,
01798                        DeviceExtension->MappedAddressList->NumberOfBytes);
01799 
01800         Ptr = DeviceExtension->MappedAddressList;
01801         DeviceExtension->MappedAddressList = DeviceExtension->MappedAddressList->NextMappedAddress;
01802 
01803         ExFreePool(Ptr);
01804     }
01805 
01806     /* Finally delete the device object */
01807     DPRINT("Deleting device %p\n", DeviceExtension->DeviceObject);
01808     IoDeleteDevice(DeviceExtension->DeviceObject);
01809 }
01810 
01811 /*
01812  * @unimplemented
01813  */
01814 VOID NTAPI
01815 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension,
01816               IN PSCSI_REQUEST_BLOCK Srb,
01817               IN PVOID LogicalAddress,
01818               IN ULONG Length)
01819 {
01820   DPRINT1("ScsiPortIoMapTransfer()\n");
01821   UNIMPLEMENTED;
01822 }
01823 
01824 /*
01825  * @unimplemented
01826  */
01827 VOID NTAPI
01828 ScsiPortLogError(IN PVOID HwDeviceExtension,
01829          IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
01830          IN UCHAR PathId,
01831          IN UCHAR TargetId,
01832          IN UCHAR Lun,
01833          IN ULONG ErrorCode,
01834          IN ULONG UniqueId)
01835 {
01836   //PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
01837 
01838   DPRINT1("ScsiPortLogError() called\n");
01839 
01840   //DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, SCSI_PORT_DEVICE_EXTENSION, MiniPortDeviceExtension);
01841 
01842 
01843   DPRINT("ScsiPortLogError() done\n");
01844 }
01845 
01846 /*
01847  * @implemented
01848  */
01849 VOID NTAPI
01850 ScsiPortMoveMemory(OUT PVOID Destination,
01851            IN PVOID Source,
01852            IN ULONG Length)
01853 {
01854   RtlMoveMemory(Destination,
01855         Source,
01856         Length);
01857 }
01858 
01859 
01860 /*
01861  * @implemented
01862  */
01863 VOID
01864 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType,
01865              IN PVOID HwDeviceExtension,
01866              ...)
01867 {
01868     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
01869     va_list ap;
01870 
01871     DPRINT("ScsiPortNotification() called\n");
01872 
01873     DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
01874         SCSI_PORT_DEVICE_EXTENSION,
01875         MiniPortDeviceExtension);
01876 
01877     DPRINT("DeviceExtension %p\n", DeviceExtension);
01878 
01879     va_start(ap, HwDeviceExtension);
01880 
01881     switch (NotificationType)
01882     {
01883     case RequestComplete:
01884         {
01885             PSCSI_REQUEST_BLOCK Srb;
01886             PSCSI_REQUEST_BLOCK_INFO SrbData;
01887 
01888             Srb = (PSCSI_REQUEST_BLOCK) va_arg (ap, PSCSI_REQUEST_BLOCK);
01889 
01890             DPRINT("Notify: RequestComplete (Srb %p)\n", Srb);
01891 
01892             /* Make sure Srb is allright */
01893             ASSERT(Srb->SrbStatus != SRB_STATUS_PENDING);
01894             ASSERT(Srb->Function != SRB_FUNCTION_EXECUTE_SCSI || Srb->SrbStatus != SRB_STATUS_SUCCESS || Srb->ScsiStatus == SCSISTAT_GOOD);
01895 
01896             if (!(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE))
01897             {
01898                 /* It's been already completed */
01899                 va_end(ap);
01900                 return;
01901             }
01902 
01903             /* It's not active anymore */
01904             Srb->SrbFlags &= ~SRB_FLAGS_IS_ACTIVE;
01905 
01906             if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
01907             {
01908                 /* TODO: Treat it specially */
01909                 ASSERT(FALSE);
01910             }
01911             else
01912             {
01913                 /* Get the SRB data */
01914                 SrbData = SpiGetSrbData(DeviceExtension,
01915                                         Srb->PathId,
01916                                         Srb->TargetId,
01917                                         Srb->Lun,
01918                                         Srb->QueueTag);
01919 
01920                 /* Make sure there are no CompletedRequests and there is a Srb */
01921                 ASSERT(SrbData->CompletedRequests == NULL && SrbData->Srb != NULL);
01922 
01923                 /* If it's a read/write request, make sure it has data inside it */
01924                 if ((Srb->SrbStatus == SRB_STATUS_SUCCESS) &&
01925                     ((Srb->Cdb[0] == SCSIOP_READ) || (Srb->Cdb[0] == SCSIOP_WRITE)))
01926                 {
01927                         ASSERT(Srb->DataTransferLength);
01928                 }
01929 
01930                 SrbData->CompletedRequests = DeviceExtension->InterruptData.CompletedRequests;
01931                 DeviceExtension->InterruptData.CompletedRequests = SrbData;
01932             }
01933         }
01934         break;
01935 
01936     case NextRequest:
01937         DPRINT("Notify: NextRequest\n");
01938         DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY;
01939         break;
01940 
01941     case NextLuRequest:
01942         {
01943             UCHAR PathId;
01944             UCHAR TargetId;
01945             UCHAR Lun;
01946             PSCSI_PORT_LUN_EXTENSION LunExtension;
01947 
01948             PathId = (UCHAR) va_arg (ap, int);
01949             TargetId = (UCHAR) va_arg (ap, int);
01950             Lun = (UCHAR) va_arg (ap, int);
01951 
01952             DPRINT("Notify: NextLuRequest(PathId %u  TargetId %u  Lun %u)\n",
01953                 PathId, TargetId, Lun);
01954 
01955             /* Mark it in the flags field */
01956             DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY;
01957 
01958             /* Get the LUN extension */
01959             LunExtension = SpiGetLunExtension(DeviceExtension,
01960                                               PathId,
01961                                               TargetId,
01962                                               Lun);
01963 
01964             /* If returned LunExtension is NULL, break out */
01965             if (!LunExtension) break;
01966 
01967             /* This request should not be processed if */
01968             if ((LunExtension->ReadyLun) ||
01969                 (LunExtension->SrbInfo.Srb))
01970             {
01971                 /* Nothing to do here */
01972                 break;
01973             }
01974 
01975             /* Add this LUN to the list */
01976             LunExtension->ReadyLun = DeviceExtension->InterruptData.ReadyLun;
01977             DeviceExtension->InterruptData.ReadyLun = LunExtension;
01978           }
01979           break;
01980 
01981       case ResetDetected:
01982           DPRINT("Notify: ResetDetected\n");
01983           /* Add RESET flags */
01984           DeviceExtension->InterruptData.Flags |=
01985                 SCSI_PORT_RESET | SCSI_PORT_RESET_REPORTED;
01986           break;
01987 
01988       case CallDisableInterrupts:
01989           DPRINT1("UNIMPLEMENTED SCSI Notification called: CallDisableInterrupts!\n");
01990           break;
01991 
01992       case CallEnableInterrupts:
01993           DPRINT1("UNIMPLEMENTED SCSI Notification called: CallEnableInterrupts!\n");
01994           break;
01995 
01996       case RequestTimerCall:
01997           DPRINT("Notify: RequestTimerCall\n");
01998           DeviceExtension->InterruptData.Flags |= SCSI_PORT_TIMER_NEEDED;
01999           DeviceExtension->InterruptData.HwScsiTimer = (PHW_TIMER)va_arg(ap, PHW_TIMER);
02000           DeviceExtension->InterruptData.MiniportTimerValue = (ULONG)va_arg(ap, ULONG);
02001           break;
02002 
02003       case BusChangeDetected:
02004           DPRINT1("UNIMPLEMENTED SCSI Notification called: BusChangeDetected!\n");
02005           break;
02006 
02007       default:
02008     DPRINT1 ("Unsupported notification from WMI: %lu\n", NotificationType);
02009     break;
02010     }
02011 
02012     va_end(ap);
02013 
02014     /* Request a DPC after we're done with the interrupt */
02015     DeviceExtension->InterruptData.Flags |= SCSI_PORT_NOTIFICATION_NEEDED;
02016 }
02017 
02018 /*
02019  * @implemented
02020  */
02021 BOOLEAN NTAPI
02022 ScsiPortValidateRange(IN PVOID HwDeviceExtension,
02023               IN INTERFACE_TYPE BusType,
02024               IN ULONG SystemIoBusNumber,
02025               IN SCSI_PHYSICAL_ADDRESS IoAddress,
02026               IN ULONG NumberOfBytes,
02027               IN BOOLEAN InIoSpace)
02028 {
02029   DPRINT("ScsiPortValidateRange()\n");
02030   return(TRUE);
02031 }
02032 
02033 
02034 /* INTERNAL FUNCTIONS ********************************************************/
02035 
02036 static VOID
02037 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData,
02038                     IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor,
02039                     IN PPORT_CONFIGURATION_INFORMATION PortConfig)
02040 {
02041     PACCESS_RANGE AccessRange;
02042     PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialData;
02043     ULONG RangeNumber;
02044     ULONG Index;
02045     ULONG Interrupt = 0;
02046     ULONG Dma = 0;
02047 
02048     RangeNumber = 0;
02049 
02050     /* Loop through all entries */
02051     for (Index = 0; Index < ResourceDescriptor->PartialResourceList.Count; Index++)
02052     {
02053         PartialData = &ResourceDescriptor->PartialResourceList.PartialDescriptors[Index];
02054 
02055         switch (PartialData->Type)
02056         {
02057         case CmResourceTypePort:
02058             /* Copy access ranges */
02059             if (RangeNumber < HwInitializationData->NumberOfAccessRanges)
02060             {
02061                 AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]);
02062 
02063                 AccessRange->RangeStart = PartialData->u.Port.Start;
02064                 AccessRange->RangeLength = PartialData->u.Port.Length;
02065 
02066                 AccessRange->RangeInMemory = FALSE;
02067                 RangeNumber++;
02068             }
02069             break;
02070 
02071         case CmResourceTypeMemory:
02072             /* Copy access ranges */
02073             if (RangeNumber < HwInitializationData->NumberOfAccessRanges)
02074             {
02075                 AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]);
02076 
02077                 AccessRange->RangeStart = PartialData->u.Memory.Start;
02078                 AccessRange->RangeLength = PartialData->u.Memory.Length;
02079 
02080                 AccessRange->RangeInMemory = TRUE;
02081                 RangeNumber++;
02082             }
02083             break;
02084 
02085         case CmResourceTypeInterrupt:
02086 
02087             if (Interrupt == 0)
02088             {
02089                 /* Copy interrupt data */
02090                 PortConfig->BusInterruptLevel = PartialData->u.Interrupt.Level;
02091                 PortConfig->BusInterruptVector = PartialData->u.Interrupt.Vector;
02092 
02093                 /* Set interrupt mode accordingly to the resource */
02094                 if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
02095                 {
02096                     PortConfig->InterruptMode = Latched;
02097                 }
02098                 else if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
02099                 {
02100                     PortConfig->InterruptMode = LevelSensitive;
02101                 }
02102             }
02103             else if (Interrupt == 1)
02104             {
02105                 /* Copy interrupt data */
02106                 PortConfig->BusInterruptLevel2 = PartialData->u.Interrupt.Level;
02107                 PortConfig->BusInterruptVector2 = PartialData->u.Interrupt.Vector;
02108 
02109                 /* Set interrupt mode accordingly to the resource */
02110                 if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
02111                 {
02112                     PortConfig->InterruptMode2 = Latched;
02113                 }
02114                 else if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
02115                 {
02116                     PortConfig->InterruptMode2 = LevelSensitive;
02117                 }
02118             }
02119 
02120             Interrupt++;
02121             break;
02122 
02123         case CmResourceTypeDma:
02124 
02125             if (Dma == 0)
02126             {
02127                 PortConfig->DmaChannel = PartialData->u.Dma.Channel;
02128                 PortConfig->DmaPort = PartialData->u.Dma.Port;
02129 
02130                 if (PartialData->Flags & CM_RESOURCE_DMA_8)
02131                     PortConfig->DmaWidth = Width8Bits;
02132                 else if ((PartialData->Flags & CM_RESOURCE_DMA_16) ||
02133                          (PartialData->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
02134                     PortConfig->DmaWidth = Width16Bits;
02135                 else if (PartialData->Flags & CM_RESOURCE_DMA_32)
02136                     PortConfig->DmaWidth = Width32Bits;
02137             }
02138             else if (Dma == 1)
02139             {
02140                 PortConfig->DmaChannel2 = PartialData->u.Dma.Channel;
02141                 PortConfig->DmaPort2 = PartialData->u.Dma.Port;
02142 
02143                 if (PartialData->Flags & CM_RESOURCE_DMA_8)
02144                     PortConfig->DmaWidth2 = Width8Bits;
02145                 else if ((PartialData->Flags & CM_RESOURCE_DMA_16) ||
02146                          (PartialData->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
02147                     PortConfig->DmaWidth2 = Width16Bits;
02148                 else if (PartialData->Flags & CM_RESOURCE_DMA_32)
02149                     PortConfig->DmaWidth2 = Width32Bits;
02150             }
02151             break;
02152         }
02153     }
02154 }
02155 
02156 static PCM_RESOURCE_LIST
02157 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
02158                     PPORT_CONFIGURATION_INFORMATION PortConfig)
02159 {
02160     PCONFIGURATION_INFORMATION ConfigInfo;
02161     PCM_RESOURCE_LIST ResourceList;
02162     PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor;
02163     PACCESS_RANGE AccessRange;
02164     ULONG ListLength = 0, i, FullSize;
02165     ULONG Interrupt, Dma;
02166 
02167     /* Get current Atdisk usage from the system */
02168     ConfigInfo = IoGetConfigurationInformation();
02169 
02170     if (PortConfig->AtdiskPrimaryClaimed)
02171         ConfigInfo->AtDiskPrimaryAddressClaimed = TRUE;
02172 
02173     if (PortConfig->AtdiskSecondaryClaimed)
02174         ConfigInfo->AtDiskSecondaryAddressClaimed = TRUE;
02175 
02176     /* Do we use DMA? */
02177     if (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE ||
02178         PortConfig->DmaPort != SP_UNINITIALIZED_VALUE)
02179     {
02180         Dma = 1;
02181 
02182         if (PortConfig->DmaChannel2 != SP_UNINITIALIZED_VALUE ||
02183             PortConfig->DmaPort2 != SP_UNINITIALIZED_VALUE)
02184             Dma++;
02185     }
02186     else
02187     {
02188         Dma = 0;
02189     }
02190     ListLength += Dma;
02191 
02192     /* How many interrupts to we have? */
02193     Interrupt = DeviceExtension->InterruptCount;
02194     ListLength += Interrupt;
02195 
02196     /* How many access ranges do we use? */
02197     AccessRange = &((*(PortConfig->AccessRanges))[0]);
02198     for (i = 0; i < PortConfig->NumberOfAccessRanges; i++)
02199     {
02200         if (AccessRange->RangeLength != 0)
02201             ListLength++;
02202 
02203         AccessRange++;
02204     }
02205 
02206     /* Allocate the resource list, since we know its size now */
02207     FullSize = sizeof(CM_RESOURCE_LIST) + (ListLength - 1) *
02208         sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
02209 
02210     ResourceList = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(PagedPool, FullSize, TAG_SCSIPORT);
02211 
02212     if (!ResourceList)
02213         return NULL;
02214 
02215     /* Zero it */
02216     RtlZeroMemory(ResourceList, FullSize);
02217 
02218     /* Initialize it */
02219     ResourceList->Count = 1;
02220     ResourceList->List[0].InterfaceType = PortConfig->AdapterInterfaceType;
02221     ResourceList->List[0].BusNumber = PortConfig->SystemIoBusNumber;
02222     ResourceList->List[0].PartialResourceList.Count = ListLength;
02223     ResourceDescriptor = ResourceList->List[0].PartialResourceList.PartialDescriptors;
02224 
02225     /* Copy access ranges array over */
02226     for (i = 0; i < PortConfig->NumberOfAccessRanges; i++)
02227     {
02228         AccessRange = &((*(PortConfig->AccessRanges))[i]);
02229 
02230         /* If the range is empty - skip it */
02231         if (AccessRange->RangeLength == 0)
02232             continue;
02233 
02234         if (AccessRange->RangeInMemory)
02235         {
02236             ResourceDescriptor->Type = CmResourceTypeMemory;
02237             ResourceDescriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
02238         }
02239         else
02240         {
02241             ResourceDescriptor->Type = CmResourceTypePort;
02242             ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
02243         }
02244 
02245         ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
02246 
02247         ResourceDescriptor->u.Memory.Start = AccessRange->RangeStart;
02248         ResourceDescriptor->u.Memory.Length = AccessRange->RangeLength;
02249 
02250         ResourceDescriptor++;
02251     }
02252 
02253     /* If we use interrupt(s), copy them */
02254     while (Interrupt)
02255     {
02256         ResourceDescriptor->Type = CmResourceTypeInterrupt;
02257 
02258         if (PortConfig->AdapterInterfaceType == MicroChannel ||
02259             ((Interrupt == 2) ? PortConfig->InterruptMode2 : PortConfig->InterruptMode) == LevelSensitive)
02260         {
02261             ResourceDescriptor->ShareDisposition = CmResourceShareShared;
02262             ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
02263         }
02264         else
02265         {
02266             ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
02267             ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
02268         }
02269 
02270         ResourceDescriptor->u.Interrupt.Level = (Interrupt == 2) ? PortConfig->BusInterruptLevel2 : PortConfig->BusInterruptLevel;
02271         ResourceDescriptor->u.Interrupt.Vector = (Interrupt == 2) ? PortConfig->BusInterruptVector2 : PortConfig->BusInterruptVector;
02272         ResourceDescriptor->u.Interrupt.Affinity = 0;
02273 
02274         ResourceDescriptor++;
02275         Interrupt--;
02276     }
02277 
02278     /* Copy DMA data */
02279     while (Dma)
02280     {
02281         ResourceDescriptor->Type = CmResourceTypeDma;
02282         ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
02283         ResourceDescriptor->u.Dma.Channel = (Dma == 2) ? PortConfig->DmaChannel2 : PortConfig->DmaChannel;
02284         ResourceDescriptor->u.Dma.Port = (Dma == 2) ? PortConfig->DmaPort2 : PortConfig->DmaPort;
02285         ResourceDescriptor->Flags = 0;
02286 
02287         if (((Dma == 2) ? PortConfig->DmaWidth2 : PortConfig->DmaWidth) == Width8Bits)
02288             ResourceDescriptor->Flags |= CM_RESOURCE_DMA_8;
02289         else if (((Dma == 2) ? PortConfig->DmaWidth2 : PortConfig->DmaWidth) == Width16Bits)
02290             ResourceDescriptor->Flags |= CM_RESOURCE_DMA_16;
02291         else
02292             ResourceDescriptor->Flags |= CM_RESOURCE_DMA_32;
02293 
02294         if (((Dma == 2) ? PortConfig->DmaChannel2 : PortConfig->DmaChannel) == SP_UNINITIALIZED_VALUE)
02295             ResourceDescriptor->u.Dma.Channel = 0;
02296 
02297         if (((Dma == 2) ? PortConfig->DmaPort2 : PortConfig->DmaPort) == SP_UNINITIALIZED_VALUE)
02298             ResourceDescriptor->u.Dma.Port = 0;
02299 
02300         ResourceDescriptor++;
02301         Dma--;
02302     }
02303 
02304     return ResourceList;
02305 }
02306 
02307 
02308 static BOOLEAN
02309 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject,
02310                     IN PDEVICE_OBJECT DeviceObject,
02311                     IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
02312                     IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,
02313                     IN PUNICODE_STRING RegistryPath,
02314                     IN ULONG BusNumber,
02315                     IN OUT PPCI_SLOT_NUMBER NextSlotNumber)
02316 {
02317     PCI_COMMON_CONFIG PciConfig;
02318     PCI_SLOT_NUMBER SlotNumber;
02319     ULONG DataSize;
02320     ULONG DeviceNumber;
02321     ULONG FunctionNumber;
02322     CHAR VendorIdString[8];
02323     CHAR DeviceIdString[8];
02324     UNICODE_STRING UnicodeStr;
02325     PCM_RESOURCE_LIST ResourceList = NULL;
02326     NTSTATUS Status;
02327 
02328     DPRINT ("SpiGetPciConfiguration() called\n");
02329 
02330     SlotNumber.u.AsULONG = 0;
02331 
02332     /* Loop through all devices */
02333     for (DeviceNumber = NextSlotNumber->u.bits.DeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
02334     {
02335         SlotNumber.u.bits.DeviceNumber = DeviceNumber;
02336 
02337         /* Loop through all functions */
02338         for (FunctionNumber = NextSlotNumber->u.bits.FunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
02339         {
02340             SlotNumber.u.bits.FunctionNumber = FunctionNumber;
02341 
02342             /* Get PCI config bytes */
02343             DataSize = HalGetBusData(PCIConfiguration,
02344                                      BusNumber,
02345                                      SlotNumber.u.AsULONG,
02346                                      &PciConfig,
02347                                      sizeof(ULONG));
02348 
02349             /* If result of HalGetBusData is 0, then the bus is wrong */
02350             if (DataSize == 0)
02351                 return FALSE;
02352 
02353             /* If result is PCI_INVALID_VENDORID, then this device has no more
02354                "Functions" */
02355             if (PciConfig.VendorID == PCI_INVALID_VENDORID)
02356                 break;
02357 
02358             sprintf (VendorIdString, "%04hx", PciConfig.VendorID);
02359             sprintf (DeviceIdString, "%04hx", PciConfig.DeviceID);
02360 
02361             if (_strnicmp(VendorIdString, HwInitializationData->VendorId, HwInitializationData->VendorIdLength) ||
02362                 _strnicmp(DeviceIdString, HwInitializationData->DeviceId, HwInitializationData->DeviceIdLength))
02363             {
02364                 /* It is not our device */
02365                 continue;
02366             }
02367 
02368             DPRINT("Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n",
02369                    PciConfig.VendorID,
02370                    PciConfig.DeviceID,
02371                    BusNumber,
02372                    SlotNumber.u.bits.DeviceNumber,
02373                    SlotNumber.u.bits.FunctionNumber);
02374 
02375 
02376             RtlInitUnicodeString(&UnicodeStr, L"ScsiAdapter");
02377             Status = HalAssignSlotResources(RegistryPath,
02378                                             &UnicodeStr,
02379                                             DriverObject,
02380                                             DeviceObject,
02381                                             PCIBus,
02382                                             BusNumber,
02383                                             SlotNumber.u.AsULONG,
02384                                             &ResourceList);
02385 
02386             if (!NT_SUCCESS(Status))
02387                 break;
02388 
02389             /* Create configuration information */
02390             SpiResourceToConfig(HwInitializationData,
02391                                 ResourceList->List,
02392                                 PortConfig);
02393 
02394             /* Free the resource list */
02395             ExFreePool(ResourceList);
02396 
02397             /* Set dev & fn numbers */
02398             NextSlotNumber->u.bits.DeviceNumber = DeviceNumber;
02399             NextSlotNumber->u.bits.FunctionNumber = FunctionNumber + 1;
02400 
02401             /* Save the slot number */
02402             PortConfig->SlotNumber = SlotNumber.u.AsULONG;
02403 
02404             return TRUE;
02405         }
02406        NextSlotNumber->u.bits.FunctionNumber = 0;
02407     }
02408 
02409     NextSlotNumber->u.bits.DeviceNumber = 0;
02410     DPRINT ("No device found\n");
02411 
02412     return FALSE;
02413 }
02414 
02415 
02416 
02417 /**********************************************************************
02418  * NAME                         INTERNAL
02419  *  ScsiPortCreateClose
02420  *
02421  * DESCRIPTION
02422  *  Answer requests for Create/Close calls: a null operation.
02423  *
02424  * RUN LEVEL
02425  *  PASSIVE_LEVEL
02426  *
02427  * ARGUMENTS
02428  *  DeviceObject
02429  *      Pointer to a device object.
02430  *
02431  *  Irp
02432  *      Pointer to an IRP.
02433  *
02434  * RETURN VALUE
02435  *  Status.
02436  */
02437 
02438 static NTSTATUS NTAPI
02439 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
02440                    IN PIRP Irp)
02441 {
02442     DPRINT("ScsiPortCreateClose()\n");
02443 
02444     Irp->IoStatus.Status = STATUS_SUCCESS;
02445     IoCompleteRequest(Irp, IO_NO_INCREMENT);
02446 
02447     return STATUS_SUCCESS;
02448 }
02449 
02450 static NTSTATUS
02451 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
02452                        PIRP Irp)
02453 {
02454     PSCSI_LUN_INFO LunInfo;
02455     PIO_STACK_LOCATION IrpStack;
02456     PDEVICE_OBJECT DeviceObject;
02457     PSCSI_REQUEST_BLOCK Srb;
02458     KIRQL Irql;
02459 
02460     /* Get pointer to the SRB */
02461     IrpStack = IoGetCurrentIrpStackLocation(Irp);
02462     Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
02463 
02464     /* Check if PathId matches number of buses */
02465     if (DeviceExtension->BusesConfig == NULL ||
02466         DeviceExtension->BusesConfig->NumberOfBuses <= Srb->PathId)
02467     {
02468         Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
02469         return STATUS_DEVICE_DOES_NOT_EXIST;
02470     }
02471 
02472     /* Get pointer to LunInfo */
02473     LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Srb->PathId]->LunInfo;
02474 
02475     /* Find matching LunInfo */
02476     while (LunInfo)
02477     {
02478         if (LunInfo->PathId == Srb->PathId &&
02479             LunInfo->TargetId == Srb->TargetId &&
02480             LunInfo->Lun == Srb->Lun)
02481         {
02482             break;
02483         }
02484 
02485         LunInfo = LunInfo->Next;
02486     }
02487 
02488     /* If we couldn't find it - exit */
02489     if (LunInfo == NULL)
02490         return STATUS_DEVICE_DOES_NOT_EXIST;
02491 
02492 
02493     /* Get spinlock */
02494     KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
02495 
02496     /* Release, if asked */
02497     if (Srb->Function == SRB_FUNCTION_RELEASE_DEVICE)
02498     {
02499         LunInfo->DeviceClaimed = FALSE;
02500         KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
02501         Srb->SrbStatus = SRB_STATUS_SUCCESS;
02502 
02503         return STATUS_SUCCESS;
02504     }
02505 
02506     /* Attach, if not already claimed */
02507     if (LunInfo->DeviceClaimed)
02508     {
02509         KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
02510         Srb->SrbStatus = SRB_STATUS_BUSY;
02511 
02512         return STATUS_DEVICE_BUSY;
02513     }
02514 
02515     /* Save the device object */
02516     DeviceObject = LunInfo->DeviceObject;
02517 
02518     if (Srb->Function == SRB_FUNCTION_CLAIM_DEVICE)
02519         LunInfo->DeviceClaimed = TRUE;
02520 
02521     if (Srb->Function == SRB_FUNCTION_ATTACH_DEVICE)
02522         LunInfo->DeviceObject = Srb->DataBuffer;
02523 
02524     Srb->DataBuffer = DeviceObject;
02525 
02526     KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
02527     Srb->SrbStatus = SRB_STATUS_SUCCESS;
02528 
02529     return STATUS_SUCCESS;
02530 }
02531 
02532 
02533 /**********************************************************************
02534  * NAME                         INTERNAL
02535  *  ScsiPortDispatchScsi
02536  *
02537  * DESCRIPTION
02538  *  Answer requests for SCSI calls
02539  *
02540  * RUN LEVEL
02541  *  PASSIVE_LEVEL
02542  *
02543  * ARGUMENTS
02544  *  Standard dispatch arguments
02545  *
02546  * RETURNS
02547  *  NTSTATUS
02548  */
02549 
02550 static NTSTATUS NTAPI
02551 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
02552              IN PIRP Irp)
02553 {
02554     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
02555     PSCSI_PORT_LUN_EXTENSION LunExtension;
02556     PIO_STACK_LOCATION Stack;
02557     PSCSI_REQUEST_BLOCK Srb;
02558     KIRQL Irql;
02559     NTSTATUS Status = STATUS_SUCCESS;
02560     PIRP NextIrp, IrpList;
02561     PKDEVICE_QUEUE_ENTRY Entry;
02562 
02563     DPRINT("ScsiPortDispatchScsi(DeviceObject %p  Irp %p)\n",
02564         DeviceObject, Irp);
02565 
02566     DeviceExtension = DeviceObject->DeviceExtension;
02567     Stack = IoGetCurrentIrpStackLocation(Irp);
02568 
02569     Srb = Stack->Parameters.Scsi.Srb;
02570     if (Srb == NULL)
02571     {
02572         DPRINT1("ScsiPortDispatchScsi() called with Srb = NULL!\n");
02573         Status = STATUS_UNSUCCESSFUL;
02574 
02575         Irp->IoStatus.Status = Status;
02576         Irp->IoStatus.Information = 0;
02577 
02578         IoCompleteRequest(Irp, IO_NO_INCREMENT);
02579 
02580         return(Status);
02581     }
02582 
02583     DPRINT("Srb: %p\n", Srb);
02584     DPRINT("Srb->Function: %lu\n", Srb->Function);
02585     DPRINT("PathId: %lu  TargetId: %lu  Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
02586 
02587     LunExtension = SpiGetLunExtension(DeviceExtension,
02588                                       Srb->PathId,
02589                                       Srb->TargetId,
02590                                       Srb->Lun);
02591     if (LunExtension == NULL)
02592     {
02593         DPRINT("ScsiPortDispatchScsi() called with an invalid LUN\n");
02594         Status = STATUS_NO_SUCH_DEVICE;
02595 
02596         Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
02597         Irp->IoStatus.Status = Status;
02598         Irp->IoStatus.Information = 0;
02599 
02600         IoCompleteRequest(Irp, IO_NO_INCREMENT);
02601 
02602         return(Status);
02603     }
02604 
02605     switch (Srb->Function)
02606     {
02607     case SRB_FUNCTION_SHUTDOWN:
02608     case SRB_FUNCTION_FLUSH:
02609         DPRINT ("  SRB_FUNCTION_SHUTDOWN or FLUSH\n");
02610         if (DeviceExtension->CachesData == FALSE)
02611         {
02612             /* All success here */
02613             Srb->SrbStatus = SRB_STATUS_SUCCESS;
02614             Irp->IoStatus.Status = STATUS_SUCCESS;
02615             IoCompleteRequest(Irp, IO_NO_INCREMENT);
02616             return STATUS_SUCCESS;
02617         }
02618         /* Fall through to a usual execute operation */
02619 
02620     case SRB_FUNCTION_EXECUTE_SCSI:
02621     case SRB_FUNCTION_IO_CONTROL:
02622         /* Mark IRP as pending in all cases */
02623         IoMarkIrpPending(Irp);
02624 
02625         if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
02626         {
02627             /* Start IO directly */
02628             IoStartPacket(DeviceObject, Irp, NULL, NULL);
02629         }
02630         else
02631         {
02632             KIRQL oldIrql;
02633 
02634             /* We need to be at DISPATCH_LEVEL */
02635             KeRaiseIrql (DISPATCH_LEVEL, &oldIrql);
02636 
02637             /* Insert IRP into the queue */
02638             if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue,
02639                 &Irp->Tail.Overlay.DeviceQueueEntry,
02640                 Srb->QueueSortKey))
02641             {
02642                 /* It means the queue is empty, and we just start this request */
02643                 IoStartPacket(DeviceObject, Irp, NULL, NULL);
02644             }
02645 
02646             /* Back to the old IRQL */
02647             KeLowerIrql (oldIrql);
02648         }
02649         return STATUS_PENDING;
02650 
02651     case SRB_FUNCTION_CLAIM_DEVICE:
02652     case SRB_FUNCTION_ATTACH_DEVICE:
02653         DPRINT ("  SRB_FUNCTION_CLAIM_DEVICE or ATTACH\n");
02654 
02655         /* Reference device object and keep the device object */
02656         Status = SpiHandleAttachRelease(DeviceExtension, Irp);
02657         break;
02658 
02659     case SRB_FUNCTION_RELEASE_DEVICE:
02660         DPRINT ("  SRB_FUNCTION_RELEASE_DEVICE\n");
02661 
02662         /* Dereference device object and clear the device object */
02663         Status = SpiHandleAttachRelease(DeviceExtension, Irp);
02664         break;
02665 
02666     case SRB_FUNCTION_RELEASE_QUEUE:
02667         DPRINT("  SRB_FUNCTION_RELEASE_QUEUE\n");
02668 
02669         /* Guard with the spinlock */
02670         KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
02671 
02672         if (!(LunExtension->Flags & LUNEX_FROZEN_QUEUE))
02673         {
02674             DPRINT("Queue is not frozen really\n");
02675 
02676             KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
02677             Srb->SrbStatus = SRB_STATUS_SUCCESS;
02678             Status = STATUS_SUCCESS;
02679             break;
02680 
02681         }
02682 
02683         /* Unfreeze the queue */
02684         LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
02685 
02686         if (LunExtension->SrbInfo.Srb == NULL)
02687         {
02688             /* Get next logical unit request */
02689             SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
02690 
02691             /* SpiGetNextRequestFromLun() releases the spinlock */
02692             KeLowerIrql(Irql);
02693         }
02694         else
02695         {
02696             DPRINT("The queue has active request\n");
02697             KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
02698         }
02699 
02700 
02701         Srb->SrbStatus = SRB_STATUS_SUCCESS;
02702         Status = STATUS_SUCCESS;
02703         break;
02704 
02705     case SRB_FUNCTION_FLUSH_QUEUE:
02706         DPRINT("  SRB_FUNCTION_FLUSH_QUEUE\n");
02707 
02708         /* Guard with the spinlock */
02709         KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
02710 
02711         if (!(LunExtension->Flags & LUNEX_FROZEN_QUEUE))
02712         {
02713             DPRINT("Queue is not frozen really\n");
02714 
02715             KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
02716             Status = STATUS_INVALID_DEVICE_REQUEST;
02717             break;
02718         }
02719 
02720         /* Make sure there is no active request */
02721         ASSERT(LunExtension->SrbInfo.Srb == NULL);
02722 
02723         /* Compile a list from the device queue */
02724         IrpList = NULL;
02725         while ((Entry = KeRemoveDeviceQueue(&LunExtension->DeviceQueue)) != NULL)
02726         {
02727                 NextIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
02728 
02729                 /* Get the Srb */
02730                 Stack = IoGetCurrentIrpStackLocation(NextIrp);
02731                 Srb = Stack->Parameters.Scsi.Srb;
02732 
02733                 /* Set statuse */
02734                 Srb->SrbStatus = SRB_STATUS_REQUEST_FLUSHED;
02735                 NextIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
02736 
02737                 /* Add then to the list */
02738                 NextIrp->Tail.Overlay.ListEntry.Flink = (PLIST_ENTRY)IrpList;
02739                 IrpList = NextIrp;
02740         }
02741 
02742         /* Unfreeze the queue */
02743         LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
02744 
02745         /* Release the spinlock */
02746         KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
02747 
02748         /* Complete those requests */
02749         while (IrpList)
02750         {
02751             NextIrp = IrpList;
02752             IrpList = (PIRP)NextIrp->Tail.Overlay.ListEntry.Flink;
02753 
02754             IoCompleteRequest(NextIrp, 0);
02755         }
02756 
02757         Status = STATUS_SUCCESS;
02758         break;
02759 
02760     default:
02761         DPRINT1("SRB function not implemented (Function %lu)\n", Srb->Function);
02762         Status = STATUS_NOT_IMPLEMENTED;
02763         break;
02764     }
02765 
02766     Irp->IoStatus.Status = Status;
02767 
02768     IoCompleteRequest(Irp, IO_NO_INCREMENT);
02769 
02770     return(Status);
02771 }
02772 
02773 
02774 /**********************************************************************
02775  * NAME                         INTERNAL
02776  *  ScsiPortDeviceControl
02777  *
02778  * DESCRIPTION
02779  *  Answer requests for device control calls
02780  *
02781  * RUN LEVEL
02782  *  PASSIVE_LEVEL
02783  *
02784  * ARGUMENTS
02785  *  Standard dispatch arguments
02786  *
02787  * RETURNS
02788  *  NTSTATUS
02789  */
02790 
02791 static NTSTATUS NTAPI
02792 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
02793               IN PIRP Irp)
02794 {
02795     PIO_STACK_LOCATION Stack;
02796     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
02797     PDUMP_POINTERS DumpPointers;
02798     NTSTATUS Status;
02799 
02800     DPRINT("ScsiPortDeviceControl()\n");
02801 
02802     Irp->IoStatus.Information = 0;
02803 
02804     Stack = IoGetCurrentIrpStackLocation(Irp);
02805     DeviceExtension = DeviceObject->DeviceExtension;
02806 
02807     switch (Stack->Parameters.DeviceIoControl.IoControlCode)
02808     {
02809       case IOCTL_SCSI_GET_DUMP_POINTERS:
02810         DPRINT("  IOCTL_SCSI_GET_DUMP_POINTERS\n");
02811 
02812         if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DUMP_POINTERS))
02813         {
02814           Status = STATUS_BUFFER_OVERFLOW;
02815           Irp->IoStatus.Information = sizeof(DUMP_POINTERS);
02816           break;
02817         }
02818 
02819         DumpPointers = Irp->AssociatedIrp.SystemBuffer;
02820         DumpPointers->DeviceObject = DeviceObject;
02821         /* More data.. ? */
02822 
02823         Status = STATUS_SUCCESS;
02824         Irp->IoStatus.Information = sizeof(DUMP_POINTERS);
02825         break;
02826 
02827       case IOCTL_SCSI_GET_CAPABILITIES:
02828         DPRINT("  IOCTL_SCSI_GET_CAPABILITIES\n");
02829         if (Stack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(PVOID))
02830         {
02831             *((PVOID *)Irp->AssociatedIrp.SystemBuffer) = &DeviceExtension->PortCapabilities;
02832 
02833             Irp->IoStatus.Information = sizeof(PVOID);
02834             Status = STATUS_SUCCESS;
02835             break;
02836         }
02837 
02838         if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(IO_SCSI_CAPABILITIES))
02839         {
02840             Status = STATUS_BUFFER_TOO_SMALL;
02841             break;
02842         }
02843 
02844         RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
02845                       &DeviceExtension->PortCapabilities,
02846                       sizeof(IO_SCSI_CAPABILITIES));
02847 
02848         Irp->IoStatus.Information = sizeof(IO_SCSI_CAPABILITIES);
02849         Status = STATUS_SUCCESS;
02850         break;
02851 
02852       case IOCTL_SCSI_GET_INQUIRY_DATA:
02853           DPRINT("  IOCTL_SCSI_GET_INQUIRY_DATA\n");
02854 
02855           /* Copy inquiry data to the port device extension */
02856           Status = SpiGetInquiryData(DeviceExtension, Irp);
02857           break;
02858 
02859       case IOCTL_SCSI_MINIPORT:
02860           DPRINT1("IOCTL_SCSI_MINIPORT unimplemented!\n");
02861           Status = STATUS_NOT_IMPLEMENTED;
02862           break;
02863 
02864       case IOCTL_SCSI_PASS_THROUGH:
02865           DPRINT1("IOCTL_SCSI_PASS_THROUGH unimplemented!\n");
02866           Status = STATUS_NOT_IMPLEMENTED;
02867           break;
02868 
02869       default:
02870           DPRINT1("  unknown ioctl code: 0x%lX\n", Stack->Parameters.DeviceIoControl.IoControlCode);
02871           Status = STATUS_NOT_IMPLEMENTED;
02872           break;
02873     }
02874 
02875     /* Complete the request with the given status */
02876     Irp->IoStatus.Status = Status;
02877     IoCompleteRequest(Irp, IO_NO_INCREMENT);
02878 
02879     return Status;
02880 }
02881 
02882 
02883 static VOID NTAPI
02884 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
02885         IN PIRP Irp)
02886 {
02887     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
02888     PSCSI_PORT_LUN_EXTENSION LunExtension;
02889     PIO_STACK_LOCATION IrpStack;
02890     PSCSI_REQUEST_BLOCK Srb;
02891     PSCSI_REQUEST_BLOCK_INFO SrbInfo;
02892     LONG CounterResult;
02893     NTSTATUS Status;
02894 
02895     DPRINT("ScsiPortStartIo() called!\n");
02896 
02897     DeviceExtension = DeviceObject->DeviceExtension;
02898     IrpStack = IoGetCurrentIrpStackLocation(Irp);
02899 
02900     DPRINT("DeviceExtension %p\n", DeviceExtension);
02901 
02902     Srb = IrpStack->Parameters.Scsi.Srb;
02903 
02904     /* Apply "default" flags */
02905     Srb->SrbFlags |= DeviceExtension->SrbFlags;
02906 
02907     /* Get LUN extension */
02908     LunExtension = SpiGetLunExtension(DeviceExtension,
02909                                       Srb->PathId,
02910                                       Srb->TargetId,
02911                                       Srb->Lun);
02912 
02913     if (DeviceExtension->NeedSrbDataAlloc ||
02914         DeviceExtension->NeedSrbExtensionAlloc)
02915     {
02916         /* Allocate them */
02917         SrbInfo = SpiAllocateSrbStructures(DeviceExtension,
02918                                            LunExtension,
02919                                            Srb);
02920 
02921         /* Couldn't alloc one or both data structures, return */
02922         if (SrbInfo == NULL)
02923         {
02924             /* We have to call IoStartNextPacket, because this request
02925                was not started */
02926             if (LunExtension->Flags & LUNEX_REQUEST_PENDING)
02927                 IoStartNextPacket(DeviceObject, FALSE);
02928 
02929             return;
02930         }
02931     }
02932     else
02933     {
02934         /* No allocations are needed */
02935         SrbInfo = &LunExtension->SrbInfo;
02936         Srb->SrbExtension = NULL;
02937         Srb->QueueTag = SP_UNTAGGED;
02938     }
02939 
02940     /* Increase sequence number of SRB */
02941     if (!SrbInfo->SequenceNumber)
02942     {
02943         /* Increase global sequence number */
02944         DeviceExtension->SequenceNumber++;
02945 
02946         /* Assign it */
02947         SrbInfo->SequenceNumber = DeviceExtension->SequenceNumber;
02948     }
02949 
02950     /* Check some special SRBs */
02951     if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
02952     {
02953         /* Some special handling */
02954         DPRINT1("Abort command! Unimplemented now\n");
02955     }
02956     else
02957     {
02958         SrbInfo->Srb = Srb;
02959     }
02960 
02961     if (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION)
02962     {
02963         // Store the MDL virtual address in SrbInfo structure
02964         SrbInfo->DataOffset = MmGetMdlVirtualAddress(Irp->MdlAddress);
02965 
02966         if (DeviceExtension->MapBuffers)
02967         {
02968             /* Calculate offset within DataBuffer */
02969             SrbInfo->DataOffset = MmGetSystemAddressForMdl(Irp->MdlAddress);
02970             Srb->DataBuffer = SrbInfo->DataOffset +
02971                 (ULONG)((PUCHAR)Srb->DataBuffer -
02972                 (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress));
02973         }
02974 
02975         if (DeviceExtension->AdapterObject)
02976         {
02977             /* Flush buffers */
02978             KeFlushIoBuffers(Irp->MdlAddress,
02979                              Srb->SrbFlags & SRB_FLAGS_DATA_IN ? TRUE : FALSE,
02980                              TRUE);
02981         }
02982 
02983         if (DeviceExtension->MapRegisters)
02984         {
02985             /* Calculate number of needed map registers */
02986             SrbInfo->NumberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
02987                     Srb->DataBuffer,
02988                     Srb->DataTransferLength);
02989 
02990             /* Allocate adapter channel */
02991             Status = IoAllocateAdapterChannel(DeviceExtension->AdapterObject,
02992                                               DeviceExtension->DeviceObject,
02993                                               SrbInfo->NumberOfMapRegisters,
02994                                               SpiAdapterControl,
02995                                               SrbInfo);
02996 
02997             if (!NT_SUCCESS(Status))
02998             {
02999                 DPRINT1("IoAllocateAdapterChannel() failed!\n");
03000 
03001                 Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
03002                 ScsiPortNotification(RequestComplete,
03003                                      DeviceExtension + 1,
03004                                      Srb);
03005 
03006                 ScsiPortNotification(NextRequest,
03007                                      DeviceExtension + 1);
03008 
03009                 /* Request DPC for that work */
03010                 IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
03011             }
03012 
03013             /* Control goes to SpiAdapterControl */
03014             return;
03015         }
03016     }
03017 
03018     /* Increase active request counter */
03019     CounterResult = InterlockedIncrement(&DeviceExtension->ActiveRequestCounter);
03020 
03021     if (CounterResult == 0 &&
03022         DeviceExtension->AdapterObject != NULL &&
03023         !DeviceExtension->MapRegisters)
03024     {
03025         IoAllocateAdapterChannel(
03026             DeviceExtension->AdapterObject,
03027             DeviceObject,
03028             DeviceExtension->PortCapabilities.MaximumPhysicalPages,
03029             ScsiPortAllocateAdapterChannel,
03030             LunExtension
03031             );
03032 
03033         return;
03034     }
03035 
03036     KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
03037 
03038     if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0],
03039                                 ScsiPortStartPacket,
03040                                 DeviceObject))
03041     {
03042         DPRINT("Synchronization failed!\n");
03043 
03044         Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
03045         Irp->IoStatus.Information = 0;
03046         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
03047 
03048         IoCompleteRequest(Irp, IO_NO_INCREMENT);
03049     }
03050     else
03051     {
03052         /* Release the spinlock only */
03053         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
03054     }
03055 
03056 
03057     DPRINT("ScsiPortStartIo() done\n");
03058 }
03059 
03060 
03061 static BOOLEAN NTAPI
03062 ScsiPortStartPacket(IN OUT PVOID Context)
03063 {
03064     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
03065     PIO_STACK_LOCATION IrpStack;
03066     PSCSI_REQUEST_BLOCK Srb;
03067     PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)Context;
03068     PSCSI_PORT_LUN_EXTENSION LunExtension;
03069     PSCSI_REQUEST_BLOCK_INFO SrbInfo;
03070     BOOLEAN Result;
03071     BOOLEAN StartTimer;
03072 
03073     DPRINT("ScsiPortStartPacket() called\n");
03074 
03075     DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
03076 
03077     IrpStack = IoGetCurrentIrpStackLocation(DeviceObject->CurrentIrp);
03078     Srb = IrpStack->Parameters.Scsi.Srb;
03079 
03080     /* Get LUN extension */
03081     LunExtension = SpiGetLunExtension(DeviceExtension,
03082                                       Srb->PathId,
03083                                       Srb->TargetId,
03084                                       Srb->Lun);
03085 
03086     /* Check if we are in a reset state */
03087     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET)
03088     {
03089         /* Mark the we've got requests while being in the reset state */
03090         DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET_REQUEST;
03091         return TRUE;
03092     }
03093 
03094     /* Set the time out value */
03095     DeviceExtension->TimerCount = Srb->TimeOutValue;
03096 
03097     /* We are busy */
03098     DeviceExtension->Flags |= SCSI_PORT_DEVICE_BUSY;
03099 
03100     if (LunExtension->RequestTimeout != -1)
03101     {
03102         /* Timer already active */
03103         StartTimer = FALSE;
03104     }
03105     else
03106     {
03107         /* It hasn't been initialized yet */
03108         LunExtension->RequestTimeout = Srb->TimeOutValue;
03109         StartTimer = TRUE;
03110     }
03111 
03112     if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
03113     {
03114         /* Handle bypass-requests */
03115 
03116         /* Is this an abort request? */
03117         if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
03118         {
03119             /* Get pointer to SRB info structure */
03120             SrbInfo = SpiGetSrbData(DeviceExtension,
03121                                     Srb->PathId,
03122                                     Srb->TargetId,
03123                                     Srb->Lun,
03124                                     Srb->QueueTag);
03125 
03126             /* Check if the request is still "active" */
03127             if (SrbInfo == NULL ||
03128                 SrbInfo->Srb == NULL ||
03129                 !(SrbInfo->Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE))
03130             {
03131                 /* It's not, mark it as active then */
03132                 Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
03133 
03134                 if (StartTimer)
03135                     LunExtension->RequestTimeout = -1;
03136 
03137                 DPRINT("Request has been already completed, but abort request came\n");
03138                 Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
03139 
03140                 /* Notify about request complete */
03141                 ScsiPortNotification(RequestComplete,
03142                                      DeviceExtension->MiniPortDeviceExtension,
03143                                      Srb);
03144 
03145                 /* and about readiness for the next request */
03146                 ScsiPortNotification(NextRequest,
03147                                      DeviceExtension->MiniPortDeviceExtension);
03148 
03149                 /* They might ask for some work, so queue the DPC for them */
03150                 IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
03151 
03152                 /* We're done in this branch */
03153                 return TRUE;
03154             }
03155         }
03156         else
03157         {
03158             /* Add number of queued requests */
03159             LunExtension->QueueCount++;
03160         }
03161 
03162         /* Bypass requests don't need request sense */
03163         LunExtension->Flags &= ~LUNEX_NEED_REQUEST_SENSE;
03164 
03165         /* Is disconnect disabled for this request? */
03166         if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
03167         {
03168             /* Set the corresponding flag */
03169             DeviceExtension->Flags &= ~SCSI_PORT_DISCONNECT_ALLOWED;
03170         }
03171 
03172         /* Transfer timeout value from Srb to Lun */
03173         LunExtension->RequestTimeout = Srb->TimeOutValue;
03174     }
03175     else
03176     {
03177         if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
03178         {
03179             /* It's a disconnect, so no more requests can go */
03180             DeviceExtension->Flags &= ~SCSI_PORT_DISCONNECT_ALLOWED;
03181         }
03182 
03183         LunExtension->Flags |= SCSI_PORT_LU_ACTIVE;
03184 
03185         /* Increment queue count */
03186         LunExtension->QueueCount++;
03187 
03188         /* If it's tagged - special thing */
03189         if (Srb->QueueTag != SP_UNTAGGED)
03190         {
03191             SrbInfo = &DeviceExtension->SrbInfo[Srb->QueueTag - 1];
03192 
03193             /* Chek for consistency */
03194             ASSERT(SrbInfo->Requests.Blink == NULL);
03195 
03196             /* Insert it into the list of requests */
03197             InsertTailList(&LunExtension->SrbInfo.Requests, &SrbInfo->Requests);
03198         }
03199     }
03200 
03201     /* Mark this Srb active */
03202     Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
03203 
03204     /* Call HwStartIo routine */
03205     Result = DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
03206                                         Srb);
03207 
03208     /* If notification is needed, then request a DPC */
03209     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
03210         IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
03211 
03212     return Result;
03213 }
03214 
03215 IO_ALLOCATION_ACTION
03216 NTAPI
03217 SpiAdapterControl(PDEVICE_OBJECT DeviceObject,
03218                   PIRP Irp,
03219                   PVOID MapRegisterBase,
03220                   PVOID Context)
03221 {
03222     PSCSI_REQUEST_BLOCK Srb;
03223     PSCSI_SG_ADDRESS ScatterGatherList;
03224     KIRQL CurrentIrql;
03225     PIO_STACK_LOCATION IrpStack;
03226     ULONG TotalLength = 0;
03227     PSCSI_REQUEST_BLOCK_INFO SrbInfo;
03228     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
03229     PUCHAR DataVA;
03230     BOOLEAN WriteToDevice;
03231 
03232     /* Get pointers to SrbInfo and DeviceExtension */
03233     SrbInfo = (PSCSI_REQUEST_BLOCK_INFO)Context;
03234     DeviceExtension = DeviceObject->DeviceExtension;
03235 
03236     /* Get pointer to SRB */
03237     IrpStack = IoGetCurrentIrpStackLocation(Irp);
03238     Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
03239 
03240     /* Depending on the map registers number, we allocate
03241        either from NonPagedPool, or from our static list */
03242     if (SrbInfo->NumberOfMapRegisters > MAX_SG_LIST)
03243     {
03244         SrbInfo->ScatterGather = ExAllocatePoolWithTag(
03245             NonPagedPool, SrbInfo->NumberOfMapRegisters * sizeof(SCSI_SG_ADDRESS), TAG_SCSIPORT);
03246 
03247         if (SrbInfo->ScatterGather == NULL)
03248             ASSERT(FALSE);
03249 
03250         Srb->SrbFlags |= SRB_FLAGS_SGLIST_FROM_POOL;
03251     }
03252     else
03253     {
03254         SrbInfo->ScatterGather = SrbInfo->ScatterGatherList;
03255     }
03256 
03257     /* Use chosen SG list source */
03258     ScatterGatherList = SrbInfo->ScatterGather;
03259 
03260     /* Save map registers base */
03261     SrbInfo->BaseOfMapRegister = MapRegisterBase;
03262 
03263     /* Determine WriteToDevice flag */
03264     WriteToDevice = Srb->SrbFlags & SRB_FLAGS_DATA_OUT ? TRUE : FALSE;
03265 
03266     /* Get virtual address of the data buffer */
03267     DataVA = (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress) +
03268                 ((PCHAR)Srb->DataBuffer - SrbInfo->DataOffset);
03269 
03270     /* Build the actual SG list */
03271     while (TotalLength < Srb->DataTransferLength)
03272     {
03273         if (!ScatterGatherList)
03274             break;
03275 
03276         ScatterGatherList->Length = Srb->DataTransferLength - TotalLength;
03277         ScatterGatherList->PhysicalAddress = IoMapTransfer(NULL,
03278                                                            Irp->MdlAddress,
03279                                                            MapRegisterBase,
03280                                                            DataVA + TotalLength,
03281                                                            &ScatterGatherList->Length,
03282                                                            WriteToDevice);
03283 
03284         TotalLength += ScatterGatherList->Length;
03285         ScatterGatherList++;
03286     }
03287 
03288     /* Schedule an active request */
03289     InterlockedIncrement(&DeviceExtension->ActiveRequestCounter );
03290     KeAcquireSpinLock(&DeviceExtension->SpinLock, &CurrentIrql);
03291     KeSynchronizeExecution(DeviceExtension->Interrupt[0],
03292                            ScsiPortStartPacket,
03293                            DeviceObject);
03294     KeReleaseSpinLock(&DeviceExtension->SpinLock, CurrentIrql);
03295 
03296     return DeallocateObjectKeepRegisters;
03297 }
03298 
03299 static PSCSI_PORT_LUN_EXTENSION
03300 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
03301 {
03302     PSCSI_PORT_LUN_EXTENSION LunExtension;
03303     ULONG LunExtensionSize;
03304 
03305     DPRINT("SpiAllocateLunExtension (%p)\n",
03306         DeviceExtension);
03307 
03308     /* Round LunExtensionSize first to the sizeof LONGLONG */
03309     LunExtensionSize = (DeviceExtension->LunExtensionSize +
03310         sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1);
03311 
03312     LunExtensionSize += sizeof(SCSI_PORT_LUN_EXTENSION);
03313     DPRINT("LunExtensionSize %lu\n", LunExtensionSize);
03314 
03315     LunExtension = ExAllocatePoolWithTag(NonPagedPool, LunExtensionSize, TAG_SCSIPORT);
03316     if (LunExtension == NULL)
03317     {
03318         DPRINT1("Out of resources!\n");
03319         return NULL;
03320     }
03321 
03322     /* Zero everything */
03323     RtlZeroMemory(LunExtension, LunExtensionSize);
03324 
03325     /* Initialize a list of requests */
03326     InitializeListHead(&LunExtension->SrbInfo.Requests);
03327 
03328     /* Initialize timeout counter */
03329     LunExtension->RequestTimeout = -1;
03330 
03331     /* Set maximum queue size */
03332     LunExtension->MaxQueueCount = 256;
03333 
03334     /* Initialize request queue */
03335     KeInitializeDeviceQueue (&LunExtension->DeviceQueue);
03336 
03337     return LunExtension;
03338 }
03339 
03340 static PSCSI_PORT_LUN_EXTENSION
03341 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
03342             IN UCHAR PathId,
03343             IN UCHAR TargetId,
03344             IN UCHAR Lun)
03345 {
03346     PSCSI_PORT_LUN_EXTENSION LunExtension;
03347 
03348     DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
03349         DeviceExtension, PathId, TargetId, Lun);
03350 
03351     /* Get appropriate list */
03352     LunExtension = DeviceExtension->LunExtensionList[(TargetId + Lun) % LUS_NUMBER];
03353 
03354     /* Iterate it until we find what we need */
03355     while (LunExtension)
03356     {
03357         if (LunExtension->TargetId == TargetId &&
03358             LunExtension->Lun == Lun &&
03359             LunExtension->PathId == PathId)
03360         {
03361             /* All matches, return */
03362             return LunExtension;
03363         }
03364 
03365         /* Advance to the next item */
03366         LunExtension = LunExtension->Next;
03367     }
03368 
03369     /* We did not find anything */
03370     DPRINT("Nothing found\n");
03371     return NULL;
03372 }
03373 
03374 static PSCSI_REQUEST_BLOCK_INFO
03375 SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
03376                          PSCSI_PORT_LUN_EXTENSION LunExtension,
03377                          PSCSI_REQUEST_BLOCK Srb)
03378 {
03379     PCHAR SrbExtension;
03380     PSCSI_REQUEST_BLOCK_INFO SrbInfo;
03381 
03382     /* Spinlock must be held while this function executes */
03383     KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
03384 
03385     /* Allocate SRB data structure */
03386     if (DeviceExtension->NeedSrbDataAlloc)
03387     {
03388         /* Treat the abort request in a special way */
03389         if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
03390         {
03391             SrbInfo = SpiGetSrbData(DeviceExtension,
03392                                     Srb->PathId,
03393                                     Srb->TargetId,
03394                                     Srb->Lun,
03395                                     Srb->QueueTag);
03396         }
03397         else if (Srb->SrbFlags &
03398                  (SRB_FLAGS_QUEUE_ACTION_ENABLE | SRB_FLAGS_NO_QUEUE_FREEZE) &&
03399                  !(Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
03400                  )
03401         {
03402             /* Do not process tagged commands if need request sense is set */
03403             if (LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE)
03404             {
03405                 ASSERT(!(LunExtension->Flags & LUNEX_REQUEST_PENDING));
03406 
03407                 LunExtension->PendingRequest = Srb->OriginalRequest;
03408                 LunExtension->Flags |= LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE;
03409 
03410                 /* Relese the spinlock and return */
03411                 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
03412                 return NULL;
03413             }
03414 
03415             ASSERT(LunExtension->SrbInfo.Srb == NULL);
03416             SrbInfo = DeviceExtension->FreeSrbInfo;
03417 
03418             if (SrbInfo == NULL)
03419             {
03420                 /* No SRB structures left in the list. We have to leave
03421                    and wait while we are called again */
03422 
03423                 DeviceExtension->Flags |= SCSI_PORT_REQUEST_PENDING;
03424                 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
03425                 return NULL;
03426             }
03427 
03428             DeviceExtension->FreeSrbInfo = (PSCSI_REQUEST_BLOCK_INFO)SrbInfo->Requests.Flink;
03429 
03430             /* QueueTag must never be 0, so +1 to it */
03431             Srb->QueueTag = (UCHAR)(SrbInfo - DeviceExtension->SrbInfo) + 1;
03432         }
03433         else
03434         {
03435             /* Usual untagged command */
03436             if (
03437                 (!IsListEmpty(&LunExtension->SrbInfo.Requests) ||
03438                 LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE) &&
03439                 !(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
03440                 )
03441             {
03442                 /* Mark it as pending and leave */
03443                 ASSERT(!(LunExtension->Flags & LUNEX_REQUEST_PENDING));
03444                 LunExtension->Flags |= LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE;
03445                 LunExtension->PendingRequest = Srb->OriginalRequest;
03446 
03447                 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
03448                 return(NULL);
03449             }
03450 
03451             Srb->QueueTag = SP_UNTAGGED;
03452             SrbInfo = &LunExtension->SrbInfo;
03453         }
03454     }
03455     else
03456     {
03457         Srb->QueueTag = SP_UNTAGGED;
03458         SrbInfo = &LunExtension->SrbInfo;
03459     }
03460 
03461     /* Allocate SRB extension structure */
03462     if (DeviceExtension->NeedSrbExtensionAlloc)
03463     {
03464         /* Check the list of free extensions */
03465         SrbExtension = DeviceExtension->FreeSrbExtensions;
03466 
03467         /* If no free extensions... */
03468         if (SrbExtension == NULL)
03469         {
03470             /* Free SRB data */
03471             if (Srb->Function != SRB_FUNCTION_ABORT_COMMAND &&
03472                 Srb->QueueTag != SP_UNTAGGED)
03473             {
03474                 SrbInfo->Requests.Blink = NULL;
03475                 SrbInfo->Requests.Flink = (PLIST_ENTRY)DeviceExtension->FreeSrbInfo;
03476                 DeviceExtension->FreeSrbInfo = SrbInfo;
03477             }
03478 
03479             /* Return, in order to be called again later */
03480             DeviceExtension->Flags |= SCSI_PORT_REQUEST_PENDING;
03481             KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
03482             return NULL;
03483         }
03484 
03485         /* Remove that free SRB extension from the list (since
03486            we're going to use it) */
03487         DeviceExtension->FreeSrbExtensions = *((PVOID *)SrbExtension);
03488 
03489         /* Spinlock can be released now */
03490         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
03491 
03492         Srb->SrbExtension = SrbExtension;
03493 
03494         if (Srb->SenseInfoBuffer != NULL &&
03495             DeviceExtension->SupportsAutoSense)
03496         {
03497             /* Store pointer to the SenseInfo buffer */
03498             SrbInfo->SaveSenseRequest = Srb->SenseInfoBuffer;
03499 
03500             /* Does data fit the buffer? */
03501             if (Srb->SenseInfoBufferLength > sizeof(SENSE_DATA))
03502             {
03503                 /* No, disabling autosense at all */
03504                 Srb->SrbFlags |= SRB_FLAGS_DISABLE_AUTOSENSE;
03505             }
03506             else
03507             {
03508                 /* Yes, update the buffer pointer */
03509                 Srb->SenseInfoBuffer = SrbExtension + DeviceExtension->SrbExtensionSize;
03510             }
03511         }
03512     }
03513     else
03514     {
03515         /* Cleanup... */
03516         Srb->SrbExtension = NULL;
03517         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
03518     }
03519 
03520     return SrbInfo;
03521 }
03522 
03523 
03524 static NTSTATUS
03525 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject,
03526         IN PSCSI_LUN_INFO LunInfo)
03527 {
03528     IO_STATUS_BLOCK IoStatusBlock;
03529     PIO_STACK_LOCATION IrpStack;
03530     KEVENT Event;
03531     KIRQL Irql;
03532     PIRP Irp;
03533     NTSTATUS Status;
03534     PINQUIRYDATA InquiryBuffer;
03535     PSENSE_DATA SenseBuffer;
03536     BOOLEAN KeepTrying = TRUE;
03537     ULONG RetryCount = 0;
03538     SCSI_REQUEST_BLOCK Srb;
03539     PCDB Cdb;
03540     PSCSI_PORT_LUN_EXTENSION LunExtension;
03541     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
03542 
03543     DPRINT ("SpiSendInquiry() called\n");
03544 
03545     DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
03546 
03547     InquiryBuffer = ExAllocatePoolWithTag (NonPagedPool, INQUIRYDATABUFFERSIZE, TAG_SCSIPORT);
03548     if (InquiryBuffer == NULL)
03549         return STATUS_INSUFFICIENT_RESOURCES;
03550 
03551     SenseBuffer = ExAllocatePoolWithTag (NonPagedPool, SENSE_BUFFER_SIZE, TAG_SCSIPORT);
03552     if (SenseBuffer == NULL)
03553     {
03554         ExFreePool(InquiryBuffer);
03555         return STATUS_INSUFFICIENT_RESOURCES;
03556     }
03557 
03558     while (KeepTrying)
03559     {
03560         /* Initialize event for waiting */
03561         KeInitializeEvent(&Event,
03562                           NotificationEvent,
03563                           FALSE);
03564 
03565         /* Create an IRP */
03566         Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_IN,
03567             DeviceObject,
03568             NULL,
03569             0,
03570             InquiryBuffer,
03571             INQUIRYDATABUFFERSIZE,
03572             TRUE,
03573             &Event,
03574             &IoStatusBlock);
03575         if (Irp == NULL)
03576         {
03577             DPRINT("IoBuildDeviceIoControlRequest() failed\n");
03578             return STATUS_INSUFFICIENT_RESOURCES;
03579         }
03580 
03581         /* Prepare SRB */
03582         RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
03583 
03584         Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
03585         Srb.OriginalRequest = Irp;
03586         Srb.PathId = LunInfo->PathId;
03587         Srb.TargetId = LunInfo->TargetId;
03588         Srb.Lun = LunInfo->Lun;
03589         Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
03590         Srb.SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
03591         Srb.TimeOutValue = 4;
03592         Srb.CdbLength = 6;
03593 
03594         Srb.SenseInfoBuffer = SenseBuffer;
03595         Srb.SenseInfoBufferLength = SENSE_BUFFER_SIZE;
03596 
03597         Srb.DataBuffer = InquiryBuffer;
03598         Srb.DataTransferLength = INQUIRYDATABUFFERSIZE;
03599 
03600         /* Attach Srb to the Irp */
03601         IrpStack = IoGetNextIrpStackLocation (Irp);
03602         IrpStack->Parameters.Scsi.Srb = &Srb;
03603 
03604         /* Fill in CDB */
03605         Cdb = (PCDB)Srb.Cdb;
03606         Cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
03607         Cdb->CDB6INQUIRY.LogicalUnitNumber = LunInfo->Lun;
03608         Cdb->CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE;
03609 
03610         /* Call the driver */
03611         Status = IoCallDriver(DeviceObject, Irp);
03612 
03613         /* Wait for it to complete */
03614         if (Status == STATUS_PENDING)
03615         {
03616             DPRINT("SpiSendInquiry(): Waiting for the driver to process request...\n");
03617             KeWaitForSingleObject(&Event,
03618                 Executive,
03619                 KernelMode,
03620                 FALSE,
03621                 NULL);
03622             Status = IoStatusBlock.Status;
03623         }
03624 
03625         DPRINT("SpiSendInquiry(): Request processed by driver, status = 0x%08X\n", Status);
03626 
03627         if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_SUCCESS)
03628         {
03629             /* All fine, copy data over */
03630             RtlCopyMemory(LunInfo->InquiryData,
03631                           InquiryBuffer,
03632                           INQUIRYDATABUFFERSIZE);
03633 
03634             Status = STATUS_SUCCESS;
03635             KeepTrying = FALSE;
03636         }
03637         else
03638         {
03639             DPRINT("Inquiry SRB failed with SrbStatus 0x%08X\n", Srb.SrbStatus);
03640             /* Check if the queue is frozen */
03641             if (Srb.SrbStatus & SRB_STATUS_QUEUE_FROZEN)
03642             {
03643                 /* Something weird happened, deal with it (unfreeze the queue) */
03644                 KeepTrying = FALSE;
03645 
03646                 DPRINT("SpiSendInquiry(): the queue is frozen at TargetId %d\n", Srb.TargetId);
03647 
03648                 LunExtension = SpiGetLunExtension(DeviceExtension,
03649                                                   LunInfo->PathId,
03650                                                   LunInfo->TargetId,
03651                                                   LunInfo->Lun);
03652 
03653                 /* Clear frozen flag */
03654                 LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
03655 
03656                 /* Acquire the spinlock */
03657                 KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
03658 
03659                 /* Process the request */
03660                 SpiGetNextRequestFromLun(DeviceObject->DeviceExtension, LunExtension);
03661 
03662                 /* SpiGetNextRequestFromLun() releases the spinlock,
03663                    so we just lower irql back to what it was before */
03664                 KeLowerIrql(Irql);
03665             }
03666 
03667             /* Check if data overrun happened */
03668             if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN)
03669             {
03670                 DPRINT("Data overrun at TargetId %d\n", LunInfo->TargetId);
03671                 /* Nothing dramatic, just copy data, but limiting the size */
03672                 RtlCopyMemory(LunInfo->InquiryData,
03673                               InquiryBuffer,
03674                               (Srb.DataTransferLength > INQUIRYDATABUFFERSIZE) ?
03675                               INQUIRYDATABUFFERSIZE : Srb.DataTransferLength);
03676 
03677                 Status = STATUS_SUCCESS;
03678                 KeepTrying = FALSE;
03679             }
03680             else if ((Srb.SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
03681                 SenseBuffer->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST)
03682             {
03683                 /* LUN is not valid, but some device responds there.
03684                    Mark it as invalid anyway */
03685 
03686                 Status = STATUS_INVALID_DEVICE_REQUEST;
03687                 KeepTrying = FALSE;
03688             }
03689             else
03690             {
03691                 /* Retry a couple of times if no timeout happened */
03692                 if ((RetryCount < 2) &&
03693                     (SRB_STATUS(Srb.SrbStatus) != SRB_STATUS_NO_DEVICE) &&
03694                     (SRB_STATUS(Srb.SrbStatus) != SRB_STATUS_SELECTION_TIMEOUT))
03695                 {
03696                     RetryCount++;
03697                     KeepTrying = TRUE;
03698                 }
03699                 else
03700                 {
03701                     /* That's all, go to exit */
03702                     KeepTrying = FALSE;
03703 
03704                     /* Set status according to SRB status */
03705                     if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_BAD_FUNCTION ||
03706                         SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_BAD_SRB_BLOCK_LENGTH)
03707                     {
03708                         Status = STATUS_INVALID_DEVICE_REQUEST;
03709                     }
03710                     else
03711                     {
03712                         Status = STATUS_IO_DEVICE_ERROR;
03713                     }
03714                 }
03715             }
03716         }
03717     }
03718 
03719     /* Free buffers */
03720     ExFreePool(InquiryBuffer);
03721     ExFreePool(SenseBuffer);
03722 
03723     DPRINT("SpiSendInquiry() done with Status 0x%08X\n", Status);
03724 
03725     return Status;
03726 }
03727 
03728 
03729 /* Scans all SCSI buses */
03730 static VOID
03731 SpiScanAdapter(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
03732 {
03733     PSCSI_PORT_LUN_EXTENSION LunExtension;
03734     ULONG Bus;
03735     ULONG Target;
03736     ULONG Lun;
03737     PSCSI_BUS_SCAN_INFO BusScanInfo;
03738     PSCSI_LUN_INFO LastLunInfo, LunInfo, LunInfoExists;
03739     BOOLEAN DeviceExists;
03740     ULONG Hint;
03741     NTSTATUS Status;
03742     ULONG DevicesFound;
03743 
03744     DPRINT("SpiScanAdapter() called\n");
03745 
03746     /* Scan all buses */
03747     for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
03748     {
03749         DPRINT("    Scanning bus %d\n", Bus);
03750         DevicesFound = 0;
03751 
03752         /* Get pointer to the scan information */
03753         BusScanInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus];
03754 
03755         if (BusScanInfo)
03756         {
03757             /* Find the last LUN info in the list */
03758             LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
03759             LastLunInfo = LunInfo;
03760 
03761             while (LunInfo != NULL)
03762             {
03763                 LastLunInfo = LunInfo;
03764                 LunInfo = LunInfo->Next;
03765             }
03766         }
03767         else
03768         {
03769             /* We need to allocate this buffer */
03770             BusScanInfo = ExAllocatePoolWithTag(NonPagedPool, sizeof(SCSI_BUS_SCAN_INFO), TAG_SCSIPORT);
03771 
03772             if (!BusScanInfo)
03773             {
03774                 DPRINT1("Out of resources!\n");
03775                 return;
03776             }
03777 
03778             /* Store the pointer in the BusScanInfo array */
03779             DeviceExtension->BusesConfig->BusScanInfo[Bus] = BusScanInfo;
03780 
03781             /* Fill this struct (length and bus ids for now) */
03782             BusScanInfo->Length = sizeof(SCSI_BUS_SCAN_INFO);
03783             BusScanInfo->LogicalUnitsCount = 0;
03784             BusScanInfo->BusIdentifier = DeviceExtension->PortConfig->InitiatorBusId[Bus];
03785             BusScanInfo->LunInfo = NULL;
03786 
03787             /* Set pointer to the last LUN info to NULL */
03788             LastLunInfo = NULL;
03789         }
03790 
03791         /* Create LUN information structure */
03792         LunInfo = ExAllocatePoolWithTag(PagedPool, sizeof(SCSI_LUN_INFO), TAG_SCSIPORT);
03793 
03794         if (LunInfo == NULL)
03795         {
03796             DPRINT1("Out of resources!\n");
03797             return;
03798         }
03799 
03800         RtlZeroMemory(LunInfo, sizeof(SCSI_LUN_INFO));
03801 
03802         /* Create LunExtension */
03803         LunExtension = SpiAllocateLunExtension (DeviceExtension);
03804 
03805         /* And send INQUIRY to every target */
03806         for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
03807         {
03808             /* TODO: Support scan bottom-up */
03809 
03810             /* Skip if it's the same address */
03811             if (Target == BusScanInfo->BusIdentifier)
03812                 continue;
03813 
03814             /* Try to find an existing device here */
03815             DeviceExists = FALSE;
03816             LunInfoExists = BusScanInfo->LunInfo;
03817 
03818             /* Find matching address on this bus */
03819             while (LunInfoExists)
03820             {
03821                 if (LunInfoExists->TargetId == Target)
03822                 {
03823                     DeviceExists = TRUE;
03824                     break;
03825                 }
03826 
03827                 /* Advance to the next one */
03828                 LunInfoExists = LunInfoExists->Next;
03829             }
03830 
03831             /* No need to bother rescanning, since we already did that before */
03832             if (DeviceExists)
03833                 continue;
03834 
03835             /* Scan all logical units */
03836             for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
03837             {
03838                 if ((!LunExtension) || (!LunInfo))
03839                     break;
03840 
03841                 /* Add extension to the list */
03842                 Hint = (Target + Lun) % LUS_NUMBER;
03843                 LunExtension->Next = DeviceExtension->LunExtensionList[Hint];
03844                 DeviceExtension->LunExtensionList[Hint] = LunExtension;
03845 
03846                 /* Fill Path, Target, Lun fields */
03847                 LunExtension->PathId = LunInfo->PathId = (UCHAR)Bus;
03848                 LunExtension->TargetId = LunInfo->TargetId = (UCHAR) Target;
03849                 LunExtension->Lun = LunInfo->Lun = (UCHAR)Lun;
03850 
03851                 /* Set flag to prevent race conditions */
03852                 LunExtension->Flags |= SCSI_PORT_SCAN_IN_PROGRESS;
03853 
03854                 /* Zero LU extension contents */
03855                 if (DeviceExtension->LunExtensionSize)
03856                 {
03857                     RtlZeroMemory(LunExtension + 1,
03858                                   DeviceExtension->LunExtensionSize);
03859                 }
03860 
03861                 /* Finally send the inquiry command */
03862                 Status = SpiSendInquiry(DeviceExtension->DeviceObject, LunInfo);
03863 
03864                 if (NT_SUCCESS(Status))
03865                 {
03866                     /* Let's see if we really found a device */
03867                     PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData;
03868 
03869                     /* Check if this device is unsupported */
03870                     if (InquiryData->DeviceTypeQualifier == DEVICE_QUALIFIER_NOT_SUPPORTED)
03871                     {
03872                         DeviceExtension->LunExtensionList[Hint] =
03873                             DeviceExtension->LunExtensionList[Hint]->Next;
03874 
03875                         continue;
03876                     }
03877 
03878                     /* Clear the "in scan" flag */
03879                     LunExtension->Flags &= ~SCSI_PORT_SCAN_IN_PROGRESS;
03880 
03881                     DPRINT("SpiScanAdapter(): Found device of type %d at bus %d tid %d lun %d\n",
03882                         InquiryData->DeviceType, Bus, Target, Lun);
03883 
03884                     /* Add this info to the linked list */
03885                     LunInfo->Next = NULL;
03886                     if (LastLunInfo)
03887                         LastLunInfo->Next = LunInfo;
03888                     else
03889                         BusScanInfo->LunInfo = LunInfo;
03890 
03891                     /* Store the last LUN info */
03892                     LastLunInfo = LunInfo;
03893 
03894                     /* Store DeviceObject */
03895                     LunInfo->DeviceObject = DeviceExtension->DeviceObject;
03896 
03897                     /* Allocate another buffer */
03898                     LunInfo = ExAllocatePoolWithTag(PagedPool, sizeof(SCSI_LUN_INFO), TAG_SCSIPORT);
03899 
03900                     if (!LunInfo)
03901                     {
03902                         DPRINT1("Out of resources!\n");
03903                         break;
03904                     }
03905 
03906                     RtlZeroMemory(LunInfo, sizeof(SCSI_LUN_INFO));
03907 
03908                     /* Create a new LU extension */
03909                     LunExtension = SpiAllocateLunExtension(DeviceExtension);
03910 
03911                     DevicesFound++;
03912                 }
03913                 else
03914                 {
03915                     /* Remove this LUN from the list */
03916                     DeviceExtension->LunExtensionList[Hint] =
03917                         DeviceExtension->LunExtensionList[Hint]->Next;
03918 
03919                     /* Decide whether we are continuing or not */
03920                     if (Status == STATUS_INVALID_DEVICE_REQUEST)
03921                         continue;
03922                     else
03923                         break;
03924                 }
03925             }
03926         }
03927 
03928         /* Free allocated buffers */
03929         if (LunExtension)
03930             ExFreePool(LunExtension);
03931 
03932         if (LunInfo)
03933             ExFreePool(LunInfo);
03934 
03935         /* Sum what we found */
03936         BusScanInfo->LogicalUnitsCount += (UCHAR) DevicesFound;
03937         DPRINT("    Found %d devices on bus %d\n", DevicesFound, Bus);
03938     }
03939 
03940     DPRINT ("SpiScanAdapter() done\n");
03941 }
03942 
03943 
03944 static NTSTATUS
03945 SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
03946           PIRP Irp)
03947 {
03948     ULONG InquiryDataSize;
03949     PSCSI_LUN_INFO LunInfo;
03950     ULONG BusCount, LunCount, Length;
03951     PIO_STACK_LOCATION IrpStack;
03952     PSCSI_ADAPTER_BUS_INFO AdapterBusInfo;
03953     PSCSI_INQUIRY_DATA InquiryData;
03954     PSCSI_BUS_DATA BusData;
03955     ULONG Bus;
03956     PUCHAR Buffer;
03957 
03958     DPRINT("SpiGetInquiryData() called\n");
03959 
03960     /* Get pointer to the buffer */
03961     IrpStack = IoGetCurrentIrpStackLocation(Irp);
03962     Buffer = Irp->AssociatedIrp.SystemBuffer;
03963 
03964     /* Initialize bus and LUN counters */
03965     BusCount = DeviceExtension->BusesConfig->NumberOfBuses;
03966     LunCount = 0;
03967 
03968     /* Calculate total number of LUNs */
03969     for (Bus = 0; Bus < BusCount; Bus++)
03970         LunCount += DeviceExtension->BusesConfig->BusScanInfo[Bus]->LogicalUnitsCount;
03971 
03972     /* Calculate size of inquiry data, rounding up to sizeof(ULONG) */
03973     InquiryDataSize =
03974         ((sizeof(SCSI_INQUIRY_DATA) - 1 + INQUIRYDATABUFFERSIZE +
03975         sizeof(ULONG) - 1) & ~(sizeof(ULONG) - 1));
03976 
03977     /* Calculate data size */
03978     Length = sizeof(SCSI_ADAPTER_BUS_INFO) + (BusCount - 1) *
03979         sizeof(SCSI_BUS_DATA);
03980 
03981     Length += InquiryDataSize * LunCount;
03982 
03983     /* Check, if all data is going to fit into provided buffer */
03984     if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < Length)
03985     {
03986         Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
03987         return STATUS_BUFFER_TOO_SMALL;
03988     }
03989 
03990     /* Store data size in the IRP */
03991     Irp->IoStatus.Information = Length;
03992 
03993     DPRINT("Data size: %lu\n", Length);
03994 
03995     AdapterBusInfo = (PSCSI_ADAPTER_BUS_INFO)Buffer;
03996 
03997     AdapterBusInfo->NumberOfBuses = (UCHAR)BusCount;
03998 
03999     /* Point InquiryData to the corresponding place inside Buffer */
04000     InquiryData = (PSCSI_INQUIRY_DATA)(Buffer + sizeof(SCSI_ADAPTER_BUS_INFO) +
04001         (BusCount - 1) * sizeof(SCSI_BUS_DATA));
04002 
04003     /* Loop each bus */
04004     for (Bus = 0; Bus < BusCount; Bus++)
04005     {
04006         BusData = &AdapterBusInfo->BusData[Bus];
04007 
04008         /* Calculate and save an offset of the inquiry data */
04009         BusData->InquiryDataOffset = (PUCHAR)InquiryData - Buffer;
04010 
04011         /* Get a pointer to the LUN information structure */
04012         LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
04013 
04014         /* Store Initiator Bus Id */
04015         BusData->InitiatorBusId =
04016             DeviceExtension->BusesConfig->BusScanInfo[Bus]->BusIdentifier;
04017 
04018         /* Store LUN count */
04019         BusData->NumberOfLogicalUnits =
04020             DeviceExtension->BusesConfig->BusScanInfo[Bus]->LogicalUnitsCount;
04021 
04022         /* Loop all LUNs */
04023         while (LunInfo != NULL)
04024         {
04025             DPRINT("(Bus %lu Target %lu Lun %lu)\n",
04026                 Bus, LunInfo->TargetId, LunInfo->Lun);
04027 
04028             /* Fill InquiryData with values */
04029             InquiryData->PathId = LunInfo->PathId;
04030             InquiryData->TargetId = LunInfo->TargetId;
04031             InquiryData->Lun = LunInfo->Lun;
04032             InquiryData->InquiryDataLength = INQUIRYDATABUFFERSIZE;
04033             InquiryData->DeviceClaimed = LunInfo->DeviceClaimed;
04034             InquiryData->NextInquiryDataOffset =
04035                 (PUCHAR)InquiryData + InquiryDataSize - Buffer;
04036 
04037             /* Copy data in it */
04038             RtlCopyMemory(InquiryData->InquiryData,
04039                           LunInfo->InquiryData,
04040                           INQUIRYDATABUFFERSIZE);
04041 
04042             /* Move to the next LUN */
04043             LunInfo = LunInfo->Next;
04044             InquiryData = (PSCSI_INQUIRY_DATA) ((PCHAR)InquiryData + InquiryDataSize);
04045         }
04046 
04047         /* Either mark the end, or set offset to 0 */
04048         if (BusData->NumberOfLogicalUnits != 0)
04049             ((PSCSI_INQUIRY_DATA) ((PCHAR) InquiryData - InquiryDataSize))->NextInquiryDataOffset = 0;
04050         else
04051             BusData->InquiryDataOffset = 0;
04052     }
04053 
04054     /* Finish with success */
04055     Irp->IoStatus.Status = STATUS_SUCCESS;
04056     return STATUS_SUCCESS;
04057 }
04058 
04059 static PSCSI_REQUEST_BLOCK_INFO
04060 SpiGetSrbData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
04061               IN UCHAR PathId,
04062               IN UCHAR TargetId,
04063               IN UCHAR Lun,
04064               IN UCHAR QueueTag)
04065 {
04066     PSCSI_PORT_LUN_EXTENSION LunExtension;
04067 
04068     if (QueueTag == SP_UNTAGGED)
04069     {
04070         /* Untagged request, get LU and return pointer to SrbInfo */
04071         LunExtension = SpiGetLunExtension(DeviceExtension,
04072                                           PathId,
04073                                           TargetId,
04074                                           Lun);
04075 
04076         /* Return NULL in case of error */
04077         if (!LunExtension)
04078             return(NULL);
04079 
04080         /* Return the pointer to SrbInfo */
04081         return &LunExtension->SrbInfo;
04082     }
04083     else
04084     {
04085         /* Make sure the tag is valid, if it is - return the data */
04086         if (QueueTag > DeviceExtension->SrbDataCount || QueueTag < 1)
04087             return NULL;
04088         else
04089             return &DeviceExtension->SrbInfo[QueueTag -1];
04090     }
04091 }
04092 
04093 static VOID
04094 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
04095                     IN PSCSI_REQUEST_BLOCK InitialSrb)
04096 {
04097     PSCSI_REQUEST_BLOCK Srb;
04098     PCDB Cdb;
04099     PIRP Irp;
04100     PIO_STACK_LOCATION IrpStack;
04101     LARGE_INTEGER LargeInt;
04102     PVOID *Ptr;
04103 
04104     DPRINT("SpiSendRequestSense() entered, InitialSrb %p\n", InitialSrb);
04105 
04106     /* Allocate Srb */
04107     Srb = ExAllocatePoolWithTag(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK) + sizeof(PVOID), TAG_SCSIPORT);
04108     RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
04109 
04110     /* Allocate IRP */
04111     LargeInt.QuadPart = (LONGLONG) 1;
04112     Irp = IoBuildAsynchronousFsdRequest(IRP_MJ_READ,
04113                                         DeviceExtension->DeviceObject,
04114                                         InitialSrb->SenseInfoBuffer,
04115                                         InitialSrb->SenseInfoBufferLength,
04116                                         &LargeInt,
04117                                         NULL);
04118 
04119     IoSetCompletionRoutine(Irp,
04120                            (PIO_COMPLETION_ROUTINE)SpiCompletionRoutine,
04121                            Srb,
04122                            TRUE,
04123                            TRUE,
04124                            TRUE);
04125 
04126     if (!Srb)
04127     {
04128         DPRINT("SpiSendRequestSense() failed, Srb %p\n", Srb);
04129         return;
04130     }
04131 
04132     IrpStack = IoGetNextIrpStackLocation(Irp);
04133     IrpStack->MajorFunction = IRP_MJ_SCSI;
04134 
04135     /* Put Srb address into Irp... */
04136     IrpStack->Parameters.Others.Argument1 = (PVOID)Srb;
04137 
04138     /* ...and vice versa */
04139     Srb->OriginalRequest = Irp;
04140 
04141     /* Save Srb */
04142     Ptr = (PVOID *)(Srb+1);
04143     *Ptr = InitialSrb;
04144 
04145     /* Build CDB for REQUEST SENSE */
04146     Srb->CdbLength = 6;
04147     Cdb = (PCDB)Srb->Cdb;
04148 
04149     Cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE;
04150     Cdb->CDB6INQUIRY.LogicalUnitNumber = 0;
04151     Cdb->CDB6INQUIRY.Reserved1 = 0;
04152     Cdb->CDB6INQUIRY.PageCode = 0;
04153     Cdb->CDB6INQUIRY.IReserved = 0;
04154     Cdb->CDB6INQUIRY.AllocationLength = (UCHAR)InitialSrb->SenseInfoBufferLength;
04155     Cdb->CDB6INQUIRY.Control = 0;
04156 
04157     /* Set address */
04158     Srb->TargetId = InitialSrb->TargetId;
04159     Srb->Lun = InitialSrb->Lun;
04160     Srb->PathId = InitialSrb->PathId;
04161 
04162     Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
04163     Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
04164 
04165     /* Timeout will be 2 seconds */
04166     Srb->TimeOutValue = 2;
04167 
04168     /* No auto request sense */
04169     Srb->SenseInfoBufferLength = 0;
04170     Srb->SenseInfoBuffer = NULL;
04171 
04172     /* Set necessary flags */
04173     Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_BYPASS_FROZEN_QUEUE |
04174                     SRB_FLAGS_DISABLE_DISCONNECT;
04175 
04176     /* Transfer disable synch transfer flag */
04177     if (InitialSrb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER)
04178         Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
04179 
04180     Srb->DataBuffer = InitialSrb->SenseInfoBuffer;
04181 
04182     /* Fill the transfer length */
04183     Srb->DataTransferLength = InitialSrb->SenseInfoBufferLength;
04184 
04185     /* Clear statuses */
04186     Srb->ScsiStatus = Srb->SrbStatus = 0;
04187     Srb->NextSrb = 0;
04188 
04189     /* Call the driver */
04190     (VOID)IoCallDriver(DeviceExtension->DeviceObject, Irp);
04191 
04192     DPRINT("SpiSendRequestSense() done\n");
04193 }
04194 
04195 
04196 static
04197 VOID
04198 NTAPI
04199 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
04200                            IN PSCSI_REQUEST_BLOCK_INFO SrbInfo,
04201                            OUT PBOOLEAN NeedToCallStartIo)
04202 {
04203     PSCSI_REQUEST_BLOCK Srb;
04204     PSCSI_PORT_LUN_EXTENSION LunExtension;
04205     LONG Result;
04206     PIRP Irp;
04207     //ULONG SequenceNumber;
04208 
04209     Srb = SrbInfo->Srb;
04210     Irp = Srb->OriginalRequest;
04211 
04212     /* Get Lun extension */
04213     LunExtension = SpiGetLunExtension(DeviceExtension,
04214                                      Srb->PathId,
04215                                      Srb->TargetId,
04216                                      Srb->Lun);
04217 
04218     if (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION &&
04219         DeviceExtension->MapBuffers &&
04220         Irp->MdlAddress)
04221     {
04222         /* MDL is shared if transfer is broken into smaller parts */
04223         Srb->DataBuffer = (PCCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress) +
04224             ((PCCHAR)Srb->DataBuffer - SrbInfo->DataOffset);
04225 
04226         /* In case of data going in, flush the buffers */
04227         if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
04228         {
04229             KeFlushIoBuffers(Irp->MdlAddress,
04230                              TRUE,
04231                              FALSE);
04232         }
04233     }
04234 
04235     /* Flush adapter if needed */
04236     if (SrbInfo->BaseOfMapRegister)
04237     {
04238         /* TODO: Implement */
04239         ASSERT(FALSE);
04240     }
04241 
04242     /* Clear the request */
04243     SrbInfo->Srb = NULL;
04244 
04245     /* If disconnect is disabled... */
04246     if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
04247     {
04248         /* Acquire the spinlock since we mess with flags */
04249         KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
04250 
04251         /* Set corresponding flag */
04252         DeviceExtension->Flags |= SCSI_PORT_DISCONNECT_ALLOWED;
04253 
04254         /* Clear the timer if needed */
04255         if (!(DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET))
04256             DeviceExtension->TimerCount = -1;
04257 
04258         /* Spinlock is not needed anymore */
04259         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
04260 
04261         if (!(DeviceExtension->Flags & SCSI_PORT_REQUEST_PENDING) &&
04262             !(DeviceExtension->Flags & SCSI_PORT_DEVICE_BUSY) &&
04263             !(*NeedToCallStartIo))
04264         {
04265             /* We're not busy, but we have a request pending */
04266             IoStartNextPacket(DeviceExtension->DeviceObject, FALSE);
04267         }
04268     }
04269 
04270     /* Scatter/gather */
04271     if (Srb->SrbFlags & SRB_FLAGS_SGLIST_FROM_POOL)
04272     {
04273         /* TODO: Implement */
04274         ASSERT(FALSE);
04275     }
04276 
04277     /* Acquire spinlock (we're freeing SrbExtension) */
04278     KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
04279 
04280     /* Free it (if needed) */
04281     if (Srb->SrbExtension)
04282     {
04283         if (Srb->SenseInfoBuffer != NULL && DeviceExtension->SupportsAutoSense)
04284         {
04285             ASSERT(Srb->SenseInfoBuffer == NULL || SrbInfo->SaveSenseRequest != NULL);
04286 
04287             if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)
04288             {
04289                 /* Copy sense data to the buffer */
04290                 RtlCopyMemory(SrbInfo->SaveSenseRequest,
04291                               Srb->SenseInfoBuffer,
04292                               Srb->SenseInfoBufferLength);
04293             }
04294 
04295             /* And restore the pointer */
04296             Srb->SenseInfoBuffer = SrbInfo->SaveSenseRequest;
04297         }
04298 
04299         /* Put it into the free srb extensions list */
04300         *((PVOID *)Srb->SrbExtension) = DeviceExtension->FreeSrbExtensions;
04301         DeviceExtension->FreeSrbExtensions = Srb->SrbExtension;
04302     }
04303 
04304     /* Save transfer length in the IRP */
04305     Irp->IoStatus.Information = Srb->DataTransferLength;
04306 
04307     //SequenceNumber = SrbInfo->SequenceNumber;
04308     SrbInfo->SequenceNumber = 0;
04309 
04310     /* Decrement the queue count */
04311     LunExtension->QueueCount--;
04312 
04313     /* Free Srb, if needed*/
04314     if (Srb->QueueTag != SP_UNTAGGED)
04315     {
04316         /* Put it into the free list */
04317         SrbInfo->Requests.Blink = NULL;
04318         SrbInfo->Requests.Flink = (PLIST_ENTRY)DeviceExtension->FreeSrbInfo;
04319         DeviceExtension->FreeSrbInfo = SrbInfo;
04320     }
04321 
04322     /* SrbInfo is not used anymore */
04323     SrbInfo = NULL;
04324 
04325     if (DeviceExtension->Flags & SCSI_PORT_REQUEST_PENDING)
04326     {
04327         /* Clear the flag */
04328         DeviceExtension->Flags &= ~SCSI_PORT_REQUEST_PENDING;
04329 
04330         /* Note the caller about StartIo */
04331         *NeedToCallStartIo = TRUE;
04332     }
04333 
04334     if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
04335     {
04336         /* Start the packet */
04337         Irp->IoStatus.Status = STATUS_SUCCESS;
04338 
04339         if (!(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE) &&
04340             LunExtension->RequestTimeout == -1)
04341         {
04342             /* Start the next packet */
04343             SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
04344         }
04345         else
04346         {
04347             /* Release the spinlock */
04348             KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
04349         }
04350 
04351         DPRINT("IoCompleting request IRP 0x%p\n", Irp);
04352 
04353         IoCompleteRequest(Irp, IO_DISK_INCREMENT);
04354 
04355         /* Decrement number of active requests, and analyze the result */
04356         Result = InterlockedDecrement(&DeviceExtension->ActiveRequestCounter);
04357 
04358         if (Result < 0 &&
04359             !DeviceExtension->MapRegisters &&
04360             DeviceExtension->AdapterObject != NULL)
04361         {
04362             /* Nullify map registers */
04363             DeviceExtension->MapRegisterBase = NULL;
04364             IoFreeAdapterChannel(DeviceExtension->AdapterObject);
04365         }
04366 
04367          /* Exit, we're done */
04368         return;
04369     }
04370 
04371     /* Decrement number of active requests, and analyze the result */
04372     Result = InterlockedDecrement(&DeviceExtension->ActiveRequestCounter);
04373 
04374     if (Result < 0 &&
04375         !DeviceExtension->MapRegisters &&
04376         DeviceExtension->AdapterObject != NULL)
04377     {
04378         /* Result is negative, so this is a slave, free map registers */
04379         DeviceExtension->MapRegisterBase = NULL;
04380         IoFreeAdapterChannel(DeviceExtension->AdapterObject);
04381     }
04382 
04383     /* Convert status */
04384     Irp->IoStatus.Status = SpiStatusSrbToNt(Srb->SrbStatus);
04385 
04386     /* It's not a bypass, it's busy or the queue is full? */
04387     if ((Srb->ScsiStatus == SCSISTAT_BUSY ||
04388          Srb->SrbStatus == SRB_STATUS_BUSY ||
04389          Srb->ScsiStatus == SCSISTAT_QUEUE_FULL) &&
04390          !(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE))
04391     {
04392 
04393         DPRINT("Busy SRB status %x\n", Srb->SrbStatus);
04394 
04395         /* Requeu, if needed */
04396         if (LunExtension->Flags & (LUNEX_FROZEN_QUEUE | LUNEX_BUSY))
04397         {
04398             DPRINT("it's being requeued\n");
04399 
04400             Srb->SrbStatus = SRB_STATUS_PENDING;
04401             Srb->ScsiStatus = 0;
04402 
04403             if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue,
04404                                           &Irp->Tail.Overlay.DeviceQueueEntry,
04405                                           Srb->QueueSortKey))
04406             {
04407                 /* It's a big f.ck up if we got here */
04408                 Srb->SrbStatus = SRB_STATUS_ERROR;
04409                 Srb->ScsiStatus = SCSISTAT_BUSY;
04410 
04411                 ASSERT(FALSE);
04412                 goto Error;
04413             }
04414 
04415             /* Release the spinlock */
04416             KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
04417 
04418         }
04419         else if (LunExtension->AttemptCount++ < 20)
04420         {
04421             /* LUN is still busy */
04422             Srb->ScsiStatus = 0;
04423             Srb->SrbStatus = SRB_STATUS_PENDING;
04424 
04425             LunExtension->BusyRequest = Irp;
04426             LunExtension->Flags |= LUNEX_BUSY;
04427 
04428             /* Release the spinlock */
04429             KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
04430         }
04431         else
04432         {
04433 Error:
04434             /* Freeze the queue*/
04435             Srb->SrbStatus |= SRB_STATUS_QUEUE_FROZEN;
04436             LunExtension->Flags |= LUNEX_FROZEN_QUEUE;
04437 
04438             /* "Unfull" the queue */
04439             LunExtension->Flags &= ~LUNEX_FULL_QUEUE;
04440 
04441             /* Release the spinlock */
04442             KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
04443 
04444             /* Return status that the device is not ready */
04445             Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
04446             IoCompleteRequest(Irp, IO_DISK_INCREMENT);
04447         }
04448 
04449         return;
04450     }
04451 
04452     /* Start the next request, if LUN is idle, and this is sense request */
04453     if (((Srb->ScsiStatus != SCSISTAT_CHECK_CONDITION) ||
04454         (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) ||
04455         !Srb->SenseInfoBuffer || !Srb->SenseInfoBufferLength)
04456         && (Srb->SrbFlags & SRB_FLAGS_NO_QUEUE_FREEZE))
04457     {
04458         if (LunExtension->RequestTimeout == -1)
04459             SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
04460         else
04461             KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
04462     }
04463     else
04464     {
04465         /* Freeze the queue */
04466         Srb->SrbStatus |= SRB_STATUS_QUEUE_FROZEN;
04467         LunExtension->Flags |= LUNEX_FROZEN_QUEUE;
04468 
04469         /* Do we need a request sense? */
04470         if (Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION &&
04471             !(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
04472             Srb->SenseInfoBuffer && Srb->SenseInfoBufferLength)
04473         {
04474             /* If LUN is busy, we have to requeue it in order to allow request sense */
04475             if (LunExtension->Flags & LUNEX_BUSY)
04476             {
04477                 DPRINT("Requeueing busy request to allow request sense\n");
04478 
04479                 if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue,
04480                     &LunExtension->BusyRequest->Tail.Overlay.DeviceQueueEntry,
04481                     Srb->QueueSortKey))
04482                 {
04483                     /* We should never get here */
04484                     ASSERT(FALSE);
04485 
04486                     KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
04487                     IoCompleteRequest(Irp, IO_DISK_INCREMENT);
04488                     return;
04489 
04490                 }
04491 
04492                 /* Clear busy flags */
04493                 LunExtension->Flags &= ~(LUNEX_FULL_QUEUE | LUNEX_BUSY);
04494             }
04495 
04496             /* Release the spinlock */
04497             KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
04498 
04499             /* Send RequestSense */
04500             SpiSendRequestSense(DeviceExtension, Srb);
04501 
04502             /* Exit */
04503             return;
04504         }
04505 
04506         /* Release the spinlock */
04507         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
04508     }
04509 
04510     /* Complete the request */
04511     IoCompleteRequest(Irp, IO_DISK_INCREMENT);
04512 }
04513 
04514 NTSTATUS
04515 NTAPI
04516 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject,
04517                      PIRP Irp,
04518                      PVOID Context)
04519 {
04520     PSCSI_REQUEST_BLOCK Srb = (PSCSI_REQUEST_BLOCK)Context;
04521     PSCSI_REQUEST_BLOCK InitialSrb;
04522     PIRP InitialIrp;
04523 
04524     DPRINT("SpiCompletionRoutine() entered, IRP %p \n", Irp);
04525 
04526     if ((Srb->Function == SRB_FUNCTION_RESET_BUS) ||
04527         (Srb->Function == SRB_FUNCTION_ABORT_COMMAND))
04528     {
04529         /* Deallocate SRB and IRP and exit */
04530         ExFreePool(Srb);
04531         IoFreeIrp(Irp);
04532 
04533         return STATUS_MORE_PROCESSING_REQUIRED;
04534     }
04535 
04536     /* Get a pointer to the SRB and IRP which were initially sent */
04537     InitialSrb = *((PVOID *)(Srb+1));
04538     InitialIrp = InitialSrb->OriginalRequest;
04539 
04540     if ((SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS) ||
04541         (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN))
04542     {
04543         /* Sense data is OK */
04544         InitialSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
04545 
04546         /* Set length to be the same */
04547         InitialSrb->SenseInfoBufferLength = (UCHAR)Srb->DataTransferLength;
04548     }
04549 
04550     /* Make sure initial SRB's queue is frozen */
04551     ASSERT(InitialSrb->SrbStatus & SRB_STATUS_QUEUE_FROZEN);
04552 
04553     /* Complete this request */
04554     IoCompleteRequest(InitialIrp, IO_DISK_INCREMENT);
04555 
04556     /* Deallocate everything (internal) */
04557     ExFreePool(Srb);
04558 
04559     if (Irp->MdlAddress != NULL)
04560     {
04561         MmUnlockPages(Irp->MdlAddress);
04562         IoFreeMdl(Irp->MdlAddress);
04563         Irp->MdlAddress = NULL;
04564     }
04565 
04566     IoFreeIrp(Irp);
04567     return STATUS_MORE_PROCESSING_REQUIRED;
04568 }
04569 
04570 static BOOLEAN NTAPI
04571 ScsiPortIsr(IN PKINTERRUPT Interrupt,
04572             IN PVOID ServiceContext)
04573 {
04574     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
04575 
04576     DPRINT("ScsiPortIsr() called!\n");
04577 
04578     DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext;
04579 
04580     /* If interrupts are disabled - we don't expect any */
04581     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_DISABLE_INTERRUPTS)
04582         return FALSE;
04583 
04584     /* Call miniport's HwInterrupt routine */
04585     DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension);
04586 
04587     /* If flag of notification is set - queue a DPC */
04588     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
04589     {
04590         IoRequestDpc(DeviceExtension->DeviceObject,
04591                      DeviceExtension->CurrentIrp,
04592                      DeviceExtension);
04593     }
04594 
04595     return TRUE;
04596 }
04597 
04598 BOOLEAN
04599 NTAPI
04600 SpiSaveInterruptData(IN PVOID Context)
04601 {
04602     PSCSI_PORT_SAVE_INTERRUPT InterruptContext = Context;
04603     PSCSI_PORT_LUN_EXTENSION LunExtension;
04604     PSCSI_REQUEST_BLOCK Srb;
04605     PSCSI_REQUEST_BLOCK_INFO SrbInfo, NextSrbInfo;
04606     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
04607     BOOLEAN IsTimed;
04608 
04609     /* Get pointer to the device extension */
04610     DeviceExtension = InterruptContext->DeviceExtension;
04611 
04612     /* If we don't have anything pending - return */
04613     if (!(DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED))
04614         return FALSE;
04615 
04616     /* Actually save the interrupt data */
04617     *InterruptContext->InterruptData = DeviceExtension->InterruptData;
04618 
04619     /* Clear the data stored in the device extension */
04620     DeviceExtension->InterruptData.Flags &=
04621         (SCSI_PORT_RESET | SCSI_PORT_RESET_REQUEST | SCSI_PORT_DISABLE_INTERRUPTS);
04622     DeviceExtension->InterruptData.CompletedAbort = NULL;
04623     DeviceExtension->InterruptData.ReadyLun = NULL;
04624     DeviceExtension->InterruptData.CompletedRequests = NULL;
04625 
04626     /* Loop through the list of completed requests */
04627     SrbInfo = InterruptContext->InterruptData->CompletedRequests;
04628 
04629     while (SrbInfo)
04630     {
04631         /* Make sure we have SRV */
04632         ASSERT(SrbInfo->Srb);
04633 
04634         /* Get SRB and LunExtension */
04635         Srb = SrbInfo->Srb;
04636 
04637         LunExtension = SpiGetLunExtension(DeviceExtension,
04638                                           Srb->PathId,
04639                                           Srb->TargetId,
04640                                           Srb->Lun);
04641 
04642         /* We have to check special cases if request is unsuccessfull*/
04643         if (Srb->SrbStatus != SRB_STATUS_SUCCESS)
04644         {
04645             /* Check if we need request sense by a few conditions */
04646             if (Srb->SenseInfoBuffer && Srb->SenseInfoBufferLength &&
04647                 Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION &&
04648                 !(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID))
04649             {
04650                 if (LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE)
04651                 {
04652                     /* It means: we tried to send REQUEST SENSE, but failed */
04653 
04654                     Srb->ScsiStatus = 0;
04655                     Srb->SrbStatus = SRB_STATUS_REQUEST_SENSE_FAILED;
04656                 }
04657                 else
04658                 {
04659                     /* Set the corresponding flag, so that REQUEST SENSE
04660                        will be sent */
04661                     LunExtension->Flags |= LUNEX_NEED_REQUEST_SENSE;
04662                 }
04663 
04664             }
04665 
04666             /* Check for a full queue */
04667             if (Srb->ScsiStatus == SCSISTAT_QUEUE_FULL)
04668             {
04669                 /* TODO: Implement when it's encountered */
04670                 ASSERT(FALSE);
04671             }
04672         }
04673 
04674         /* Let's decide if we need to watch timeout or not */
04675         if (Srb->QueueTag == SP_UNTAGGED)
04676         {
04677             IsTimed = TRUE;
04678         }
04679         else
04680         {
04681             if (LunExtension->SrbInfo.Requests.Flink == &SrbInfo->Requests)
04682                 IsTimed = TRUE;
04683             else
04684                 IsTimed = FALSE;
04685 
04686             /* Remove it from the queue */
04687             RemoveEntryList(&SrbInfo->Requests);
04688         }
04689 
04690         if (IsTimed)
04691         {
04692             /* We have to maintain timeout counter */
04693             if (IsListEmpty(&LunExtension->SrbInfo.Requests))
04694             {
04695                 LunExtension->RequestTimeout = -1;
04696             }
04697             else
04698             {
04699                 NextSrbInfo = CONTAINING_RECORD(LunExtension->SrbInfo.Requests.Flink,
04700                                                 SCSI_REQUEST_BLOCK_INFO,
04701                                                 Requests);
04702 
04703                 Srb = NextSrbInfo->Srb;
04704 
04705                 /* Update timeout counter */
04706                 LunExtension->RequestTimeout = Srb->TimeOutValue;
04707             }
04708         }
04709 
04710         SrbInfo = SrbInfo->CompletedRequests;
04711     }
04712 
04713     return TRUE;
04714 }
04715 
04716 VOID
04717 NTAPI
04718 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
04719                          IN PSCSI_PORT_LUN_EXTENSION LunExtension)
04720 {
04721     PIO_STACK_LOCATION IrpStack;
04722     PIRP NextIrp;
04723     PKDEVICE_QUEUE_ENTRY Entry;
04724     PSCSI_REQUEST_BLOCK Srb;
04725 
04726 
04727     /* If LUN is not active or queue is more than maximum allowed  */
04728     if (LunExtension->QueueCount >= LunExtension->MaxQueueCount ||
04729         !(LunExtension->Flags & SCSI_PORT_LU_ACTIVE))
04730     {
04731         /* Release the spinlock and exit */
04732         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
04733         return;
04734     }
04735 
04736     /* Check if we can get a next request */
04737     if (LunExtension->Flags &
04738         (LUNEX_NEED_REQUEST_SENSE | LUNEX_BUSY |
04739          LUNEX_FULL_QUEUE | LUNEX_FROZEN_QUEUE | LUNEX_REQUEST_PENDING))
04740     {
04741         /* Pending requests can only be started if the queue is empty */
04742         if (IsListEmpty(&LunExtension->SrbInfo.Requests) &&
04743             !(LunExtension->Flags &
04744               (LUNEX_BUSY | LUNEX_FROZEN_QUEUE | LUNEX_FULL_QUEUE | LUNEX_NEED_REQUEST_SENSE)))
04745         {
04746             /* Make sure we have SRB */
04747             ASSERT(LunExtension->SrbInfo.Srb == NULL);
04748 
04749             /* Clear active and pending flags */
04750             LunExtension->Flags &= ~(LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE);
04751 
04752             /* Get next Irp, and clear pending requests list */
04753             NextIrp = LunExtension->PendingRequest;
04754             LunExtension->PendingRequest = NULL;
04755 
04756             /* Set attempt counter to zero */
04757             LunExtension->AttemptCount = 0;
04758 
04759             /* Release the spinlock */
04760             KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
04761 
04762             /* Start the next pending request */
04763             IoStartPacket(DeviceExtension->DeviceObject, NextIrp, (PULONG)NULL, NULL);
04764 
04765             return;
04766         }
04767         else
04768         {
04769             /* Release the spinlock, without clearing any flags and exit */
04770             KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
04771 
04772             return;
04773         }
04774     }
04775 
04776     /* Reset active flag */
04777     LunExtension->Flags &= ~SCSI_PORT_LU_ACTIVE;
04778 
04779     /* Set attempt counter to zero */
04780     LunExtension->AttemptCount = 0;
04781 
04782     /* Remove packet from the device queue */
04783     Entry = KeRemoveByKeyDeviceQueue(&LunExtension->DeviceQueue, LunExtension->SortKey);
04784 
04785     if (Entry != NULL)
04786     {
04787         /* Get pointer to the next irp */
04788         NextIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
04789 
04790         /* Get point to the SRB */
04791         IrpStack = IoGetCurrentIrpStackLocation(NextIrp);
04792         Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
04793 
04794         /* Set new key*/
04795         LunExtension->SortKey = Srb->QueueSortKey;
04796         LunExtension->SortKey++;
04797 
04798         /* Release the spinlock */
04799         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
04800 
04801         /* Start the next pending request */
04802         IoStartPacket(DeviceExtension->DeviceObject, NextIrp, (PULONG)NULL, NULL);
04803     }
04804     else
04805     {
04806         /* Release the spinlock */
04807         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
04808     }
04809 }
04810 
04811 
04812 
04813 //    ScsiPortDpcForIsr
04814 //  DESCRIPTION:
04815 //
04816 //  RUN LEVEL:
04817 //
04818 //  ARGUMENTS:
04819 //    IN PKDPC          Dpc
04820 //    IN PDEVICE_OBJECT DpcDeviceObject
04821 //    IN PIRP           DpcIrp
04822 //    IN PVOID          DpcContext
04823 //
04824 static VOID NTAPI
04825 ScsiPortDpcForIsr(IN PKDPC Dpc,
04826           IN PDEVICE_OBJECT DpcDeviceObject,
04827           IN PIRP DpcIrp,
04828           IN PVOID DpcContext)
04829 {
04830     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DpcDeviceObject->DeviceExtension;
04831     SCSI_PORT_INTERRUPT_DATA InterruptData;
04832     SCSI_PORT_SAVE_INTERRUPT Context;
04833     PSCSI_PORT_LUN_EXTENSION LunExtension;
04834     BOOLEAN NeedToStartIo;
04835     PSCSI_REQUEST_BLOCK_INFO SrbInfo;
04836     LARGE_INTEGER TimerValue;
04837 
04838     DPRINT("ScsiPortDpcForIsr(Dpc %p  DpcDeviceObject %p  DpcIrp %p  DpcContext %p)\n",
04839            Dpc, DpcDeviceObject, DpcIrp, DpcContext);
04840 
04841     /* We need to acquire spinlock */
04842     KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
04843 
04844     RtlZeroMemory(&InterruptData, sizeof(SCSI_PORT_INTERRUPT_DATA));
04845 
04846 TryAgain:
04847 
04848     /* Interrupt structure must be snapshotted, and only then analyzed */
04849     Context.InterruptData = &InterruptData;
04850     Context.DeviceExtension = DeviceExtension;
04851 
04852     if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0],
04853                                 SpiSaveInterruptData,
04854                                 &Context))
04855     {
04856         /* Nothing - just return (don't forget to release the spinlock */
04857         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
04858         DPRINT("ScsiPortDpcForIsr() done\n");
04859         return;
04860     }
04861 
04862     /* If flush of adapters is needed - do it */
04863     if (InterruptData.Flags & SCSI_PORT_FLUSH_ADAPTERS)
04864     {
04865         /* TODO: Implement */
04866         ASSERT(FALSE);
04867     }
04868 
04869     /* Check for IoMapTransfer */
04870     if (InterruptData.Flags & SCSI_PORT_MAP_TRANSFER)
04871     {
04872         /* TODO: Implement */
04873         ASSERT(FALSE);
04874     }
04875 
04876     /* Check if timer is needed */
04877     if (InterruptData.Flags & SCSI_PORT_TIMER_NEEDED)
04878     {
04879         /* Save the timer routine */
04880         DeviceExtension->HwScsiTimer = InterruptData.HwScsiTimer;
04881 
04882         if (InterruptData.MiniportTimerValue == 0)
04883         {
04884             /* Cancel the timer */
04885             KeCancelTimer(&DeviceExtension->MiniportTimer);
04886         }
04887         else
04888         {
04889             /* Convert timer value */
04890             TimerValue.QuadPart = Int32x32To64(InterruptData.MiniportTimerValue, -10);
04891 
04892             /* Set the timer */
04893             KeSetTimer(&DeviceExtension->MiniportTimer,
04894                        TimerValue,
04895                        &DeviceExtension->MiniportTimerDpc);
04896         }
04897     }
04898 
04899     /* If it's ready for the next request */
04900     if (InterruptData.Flags & SCSI_PORT_NEXT_REQUEST_READY)
04901     {
04902         /* Check for a duplicate request (NextRequest+NextLuRequest) */
04903         if ((DeviceExtension->Flags &
04904             (SCSI_PORT_DEVICE_BUSY | SCSI_PORT_DISCONNECT_ALLOWED)) ==
04905             (SCSI_PORT_DEVICE_BUSY | SCSI_PORT_DISCONNECT_ALLOWED))
04906         {
04907             /* Clear busy flag set by ScsiPortStartPacket() */
04908             DeviceExtension->Flags &= ~SCSI_PORT_DEVICE_BUSY;
04909 
04910             if (!(InterruptData.Flags & SCSI_PORT_RESET))
04911             {
04912                 /* Ready for next, and no reset is happening */
04913                 DeviceExtension->TimerCount = -1;
04914             }
04915         }
04916         else
04917         {
04918             /* Not busy, but not ready for the next request */
04919             DeviceExtension->Flags &= ~SCSI_PORT_DEVICE_BUSY;
04920             InterruptData.Flags &= ~SCSI_PORT_NEXT_REQUEST_READY;
04921         }
04922     }
04923 
04924     /* Any resets? */
04925     if (InterruptData.Flags & SCSI_PORT_RESET_REPORTED)
04926     {
04927         /* Hold for a bit */
04928         DeviceExtension->TimerCount = 4;
04929     }
04930 
04931     /* Any ready LUN? */
04932     if (InterruptData.ReadyLun != NULL)
04933     {
04934 
04935         /* Process all LUNs from the list*/
04936         while (TRUE)
04937         {
04938             /* Remove it from the list first (as processed) */
04939             LunExtension = InterruptData.ReadyLun;
04940             InterruptData.ReadyLun = LunExtension->ReadyLun;
04941             LunExtension->ReadyLun = NULL;
04942 
04943             /* Get next request for this LUN */
04944             SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
04945 
04946             /* Still ready requests exist?
04947                If yes - get spinlock, if no - stop here */
04948             if (InterruptData.ReadyLun != NULL)
04949                 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
04950             else
04951                 break;
04952         }
04953     }
04954     else
04955     {
04956         /* Release the spinlock */
04957         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
04958     }
04959 
04960     /* If we ready for next packet, start it */
04961     if (InterruptData.Flags & SCSI_PORT_NEXT_REQUEST_READY)
04962         IoStartNextPacket(DeviceExtension->DeviceObject, FALSE);
04963 
04964     NeedToStartIo = FALSE;
04965 
04966     /* Loop the completed request list */
04967     while (InterruptData.CompletedRequests)
04968     {
04969         /* Remove the request */
04970         SrbInfo = InterruptData.CompletedRequests;
04971         InterruptData.CompletedRequests = SrbInfo->CompletedRequests;
04972         SrbInfo->CompletedRequests = NULL;
04973 
04974         /* Process it */
04975         SpiProcessCompletedRequest(DeviceExtension,
04976                                   SrbInfo,
04977                                   &NeedToStartIo);
04978     }
04979 
04980     /* Loop abort request list */
04981     while (InterruptData.CompletedAbort)
04982     {
04983         LunExtension = InterruptData.CompletedAbort;
04984 
04985         /* Remove the request */
04986         InterruptData.CompletedAbort = LunExtension->CompletedAbortRequests;
04987 
04988         /* Get spinlock since we're going to change flags */
04989         KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
04990 
04991         /* TODO: Put SrbExtension to the list of free extensions */
04992         ASSERT(FALSE);
04993     }
04994 
04995     /* If we need - call StartIo routine */
04996     if (NeedToStartIo)
04997     {
04998         /* Make sure CurrentIrp is not null! */
04999         ASSERT(DpcDeviceObject->CurrentIrp != NULL);
05000         ScsiPortStartIo(DpcDeviceObject, DpcDeviceObject->CurrentIrp);
05001     }
05002 
05003     /* Everything has been done, check */
05004     if (InterruptData.Flags & SCSI_PORT_ENABLE_INT_REQUEST)
05005     {
05006         /* Synchronize using spinlock */
05007         KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
05008 
05009         /* Request an interrupt */
05010         DeviceExtension->HwInterrupt(DeviceExtension->MiniPortDeviceExtension);
05011 
05012         ASSERT(DeviceExtension->Flags & SCSI_PORT_DISABLE_INT_REQUESET);
05013 
05014         /* Should interrupts be enabled again? */
05015         if (DeviceExtension->Flags & SCSI_PORT_DISABLE_INT_REQUESET)
05016         {
05017             /* Clear this flag */
05018             DeviceExtension->Flags &= ~SCSI_PORT_DISABLE_INT_REQUESET;
05019 
05020             /* Call a special routine to do this */
05021             ASSERT(FALSE);
05022 #if 0
05023             KeSynchronizeExecution(DeviceExtension->Interrupt,
05024                                    SpiEnableInterrupts,
05025                                    DeviceExtension);
05026 #endif
05027         }
05028 
05029         /* If we need a notification again - loop */
05030         if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
05031             goto TryAgain;
05032 
05033         /* Release the spinlock */
05034         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
05035     }
05036 
05037     DPRINT("ScsiPortDpcForIsr() done\n");
05038 }
05039 
05040 BOOLEAN
05041 NTAPI
05042 SpiProcessTimeout(PVOID ServiceContext)
05043 {
05044     PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)ServiceContext;
05045     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
05046     ULONG Bus;
05047 
05048     DPRINT("SpiProcessTimeout() entered\n");
05049 
05050     DeviceExtension->TimerCount = -1;
05051 
05052     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET)
05053     {
05054         DeviceExtension->InterruptData.Flags &= ~SCSI_PORT_RESET;
05055 
05056         if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET_REQUEST)
05057         {
05058             DeviceExtension->InterruptData.Flags &=  ~SCSI_PORT_RESET_REQUEST;
05059             ScsiPortStartPacket(ServiceContext);
05060         }
05061 
05062         return FALSE;
05063     }
05064     else
05065     {
05066         DPRINT("Resetting the bus\n");
05067 
05068         for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
05069         {
05070             DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension, Bus);
05071 
05072             /* Reset flags and set reset timeout to 4 seconds */
05073             DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET;
05074             DeviceExtension->TimerCount = 4;
05075         }
05076 
05077         /* If miniport requested - request a dpc for it */
05078         if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
05079             IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
05080     }
05081 
05082     return TRUE;
05083 }
05084 
05085 
05086 BOOLEAN
05087 NTAPI
05088 SpiResetBus(PVOID ServiceContext)
05089 {
05090     PRESETBUS_PARAMS ResetParams = (PRESETBUS_PARAMS)ServiceContext;
05091     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
05092 
05093     /* Perform the bus reset */
05094     DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ResetParams->DeviceExtension;
05095     DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension,
05096                                 ResetParams->PathId);
05097 
05098     /* Set flags and start the timer */
05099     DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET;
05100     DeviceExtension->TimerCount = 4;
05101 
05102     /* If miniport requested - give him a DPC */
05103     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
05104         IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
05105 
05106     return TRUE;
05107 }
05108 
05109 //    ScsiPortIoTimer
05110 //  DESCRIPTION:
05111 //    This function handles timeouts and other time delayed processing
05112 //
05113 //  RUN LEVEL:
05114 //
05115 //  ARGUMENTS:
05116 //    IN  PDEVICE_OBJECT  DeviceObject  Device object registered with timer
05117 //    IN  PVOID           Context       the Controller extension for the
05118 //                                      controller the device is on
05119 //
05120 static VOID NTAPI
05121 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
05122                 PVOID Context)
05123 {
05124     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
05125     PSCSI_PORT_LUN_EXTENSION LunExtension;
05126     ULONG Lun;
05127     PIRP Irp;
05128 
05129     DPRINT("ScsiPortIoTimer()\n");
05130 
05131     DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
05132 
05133     /* Protect with the spinlock */
05134     KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
05135 
05136     /* Check timeouts */
05137     if (DeviceExtension->TimerCount > 0)
05138     {
05139         /* Decrease the timeout counter */
05140         DeviceExtension->TimerCount--;
05141 
05142         if (DeviceExtension->TimerCount == 0)
05143         {
05144             /* Timeout, process it */
05145             if (KeSynchronizeExecution(DeviceExtension->Interrupt[0],
05146                                        SpiProcessTimeout,
05147                                        DeviceExtension->DeviceObject))
05148             {
05149                 DPRINT("Error happened during processing timeout, but nothing critical\n");
05150             }
05151         }
05152 
05153         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
05154 
05155         /* We should exit now, since timeout is processed */
05156         return;
05157     }
05158 
05159     /* Per-Lun scanning of timeouts is needed... */
05160     for (Lun = 0; Lun < LUS_NUMBER; Lun++)
05161     {
05162         LunExtension = DeviceExtension->LunExtensionList[Lun];
05163 
05164         while (LunExtension)
05165         {
05166             if (LunExtension->Flags & LUNEX_BUSY)
05167             {
05168                 if (!(LunExtension->Flags &
05169                     (LUNEX_NEED_REQUEST_SENSE | LUNEX_FROZEN_QUEUE)))
05170                 {
05171                     DPRINT("Retrying busy request\n");
05172 
05173                     /* Clear flags, and retry busy request */
05174                     LunExtension->Flags &= ~(LUNEX_BUSY | LUNEX_FULL_QUEUE);
05175                     Irp = LunExtension->BusyRequest;
05176 
05177                     /* Clearing busy request */
05178                     LunExtension->BusyRequest = NULL;
05179 
05180                     KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
05181 
05182                     IoStartPacket(DeviceObject, Irp, (PULONG)NULL, NULL);
05183 
05184                     KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
05185                 }
05186             }
05187             else if (LunExtension->RequestTimeout == 0)
05188             {
05189                 RESETBUS_PARAMS ResetParams;
05190 
05191                 LunExtension->RequestTimeout = -1;
05192 
05193                 DPRINT("Request timed out, resetting bus\n");
05194 
05195                 /* Pass params to the bus reset routine */
05196                 ResetParams.PathId = LunExtension->PathId;
05197                 ResetParams.DeviceExtension = DeviceExtension;
05198 
05199                 if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0],
05200                                             SpiResetBus,
05201                                             &ResetParams))
05202                 {
05203                     DPRINT1("Reset failed\n");
05204                 }
05205             }
05206             else if (LunExtension->RequestTimeout > 0)
05207             {
05208                 /* Decrement the timeout counter */
05209                 LunExtension->RequestTimeout--;
05210             }
05211 
05212             LunExtension = LunExtension->Next;
05213         }
05214     }
05215 
05216     /* Release the spinlock */
05217     KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
05218 }
05219 
05220 /**********************************************************************
05221  * NAME                         INTERNAL
05222  *  SpiBuildDeviceMap
05223  *
05224  * DESCRIPTION
05225  *  Builds the registry device map of all device which are attached
05226  *  to the given SCSI HBA port. The device map is located at:
05227  *    \Registry\Machine\DeviceMap\Scsi
05228  *
05229  * RUN LEVEL
05230  *  PASSIVE_LEVEL
05231  *
05232  * ARGUMENTS
05233  *  DeviceExtension
05234  *      ...
05235  *
05236  *  RegistryPath
05237  *      Name of registry driver service key.
05238  *
05239  * RETURNS
05240  *  NTSTATUS
05241  */
05242 
05243 static NTSTATUS
05244 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
05245            PUNICODE_STRING RegistryPath)
05246 {
05247   PSCSI_PORT_LUN_EXTENSION LunExtension;
05248   OBJECT_ATTRIBUTES ObjectAttributes;
05249   UNICODE_STRING KeyName;
05250   UNICODE_STRING ValueName;
05251   WCHAR NameBuffer[64];
05252   ULONG Disposition;
05253   HANDLE ScsiKey;
05254   HANDLE ScsiPortKey = NULL;
05255   HANDLE ScsiBusKey = NULL;
05256   HANDLE ScsiInitiatorKey = NULL;
05257   HANDLE ScsiTargetKey = NULL;
05258   HANDLE ScsiLunKey = NULL;
05259   ULONG BusNumber;
05260   ULONG Target;
05261   ULONG CurrentTarget;
05262   ULONG Lun;
05263   PWCHAR DriverName;
05264   ULONG UlongData;
05265   PWCHAR TypeName;
05266   NTSTATUS Status;
05267 
05268   DPRINT("SpiBuildDeviceMap() called\n");
05269 
05270   if (DeviceExtension == NULL || RegistryPath == NULL)
05271     {
05272       DPRINT1("Invalid parameter\n");
05273       return(STATUS_INVALID_PARAMETER);
05274     }
05275 
05276   /* Open or create the 'Scsi' subkey */
05277   RtlInitUnicodeString(&KeyName,
05278               L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
05279   InitializeObjectAttributes(&ObjectAttributes,
05280                  &KeyName,
05281                  OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
05282                  0,
05283                  NULL);
05284   Status = ZwCreateKey(&ScsiKey,
05285                KEY_ALL_ACCESS,
05286                &ObjectAttributes,
05287                0,
05288                NULL,
05289                REG_OPTION_VOLATILE,
05290                &Disposition);
05291   if (!NT_SUCCESS(Status))
05292     {
05293       DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
05294       return(Status);
05295     }
05296 
05297   /* Create new 'Scsi Port X' subkey */
05298   DPRINT("Scsi Port %lu\n",
05299      DeviceExtension->PortNumber);
05300 
05301   swprintf(NameBuffer,
05302        L"Scsi Port %lu",
05303        DeviceExtension->PortNumber);
05304   RtlInitUnicodeString(&KeyName,
05305                NameBuffer);
05306   InitializeObjectAttributes(&ObjectAttributes,
05307                  &KeyName,
05308                  0,
05309                  ScsiKey,
05310                  NULL);
05311   Status = ZwCreateKey(&ScsiPortKey,
05312                KEY_ALL_ACCESS,
05313                &ObjectAttributes,
05314                0,
05315                NULL,
05316                REG_OPTION_VOLATILE,
05317                &Disposition);
05318   ZwClose(ScsiKey);
05319   if (!NT_SUCCESS(Status))
05320     {
05321       DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
05322       return(Status);
05323     }
05324 
05325   /*
05326    * Create port-specific values
05327    */
05328 
05329   /* Set 'DMA Enabled' (REG_DWORD) value */
05330   UlongData = (ULONG)!DeviceExtension->PortCapabilities.AdapterUsesPio;
05331   DPRINT("  DMA Enabled = %s\n", (UlongData) ? "TRUE" : "FALSE");
05332   RtlInitUnicodeString(&ValueName,
05333                L"DMA Enabled");
05334   Status = ZwSetValueKey(ScsiPortKey,
05335              &ValueName,
05336              0,
05337              REG_DWORD,
05338              &UlongData,
05339              sizeof(ULONG));
05340   if (!NT_SUCCESS(Status))
05341     {
05342       DPRINT("ZwSetValueKey('DMA Enabled') failed (Status %lx)\n", Status);
05343       ZwClose(ScsiPortKey);
05344       return(Status);
05345     }
05346 
05347   /* Set 'Driver' (REG_SZ) value */
05348   DriverName = wcsrchr(RegistryPath->Buffer, L'\\') + 1;
05349   RtlInitUnicodeString(&ValueName,
05350                L"Driver");
05351   Status = ZwSetValueKey(ScsiPortKey,
05352              &ValueName,
05353              0,
05354              REG_SZ,
05355              DriverName,
05356              (wcslen(DriverName) + 1) * sizeof(WCHAR));
05357   if (!NT_SUCCESS(Status))
05358     {
05359       DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status);
05360       ZwClose(ScsiPortKey);
05361       return(Status);
05362     }
05363 
05364   /* Set 'Interrupt' (REG_DWORD) value (NT4 only) */
05365   UlongData = (ULONG)DeviceExtension->PortConfig->BusInterruptLevel;
05366   DPRINT("  Interrupt = %lu\n", UlongData);
05367   RtlInitUnicodeString(&ValueName,
05368                L"Interrupt");
05369   Status = ZwSetValueKey(ScsiPortKey,
05370              &ValueName,
05371              0,
05372              REG_DWORD,
05373              &UlongData,
05374              sizeof(ULONG));
05375   if (!NT_SUCCESS(Status))
05376     {
05377       DPRINT("ZwSetValueKey('Interrupt') failed (Status %lx)\n", Status);
05378       ZwClose(ScsiPortKey);
05379       return(Status);
05380     }
05381 
05382   /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
05383   UlongData = ScsiPortConvertPhysicalAddressToUlong((*DeviceExtension->PortConfig->AccessRanges)[0].RangeStart);
05384   DPRINT("  IOAddress = %lx\n", UlongData);
05385   RtlInitUnicodeString(&ValueName,
05386                L"IOAddress");
05387   Status = ZwSetValueKey(ScsiPortKey,
05388              &ValueName,
05389              0,
05390              REG_DWORD,
05391              &UlongData,
05392              sizeof(ULONG));
05393   if (!NT_SUCCESS(Status))
05394     {
05395       DPRINT("ZwSetValueKey('IOAddress') failed (Status %lx)\n", Status);
05396       ZwClose(ScsiPortKey);
05397       return(Status);
05398     }
05399 
05400   /* Enumerate buses */
05401   for (BusNumber = 0; BusNumber < DeviceExtension->PortConfig->NumberOfBuses; BusNumber++)
05402     {
05403       /* Create 'Scsi Bus X' key */
05404       DPRINT("    Scsi Bus %lu\n", BusNumber);
05405       swprintf(NameBuffer,
05406            L"Scsi Bus %lu",
05407            BusNumber);
05408       RtlInitUnicodeString(&KeyName,
05409                NameBuffer);
05410       InitializeObjectAttributes(&ObjectAttributes,
05411                  &KeyName,
05412                  0,
05413                  ScsiPortKey,
05414                  NULL);
05415       Status = ZwCreateKey(&ScsiBusKey,
05416                KEY_ALL_ACCESS,
05417                &ObjectAttributes,
05418                0,
05419                NULL,
05420                REG_OPTION_VOLATILE,
05421                &Disposition);
05422       if (!NT_SUCCESS(Status))
05423     {
05424       DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
05425       goto ByeBye;
05426     }
05427 
05428       /* Create 'Initiator Id X' key */
05429       DPRINT("      Initiator Id %u\n",
05430           DeviceExtension->PortConfig->InitiatorBusId[BusNumber]);
05431       swprintf(NameBuffer,
05432            L"Initiator Id %u",
05433            (unsigned int)(UCHAR)DeviceExtension->PortConfig->InitiatorBusId[BusNumber]);
05434       RtlInitUnicodeString(&KeyName,
05435                NameBuffer);
05436       InitializeObjectAttributes(&ObjectAttributes,
05437                  &KeyName,
05438                  0,
05439                  ScsiBusKey,
05440                  NULL);
05441       Status = ZwCreateKey(&ScsiInitiatorKey,
05442                KEY_ALL_ACCESS,
05443                &ObjectAttributes,
05444                0,
05445                NULL,
05446                REG_OPTION_VOLATILE,
05447                &Disposition);
05448       if (!NT_SUCCESS(Status))
05449     {
05450       DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
05451       goto ByeBye;
05452     }
05453 
05454       /* FIXME: Are there any initiator values (??) */
05455 
05456       ZwClose(ScsiInitiatorKey);
05457       ScsiInitiatorKey = NULL;
05458 
05459 
05460       /* Enumerate targets */
05461       CurrentTarget = (ULONG)-1;
05462       ScsiTargetKey = NULL;
05463       for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
05464     {
05465       for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
05466         {
05467           LunExtension = SpiGetLunExtension(DeviceExtension,
05468                         (UCHAR)BusNumber,
05469                         (UCHAR)Target,
05470                         (UCHAR)Lun);
05471           if (LunExtension != NULL)
05472         {
05473           if (Target != CurrentTarget)
05474             {
05475               /* Close old target key */
05476               if (ScsiTargetKey != NULL)
05477             {
05478               ZwClose(ScsiTargetKey);
05479               ScsiTargetKey = NULL;
05480             }
05481 
05482               /* Create 'Target Id X' key */
05483               DPRINT("      Target Id %lu\n", Target);
05484               swprintf(NameBuffer,
05485                    L"Target Id %lu",
05486                    Target);
05487               RtlInitUnicodeString(&KeyName,
05488                        NameBuffer);
05489               InitializeObjectAttributes(&ObjectAttributes,
05490                          &KeyName,
05491                          0,
05492                          ScsiBusKey,
05493                          NULL);
05494               Status = ZwCreateKey(&ScsiTargetKey,
05495                        KEY_ALL_ACCESS,
05496                        &ObjectAttributes,
05497                        0,
05498                        NULL,
05499                        REG_OPTION_VOLATILE,
05500                        &Disposition);
05501               if (!NT_SUCCESS(Status))
05502             {
05503               DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
05504               goto ByeBye;
05505             }
05506 
05507               CurrentTarget = Target;
05508             }
05509 
05510           /* Create 'Logical Unit Id X' key */
05511           DPRINT("        Logical Unit Id %lu\n", Lun);
05512           swprintf(NameBuffer,
05513                L"Logical Unit Id %lu",
05514                Lun);
05515           RtlInitUnicodeString(&KeyName,
05516                        NameBuffer);
05517           InitializeObjectAttributes(&ObjectAttributes,
05518                          &KeyName,
05519                          0,
05520                          ScsiTargetKey,
05521                          NULL);
05522           Status = ZwCreateKey(&ScsiLunKey,
05523                        KEY_ALL_ACCESS,
05524                        &ObjectAttributes,
05525                        0,
05526                        NULL,
05527                        REG_OPTION_VOLATILE,
05528                        &Disposition);
05529           if (!NT_SUCCESS(Status))
05530             {
05531               DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
05532               goto ByeBye;
05533             }
05534 
05535           /* Set 'Identifier' (REG_SZ) value */
05536           swprintf(NameBuffer,
05537                L"%.8S%.16S%.4S",
05538                LunExtension->InquiryData.VendorId,
05539                LunExtension->InquiryData.ProductId,
05540                LunExtension->InquiryData.ProductRevisionLevel);
05541           DPRINT("          Identifier = '%S'\n", NameBuffer);
05542           RtlInitUnicodeString(&ValueName,
05543                        L"Identifier");
05544           Status = ZwSetValueKey(ScsiLunKey,
05545                      &ValueName,
05546                      0,
05547                      REG_SZ,
05548                      NameBuffer,
05549                      (wcslen(NameBuffer) + 1) * sizeof(WCHAR));
05550           if (!NT_SUCCESS(Status))
05551             {
05552               DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", Status);
05553               goto ByeBye;
05554             }
05555 
05556           /* Set 'Type' (REG_SZ) value */
05557           switch (LunExtension->InquiryData.DeviceType)
05558             {
05559               case 0:
05560             TypeName = L"DiskPeripheral";
05561             break;
05562               case 1:
05563             TypeName = L"TapePeripheral";
05564             break;
05565               case 2:
05566             TypeName = L"PrinterPeripheral";
05567             break;
05568               case 4:
05569             TypeName = L"WormPeripheral";
05570             break;
05571               case 5:
05572             TypeName = L"CdRomPeripheral";
05573             break;
05574               case 6:
05575             TypeName = L"ScannerPeripheral";
05576             break;
05577               case 7:
05578             TypeName = L"OpticalDiskPeripheral";
05579             break;
05580               case 8:
05581             TypeName = L"MediumChangerPeripheral";
05582             break;
05583               case 9:
05584             TypeName = L"CommunicationPeripheral";
05585             break;
05586               default:
05587             TypeName = L"OtherPeripheral";
05588             break;
05589             }
05590           DPRINT("          Type = '%S'\n", TypeName);
05591           RtlInitUnicodeString(&ValueName,
05592                        L"Type");
05593           Status = ZwSetValueKey(ScsiLunKey,
05594                      &ValueName,
05595                      0,
05596                      REG_SZ,
05597                      TypeName,
05598                      (wcslen(TypeName) + 1) * sizeof(WCHAR));
05599           if (!NT_SUCCESS(Status))
05600             {
05601               DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status);
05602               goto ByeBye;
05603             }
05604 
05605           ZwClose(ScsiLunKey);
05606           ScsiLunKey = NULL;
05607         }
05608         }
05609 
05610       /* Close old target key */
05611       if (ScsiTargetKey != NULL)
05612         {
05613           ZwClose(ScsiTargetKey);
05614           ScsiTargetKey = NULL;
05615         }
05616     }
05617 
05618       ZwClose(ScsiBusKey);
05619       ScsiBusKey = NULL;
05620     }
05621 
05622 ByeBye:
05623   if (ScsiLunKey != NULL)
05624     ZwClose (ScsiLunKey);
05625 
05626   if (ScsiInitiatorKey != NULL)
05627     ZwClose (ScsiInitiatorKey);
05628 
05629   if (ScsiTargetKey != NULL)
05630     ZwClose (ScsiTargetKey);
05631 
05632   if (ScsiBusKey != NULL)
05633     ZwClose (ScsiBusKey);
05634 
05635   if (ScsiPortKey != NULL)
05636     ZwClose (ScsiPortKey);
05637 
05638   DPRINT("SpiBuildDeviceMap() done\n");
05639 
05640   return Status;
05641 }
05642 
05643 VOID
05644 NTAPI
05645 SpiMiniportTimerDpc(IN struct _KDPC *Dpc,
05646                     IN PVOID DeviceObject,
05647                     IN PVOID SystemArgument1,
05648                     IN PVOID SystemArgument2)
05649 {
05650     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
05651 
05652     DPRINT("Miniport timer DPC\n");
05653 
05654     DeviceExtension = ((PDEVICE_OBJECT)DeviceObject)->DeviceExtension;
05655 
05656     /* Acquire the spinlock */
05657     KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
05658 
05659     /* Call the timer routine */
05660     if (DeviceExtension->HwScsiTimer != NULL)
05661     {
05662         DeviceExtension->HwScsiTimer(&DeviceExtension->MiniPortDeviceExtension);
05663     }
05664 
05665     /* Release the spinlock */
05666     KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
05667 
05668     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
05669     {
05670         ScsiPortDpcForIsr(NULL,
05671                           DeviceExtension->DeviceObject,
05672                           NULL,
05673                           NULL);
05674     }
05675 }
05676 
05677 static NTSTATUS
05678 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
05679                     PHW_INITIALIZATION_DATA HwInitData,
05680                     PCONFIGURATION_INFO InternalConfigInfo,
05681                     PPORT_CONFIGURATION_INFORMATION ConfigInfo,
05682                     BOOLEAN ZeroStruct)
05683 {
05684     UNICODE_STRING UnicodeString;
05685     OBJECT_ATTRIBUTES ObjectAttributes;
05686     PCONFIGURATION_INFORMATION DdkConfigInformation;
05687     HANDLE RootKey, Key;
05688     BOOLEAN Found;
05689     WCHAR DeviceBuffer[16];
05690     WCHAR StrBuffer[512];
05691     ULONG Bus;
05692     NTSTATUS Status;
05693 
05694     /* Zero out the struct if told so */
05695     if (ZeroStruct)
05696     {
05697         /* First zero the portconfig */
05698         RtlZeroMemory(ConfigInfo, sizeof(PORT_CONFIGURATION_INFORMATION));
05699 
05700         /* Then access ranges */
05701         RtlZeroMemory(InternalConfigInfo->AccessRanges,
05702                       HwInitData->NumberOfAccessRanges * sizeof(ACCESS_RANGE));
05703 
05704         /* Initialize the struct */
05705         ConfigInfo->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
05706         ConfigInfo->AdapterInterfaceType = HwInitData->AdapterInterfaceType;
05707         ConfigInfo->InterruptMode = Latched;
05708         ConfigInfo->DmaChannel = SP_UNINITIALIZED_VALUE;
05709         ConfigInfo->DmaPort = SP_UNINITIALIZED_VALUE;
05710         ConfigInfo->DmaChannel2 = SP_UNINITIALIZED_VALUE;
05711         ConfigInfo->DmaPort2 = SP_UNINITIALIZED_VALUE;
05712         ConfigInfo->MaximumTransferLength = SP_UNINITIALIZED_VALUE;
05713         ConfigInfo->NumberOfAccessRanges = HwInitData->NumberOfAccessRanges;
05714         ConfigInfo->MaximumNumberOfTargets = 8;
05715 
05716         /* Store parameters */
05717         ConfigInfo->NeedPhysicalAddresses = HwInitData->NeedPhysicalAddresses;
05718         ConfigInfo->MapBuffers = HwInitData->MapBuffers;
05719         ConfigInfo->AutoRequestSense = HwInitData->AutoRequestSense;
05720         ConfigInfo->ReceiveEvent = HwInitData->ReceiveEvent;
05721         ConfigInfo->TaggedQueuing = HwInitData->TaggedQueuing;
05722         ConfigInfo->MultipleRequestPerLu = HwInitData->MultipleRequestPerLu;
05723 
05724         /* Get the disk usage */
05725         DdkConfigInformation = IoGetConfigurationInformation();
05726         ConfigInfo->AtdiskPrimaryClaimed = DdkConfigInformation->AtDiskPrimaryAddressClaimed;
05727         ConfigInfo->AtdiskSecondaryClaimed = DdkConfigInformation->AtDiskSecondaryAddressClaimed;
05728 
05729         /* Initiator bus id is not set */
05730         for (Bus = 0; Bus < 8; Bus++)
05731             ConfigInfo->InitiatorBusId[Bus] = (CCHAR)SP_UNINITIALIZED_VALUE;
05732     }
05733 
05734     ConfigInfo->NumberOfPhysicalBreaks = 17;
05735 
05736     /* Clear this information */
05737     InternalConfigInfo->DisableTaggedQueueing = FALSE;
05738     InternalConfigInfo->DisableMultipleLun = FALSE;
05739 
05740     /* Store Bus Number */
05741     ConfigInfo->SystemIoBusNumber = InternalConfigInfo->BusNumber;
05742 
05743 TryNextAd:
05744 
05745     if (ConfigInfo->AdapterInterfaceType == Internal)
05746     {
05747         /* Open registry key for HW database */
05748         InitializeObjectAttributes(&ObjectAttributes,
05749                                    DeviceExtension->DeviceObject->DriverObject->HardwareDatabase,
05750                                    OBJ_CASE_INSENSITIVE,
05751                                    NULL,
05752                                    NULL);
05753 
05754         Status = ZwOpenKey(&RootKey,
05755                            KEY_READ,
05756                            &ObjectAttributes);
05757 
05758         if (NT_SUCCESS(Status))
05759         {
05760             /* Create name for it */
05761             swprintf(StrBuffer, L"ScsiAdapter\\%lu",
05762                 InternalConfigInfo->AdapterNumber);
05763 
05764             RtlInitUnicodeString(&UnicodeString, StrBuffer);
05765 
05766             /* Open device key */
05767             InitializeObjectAttributes(&ObjectAttributes,
05768                                        &UnicodeString,
05769                                        OBJ_CASE_INSENSITIVE,
05770                                        RootKey,
05771                                        NULL);
05772 
05773             Status = ZwOpenKey(&Key,
05774                                KEY_READ,
05775                                &ObjectAttributes);
05776 
05777             ZwClose(RootKey);
05778 
05779             if (NT_SUCCESS(Status))
05780             {
05781                 if (InternalConfigInfo->LastAdapterNumber != InternalConfigInfo->AdapterNumber)
05782                 {
05783                     DPRINT("Hardware info found at %S\n", StrBuffer);
05784 
05785                     /* Parse it */
05786                     SpiParseDeviceInfo(DeviceExtension,
05787                                        Key,
05788                                        ConfigInfo,
05789                                        InternalConfigInfo,
05790                                        (PUCHAR)StrBuffer);
05791 
05792                      InternalConfigInfo->BusNumber = 0;
05793                 }
05794                 else
05795                 {
05796                     /* Try the next adapter */
05797                     InternalConfigInfo->AdapterNumber++;
05798                     goto TryNextAd;
05799                 }
05800             }
05801             else
05802             {
05803                 /* Info was not found, exit */
05804                 DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status);
05805                 return STATUS_DEVICE_DOES_NOT_EXIST;
05806             }
05807         }
05808         else
05809         {
05810             DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status);
05811         }
05812     }
05813 
05814     /* Look at device params */
05815     Key = NULL;
05816     if (InternalConfigInfo->Parameter)
05817     {
05818         ExFreePool(InternalConfigInfo->Parameter);
05819         InternalConfigInfo->Parameter = NULL;
05820     }
05821 
05822     if (InternalConfigInfo->ServiceKey != NULL)
05823     {
05824         swprintf(DeviceBuffer, L"Device%lu", InternalConfigInfo->AdapterNumber);
05825         RtlInitUnicodeString(&UnicodeString, DeviceBuffer);
05826 
05827         /* Open the service key */
05828         InitializeObjectAttributes(&ObjectAttributes,
05829                                    &UnicodeString,
05830                                    OBJ_CASE_INSENSITIVE,
05831                                    InternalConfigInfo->ServiceKey,
05832                                    NULL);
05833 
05834         Status = ZwOpenKey(&Key,
05835                            KEY_READ,
05836                            &ObjectAttributes);
05837     }
05838 
05839     /* Parse device key */
05840     if (InternalConfigInfo->DeviceKey != NULL)
05841     {
05842         SpiParseDeviceInfo(DeviceExtension,
05843                            InternalConfigInfo->DeviceKey,
05844                            ConfigInfo,
05845                            InternalConfigInfo,
05846                            (PUCHAR)StrBuffer);
05847     }
05848 
05849     /* Then parse hw info */
05850     if (Key != NULL)
05851     {
05852         if (InternalConfigInfo->LastAdapterNumber != InternalConfigInfo->AdapterNumber)
05853         {
05854             SpiParseDeviceInfo(DeviceExtension,
05855                                Key,
05856                                ConfigInfo,
05857                                InternalConfigInfo,
05858                                (PUCHAR)StrBuffer);
05859 
05860             /* Close the key */
05861             ZwClose(Key);
05862         }
05863         else
05864         {
05865             /* Adapter not found, go try the next one */
05866             InternalConfigInfo->AdapterNumber++;
05867 
05868             /* Close the key */
05869             ZwClose(Key);
05870 
05871             goto TryNextAd;
05872         }
05873     }
05874 
05875     /* Update the last adapter number */
05876     InternalConfigInfo->LastAdapterNumber = InternalConfigInfo->AdapterNumber;
05877 
05878     /* Do we have this kind of bus at all? */
05879     Found = FALSE;
05880     Status = IoQueryDeviceDescription(&HwInitData->AdapterInterfaceType,
05881                                       &InternalConfigInfo->BusNumber,
05882                                       NULL,
05883                                       NULL,
05884                                       NULL,
05885                                       NULL,
05886                                       SpQueryDeviceCallout,
05887                                       &Found);
05888 
05889     /* This bus was not found */
05890     if (!Found)
05891     {
05892         INTERFACE_TYPE InterfaceType = Eisa;
05893 
05894         /* Check for EISA */
05895         if (HwInitData->AdapterInterfaceType == Isa)
05896         {
05897             Status = IoQueryDeviceDescription(&InterfaceType,
05898                                               &InternalConfigInfo->BusNumber,
05899                                               NULL,
05900                                               NULL,
05901                                               NULL,
05902                                               NULL,
05903                                               SpQueryDeviceCallout,
05904                                               &Found);
05905 
05906             /* Return respectively */
05907             if (Found)
05908                 return STATUS_SUCCESS;
05909             else
05910                 return STATUS_DEVICE_DOES_NOT_EXIST;
05911         }
05912         else
05913         {
05914             return STATUS_DEVICE_DOES_NOT_EXIST;
05915         }
05916     }
05917     else
05918     {
05919         return STATUS_SUCCESS;
05920     }
05921 }
05922 
05923 static VOID
05924 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
05925                    IN HANDLE Key,
05926                    IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
05927                    IN PCONFIGURATION_INFO InternalConfigInfo,
05928                    IN PUCHAR Buffer)
05929 {
05930     PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
05931     PCM_FULL_RESOURCE_DESCRIPTOR FullResource;
05932     PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
05933     PCM_SCSI_DEVICE_DATA ScsiDeviceData;
05934     ULONG Length, Count, Dma = 0, Interrupt = 0;
05935     ULONG Index = 0, RangeCount = 0;
05936     UNICODE_STRING UnicodeString;
05937     ANSI_STRING AnsiString;
05938     NTSTATUS Status = STATUS_SUCCESS;
05939 
05940 
05941     KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION) Buffer;
05942 
05943     /* Loop through all values in the device node */
05944     while(TRUE)
05945     {
05946         Status = ZwEnumerateValueKey(Key,
05947                                      Index,
05948                                      KeyValueFullInformation,
05949                                      Buffer,
05950                                      512,
05951                                      &Length);
05952 
05953         if (!NT_SUCCESS(Status))
05954             return;
05955 
05956         Index++;
05957 
05958         /* Length for DWORD is ok? */
05959         if (KeyValueInformation->Type == REG_DWORD &&
05960             KeyValueInformation->DataLength != sizeof(ULONG))
05961         {
05962             continue;
05963         }
05964 
05965         /* Get MaximumLogicalUnit */
05966         if (_wcsnicmp(KeyValueInformation->Name, L"MaximumLogicalUnit",
05967             KeyValueInformation->NameLength/2) == 0)
05968         {
05969 
05970             if (KeyValueInformation->Type != REG_DWORD)
05971             {
05972                 DPRINT("Bad data type for MaximumLogicalUnit\n");
05973                 continue;
05974             }
05975 
05976             DeviceExtension->MaxLunCount = *((PUCHAR)
05977                 (Buffer + KeyValueInformation->DataOffset));
05978 
05979             /* Check / reset if needed */
05980             if (DeviceExtension->MaxLunCount > SCSI_MAXIMUM_LOGICAL_UNITS)
05981                 DeviceExtension->MaxLunCount = SCSI_MAXIMUM_LOGICAL_UNITS;
05982 
05983             DPRINT("MaximumLogicalUnit = %d\n", DeviceExtension->MaxLunCount);
05984         }
05985 
05986         /* Get InitiatorTargetId */
05987         if (_wcsnicmp(KeyValueInformation->Name, L"InitiatorTargetId",
05988             KeyValueInformation->NameLength / 2) == 0)
05989         {
05990 
05991             if (KeyValueInformation->Type != REG_DWORD)
05992             {
05993                 DPRINT("Bad data type for InitiatorTargetId\n");
05994                 continue;
05995             }
05996 
05997             ConfigInfo->InitiatorBusId[0] = *((PUCHAR)
05998                 (Buffer + KeyValueInformation->DataOffset));
05999 
06000             /* Check / reset if needed */
06001             if (ConfigInfo->InitiatorBusId[0] > ConfigInfo->MaximumNumberOfTargets - 1)
06002                 ConfigInfo->InitiatorBusId[0] = (CCHAR)-1;
06003 
06004             DPRINT("InitiatorTargetId = %d\n", ConfigInfo->InitiatorBusId[0]);
06005         }
06006 
06007         /* Get ScsiDebug */
06008         if (_wcsnicmp(KeyValueInformation->Name, L"ScsiDebug",
06009             KeyValueInformation->NameLength/2) == 0)
06010         {
06011             DPRINT("ScsiDebug key not supported\n");
06012         }
06013 
06014         /* Check for a breakpoint */
06015         if (_wcsnicmp(KeyValueInformation->Name, L"BreakPointOnEntry",
06016             KeyValueInformation->NameLength/2) == 0)
06017         {
06018             DPRINT1("Breakpoint on entry requested!\n");
06019             DbgBreakPoint();
06020         }
06021 
06022         /* Get DisableSynchronousTransfers */
06023         if (_wcsnicmp(KeyValueInformation->Name, L"DisableSynchronousTransfers",
06024             KeyValueInformation->NameLength/2) == 0)
06025         {
06026             DeviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
06027             DPRINT("Synch transfers disabled\n");
06028         }
06029 
06030         /* Get DisableDisconnects */
06031         if (_wcsnicmp(KeyValueInformation->Name, L"DisableDisconnects",
06032             KeyValueInformation->NameLength/2) == 0)
06033         {
06034             DeviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT;
06035             DPRINT("Disconnects disabled\n");
06036         }
06037 
06038         /* Get DisableTaggedQueuing */
06039         if (_wcsnicmp(KeyValueInformation->Name, L"DisableTaggedQueuing",
06040             KeyValueInformation->NameLength/2) == 0)
06041         {
06042             InternalConfigInfo->DisableTaggedQueueing = TRUE;
06043             DPRINT("Tagged queueing disabled\n");
06044         }
06045 
06046         /* Get DisableMultipleRequests */
06047         if (_wcsnicmp(KeyValueInformation->Name, L"DisableMultipleRequests",
06048             KeyValueInformation->NameLength/2) == 0)
06049         {
06050             InternalConfigInfo->DisableMultipleLun = TRUE;
06051             DPRINT("Multiple requests disabled\n");
06052         }
06053 
06054         /* Get DriverParameters */
06055         if (_wcsnicmp(KeyValueInformation->Name, L"DriverParameters",
06056             KeyValueInformation->NameLength/2) == 0)
06057         {
06058             /* Skip if nothing */
06059             if (KeyValueInformation->DataLength == 0)
06060                 continue;
06061 
06062             /* If there was something previously allocated - free it */
06063             if (InternalConfigInfo->Parameter != NULL)
06064                 ExFreePool(InternalConfigInfo->Parameter);
06065 
06066             /* Allocate it */
06067             InternalConfigInfo->Parameter = ExAllocatePoolWithTag(NonPagedPool,
06068                                                            KeyValueInformation->DataLength, TAG_SCSIPORT);
06069 
06070             if (InternalConfigInfo->Parameter != NULL)
06071             {
06072                 if (KeyValueInformation->Type != REG_SZ)
06073                 {
06074                     /* Just copy */
06075                     RtlCopyMemory(
06076                         InternalConfigInfo->Parameter,
06077                         (PCCHAR)KeyValueInformation + KeyValueInformation->DataOffset,
06078                         KeyValueInformation->DataLength);
06079                 }
06080                 else
06081                 {
06082                     /* If it's a unicode string, convert it to ansi */
06083                     UnicodeString.Length = (USHORT)KeyValueInformation->DataLength;
06084                     UnicodeString.MaximumLength = (USHORT)KeyValueInformation->DataLength;
06085                     UnicodeString.Buffer =
06086                         (PWSTR)((PCCHAR)KeyValueInformation + KeyValueInformation->DataOffset);
06087 
06088                     AnsiString.Length = 0;
06089                     AnsiString.MaximumLength = (USHORT)KeyValueInformation->DataLength;
06090                     AnsiString.Buffer = (PCHAR)InternalConfigInfo->Parameter;
06091 
06092                     Status = RtlUnicodeStringToAnsiString(&AnsiString,
06093                                                           &UnicodeString,
06094                                                           FALSE);
06095 
06096                     /* In case of error, free the allocated space */
06097                     if (!NT_SUCCESS(Status))
06098                     {
06099                         ExFreePool(InternalConfigInfo->Parameter);
06100                         InternalConfigInfo->Parameter = NULL;
06101                     }
06102 
06103                 }
06104             }
06105 
06106             DPRINT("Found driver parameter\n");
06107         }
06108 
06109         /* Get MaximumSGList */
06110         if (_wcsnicmp(KeyValueInformation->Name, L"MaximumSGList",
06111             KeyValueInformation->NameLength/2) == 0)
06112         {
06113             if (KeyValueInformation->Type != REG_DWORD)
06114             {
06115                 DPRINT("Bad data type for MaximumSGList\n");
06116                 continue;
06117             }
06118 
06119             ConfigInfo->NumberOfPhysicalBreaks = *((PUCHAR)(Buffer + KeyValueInformation->DataOffset));
06120 
06121             /* Check / fix */
06122             if (ConfigInfo->NumberOfPhysicalBreaks > SCSI_MAXIMUM_PHYSICAL_BREAKS)
06123             {
06124                 ConfigInfo->NumberOfPhysicalBreaks = SCSI_MAXIMUM_PHYSICAL_BREAKS;
06125             }
06126             else if (ConfigInfo->NumberOfPhysicalBreaks < SCSI_MINIMUM_PHYSICAL_BREAKS)
06127             {
06128                 ConfigInfo->NumberOfPhysicalBreaks = SCSI_MINIMUM_PHYSICAL_BREAKS;
06129             }
06130 
06131             DPRINT("MaximumSGList = %d\n", ConfigInfo->NumberOfPhysicalBreaks);
06132         }
06133 
06134         /* Get NumberOfRequests */
06135         if (_wcsnicmp(KeyValueInformation->Name, L"NumberOfRequests",
06136             KeyValueInformation->NameLength/2) == 0)
06137         {
06138             if (KeyValueInformation->Type != REG_DWORD)
06139             {
06140                 DPRINT("NumberOfRequests has wrong data type\n");
06141                 continue;
06142             }
06143 
06144             DeviceExtension->RequestsNumber = *((PUCHAR)(Buffer + KeyValueInformation->DataOffset));
06145 
06146             /* Check / fix */
06147             if (DeviceExtension->RequestsNumber < 16)
06148             {
06149                 DeviceExtension->RequestsNumber = 16;
06150             }
06151             else if (DeviceExtension->RequestsNumber > 512)
06152             {
06153                 DeviceExtension->RequestsNumber = 512;
06154             }
06155 
06156             DPRINT("Number Of Requests = %d\n", DeviceExtension->RequestsNumber);
06157         }
06158 
06159         /* Get resource list */
06160         if (_wcsnicmp(KeyValueInformation->Name, L"ResourceList",
06161                 KeyValueInformation->NameLength/2) == 0 ||
06162             _wcsnicmp(KeyValueInformation->Name, L"Configuration Data",
06163                 KeyValueInformation->NameLength/2) == 0 )
06164         {
06165             if (KeyValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR ||
06166                 KeyValueInformation->DataLength < sizeof(REG_FULL_RESOURCE_DESCRIPTOR))
06167             {
06168                 DPRINT("Bad data type for ResourceList\n");
06169                 continue;
06170             }
06171             else
06172             {
06173                 DPRINT("Found ResourceList\n");
06174             }
06175 
06176             FullResource = (PCM_FULL_RESOURCE_DESCRIPTOR)(Buffer + KeyValueInformation->DataOffset);
06177 
06178             /* Copy some info from it */
06179             InternalConfigInfo->BusNumber = FullResource->BusNumber;
06180             ConfigInfo->SystemIoBusNumber = FullResource->BusNumber;
06181 
06182             /* Loop through it */
06183             for (Count = 0; Count < FullResource->PartialResourceList.Count; Count++)
06184             {
06185                 /* Get partial descriptor */
06186                 PartialDescriptor =
06187                     &FullResource->PartialResourceList.PartialDescriptors[Count];
06188 
06189                 /* Check datalength */
06190                 if ((ULONG)((PCHAR)(PartialDescriptor + 1) -
06191                     (PCHAR)FullResource) > KeyValueInformation->DataLength)
06192                 {
06193                     DPRINT("Resource data is of incorrect size\n");
06194                     break;
06195                 }
06196 
06197                 switch (PartialDescriptor->Type)
06198                 {
06199                 case CmResourceTypePort:
06200                     if (RangeCount >= ConfigInfo->NumberOfAccessRanges)
06201                     {
06202                         DPRINT("Too many access ranges\n");
06203                         continue;
06204                     }
06205 
06206                     InternalConfigInfo->AccessRanges[RangeCount].RangeInMemory = FALSE;
06207                     InternalConfigInfo->AccessRanges[RangeCount].RangeStart = PartialDescriptor->u.Port.Start;
06208                     InternalConfigInfo->AccessRanges[RangeCount].RangeLength = PartialDescriptor->u.Port.Length;
06209                     RangeCount++;
06210 
06211                     break;
06212 
06213                 case CmResourceTypeMemory:
06214                     if (RangeCount >= ConfigInfo->NumberOfAccessRanges)
06215                     {
06216                         DPRINT("Too many access ranges\n");
06217                         continue;
06218                     }
06219 
06220                     InternalConfigInfo->AccessRanges[RangeCount].RangeInMemory = TRUE;
06221                     InternalConfigInfo->AccessRanges[RangeCount].RangeStart = PartialDescriptor->u.Memory.Start;
06222                     InternalConfigInfo->AccessRanges[RangeCount].RangeLength = PartialDescriptor->u.Memory.Length;
06223                     RangeCount++;
06224 
06225                     break;
06226 
06227                 case CmResourceTypeInterrupt:
06228 
06229                     if (Interrupt == 0)
06230                     {
06231                         ConfigInfo->BusInterruptLevel =
06232                             PartialDescriptor->u.Interrupt.Level;
06233 
06234                         ConfigInfo->BusInterruptVector =
06235                             PartialDescriptor->u.Interrupt.Vector;
06236 
06237                         ConfigInfo->InterruptMode = (PartialDescriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive;
06238                     }
06239                     else if (Interrupt == 1)
06240                     {
06241                         ConfigInfo->BusInterruptLevel2 =
06242                         PartialDescriptor->u.Interrupt.Level;
06243 
06244                         ConfigInfo->BusInterruptVector2 =
06245                         PartialDescriptor->u.Interrupt.Vector;
06246 
06247                         ConfigInfo->InterruptMode2 = (PartialDescriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive;
06248                     }
06249 
06250                     Interrupt++;
06251                     break;
06252 
06253                 case CmResourceTypeDma:
06254 
06255                     if (Dma == 0)
06256                     {
06257                         ConfigInfo->DmaChannel = PartialDescriptor->u.Dma.Channel;
06258                         ConfigInfo->DmaPort = PartialDescriptor->u.Dma.Port;
06259 
06260                         if (PartialDescriptor->Flags & CM_RESOURCE_DMA_8)
06261                             ConfigInfo->DmaWidth = Width8Bits;
06262                         else if ((PartialDescriptor->Flags & CM_RESOURCE_DMA_16) ||
06263                                  (PartialDescriptor->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
06264                             ConfigInfo->DmaWidth = Width16Bits;
06265                         else if (PartialDescriptor->Flags & CM_RESOURCE_DMA_32)
06266                             ConfigInfo->DmaWidth = Width32Bits;
06267                     }
06268                     else if (Dma == 1)
06269                     {
06270                         ConfigInfo->DmaChannel2 = PartialDescriptor->u.Dma.Channel;
06271                         ConfigInfo->DmaPort2 = PartialDescriptor->u.Dma.Port;
06272 
06273                         if (PartialDescriptor->Flags & CM_RESOURCE_DMA_8)
06274                             ConfigInfo->DmaWidth2 = Width8Bits;
06275                         else if ((PartialDescriptor->Flags & CM_RESOURCE_DMA_16) ||
06276                                  (PartialDescriptor->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
06277                             ConfigInfo->DmaWidth2 = Width16Bits;
06278                         else if (PartialDescriptor->Flags & CM_RESOURCE_DMA_32)
06279                             ConfigInfo->DmaWidth2 = Width32Bits;
06280                     }
06281 
06282                     Dma++;
06283                     break;
06284 
06285                 case CmResourceTypeDeviceSpecific:
06286                     if (PartialDescriptor->u.DeviceSpecificData.DataSize <
06287                         sizeof(CM_SCSI_DEVICE_DATA) ||
06288                         (PCHAR) (PartialDescriptor + 1) - (PCHAR)FullResource +
06289                         PartialDescriptor->u.DeviceSpecificData.DataSize >
06290                         KeyValueInformation->DataLength)
06291                     {
06292                         DPRINT("Resource data length is incorrect");
06293                         break;
06294                     }
06295 
06296                     /* Set only one field from it */
06297                     ScsiDeviceData = (PCM_SCSI_DEVICE_DATA) (PartialDescriptor+1);
06298                     ConfigInfo->InitiatorBusId[0] = ScsiDeviceData->HostIdentifier;
06299                     break;
06300                 }
06301             }
06302         }
06303     }
06304 }
06305 
06306 NTSTATUS
06307 NTAPI
06308 SpQueryDeviceCallout(IN PVOID  Context,
06309                      IN PUNICODE_STRING  PathName,
06310                      IN INTERFACE_TYPE  BusType,
06311                      IN ULONG  BusNumber,
06312                      IN PKEY_VALUE_FULL_INFORMATION  *BusInformation,
06313                      IN CONFIGURATION_TYPE  ControllerType,
06314                      IN ULONG  ControllerNumber,
06315                      IN PKEY_VALUE_FULL_INFORMATION  *ControllerInformation,
06316                      IN CONFIGURATION_TYPE  PeripheralType,
06317                      IN ULONG  PeripheralNumber,
06318                      IN PKEY_VALUE_FULL_INFORMATION  *PeripheralInformation)
06319 {
06320     PBOOLEAN Found = (PBOOLEAN)Context;
06321     /* We just set our Found variable to TRUE */
06322 
06323     *Found = TRUE;
06324     return STATUS_SUCCESS;
06325 }
06326 
06327 IO_ALLOCATION_ACTION
06328 NTAPI
06329 ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject,
06330                                IN PIRP Irp,
06331                                IN PVOID MapRegisterBase,
06332                                IN PVOID Context)
06333 {
06334     KIRQL Irql;
06335     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
06336 
06337     /* Guard access with the spinlock */
06338     KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
06339 
06340     /* Save MapRegisterBase we've got here */
06341     DeviceExtension->MapRegisterBase = MapRegisterBase;
06342 
06343     /* Start pending request */
06344     KeSynchronizeExecution(DeviceExtension->Interrupt[0],
06345         ScsiPortStartPacket, DeviceObject);
06346 
06347     /* Release spinlock we took */
06348     KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
06349 
06350     return KeepObject;
06351 }
06352 
06353 static
06354 NTSTATUS
06355 SpiStatusSrbToNt(UCHAR SrbStatus)
06356 {
06357     switch (SRB_STATUS(SrbStatus))
06358     {
06359     case SRB_STATUS_TIMEOUT:
06360     case SRB_STATUS_COMMAND_TIMEOUT:
06361         return STATUS_IO_TIMEOUT;
06362 
06363     case SRB_STATUS_BAD_SRB_BLOCK_LENGTH:
06364     case SRB_STATUS_BAD_FUNCTION:
06365         return STATUS_INVALID_DEVICE_REQUEST;
06366 
06367     case SRB_STATUS_NO_DEVICE:
06368     case SRB_STATUS_INVALID_LUN:
06369     case SRB_STATUS_INVALID_TARGET_ID:
06370     case SRB_STATUS_NO_HBA:
06371         return STATUS_DEVICE_DOES_NOT_EXIST;
06372 
06373     case SRB_STATUS_DATA_OVERRUN:
06374         return STATUS_BUFFER_OVERFLOW;
06375 
06376     case SRB_STATUS_SELECTION_TIMEOUT:
06377         return STATUS_DEVICE_NOT_CONNECTED;
06378 
06379     default:
06380         return STATUS_IO_DEVICE_ERROR;
06381     }
06382 
06383     return STATUS_IO_DEVICE_ERROR;
06384 }
06385 
06386 
06387 #undef ScsiPortConvertPhysicalAddressToUlong
06388 /*
06389  * @implemented
06390  */
06391 ULONG NTAPI
06392 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address)
06393 {
06394   DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
06395   return(Address.u.LowPart);
06396 }
06397 
06398 
06399 /* EOF */

Generated on Mon May 28 2012 04:18:55 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.