1 /*
2  * PROJECT:     ReactOS Storage Stack / SCSIPORT storage port library
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Main and exported functions
5  * COPYRIGHT:   Eric Kohl (eric.kohl@reactos.org)
6  *              Aleksey Bragin (aleksey@reactos.org)
7  *              2020 Victor Perevertkin (victor.perevertkin@reactos.org)
8  */
9 
10 /* INCLUDES *****************************************************************/
11 
12 #include "scsiport.h"
13 
14 #define NDEBUG
15 #include <debug.h>
16 
17 ULONG InternalDebugLevel = 0x00;
18 
19 #undef ScsiPortMoveMemory
20 
21 /* GLOBALS *******************************************************************/
22 
23 static BOOLEAN
24 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject,
25                     IN PDEVICE_OBJECT DeviceObject,
26                     IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
27                     IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,
28                     IN PUNICODE_STRING RegistryPath,
29                     IN ULONG BusNumber,
30                     IN OUT PPCI_SLOT_NUMBER NextSlotNumber);
31 
32 static NTSTATUS NTAPI
33 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
34             IN PIRP Irp);
35 
36 static VOID NTAPI
37 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
38         PVOID Context);
39 
40 VOID NTAPI
41 SpiMiniportTimerDpc(IN struct _KDPC *Dpc,
42                     IN PVOID DeviceObject,
43                     IN PVOID SystemArgument1,
44                     IN PVOID SystemArgument2);
45 
46 static NTSTATUS
47 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
48                     PHW_INITIALIZATION_DATA HwInitData,
49                     PCONFIGURATION_INFO InternalConfigInfo,
50                     PPORT_CONFIGURATION_INFORMATION ConfigInfo,
51                     BOOLEAN FirstCall);
52 
53 NTSTATUS NTAPI
54 SpQueryDeviceCallout(IN PVOID  Context,
55                      IN PUNICODE_STRING  PathName,
56                      IN INTERFACE_TYPE  BusType,
57                      IN ULONG  BusNumber,
58                      IN PKEY_VALUE_FULL_INFORMATION  *BusInformation,
59                      IN CONFIGURATION_TYPE  ControllerType,
60                      IN ULONG  ControllerNumber,
61                      IN PKEY_VALUE_FULL_INFORMATION  *ControllerInformation,
62                      IN CONFIGURATION_TYPE  PeripheralType,
63                      IN ULONG  PeripheralNumber,
64                      IN PKEY_VALUE_FULL_INFORMATION  *PeripheralInformation);
65 
66 static VOID
67 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
68                    IN HANDLE Key,
69                    IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
70                    IN PCONFIGURATION_INFO InternalConfigInfo,
71                    IN PUCHAR Buffer);
72 
73 static VOID
74 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData,
75                     IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor,
76                     IN PPORT_CONFIGURATION_INFORMATION PortConfig);
77 
78 static PCM_RESOURCE_LIST
79 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
80                     PPORT_CONFIGURATION_INFORMATION PortConfig);
81 
82 static NTSTATUS
83 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, ULONG NonCachedSize);
84 
85 NTHALAPI ULONG NTAPI HalGetBusData(BUS_DATA_TYPE, ULONG, ULONG, PVOID, ULONG);
86 NTHALAPI ULONG NTAPI HalGetInterruptVector(INTERFACE_TYPE, ULONG, ULONG, ULONG, PKIRQL, PKAFFINITY);
87 NTHALAPI NTSTATUS NTAPI HalAssignSlotResources(PUNICODE_STRING, PUNICODE_STRING, PDRIVER_OBJECT, PDEVICE_OBJECT, INTERFACE_TYPE, ULONG, ULONG, PCM_RESOURCE_LIST *);
88 
89 /* FUNCTIONS *****************************************************************/
90 
91 /**********************************************************************
92  * NAME                         EXPORTED
93  *  DriverEntry
94  *
95  * DESCRIPTION
96  *  This function initializes the driver.
97  *
98  * RUN LEVEL
99  *  PASSIVE_LEVEL
100  *
101  * ARGUMENTS
102  *  DriverObject
103  *      System allocated Driver Object for this driver.
104  *
105  *  RegistryPath
106  *      Name of registry driver service key.
107  *
108  * RETURN VALUE
109  *  Status.
110  */
111 
112 NTSTATUS NTAPI
113 DriverEntry(IN PDRIVER_OBJECT DriverObject,
114         IN PUNICODE_STRING RegistryPath)
115 {
116     return STATUS_SUCCESS;
117 }
118 
119 VOID
120 NTAPI
121 ScsiPortUnload(
122     _In_ PDRIVER_OBJECT DriverObject)
123 {
124     // no-op
125 }
126 
127 NTSTATUS
128 NTAPI
129 ScsiPortDispatchPnp(
130     PDEVICE_OBJECT DeviceObject,
131     PIRP Irp)
132 {
133     if (((PSCSI_PORT_COMMON_EXTENSION)DeviceObject->DeviceExtension)->IsFDO)
134     {
135         return FdoDispatchPnp(DeviceObject, Irp);
136     }
137     else
138     {
139         return PdoDispatchPnp(DeviceObject, Irp);
140     }
141 }
142 
143 NTSTATUS
144 NTAPI
145 ScsiPortAddDevice(
146     _In_ PDRIVER_OBJECT DriverObject,
147     _In_ PDEVICE_OBJECT PhysicalDeviceObject)
148 {
149 
150     DPRINT("AddDevice no-op DriverObj: %p, PDO: %p\n", DriverObject, PhysicalDeviceObject);
151 
152     return STATUS_SUCCESS;
153 }
154 
155 
156 /**********************************************************************
157  * NAME                         EXPORTED
158  *  ScsiDebugPrint
159  *
160  * DESCRIPTION
161  *  Prints debugging messages.
162  *
163  * RUN LEVEL
164  *  PASSIVE_LEVEL
165  *
166  * ARGUMENTS
167  *  DebugPrintLevel
168  *      Debug level of the given message.
169  *
170  *  DebugMessage
171  *      Pointer to printf()-compatible format string.
172  *
173  *  ...
174         Additional output data (see printf()).
175  *
176  * RETURN VALUE
177  *  None.
178  *
179  * @implemented
180  */
181 
182 VOID
183 ScsiDebugPrint(IN ULONG DebugPrintLevel,
184            IN PCHAR DebugMessage,
185            ...)
186 {
187     char Buffer[256];
188     va_list ap;
189 
190     if (DebugPrintLevel > InternalDebugLevel)
191         return;
192 
193     va_start(ap, DebugMessage);
194     vsprintf(Buffer, DebugMessage, ap);
195     va_end(ap);
196 
197     DbgPrint(Buffer);
198 }
199 
200 /* An internal helper function for ScsiPortCompleteRequest */
201 VOID
202 NTAPI
203 SpiCompleteRequest(IN PVOID HwDeviceExtension,
204                    IN PSCSI_REQUEST_BLOCK_INFO SrbInfo,
205                    IN UCHAR SrbStatus)
206 {
207     PSCSI_REQUEST_BLOCK Srb;
208 
209     /* Get current SRB */
210     Srb = SrbInfo->Srb;
211 
212     /* Return if there is no SRB or it is not active */
213     if (!Srb || !(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE)) return;
214 
215     /* Set status */
216     Srb->SrbStatus = SrbStatus;
217 
218     /* Set data transfered to 0 */
219     Srb->DataTransferLength = 0;
220 
221     /* Notify */
222     ScsiPortNotification(RequestComplete,
223                          HwDeviceExtension,
224                          Srb);
225 }
226 
227 /*
228  * @unimplemented
229  */
230 VOID NTAPI
231 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension,
232                         IN UCHAR PathId,
233                         IN UCHAR TargetId,
234                         IN UCHAR Lun,
235                         IN UCHAR SrbStatus)
236 {
237     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
238     PSCSI_PORT_LUN_EXTENSION LunExtension;
239     PSCSI_REQUEST_BLOCK_INFO SrbInfo;
240     PLIST_ENTRY ListEntry;
241 
242     DPRINT("ScsiPortCompleteRequest() called\n");
243 
244     DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
245                                         SCSI_PORT_DEVICE_EXTENSION,
246                                         MiniPortDeviceExtension);
247 
248     /* Go through all buses */
249     for (UINT8 pathId = 0; pathId < DeviceExtension->NumberOfBuses; pathId++)
250     {
251         PSCSI_BUS_INFO bus = &DeviceExtension->Buses[pathId];
252 
253         /* Go through all logical units */
254         for (PLIST_ENTRY lunEntry = bus->LunsListHead.Flink;
255              lunEntry != &bus->LunsListHead;
256              lunEntry = lunEntry->Flink)
257         {
258             LunExtension = CONTAINING_RECORD(lunEntry, SCSI_PORT_LUN_EXTENSION, LunEntry);
259 
260             /* Now match what caller asked with what we are at now */
261             if ((PathId == SP_UNTAGGED || PathId == LunExtension->PathId) &&
262                 (TargetId == SP_UNTAGGED || TargetId == LunExtension->TargetId) &&
263                 (Lun == SP_UNTAGGED || Lun == LunExtension->Lun))
264             {
265                 /* Yes, that's what caller asked for. Complete abort requests */
266                 if (LunExtension->CompletedAbortRequests)
267                 {
268                     /* TODO: Save SrbStatus in this request */
269                     DPRINT1("Completing abort request without setting SrbStatus!\n");
270 
271                     /* Issue a notification request */
272                     ScsiPortNotification(RequestComplete,
273                                          HwDeviceExtension,
274                                          LunExtension->CompletedAbortRequests);
275                 }
276 
277                 /* Complete the request using our helper */
278                 SpiCompleteRequest(HwDeviceExtension,
279                                    &LunExtension->SrbInfo,
280                                    SrbStatus);
281 
282                 /* Go through the queue and complete everything there too */
283                 ListEntry = LunExtension->SrbInfo.Requests.Flink;
284                 while (ListEntry != &LunExtension->SrbInfo.Requests)
285                 {
286                     /* Get the actual SRB info entry */
287                     SrbInfo = CONTAINING_RECORD(ListEntry,
288                                                 SCSI_REQUEST_BLOCK_INFO,
289                                                 Requests);
290 
291                     /* Complete it */
292                     SpiCompleteRequest(HwDeviceExtension,
293                                        SrbInfo,
294                                        SrbStatus);
295 
296                     /* Advance to the next request in queue */
297                     ListEntry = SrbInfo->Requests.Flink;
298                 }
299             }
300         }
301     }
302 }
303 
304 /*
305  * @unimplemented
306  */
307 VOID NTAPI
308 ScsiPortFlushDma(IN PVOID HwDeviceExtension)
309 {
310   DPRINT("ScsiPortFlushDma()\n");
311   UNIMPLEMENTED;
312 }
313 
314 
315 /*
316  * @implemented
317  */
318 VOID NTAPI
319 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension,
320                IN PVOID MappedAddress)
321 {
322     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
323     PMAPPED_ADDRESS NextMa, LastMa;
324 
325     //DPRINT("ScsiPortFreeDeviceBase() called\n");
326 
327     DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
328                                         SCSI_PORT_DEVICE_EXTENSION,
329                                         MiniPortDeviceExtension);
330 
331     /* Initialize our pointers */
332     NextMa = DeviceExtension->MappedAddressList;
333     LastMa = NextMa;
334 
335     while (NextMa)
336     {
337         if (NextMa->MappedAddress == MappedAddress)
338         {
339             /* Unmap it first */
340             MmUnmapIoSpace(MappedAddress, NextMa->NumberOfBytes);
341 
342             /* Remove it from the list */
343             if (NextMa == DeviceExtension->MappedAddressList)
344             {
345                 /* Remove the first entry */
346                 DeviceExtension->MappedAddressList = NextMa->NextMappedAddress;
347             }
348             else
349             {
350                 LastMa->NextMappedAddress = NextMa->NextMappedAddress;
351             }
352 
353             /* Free the resources and quit */
354             ExFreePool(NextMa);
355 
356             return;
357         }
358         else
359         {
360             LastMa = NextMa;
361             NextMa = NextMa->NextMappedAddress;
362         }
363     }
364 }
365 
366 
367 /*
368  * @implemented
369  */
370 ULONG NTAPI
371 ScsiPortGetBusData(IN PVOID DeviceExtension,
372            IN ULONG BusDataType,
373            IN ULONG SystemIoBusNumber,
374            IN ULONG SlotNumber,
375            IN PVOID Buffer,
376            IN ULONG Length)
377 {
378     DPRINT("ScsiPortGetBusData()\n");
379 
380     if (Length)
381     {
382         /* If Length is non-zero, just forward the call to
383         HalGetBusData() function */
384         return HalGetBusData(BusDataType,
385                              SystemIoBusNumber,
386                              SlotNumber,
387                              Buffer,
388                              Length);
389     }
390 
391     /* We have a more complex case here */
392     UNIMPLEMENTED;
393     return 0;
394 }
395 
396 /*
397  * @implemented
398  */
399 ULONG NTAPI
400 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension,
401                            IN ULONG BusDataType,
402                            IN ULONG SystemIoBusNumber,
403                            IN ULONG SlotNumber,
404                            IN PVOID Buffer,
405                            IN ULONG Offset,
406                            IN ULONG Length)
407 {
408     DPRINT("ScsiPortSetBusDataByOffset()\n");
409     return HalSetBusDataByOffset(BusDataType,
410                                  SystemIoBusNumber,
411                                  SlotNumber,
412                                  Buffer,
413                                  Offset,
414                                  Length);
415 }
416 
417 /*
418  * @implemented
419  */
420 PVOID NTAPI
421 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension,
422               IN INTERFACE_TYPE BusType,
423               IN ULONG SystemIoBusNumber,
424               IN SCSI_PHYSICAL_ADDRESS IoAddress,
425               IN ULONG NumberOfBytes,
426               IN BOOLEAN InIoSpace)
427 {
428     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
429     PHYSICAL_ADDRESS TranslatedAddress;
430     PMAPPED_ADDRESS DeviceBase;
431     ULONG AddressSpace;
432     PVOID MappedAddress;
433 
434     //DPRINT ("ScsiPortGetDeviceBase() called\n");
435 
436     DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
437                                         SCSI_PORT_DEVICE_EXTENSION,
438                                         MiniPortDeviceExtension);
439 
440     AddressSpace = (ULONG)InIoSpace;
441     if (HalTranslateBusAddress(BusType,
442                                SystemIoBusNumber,
443                                IoAddress,
444                                &AddressSpace,
445                                &TranslatedAddress) == FALSE)
446     {
447         return NULL;
448     }
449 
450     /* i/o space */
451     if (AddressSpace != 0)
452         return((PVOID)(ULONG_PTR)TranslatedAddress.QuadPart);
453 
454     MappedAddress = MmMapIoSpace(TranslatedAddress,
455                                  NumberOfBytes,
456                                  FALSE);
457 
458     DeviceBase = ExAllocatePoolWithTag(NonPagedPool,
459                                 sizeof(MAPPED_ADDRESS), TAG_SCSIPORT);
460 
461     if (DeviceBase == NULL)
462         return MappedAddress;
463 
464     DeviceBase->MappedAddress = MappedAddress;
465     DeviceBase->NumberOfBytes = NumberOfBytes;
466     DeviceBase->IoAddress = IoAddress;
467     DeviceBase->BusNumber = SystemIoBusNumber;
468 
469     /* Link it to the Device Extension list */
470     DeviceBase->NextMappedAddress = DeviceExtension->MappedAddressList;
471     DeviceExtension->MappedAddressList = DeviceBase;
472 
473     return MappedAddress;
474 }
475 
476 /*
477  * @unimplemented
478  */
479 PVOID NTAPI
480 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension,
481                IN UCHAR PathId,
482                IN UCHAR TargetId,
483                IN UCHAR Lun)
484 {
485     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
486     PSCSI_PORT_LUN_EXTENSION LunExtension;
487 
488     DPRINT("ScsiPortGetLogicalUnit() called\n");
489 
490     DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
491                                         SCSI_PORT_DEVICE_EXTENSION,
492                                         MiniPortDeviceExtension);
493 
494     /* Check the extension size */
495     if (!DeviceExtension->LunExtensionSize)
496     {
497         /* They didn't want one */
498         return NULL;
499     }
500 
501     LunExtension = GetLunByPath(DeviceExtension, PathId, TargetId, Lun);
502 
503     /* Check that the logical unit exists */
504     if (!LunExtension)
505     {
506         /* Nope, return NULL */
507         return NULL;
508     }
509 
510     /* Return the logical unit miniport extension */
511     return (LunExtension + 1);
512 }
513 
514 
515 /*
516  * @implemented
517  */
518 SCSI_PHYSICAL_ADDRESS NTAPI
519 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension,
520                            IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
521                            IN PVOID VirtualAddress,
522                            OUT ULONG *Length)
523 {
524     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
525     SCSI_PHYSICAL_ADDRESS PhysicalAddress;
526     SIZE_T BufferLength = 0;
527     ULONG_PTR Offset;
528     PSCSI_SG_ADDRESS SGList;
529     PSCSI_REQUEST_BLOCK_INFO SrbInfo;
530 
531     DPRINT("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
532         HwDeviceExtension, Srb, VirtualAddress, Length);
533 
534     DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
535                                         SCSI_PORT_DEVICE_EXTENSION,
536                                         MiniPortDeviceExtension);
537 
538     if (Srb == NULL || Srb->SenseInfoBuffer == VirtualAddress)
539     {
540         /* Simply look it up in the allocated common buffer */
541         Offset = (PUCHAR)VirtualAddress - (PUCHAR)DeviceExtension->SrbExtensionBuffer;
542 
543         BufferLength = DeviceExtension->CommonBufferLength - Offset;
544         PhysicalAddress.QuadPart = DeviceExtension->PhysicalAddress.QuadPart + Offset;
545     }
546     else if (DeviceExtension->MapRegisters)
547     {
548         PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Srb->OriginalRequest);
549         PSCSI_PORT_LUN_EXTENSION LunExtension = IoStack->DeviceObject->DeviceExtension;
550         ASSERT(LunExtension && !LunExtension->Common.IsFDO);
551 
552         /* Scatter-gather list must be used */
553         SrbInfo = SpiGetSrbData(DeviceExtension, LunExtension, Srb->QueueTag);
554 
555         SGList = SrbInfo->ScatterGather;
556 
557         /* Find needed item in the SG list */
558         Offset = (PCHAR)VirtualAddress - (PCHAR)Srb->DataBuffer;
559         while (Offset >= SGList->Length)
560         {
561             Offset -= SGList->Length;
562             SGList++;
563         }
564 
565         /* We're done, store length and physical address */
566         BufferLength = SGList->Length - Offset;
567         PhysicalAddress.QuadPart = SGList->PhysicalAddress.QuadPart + Offset;
568     }
569     else
570     {
571         /* Nothing */
572         PhysicalAddress.QuadPart = (LONGLONG)(SP_UNINITIALIZED_VALUE);
573     }
574 
575     *Length = (ULONG)BufferLength;
576     return PhysicalAddress;
577 }
578 
579 
580 /*
581  * @unimplemented
582  */
583 PSCSI_REQUEST_BLOCK NTAPI
584 ScsiPortGetSrb(IN PVOID DeviceExtension,
585            IN UCHAR PathId,
586            IN UCHAR TargetId,
587            IN UCHAR Lun,
588            IN LONG QueueTag)
589 {
590   DPRINT1("ScsiPortGetSrb() unimplemented\n");
591   UNIMPLEMENTED;
592   return NULL;
593 }
594 
595 
596 /*
597  * @implemented
598  */
599 PVOID NTAPI
600 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension,
601                  IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
602                  IN ULONG NumberOfBytes)
603 {
604     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
605     DEVICE_DESCRIPTION DeviceDescription;
606     ULONG MapRegistersCount;
607     NTSTATUS Status;
608 
609     DPRINT("ScsiPortGetUncachedExtension(%p %p %lu)\n",
610         HwDeviceExtension, ConfigInfo, NumberOfBytes);
611 
612     DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
613                                         SCSI_PORT_DEVICE_EXTENSION,
614                                         MiniPortDeviceExtension);
615 
616     /* Check for allocated common DMA buffer */
617     if (DeviceExtension->SrbExtensionBuffer != NULL)
618     {
619         DPRINT1("The HBA has already got a common DMA buffer!\n");
620         return NULL;
621     }
622 
623     /* Check for DMA adapter object */
624     if (DeviceExtension->AdapterObject == NULL)
625     {
626         /* Initialize DMA adapter description */
627         RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
628 
629         DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
630         DeviceDescription.Master = ConfigInfo->Master;
631         DeviceDescription.ScatterGather = ConfigInfo->ScatterGather;
632         DeviceDescription.DemandMode = ConfigInfo->DemandMode;
633         DeviceDescription.Dma32BitAddresses = ConfigInfo->Dma32BitAddresses;
634         DeviceDescription.BusNumber = ConfigInfo->SystemIoBusNumber;
635         DeviceDescription.DmaChannel = ConfigInfo->DmaChannel;
636         DeviceDescription.InterfaceType = ConfigInfo->AdapterInterfaceType;
637         DeviceDescription.DmaWidth = ConfigInfo->DmaWidth;
638         DeviceDescription.DmaSpeed = ConfigInfo->DmaSpeed;
639         DeviceDescription.MaximumLength = ConfigInfo->MaximumTransferLength;
640         DeviceDescription.DmaPort = ConfigInfo->DmaPort;
641 
642         /* Get a DMA adapter object */
643         DeviceExtension->AdapterObject =
644             HalGetAdapter(&DeviceDescription, &MapRegistersCount);
645 
646         /* Fail in case of error */
647         if (DeviceExtension->AdapterObject == NULL)
648         {
649             DPRINT1("HalGetAdapter() failed\n");
650             return NULL;
651         }
652 
653         /* Set number of physical breaks */
654         if (ConfigInfo->NumberOfPhysicalBreaks != 0 &&
655             MapRegistersCount > ConfigInfo->NumberOfPhysicalBreaks)
656         {
657             DeviceExtension->PortCapabilities.MaximumPhysicalPages =
658                 ConfigInfo->NumberOfPhysicalBreaks;
659         }
660         else
661         {
662             DeviceExtension->PortCapabilities.MaximumPhysicalPages = MapRegistersCount;
663         }
664     }
665 
666     /* Update auto request sense feature */
667     DeviceExtension->SupportsAutoSense = ConfigInfo->AutoRequestSense;
668 
669     /* Update Srb extension size */
670     if (DeviceExtension->SrbExtensionSize != ConfigInfo->SrbExtensionSize)
671         DeviceExtension->SrbExtensionSize = ConfigInfo->SrbExtensionSize;
672 
673     /* Update Srb extension alloc flag */
674     if (ConfigInfo->AutoRequestSense || DeviceExtension->SrbExtensionSize)
675         DeviceExtension->NeedSrbExtensionAlloc = TRUE;
676 
677     /* Allocate a common DMA buffer */
678     Status = SpiAllocateCommonBuffer(DeviceExtension, NumberOfBytes);
679 
680     if (!NT_SUCCESS(Status))
681     {
682         DPRINT1("SpiAllocateCommonBuffer() failed with Status = 0x%08X!\n", Status);
683         return NULL;
684     }
685 
686     return DeviceExtension->NonCachedExtension;
687 }
688 
689 static NTSTATUS
690 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, ULONG NonCachedSize)
691 {
692     PVOID *SrbExtension, CommonBuffer;
693     ULONG CommonBufferLength, BufSize;
694 
695     /* If size is 0, set it to 16 */
696     if (!DeviceExtension->SrbExtensionSize)
697         DeviceExtension->SrbExtensionSize = 16;
698 
699     /* Calculate size */
700     BufSize = DeviceExtension->SrbExtensionSize;
701 
702     /* Add autosense data size if needed */
703     if (DeviceExtension->SupportsAutoSense)
704         BufSize += sizeof(SENSE_DATA);
705 
706 
707     /* Round it */
708     BufSize = (BufSize + sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1);
709 
710     /* Sum up into the total common buffer length, and round it to page size */
711     CommonBufferLength =
712         ROUND_TO_PAGES(NonCachedSize + BufSize * DeviceExtension->RequestsNumber);
713 
714     /* Allocate it */
715     if (!DeviceExtension->AdapterObject)
716     {
717         /* From nonpaged pool if there is no DMA */
718         CommonBuffer = ExAllocatePoolWithTag(NonPagedPool, CommonBufferLength, TAG_SCSIPORT);
719     }
720     else
721     {
722         /* Perform a full request since we have a DMA adapter*/
723         CommonBuffer = HalAllocateCommonBuffer(DeviceExtension->AdapterObject,
724             CommonBufferLength,
725             &DeviceExtension->PhysicalAddress,
726             FALSE );
727     }
728 
729     /* Fail in case of error */
730     if (!CommonBuffer)
731         return STATUS_INSUFFICIENT_RESOURCES;
732 
733     /* Zero it */
734     RtlZeroMemory(CommonBuffer, CommonBufferLength);
735 
736     /* Store its size in Device Extension */
737     DeviceExtension->CommonBufferLength = CommonBufferLength;
738 
739     /* SrbExtension buffer is located at the beginning of the buffer */
740     DeviceExtension->SrbExtensionBuffer = CommonBuffer;
741 
742     /* Non-cached extension buffer is located at the end of
743        the common buffer */
744     if (NonCachedSize)
745     {
746         CommonBufferLength -=  NonCachedSize;
747         DeviceExtension->NonCachedExtension = (PUCHAR)CommonBuffer + CommonBufferLength;
748     }
749     else
750     {
751         DeviceExtension->NonCachedExtension = NULL;
752     }
753 
754     if (DeviceExtension->NeedSrbExtensionAlloc)
755     {
756         /* Look up how many SRB data structures we need */
757         DeviceExtension->SrbDataCount = CommonBufferLength / BufSize;
758 
759         /* Initialize the free SRB extensions list */
760         SrbExtension = (PVOID *)CommonBuffer;
761         DeviceExtension->FreeSrbExtensions = SrbExtension;
762 
763         /* Fill the remaining pointers (if we have more than 1 SRB) */
764         while (CommonBufferLength >= 2 * BufSize)
765         {
766             *SrbExtension = (PVOID*)((PCHAR)SrbExtension + BufSize);
767             SrbExtension = *SrbExtension;
768 
769             CommonBufferLength -= BufSize;
770         }
771     }
772 
773     return STATUS_SUCCESS;
774 }
775 
776 
777 
778 /*
779  * @implemented
780  */
781 PVOID NTAPI
782 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension,
783                           IN SCSI_PHYSICAL_ADDRESS PhysicalAddress)
784 {
785     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
786     ULONG Offset;
787 
788     DPRINT("ScsiPortGetVirtualAddress(%p %I64x)\n",
789         HwDeviceExtension, PhysicalAddress.QuadPart);
790 
791     DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
792                                         SCSI_PORT_DEVICE_EXTENSION,
793                                         MiniPortDeviceExtension);
794 
795     if (DeviceExtension->PhysicalAddress.QuadPart > PhysicalAddress.QuadPart)
796         return NULL;
797 
798     Offset = (ULONG)(PhysicalAddress.QuadPart - DeviceExtension->PhysicalAddress.QuadPart);
799 
800     if (Offset >= DeviceExtension->CommonBufferLength)
801         return NULL;
802 
803     return (PVOID)((ULONG_PTR)DeviceExtension->SrbExtensionBuffer + Offset);
804 }
805 
806 /**********************************************************************
807  * NAME                         EXPORTED
808  *  ScsiPortInitialize
809  *
810  * DESCRIPTION
811  *  Initializes SCSI port driver specific data.
812  *
813  * RUN LEVEL
814  *  PASSIVE_LEVEL
815  *
816  * ARGUMENTS
817  *  Argument1
818  *      Pointer to the miniport driver's driver object.
819  *
820  *  Argument2
821  *      Pointer to the miniport driver's registry path.
822  *
823  *  HwInitializationData
824  *      Pointer to port driver specific configuration data.
825  *
826  *  HwContext
827         Miniport driver specific context.
828  *
829  * RETURN VALUE
830  *  Status.
831  *
832  * @implemented
833  */
834 
835 ULONG NTAPI
836 ScsiPortInitialize(
837     IN PVOID Argument1,
838     IN PVOID Argument2,
839     IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
840     IN PVOID HwContext)
841 {
842     PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Argument1;
843     PUNICODE_STRING RegistryPath = (PUNICODE_STRING)Argument2;
844     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = NULL;
845     PCONFIGURATION_INFORMATION SystemConfig;
846     PPORT_CONFIGURATION_INFORMATION PortConfig;
847     CONFIGURATION_INFO ConfigInfo;
848     ULONG DeviceExtensionSize;
849     ULONG PortConfigSize;
850     BOOLEAN Again;
851     BOOLEAN DeviceFound = FALSE;
852     BOOLEAN FirstConfigCall = TRUE;
853     ULONG Result;
854     NTSTATUS Status;
855     ULONG MaxBus;
856     PCI_SLOT_NUMBER SlotNumber;
857 
858     PDEVICE_OBJECT PortDeviceObject;
859     UNICODE_STRING DeviceName;
860     PIO_SCSI_CAPABILITIES PortCapabilities;
861 
862     PCM_RESOURCE_LIST ResourceList;
863 
864     DPRINT ("ScsiPortInitialize() called!\n");
865 
866     /* Check params for validity */
867     if ((HwInitializationData->HwInitialize == NULL) ||
868         (HwInitializationData->HwStartIo == NULL) ||
869         (HwInitializationData->HwInterrupt == NULL) ||
870         (HwInitializationData->HwFindAdapter == NULL) ||
871         (HwInitializationData->HwResetBus == NULL))
872     {
873         return STATUS_REVISION_MISMATCH;
874     }
875 
876     PSCSI_PORT_DRIVER_EXTENSION driverExtension;
877 
878     // ScsiPortInitialize may be called multiple times by the same driver
879     driverExtension = IoGetDriverObjectExtension(DriverObject, HwInitializationData->HwInitialize);
880 
881     if (!driverExtension)
882     {
883         Status = IoAllocateDriverObjectExtension(DriverObject,
884                                                  HwInitializationData->HwInitialize,
885                                                  sizeof(SCSI_PORT_DRIVER_EXTENSION),
886                                                  (PVOID *)&driverExtension);
887 
888         if (!NT_SUCCESS(Status))
889         {
890             DPRINT1("Failed to allocate the driver extension! Status 0x%x\n", Status);
891             return Status;
892         }
893     }
894 
895     // set up the driver extension
896     driverExtension->RegistryPath.Buffer =
897         ExAllocatePoolWithTag(PagedPool, RegistryPath->MaximumLength, TAG_SCSIPORT);
898     driverExtension->RegistryPath.MaximumLength = RegistryPath->MaximumLength;
899     RtlCopyUnicodeString(&driverExtension->RegistryPath, RegistryPath);
900 
901     driverExtension->DriverObject = DriverObject;
902 
903     /* Set handlers */
904     DriverObject->DriverUnload = ScsiPortUnload;
905     DriverObject->DriverStartIo = ScsiPortStartIo;
906     DriverObject->DriverExtension->AddDevice = ScsiPortAddDevice;
907     DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiPortCreateClose;
908     DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiPortCreateClose;
909     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiPortDeviceControl;
910     DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiPortDispatchScsi;
911     DriverObject->MajorFunction[IRP_MJ_PNP] = ScsiPortDispatchPnp;
912     DriverObject->MajorFunction[IRP_MJ_POWER] = ScsiPortDispatchPower;
913 
914     /* Obtain configuration information */
915     SystemConfig = IoGetConfigurationInformation();
916 
917     /* Zero the internal configuration info structure */
918     RtlZeroMemory(&ConfigInfo, sizeof(CONFIGURATION_INFO));
919 
920     /* Zero starting slot number */
921     SlotNumber.u.AsULONG = 0;
922 
923     /* Allocate space for access ranges */
924     if (HwInitializationData->NumberOfAccessRanges)
925     {
926         ConfigInfo.AccessRanges =
927             ExAllocatePoolWithTag(PagedPool,
928             HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE), TAG_SCSIPORT);
929 
930         /* Fail if failed */
931         if (ConfigInfo.AccessRanges == NULL)
932             return STATUS_INSUFFICIENT_RESOURCES;
933     }
934 
935     /* Open registry keys and fill the driverExtension */
936     SpiInitOpenKeys(&ConfigInfo, driverExtension);
937 
938     // FIXME: PnP miniports are not supported
939     ASSERT(driverExtension->IsLegacyDriver);
940 
941     /* Last adapter number = not known */
942     ConfigInfo.LastAdapterNumber = SP_UNINITIALIZED_VALUE;
943 
944     /* Calculate sizes of DeviceExtension and PortConfig */
945     DeviceExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) +
946         HwInitializationData->DeviceExtensionSize;
947 
948     MaxBus = (HwInitializationData->AdapterInterfaceType == PCIBus) ? 8 : 1;
949     DPRINT("MaxBus: %lu\n", MaxBus);
950 
951     while (TRUE)
952     {
953         WCHAR NameBuffer[27];
954         /* Create a unicode device name */
955         swprintf(NameBuffer,
956                  L"\\Device\\ScsiPort%lu",
957                  SystemConfig->ScsiPortCount);
958         if (!RtlCreateUnicodeString(&DeviceName, NameBuffer))
959         {
960             DPRINT1("Failed to allocate memory for device name!\n");
961             Status = STATUS_INSUFFICIENT_RESOURCES;
962             PortDeviceObject = NULL;
963             break;
964         }
965 
966         DPRINT("Creating device: %wZ\n", &DeviceName);
967 
968         /* Create the port device */
969         Status = IoCreateDevice(DriverObject,
970                                 DeviceExtensionSize,
971                                 &DeviceName,
972                                 FILE_DEVICE_CONTROLLER,
973                                 FILE_DEVICE_SECURE_OPEN,
974                                 FALSE,
975                                 &PortDeviceObject);
976 
977         if (!NT_SUCCESS(Status))
978         {
979             DPRINT1("IoCreateDevice call failed! (Status 0x%lX)\n", Status);
980             PortDeviceObject = NULL;
981             break;
982         }
983 
984         /* Set the buffering strategy here... */
985         PortDeviceObject->Flags |= DO_DIRECT_IO;
986         PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT; /* FIXME: Is this really needed? */
987 
988         /* Fill Device Extension */
989         DeviceExtension = PortDeviceObject->DeviceExtension;
990         RtlZeroMemory(DeviceExtension, DeviceExtensionSize);
991         DeviceExtension->Common.DeviceObject = PortDeviceObject;
992         DeviceExtension->Common.IsFDO = TRUE;
993         DeviceExtension->Length = DeviceExtensionSize;
994         DeviceExtension->PortNumber = SystemConfig->ScsiPortCount;
995         DeviceExtension->DeviceName = DeviceName;
996 
997         /* Driver's routines... */
998         DeviceExtension->HwInitialize = HwInitializationData->HwInitialize;
999         DeviceExtension->HwStartIo = HwInitializationData->HwStartIo;
1000         DeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
1001         DeviceExtension->HwResetBus = HwInitializationData->HwResetBus;
1002         DeviceExtension->HwDmaStarted = HwInitializationData->HwDmaStarted;
1003 
1004         /* Extensions sizes */
1005         DeviceExtension->MiniPortExtensionSize = HwInitializationData->DeviceExtensionSize;
1006         DeviceExtension->LunExtensionSize =
1007             ALIGN_UP(HwInitializationData->SpecificLuExtensionSize, INT64);
1008         DeviceExtension->SrbExtensionSize =
1009             ALIGN_UP(HwInitializationData->SrbExtensionSize, INT64);
1010 
1011         /* Fill some numbers (bus count, lun count, etc) */
1012         DeviceExtension->MaxLunCount = SCSI_MAXIMUM_LOGICAL_UNITS;
1013         DeviceExtension->RequestsNumber = 16;
1014 
1015         /* Initialize the spin lock in the controller extension */
1016         KeInitializeSpinLock(&DeviceExtension->IrqLock);
1017         KeInitializeSpinLock(&DeviceExtension->SpinLock);
1018 
1019         /* Initialize the DPC object */
1020         IoInitializeDpcRequest(PortDeviceObject,
1021                                ScsiPortDpcForIsr);
1022 
1023         /* Initialize the device timer */
1024         DeviceExtension->TimerCount = -1;
1025         IoInitializeTimer(PortDeviceObject,
1026                           ScsiPortIoTimer,
1027                           DeviceExtension);
1028 
1029         /* Initialize miniport timer */
1030         KeInitializeTimer(&DeviceExtension->MiniportTimer);
1031         KeInitializeDpc(&DeviceExtension->MiniportTimerDpc,
1032                         SpiMiniportTimerDpc,
1033                         PortDeviceObject);
1034 
1035 CreatePortConfig:
1036 
1037         /* Allocate and initialize port configuration info */
1038         PortConfigSize = sizeof(PORT_CONFIGURATION_INFORMATION) +
1039                          HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE);
1040         PortConfigSize = ALIGN_UP(PortConfigSize, INT64);
1041         DeviceExtension->PortConfig = ExAllocatePoolWithTag(NonPagedPool, PortConfigSize, TAG_SCSIPORT);
1042 
1043         /* Fail if failed */
1044         if (DeviceExtension->PortConfig == NULL)
1045         {
1046             Status = STATUS_INSUFFICIENT_RESOURCES;
1047             break;
1048         }
1049 
1050         Status = SpiCreatePortConfig(DeviceExtension,
1051                                      HwInitializationData,
1052                                      &ConfigInfo,
1053                                      DeviceExtension->PortConfig,
1054                                      FirstConfigCall);
1055 
1056         if (!NT_SUCCESS(Status))
1057         {
1058             DPRINT("SpiCreatePortConfig() failed with Status 0x%08X\n", Status);
1059             break;
1060         }
1061 
1062         PortConfig = DeviceExtension->PortConfig;
1063 
1064         /* Copy extension sizes into the PortConfig */
1065         PortConfig->SpecificLuExtensionSize = DeviceExtension->LunExtensionSize;
1066         PortConfig->SrbExtensionSize = DeviceExtension->SrbExtensionSize;
1067 
1068         /* Initialize Access ranges */
1069         if (HwInitializationData->NumberOfAccessRanges != 0)
1070         {
1071             PortConfig->AccessRanges = ALIGN_UP_POINTER(PortConfig + 1, INT64);
1072 
1073             /* Copy the data */
1074             RtlCopyMemory(PortConfig->AccessRanges,
1075                           ConfigInfo.AccessRanges,
1076                           HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE));
1077         }
1078 
1079         /* Search for matching PCI device */
1080         if ((HwInitializationData->AdapterInterfaceType == PCIBus) &&
1081             (HwInitializationData->VendorIdLength > 0) &&
1082             (HwInitializationData->VendorId != NULL) &&
1083             (HwInitializationData->DeviceIdLength > 0) && (HwInitializationData->DeviceId != NULL))
1084         {
1085             PortConfig->BusInterruptLevel = 0;
1086 
1087             /* Get PCI device data */
1088             DPRINT(
1089                 "VendorId '%.*s'  DeviceId '%.*s'\n", HwInitializationData->VendorIdLength,
1090                 HwInitializationData->VendorId, HwInitializationData->DeviceIdLength,
1091                 HwInitializationData->DeviceId);
1092 
1093             if (!SpiGetPciConfigData(
1094                     DriverObject, PortDeviceObject, HwInitializationData, PortConfig, RegistryPath,
1095                     ConfigInfo.BusNumber, &SlotNumber))
1096             {
1097                 /* Continue to the next bus, nothing here */
1098                 ConfigInfo.BusNumber++;
1099                 DeviceExtension->PortConfig = NULL;
1100                 ExFreePool(PortConfig);
1101                 Again = FALSE;
1102                 goto CreatePortConfig;
1103             }
1104 
1105             if (!PortConfig->BusInterruptLevel)
1106             {
1107                 /* Bypass this slot, because no interrupt was assigned */
1108                 DeviceExtension->PortConfig = NULL;
1109                 ExFreePool(PortConfig);
1110                 goto CreatePortConfig;
1111             }
1112         }
1113         else
1114         {
1115             DPRINT("Non-pci bus\n");
1116         }
1117 
1118         /* Note: HwFindAdapter is called once for each bus */
1119         Again = FALSE;
1120         DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber);
1121         Result = (HwInitializationData->HwFindAdapter)(
1122             &DeviceExtension->MiniPortDeviceExtension, HwContext, 0, /* BusInformation */
1123             ConfigInfo.Parameter,                                    /* ArgumentString */
1124             PortConfig, &Again);
1125 
1126         DPRINT("HwFindAdapter() Result: %lu  Again: %s\n", Result, (Again) ? "True" : "False");
1127 
1128         /* Free MapRegisterBase, it's not needed anymore */
1129         if (DeviceExtension->MapRegisterBase != NULL)
1130         {
1131             ExFreePool(DeviceExtension->MapRegisterBase);
1132             DeviceExtension->MapRegisterBase = NULL;
1133         }
1134 
1135         /* If result is nothing good... */
1136         if (Result != SP_RETURN_FOUND)
1137         {
1138             DPRINT("HwFindAdapter() Result: %lu\n", Result);
1139 
1140             if (Result == SP_RETURN_NOT_FOUND)
1141             {
1142                 /* We can continue on the next bus */
1143                 ConfigInfo.BusNumber++;
1144                 Again = FALSE;
1145 
1146                 DeviceExtension->PortConfig = NULL;
1147                 ExFreePool(PortConfig);
1148                 goto CreatePortConfig;
1149             }
1150 
1151             /* Otherwise, break */
1152             Status = STATUS_INTERNAL_ERROR;
1153             break;
1154         }
1155 
1156         DPRINT(
1157             "ScsiPortInitialize(): Found HBA! (%x), adapter Id %d\n",
1158             PortConfig->BusInterruptVector, PortConfig->InitiatorBusId[0]);
1159 
1160         /* If the SRB extension size was updated */
1161         if (!DeviceExtension->NonCachedExtension &&
1162             (PortConfig->SrbExtensionSize != DeviceExtension->SrbExtensionSize))
1163         {
1164             /* Set it (rounding to LONGLONG again) */
1165             DeviceExtension->SrbExtensionSize = ALIGN_UP(PortConfig->SrbExtensionSize, INT64);
1166         }
1167 
1168         /* The same with LUN extension size */
1169         if (PortConfig->SpecificLuExtensionSize != DeviceExtension->LunExtensionSize)
1170             DeviceExtension->LunExtensionSize = PortConfig->SpecificLuExtensionSize;
1171 
1172         /* Construct a resource list */
1173         ResourceList = SpiConfigToResource(DeviceExtension, PortConfig);
1174 
1175         PDEVICE_OBJECT LowerPDO = NULL;
1176 
1177         Status = IoReportDetectedDevice(DriverObject,
1178                                         HwInitializationData->AdapterInterfaceType,
1179                                         ConfigInfo.BusNumber,
1180                                         PortConfig->SlotNumber,
1181                                         ResourceList,
1182                                         NULL,
1183                                         TRUE,
1184                                         &LowerPDO);
1185 
1186         if (!NT_SUCCESS(Status))
1187         {
1188             DPRINT1("IoReportDetectedDevice failed. Status: 0x%x\n", Status);
1189             __debugbreak();
1190             break;
1191         }
1192 
1193         DeviceExtension->Common.LowerDevice = IoAttachDeviceToDeviceStack(PortDeviceObject, LowerPDO);
1194 
1195         ASSERT(DeviceExtension->Common.LowerDevice);
1196 
1197         PortDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1198 
1199         if (ResourceList)
1200         {
1201             ExFreePoolWithTag(ResourceList, TAG_SCSIPORT);
1202         }
1203 
1204         /* Copy all stuff which we ever need from PortConfig to the DeviceExtension */
1205         if (PortConfig->MaximumNumberOfTargets > SCSI_MAXIMUM_TARGETS_PER_BUS)
1206             DeviceExtension->MaxTargedIds = SCSI_MAXIMUM_TARGETS_PER_BUS;
1207         else
1208             DeviceExtension->MaxTargedIds = PortConfig->MaximumNumberOfTargets;
1209 
1210         DeviceExtension->NumberOfBuses = PortConfig->NumberOfBuses;
1211         DeviceExtension->CachesData = PortConfig->CachesData;
1212         DeviceExtension->ReceiveEvent = PortConfig->ReceiveEvent;
1213         DeviceExtension->SupportsTaggedQueuing = PortConfig->TaggedQueuing;
1214         DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu;
1215 
1216         /* Initialize bus scanning information */
1217         size_t BusConfigSize = DeviceExtension->NumberOfBuses * sizeof(*DeviceExtension->Buses);
1218         DeviceExtension->Buses = ExAllocatePoolZero(NonPagedPool, BusConfigSize, TAG_SCSIPORT);
1219         if (!DeviceExtension->Buses)
1220         {
1221             DPRINT1("Out of resources!\n");
1222             Status = STATUS_INSUFFICIENT_RESOURCES;
1223             break;
1224         }
1225 
1226         // initialize bus data
1227         for (UINT8 pathId = 0; pathId < DeviceExtension->NumberOfBuses; pathId++)
1228         {
1229             DeviceExtension->Buses[pathId].BusIdentifier =
1230                 DeviceExtension->PortConfig->InitiatorBusId[pathId];
1231             InitializeListHead(&DeviceExtension->Buses[pathId].LunsListHead);
1232         }
1233 
1234         /* If something was disabled via registry - apply it */
1235         if (ConfigInfo.DisableMultipleLun)
1236             DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu = FALSE;
1237 
1238         if (ConfigInfo.DisableTaggedQueueing)
1239             DeviceExtension->SupportsTaggedQueuing = PortConfig->MultipleRequestPerLu = FALSE;
1240 
1241         /* Check if we need to alloc SRB data */
1242         if (DeviceExtension->SupportsTaggedQueuing || DeviceExtension->MultipleReqsPerLun)
1243         {
1244             DeviceExtension->NeedSrbDataAlloc = TRUE;
1245         }
1246         else
1247         {
1248             DeviceExtension->NeedSrbDataAlloc = FALSE;
1249         }
1250 
1251         /* Get a pointer to the port capabilities */
1252         PortCapabilities = &DeviceExtension->PortCapabilities;
1253 
1254         /* Copy one field there */
1255         DeviceExtension->MapBuffers = PortConfig->MapBuffers;
1256         PortCapabilities->AdapterUsesPio = PortConfig->MapBuffers;
1257 
1258         if (DeviceExtension->AdapterObject == NULL &&
1259             (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE || PortConfig->Master))
1260         {
1261             DPRINT1("DMA is not supported yet\n");
1262             ASSERT(FALSE);
1263         }
1264 
1265         if (DeviceExtension->SrbExtensionBuffer == NULL &&
1266             (DeviceExtension->SrbExtensionSize != 0 || PortConfig->AutoRequestSense))
1267         {
1268             DeviceExtension->SupportsAutoSense = PortConfig->AutoRequestSense;
1269             DeviceExtension->NeedSrbExtensionAlloc = TRUE;
1270 
1271             /* Allocate common buffer */
1272             Status = SpiAllocateCommonBuffer(DeviceExtension, 0);
1273 
1274             /* Check for failure */
1275             if (!NT_SUCCESS(Status))
1276                 break;
1277         }
1278 
1279         /* Allocate SrbData, if needed */
1280         if (DeviceExtension->NeedSrbDataAlloc)
1281         {
1282             ULONG Count;
1283             PSCSI_REQUEST_BLOCK_INFO SrbData;
1284 
1285             if (DeviceExtension->SrbDataCount != 0)
1286                 Count = DeviceExtension->SrbDataCount;
1287             else
1288                 Count = DeviceExtension->RequestsNumber * 2;
1289 
1290             /* Allocate the data */
1291             SrbData = ExAllocatePoolWithTag(
1292                 NonPagedPool, Count * sizeof(SCSI_REQUEST_BLOCK_INFO), TAG_SCSIPORT);
1293             if (SrbData == NULL)
1294                 return STATUS_INSUFFICIENT_RESOURCES;
1295 
1296             RtlZeroMemory(SrbData, Count * sizeof(SCSI_REQUEST_BLOCK_INFO));
1297 
1298             DeviceExtension->SrbInfo = SrbData;
1299             DeviceExtension->FreeSrbInfo = SrbData;
1300             DeviceExtension->SrbDataCount = Count;
1301 
1302             /* Link it to the list */
1303             while (Count > 0)
1304             {
1305                 SrbData->Requests.Flink = (PLIST_ENTRY)(SrbData + 1);
1306                 SrbData++;
1307                 Count--;
1308             }
1309 
1310             /* Mark the last entry of the list */
1311             SrbData--;
1312             SrbData->Requests.Flink = NULL;
1313         }
1314 
1315         /* Initialize port capabilities */
1316         PortCapabilities = &DeviceExtension->PortCapabilities;
1317         PortCapabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
1318         PortCapabilities->MaximumTransferLength = PortConfig->MaximumTransferLength;
1319 
1320         if (PortConfig->ReceiveEvent)
1321             PortCapabilities->SupportedAsynchronousEvents |= SRBEV_SCSI_ASYNC_NOTIFICATION;
1322 
1323         PortCapabilities->TaggedQueuing = DeviceExtension->SupportsTaggedQueuing;
1324         PortCapabilities->AdapterScansDown = PortConfig->AdapterScansDown;
1325 
1326         if (PortConfig->AlignmentMask > PortDeviceObject->AlignmentRequirement)
1327             PortDeviceObject->AlignmentRequirement = PortConfig->AlignmentMask;
1328 
1329         PortCapabilities->AlignmentMask = PortDeviceObject->AlignmentRequirement;
1330 
1331         if (PortCapabilities->MaximumPhysicalPages == 0)
1332         {
1333             PortCapabilities->MaximumPhysicalPages =
1334                 BYTES_TO_PAGES(PortCapabilities->MaximumTransferLength);
1335 
1336             /* Apply miniport's limits */
1337             if (PortConfig->NumberOfPhysicalBreaks < PortCapabilities->MaximumPhysicalPages)
1338             {
1339                 PortCapabilities->MaximumPhysicalPages = PortConfig->NumberOfPhysicalBreaks;
1340             }
1341         }
1342 
1343         FdoCallHWInitialize(DeviceExtension);
1344 
1345         Status = FdoStartAdapter(DeviceExtension);
1346 
1347         if (!NT_SUCCESS(Status))
1348         {
1349             DPRINT1("Failed to start the legacy adapter. Status 0x%x\n", Status);
1350             break;
1351         }
1352 
1353         FdoScanAdapter(DeviceExtension);
1354 
1355         FirstConfigCall = FALSE;
1356 
1357         /* Increase adapter number and bus number respectively */
1358         ConfigInfo.AdapterNumber++;
1359 
1360         if (!Again)
1361             ConfigInfo.BusNumber++;
1362 
1363         DPRINT("Bus: %lu  MaxBus: %lu\n", ConfigInfo.BusNumber, MaxBus);
1364 
1365         DeviceFound = TRUE;
1366     }
1367 
1368     /* Clean up the mess */
1369     if (!NT_SUCCESS(Status) && PortDeviceObject)
1370     {
1371         FdoRemoveAdapter(DeviceExtension);
1372     }
1373 
1374     /* Close registry keys */
1375     if (ConfigInfo.ServiceKey != NULL)
1376         ZwClose(ConfigInfo.ServiceKey);
1377 
1378     if (ConfigInfo.DeviceKey != NULL)
1379         ZwClose(ConfigInfo.DeviceKey);
1380 
1381     if (ConfigInfo.BusKey != NULL)
1382         ZwClose(ConfigInfo.BusKey);
1383 
1384     if (ConfigInfo.AccessRanges != NULL)
1385         ExFreePool(ConfigInfo.AccessRanges);
1386 
1387     if (ConfigInfo.Parameter != NULL)
1388         ExFreePool(ConfigInfo.Parameter);
1389 
1390     DPRINT("ScsiPortInitialize() done, Status = 0x%08X, DeviceFound = %d!\n",
1391         Status, DeviceFound);
1392 
1393     return (DeviceFound == FALSE) ? Status : STATUS_SUCCESS;
1394 }
1395 
1396 /*
1397  * @unimplemented
1398  */
1399 VOID NTAPI
1400 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension,
1401               IN PSCSI_REQUEST_BLOCK Srb,
1402               IN PVOID LogicalAddress,
1403               IN ULONG Length)
1404 {
1405   DPRINT1("ScsiPortIoMapTransfer()\n");
1406   UNIMPLEMENTED;
1407 }
1408 
1409 /*
1410  * @unimplemented
1411  */
1412 VOID NTAPI
1413 ScsiPortLogError(IN PVOID HwDeviceExtension,
1414          IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
1415          IN UCHAR PathId,
1416          IN UCHAR TargetId,
1417          IN UCHAR Lun,
1418          IN ULONG ErrorCode,
1419          IN ULONG UniqueId)
1420 {
1421   //PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1422 
1423   DPRINT1("ScsiPortLogError() called\n");
1424   DPRINT1("PathId: 0x%02x  TargetId: 0x%02x  Lun: 0x%02x  ErrorCode: 0x%08lx  UniqueId: 0x%08lx\n",
1425           PathId, TargetId, Lun, ErrorCode, UniqueId);
1426 
1427   //DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, SCSI_PORT_DEVICE_EXTENSION, MiniPortDeviceExtension);
1428 
1429 
1430   DPRINT("ScsiPortLogError() done\n");
1431 }
1432 
1433 /*
1434  * @implemented
1435  */
1436 VOID NTAPI
1437 ScsiPortMoveMemory(OUT PVOID Destination,
1438            IN PVOID Source,
1439            IN ULONG Length)
1440 {
1441   RtlMoveMemory(Destination,
1442         Source,
1443         Length);
1444 }
1445 
1446 
1447 /*
1448  * @implemented
1449  */
1450 VOID
1451 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType, IN PVOID HwDeviceExtension, ...)
1452 {
1453     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1454     va_list ap;
1455 
1456     DPRINT("ScsiPortNotification() called\n");
1457 
1458     DeviceExtension =
1459         CONTAINING_RECORD(HwDeviceExtension, SCSI_PORT_DEVICE_EXTENSION, MiniPortDeviceExtension);
1460 
1461     DPRINT("DeviceExtension %p\n", DeviceExtension);
1462 
1463     va_start(ap, HwDeviceExtension);
1464 
1465     switch (NotificationType)
1466     {
1467         case RequestComplete:
1468         {
1469             PSCSI_REQUEST_BLOCK Srb;
1470             PSCSI_REQUEST_BLOCK_INFO SrbData;
1471 
1472             Srb = (PSCSI_REQUEST_BLOCK)va_arg(ap, PSCSI_REQUEST_BLOCK);
1473 
1474             DPRINT("Notify: RequestComplete (Srb %p)\n", Srb);
1475 
1476             /* Make sure Srb is alright */
1477             ASSERT(Srb->SrbStatus != SRB_STATUS_PENDING);
1478             ASSERT(
1479                 Srb->Function != SRB_FUNCTION_EXECUTE_SCSI ||
1480                 Srb->SrbStatus != SRB_STATUS_SUCCESS || Srb->ScsiStatus == SCSISTAT_GOOD);
1481 
1482             if (!(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE))
1483             {
1484                 /* It's been already completed */
1485                 va_end(ap);
1486                 return;
1487             }
1488 
1489             /* It's not active anymore */
1490             Srb->SrbFlags &= ~SRB_FLAGS_IS_ACTIVE;
1491 
1492             if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
1493             {
1494                 /* TODO: Treat it specially */
1495                 ASSERT(FALSE);
1496             }
1497             else
1498             {
1499                 PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Srb->OriginalRequest);
1500                 PSCSI_PORT_LUN_EXTENSION LunExtension = IoStack->DeviceObject->DeviceExtension;
1501                 ASSERT(LunExtension && !LunExtension->Common.IsFDO);
1502 
1503                 /* Get the SRB data */
1504                 SrbData = SpiGetSrbData(DeviceExtension, LunExtension, Srb->QueueTag);
1505 
1506                 /* Make sure there are no CompletedRequests and there is a Srb */
1507                 ASSERT(SrbData->CompletedRequests == NULL && SrbData->Srb != NULL);
1508 
1509                 /* If it's a read/write request, make sure it has data inside it */
1510                 if ((Srb->SrbStatus == SRB_STATUS_SUCCESS) &&
1511                     ((Srb->Cdb[0] == SCSIOP_READ) || (Srb->Cdb[0] == SCSIOP_WRITE)))
1512                 {
1513                     ASSERT(Srb->DataTransferLength);
1514                 }
1515 
1516                 SrbData->CompletedRequests = DeviceExtension->InterruptData.CompletedRequests;
1517                 DeviceExtension->InterruptData.CompletedRequests = SrbData;
1518             }
1519         }
1520         break;
1521 
1522         case NextRequest:
1523             DPRINT("Notify: NextRequest\n");
1524             DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY;
1525             break;
1526 
1527         case NextLuRequest:
1528         {
1529             UCHAR PathId;
1530             UCHAR TargetId;
1531             UCHAR Lun;
1532             PSCSI_PORT_LUN_EXTENSION LunExtension;
1533 
1534             PathId = (UCHAR)va_arg(ap, int);
1535             TargetId = (UCHAR)va_arg(ap, int);
1536             Lun = (UCHAR)va_arg(ap, int);
1537 
1538             DPRINT(
1539                 "Notify: NextLuRequest(PathId %u  TargetId %u  Lun %u)\n", PathId, TargetId, Lun);
1540 
1541             /* Mark it in the flags field */
1542             DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY;
1543 
1544             /* Get the LUN extension */
1545             LunExtension = GetLunByPath(DeviceExtension, PathId, TargetId, Lun);
1546 
1547             /* If returned LunExtension is NULL, break out */
1548             if (!LunExtension)
1549                 break;
1550 
1551             /* This request should not be processed if */
1552             if ((LunExtension->ReadyLun) || (LunExtension->SrbInfo.Srb))
1553             {
1554                 /* Nothing to do here */
1555                 break;
1556             }
1557 
1558             /* Add this LUN to the list */
1559             LunExtension->ReadyLun = DeviceExtension->InterruptData.ReadyLun;
1560             DeviceExtension->InterruptData.ReadyLun = LunExtension;
1561         }
1562         break;
1563 
1564         case ResetDetected:
1565             DPRINT("Notify: ResetDetected\n");
1566             /* Add RESET flags */
1567             DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET | SCSI_PORT_RESET_REPORTED;
1568             break;
1569 
1570         case CallDisableInterrupts:
1571             DPRINT1("UNIMPLEMENTED SCSI Notification called: CallDisableInterrupts!\n");
1572             break;
1573 
1574         case CallEnableInterrupts:
1575             DPRINT1("UNIMPLEMENTED SCSI Notification called: CallEnableInterrupts!\n");
1576             break;
1577 
1578         case RequestTimerCall:
1579             DPRINT("Notify: RequestTimerCall\n");
1580             DeviceExtension->InterruptData.Flags |= SCSI_PORT_TIMER_NEEDED;
1581             DeviceExtension->InterruptData.HwScsiTimer = (PHW_TIMER)va_arg(ap, PHW_TIMER);
1582             DeviceExtension->InterruptData.MiniportTimerValue = (ULONG)va_arg(ap, ULONG);
1583             break;
1584 
1585         case BusChangeDetected:
1586             DPRINT1("UNIMPLEMENTED SCSI Notification called: BusChangeDetected!\n");
1587             break;
1588 
1589         default:
1590             DPRINT1("Unsupported notification from WMI: %lu\n", NotificationType);
1591             break;
1592     }
1593 
1594     va_end(ap);
1595 
1596     /* Request a DPC after we're done with the interrupt */
1597     DeviceExtension->InterruptData.Flags |= SCSI_PORT_NOTIFICATION_NEEDED;
1598 }
1599 
1600 /*
1601  * @implemented
1602  */
1603 BOOLEAN NTAPI
1604 ScsiPortValidateRange(IN PVOID HwDeviceExtension,
1605               IN INTERFACE_TYPE BusType,
1606               IN ULONG SystemIoBusNumber,
1607               IN SCSI_PHYSICAL_ADDRESS IoAddress,
1608               IN ULONG NumberOfBytes,
1609               IN BOOLEAN InIoSpace)
1610 {
1611   DPRINT("ScsiPortValidateRange()\n");
1612   return(TRUE);
1613 }
1614 
1615 
1616 /* INTERNAL FUNCTIONS ********************************************************/
1617 
1618 static VOID
1619 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData,
1620                     IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor,
1621                     IN PPORT_CONFIGURATION_INFORMATION PortConfig)
1622 {
1623     PACCESS_RANGE AccessRange;
1624     PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialData;
1625     ULONG RangeNumber;
1626     ULONG Index;
1627     ULONG Interrupt = 0;
1628     ULONG Dma = 0;
1629 
1630     RangeNumber = 0;
1631 
1632     /* Loop through all entries */
1633     for (Index = 0; Index < ResourceDescriptor->PartialResourceList.Count; Index++)
1634     {
1635         PartialData = &ResourceDescriptor->PartialResourceList.PartialDescriptors[Index];
1636 
1637         switch (PartialData->Type)
1638         {
1639         case CmResourceTypePort:
1640             /* Copy access ranges */
1641             if (RangeNumber < HwInitializationData->NumberOfAccessRanges)
1642             {
1643                 AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]);
1644 
1645                 AccessRange->RangeStart = PartialData->u.Port.Start;
1646                 AccessRange->RangeLength = PartialData->u.Port.Length;
1647 
1648                 AccessRange->RangeInMemory = FALSE;
1649                 RangeNumber++;
1650             }
1651             break;
1652 
1653         case CmResourceTypeMemory:
1654             /* Copy access ranges */
1655             if (RangeNumber < HwInitializationData->NumberOfAccessRanges)
1656             {
1657                 AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]);
1658 
1659                 AccessRange->RangeStart = PartialData->u.Memory.Start;
1660                 AccessRange->RangeLength = PartialData->u.Memory.Length;
1661 
1662                 AccessRange->RangeInMemory = TRUE;
1663                 RangeNumber++;
1664             }
1665             break;
1666 
1667         case CmResourceTypeInterrupt:
1668 
1669             if (Interrupt == 0)
1670             {
1671                 /* Copy interrupt data */
1672                 PortConfig->BusInterruptLevel = PartialData->u.Interrupt.Level;
1673                 PortConfig->BusInterruptVector = PartialData->u.Interrupt.Vector;
1674 
1675                 /* Set interrupt mode accordingly to the resource */
1676                 if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
1677                 {
1678                     PortConfig->InterruptMode = Latched;
1679                 }
1680                 else if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
1681                 {
1682                     PortConfig->InterruptMode = LevelSensitive;
1683                 }
1684             }
1685             else if (Interrupt == 1)
1686             {
1687                 /* Copy interrupt data */
1688                 PortConfig->BusInterruptLevel2 = PartialData->u.Interrupt.Level;
1689                 PortConfig->BusInterruptVector2 = PartialData->u.Interrupt.Vector;
1690 
1691                 /* Set interrupt mode accordingly to the resource */
1692                 if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
1693                 {
1694                     PortConfig->InterruptMode2 = Latched;
1695                 }
1696                 else if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
1697                 {
1698                     PortConfig->InterruptMode2 = LevelSensitive;
1699                 }
1700             }
1701 
1702             Interrupt++;
1703             break;
1704 
1705         case CmResourceTypeDma:
1706 
1707             if (Dma == 0)
1708             {
1709                 PortConfig->DmaChannel = PartialData->u.Dma.Channel;
1710                 PortConfig->DmaPort = PartialData->u.Dma.Port;
1711 
1712                 if (PartialData->Flags & CM_RESOURCE_DMA_8)
1713                     PortConfig->DmaWidth = Width8Bits;
1714                 else if ((PartialData->Flags & CM_RESOURCE_DMA_16) ||
1715                          (PartialData->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
1716                     PortConfig->DmaWidth = Width16Bits;
1717                 else if (PartialData->Flags & CM_RESOURCE_DMA_32)
1718                     PortConfig->DmaWidth = Width32Bits;
1719             }
1720             else if (Dma == 1)
1721             {
1722                 PortConfig->DmaChannel2 = PartialData->u.Dma.Channel;
1723                 PortConfig->DmaPort2 = PartialData->u.Dma.Port;
1724 
1725                 if (PartialData->Flags & CM_RESOURCE_DMA_8)
1726                     PortConfig->DmaWidth2 = Width8Bits;
1727                 else if ((PartialData->Flags & CM_RESOURCE_DMA_16) ||
1728                          (PartialData->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
1729                     PortConfig->DmaWidth2 = Width16Bits;
1730                 else if (PartialData->Flags & CM_RESOURCE_DMA_32)
1731                     PortConfig->DmaWidth2 = Width32Bits;
1732             }
1733             break;
1734         }
1735     }
1736 }
1737 
1738 static PCM_RESOURCE_LIST
1739 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1740                     PPORT_CONFIGURATION_INFORMATION PortConfig)
1741 {
1742     PCONFIGURATION_INFORMATION ConfigInfo;
1743     PCM_RESOURCE_LIST ResourceList;
1744     PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor;
1745     PACCESS_RANGE AccessRange;
1746     ULONG ListLength = 0, i, FullSize;
1747     ULONG Interrupt, Dma;
1748 
1749     /* Get current Atdisk usage from the system */
1750     ConfigInfo = IoGetConfigurationInformation();
1751 
1752     if (PortConfig->AtdiskPrimaryClaimed)
1753         ConfigInfo->AtDiskPrimaryAddressClaimed = TRUE;
1754 
1755     if (PortConfig->AtdiskSecondaryClaimed)
1756         ConfigInfo->AtDiskSecondaryAddressClaimed = TRUE;
1757 
1758     /* Do we use DMA? */
1759     if (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE ||
1760         PortConfig->DmaPort != SP_UNINITIALIZED_VALUE)
1761     {
1762         Dma = 1;
1763 
1764         if (PortConfig->DmaChannel2 != SP_UNINITIALIZED_VALUE ||
1765             PortConfig->DmaPort2 != SP_UNINITIALIZED_VALUE)
1766             Dma++;
1767     }
1768     else
1769     {
1770         Dma = 0;
1771     }
1772     ListLength += Dma;
1773 
1774     /* How many interrupts to we have? */
1775     Interrupt = DeviceExtension->InterruptCount;
1776     ListLength += Interrupt;
1777 
1778     /* How many access ranges do we use? */
1779     AccessRange = &((*(PortConfig->AccessRanges))[0]);
1780     for (i = 0; i < PortConfig->NumberOfAccessRanges; i++)
1781     {
1782         if (AccessRange->RangeLength != 0)
1783             ListLength++;
1784 
1785         AccessRange++;
1786     }
1787 
1788     /* Allocate the resource list, since we know its size now */
1789     FullSize = sizeof(CM_RESOURCE_LIST) + (ListLength - 1) *
1790         sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1791 
1792     ResourceList = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(PagedPool, FullSize, TAG_SCSIPORT);
1793 
1794     if (!ResourceList)
1795         return NULL;
1796 
1797     /* Zero it */
1798     RtlZeroMemory(ResourceList, FullSize);
1799 
1800     /* Initialize it */
1801     ResourceList->Count = 1;
1802     ResourceList->List[0].InterfaceType = PortConfig->AdapterInterfaceType;
1803     ResourceList->List[0].BusNumber = PortConfig->SystemIoBusNumber;
1804     ResourceList->List[0].PartialResourceList.Count = ListLength;
1805     ResourceDescriptor = ResourceList->List[0].PartialResourceList.PartialDescriptors;
1806 
1807     /* Copy access ranges array over */
1808     for (i = 0; i < PortConfig->NumberOfAccessRanges; i++)
1809     {
1810         AccessRange = &((*(PortConfig->AccessRanges))[i]);
1811 
1812         /* If the range is empty - skip it */
1813         if (AccessRange->RangeLength == 0)
1814             continue;
1815 
1816         if (AccessRange->RangeInMemory)
1817         {
1818             ResourceDescriptor->Type = CmResourceTypeMemory;
1819             ResourceDescriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
1820         }
1821         else
1822         {
1823             ResourceDescriptor->Type = CmResourceTypePort;
1824             ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
1825         }
1826 
1827         ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1828 
1829         ResourceDescriptor->u.Memory.Start = AccessRange->RangeStart;
1830         ResourceDescriptor->u.Memory.Length = AccessRange->RangeLength;
1831 
1832         ResourceDescriptor++;
1833     }
1834 
1835     /* If we use interrupt(s), copy them */
1836     while (Interrupt)
1837     {
1838         ResourceDescriptor->Type = CmResourceTypeInterrupt;
1839 
1840         if (PortConfig->AdapterInterfaceType == MicroChannel ||
1841             ((Interrupt == 2) ? PortConfig->InterruptMode2 : PortConfig->InterruptMode) == LevelSensitive)
1842         {
1843             ResourceDescriptor->ShareDisposition = CmResourceShareShared;
1844             ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
1845         }
1846         else
1847         {
1848             ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1849             ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
1850         }
1851 
1852         ResourceDescriptor->u.Interrupt.Level = (Interrupt == 2) ? PortConfig->BusInterruptLevel2 : PortConfig->BusInterruptLevel;
1853         ResourceDescriptor->u.Interrupt.Vector = (Interrupt == 2) ? PortConfig->BusInterruptVector2 : PortConfig->BusInterruptVector;
1854         ResourceDescriptor->u.Interrupt.Affinity = 0;
1855 
1856         ResourceDescriptor++;
1857         Interrupt--;
1858     }
1859 
1860     /* Copy DMA data */
1861     while (Dma)
1862     {
1863         ResourceDescriptor->Type = CmResourceTypeDma;
1864         ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1865         ResourceDescriptor->u.Dma.Channel = (Dma == 2) ? PortConfig->DmaChannel2 : PortConfig->DmaChannel;
1866         ResourceDescriptor->u.Dma.Port = (Dma == 2) ? PortConfig->DmaPort2 : PortConfig->DmaPort;
1867         ResourceDescriptor->Flags = 0;
1868 
1869         if (((Dma == 2) ? PortConfig->DmaWidth2 : PortConfig->DmaWidth) == Width8Bits)
1870             ResourceDescriptor->Flags |= CM_RESOURCE_DMA_8;
1871         else if (((Dma == 2) ? PortConfig->DmaWidth2 : PortConfig->DmaWidth) == Width16Bits)
1872             ResourceDescriptor->Flags |= CM_RESOURCE_DMA_16;
1873         else
1874             ResourceDescriptor->Flags |= CM_RESOURCE_DMA_32;
1875 
1876         if (((Dma == 2) ? PortConfig->DmaChannel2 : PortConfig->DmaChannel) == SP_UNINITIALIZED_VALUE)
1877             ResourceDescriptor->u.Dma.Channel = 0;
1878 
1879         if (((Dma == 2) ? PortConfig->DmaPort2 : PortConfig->DmaPort) == SP_UNINITIALIZED_VALUE)
1880             ResourceDescriptor->u.Dma.Port = 0;
1881 
1882         ResourceDescriptor++;
1883         Dma--;
1884     }
1885 
1886     return ResourceList;
1887 }
1888 
1889 
1890 static BOOLEAN
1891 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject,
1892                     IN PDEVICE_OBJECT DeviceObject,
1893                     IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
1894                     IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,
1895                     IN PUNICODE_STRING RegistryPath,
1896                     IN ULONG BusNumber,
1897                     IN OUT PPCI_SLOT_NUMBER NextSlotNumber)
1898 {
1899     PCI_COMMON_CONFIG PciConfig;
1900     PCI_SLOT_NUMBER SlotNumber;
1901     ULONG DataSize;
1902     ULONG DeviceNumber;
1903     ULONG FunctionNumber;
1904     CHAR VendorIdString[8];
1905     CHAR DeviceIdString[8];
1906     UNICODE_STRING UnicodeStr;
1907     PCM_RESOURCE_LIST ResourceList = NULL;
1908     NTSTATUS Status;
1909 
1910     DPRINT ("SpiGetPciConfiguration() called\n");
1911 
1912     SlotNumber.u.AsULONG = 0;
1913 
1914     /* Loop through all devices */
1915     for (DeviceNumber = NextSlotNumber->u.bits.DeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
1916     {
1917         SlotNumber.u.bits.DeviceNumber = DeviceNumber;
1918 
1919         /* Loop through all functions */
1920         for (FunctionNumber = NextSlotNumber->u.bits.FunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
1921         {
1922             SlotNumber.u.bits.FunctionNumber = FunctionNumber;
1923 
1924             /* Get PCI config bytes */
1925             DataSize = HalGetBusData(PCIConfiguration,
1926                                      BusNumber,
1927                                      SlotNumber.u.AsULONG,
1928                                      &PciConfig,
1929                                      sizeof(ULONG));
1930 
1931             /* If result of HalGetBusData is 0, then the bus is wrong */
1932             if (DataSize == 0)
1933                 return FALSE;
1934 
1935             /* Check if result is PCI_INVALID_VENDORID or too small */
1936             if ((DataSize < sizeof(ULONG)) ||
1937                 (PciConfig.VendorID == PCI_INVALID_VENDORID))
1938             {
1939                 /* Continue to try the next function */
1940                 continue;
1941             }
1942 
1943             sprintf (VendorIdString, "%04hx", PciConfig.VendorID);
1944             sprintf (DeviceIdString, "%04hx", PciConfig.DeviceID);
1945 
1946             if (_strnicmp(VendorIdString, HwInitializationData->VendorId, HwInitializationData->VendorIdLength) ||
1947                 _strnicmp(DeviceIdString, HwInitializationData->DeviceId, HwInitializationData->DeviceIdLength))
1948             {
1949                 /* It is not our device */
1950                 continue;
1951             }
1952 
1953             DPRINT("Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n",
1954                    PciConfig.VendorID,
1955                    PciConfig.DeviceID,
1956                    BusNumber,
1957                    SlotNumber.u.bits.DeviceNumber,
1958                    SlotNumber.u.bits.FunctionNumber);
1959 
1960 
1961             RtlInitUnicodeString(&UnicodeStr, L"ScsiAdapter");
1962             Status = HalAssignSlotResources(RegistryPath,
1963                                             &UnicodeStr,
1964                                             DriverObject,
1965                                             DeviceObject,
1966                                             PCIBus,
1967                                             BusNumber,
1968                                             SlotNumber.u.AsULONG,
1969                                             &ResourceList);
1970 
1971             if (!NT_SUCCESS(Status))
1972                 break;
1973 
1974             /* Create configuration information */
1975             SpiResourceToConfig(HwInitializationData,
1976                                 ResourceList->List,
1977                                 PortConfig);
1978 
1979             /* Free the resource list */
1980             ExFreePool(ResourceList);
1981 
1982             /* Set dev & fn numbers */
1983             NextSlotNumber->u.bits.DeviceNumber = DeviceNumber;
1984             NextSlotNumber->u.bits.FunctionNumber = FunctionNumber + 1;
1985 
1986             /* Save the slot number */
1987             PortConfig->SlotNumber = SlotNumber.u.AsULONG;
1988 
1989             return TRUE;
1990         }
1991        NextSlotNumber->u.bits.FunctionNumber = 0;
1992     }
1993 
1994     NextSlotNumber->u.bits.DeviceNumber = 0;
1995     DPRINT ("No device found\n");
1996 
1997     return FALSE;
1998 }
1999 
2000 
2001 
2002 /**********************************************************************
2003  * NAME                         INTERNAL
2004  *  ScsiPortCreateClose
2005  *
2006  * DESCRIPTION
2007  *  Answer requests for Create/Close calls: a null operation.
2008  *
2009  * RUN LEVEL
2010  *  PASSIVE_LEVEL
2011  *
2012  * ARGUMENTS
2013  *  DeviceObject
2014  *      Pointer to a device object.
2015  *
2016  *  Irp
2017  *      Pointer to an IRP.
2018  *
2019  * RETURN VALUE
2020  *  Status.
2021  */
2022 
2023 static NTSTATUS NTAPI
2024 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
2025                    IN PIRP Irp)
2026 {
2027     DPRINT("ScsiPortCreateClose()\n");
2028 
2029     Irp->IoStatus.Status = STATUS_SUCCESS;
2030     IoCompleteRequest(Irp, IO_NO_INCREMENT);
2031 
2032     return STATUS_SUCCESS;
2033 }
2034 
2035 IO_ALLOCATION_ACTION
2036 NTAPI
2037 SpiAdapterControl(PDEVICE_OBJECT DeviceObject,
2038                   PIRP Irp,
2039                   PVOID MapRegisterBase,
2040                   PVOID Context)
2041 {
2042     PSCSI_REQUEST_BLOCK Srb;
2043     PSCSI_SG_ADDRESS ScatterGatherList;
2044     KIRQL CurrentIrql;
2045     PIO_STACK_LOCATION IrpStack;
2046     ULONG TotalLength = 0;
2047     PSCSI_REQUEST_BLOCK_INFO SrbInfo;
2048     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2049     PUCHAR DataVA;
2050     BOOLEAN WriteToDevice;
2051 
2052     /* Get pointers to SrbInfo and DeviceExtension */
2053     SrbInfo = (PSCSI_REQUEST_BLOCK_INFO)Context;
2054     DeviceExtension = DeviceObject->DeviceExtension;
2055 
2056     /* Get pointer to SRB */
2057     IrpStack = IoGetCurrentIrpStackLocation(Irp);
2058     Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
2059 
2060     /* Depending on the map registers number, we allocate
2061        either from NonPagedPool, or from our static list */
2062     if (SrbInfo->NumberOfMapRegisters > MAX_SG_LIST)
2063     {
2064         SrbInfo->ScatterGather = ExAllocatePoolWithTag(
2065             NonPagedPool, SrbInfo->NumberOfMapRegisters * sizeof(SCSI_SG_ADDRESS), TAG_SCSIPORT);
2066 
2067         if (SrbInfo->ScatterGather == NULL)
2068             ASSERT(FALSE);
2069 
2070         Srb->SrbFlags |= SRB_FLAGS_SGLIST_FROM_POOL;
2071     }
2072     else
2073     {
2074         SrbInfo->ScatterGather = SrbInfo->ScatterGatherList;
2075     }
2076 
2077     /* Use chosen SG list source */
2078     ScatterGatherList = SrbInfo->ScatterGather;
2079 
2080     /* Save map registers base */
2081     SrbInfo->BaseOfMapRegister = MapRegisterBase;
2082 
2083     /* Determine WriteToDevice flag */
2084     WriteToDevice = Srb->SrbFlags & SRB_FLAGS_DATA_OUT ? TRUE : FALSE;
2085 
2086     /* Get virtual address of the data buffer */
2087     DataVA = (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress) +
2088                 ((PCHAR)Srb->DataBuffer - SrbInfo->DataOffset);
2089 
2090     /* Build the actual SG list */
2091     while (TotalLength < Srb->DataTransferLength)
2092     {
2093         if (!ScatterGatherList)
2094             break;
2095 
2096         ScatterGatherList->Length = Srb->DataTransferLength - TotalLength;
2097         ScatterGatherList->PhysicalAddress = IoMapTransfer(DeviceExtension->AdapterObject,
2098                                                            Irp->MdlAddress,
2099                                                            MapRegisterBase,
2100                                                            DataVA + TotalLength,
2101                                                            &ScatterGatherList->Length,
2102                                                            WriteToDevice);
2103 
2104         TotalLength += ScatterGatherList->Length;
2105         ScatterGatherList++;
2106     }
2107 
2108     /* Schedule an active request */
2109     InterlockedIncrement(&DeviceExtension->ActiveRequestCounter );
2110     KeAcquireSpinLock(&DeviceExtension->SpinLock, &CurrentIrql);
2111     KeSynchronizeExecution(DeviceExtension->Interrupt[0],
2112                            ScsiPortStartPacket,
2113                            DeviceObject);
2114     KeReleaseSpinLock(&DeviceExtension->SpinLock, CurrentIrql);
2115 
2116     return DeallocateObjectKeepRegisters;
2117 }
2118 
2119 BOOLEAN
2120 NTAPI
2121 ScsiPortIsr(
2122     _In_ PKINTERRUPT Interrupt,
2123     _In_ PVOID ServiceContext)
2124 {
2125     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2126 
2127     DPRINT("ScsiPortIsr() called!\n");
2128 
2129     DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext;
2130 
2131     /* If interrupts are disabled - we don't expect any */
2132     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_DISABLE_INTERRUPTS)
2133         return FALSE;
2134 
2135     /* Call miniport's HwInterrupt routine */
2136     if (DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension) == FALSE)
2137     {
2138         /* This interrupt doesn't belong to us */
2139         return FALSE;
2140     }
2141 
2142     /* If flag of notification is set - queue a DPC */
2143     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
2144     {
2145         IoRequestDpc(DeviceExtension->Common.DeviceObject,
2146                      DeviceExtension->CurrentIrp,
2147                      DeviceExtension);
2148     }
2149 
2150     return TRUE;
2151 }
2152 
2153 BOOLEAN
2154 NTAPI
2155 SpiProcessTimeout(PVOID ServiceContext)
2156 {
2157     PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)ServiceContext;
2158     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
2159     ULONG Bus;
2160 
2161     DPRINT("SpiProcessTimeout() entered\n");
2162 
2163     DeviceExtension->TimerCount = -1;
2164 
2165     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET)
2166     {
2167         DeviceExtension->InterruptData.Flags &= ~SCSI_PORT_RESET;
2168 
2169         if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET_REQUEST)
2170         {
2171             DeviceExtension->InterruptData.Flags &=  ~SCSI_PORT_RESET_REQUEST;
2172             ScsiPortStartPacket(ServiceContext);
2173         }
2174 
2175         return FALSE;
2176     }
2177     else
2178     {
2179         DPRINT("Resetting the bus\n");
2180 
2181         for (Bus = 0; Bus < DeviceExtension->NumberOfBuses; Bus++)
2182         {
2183             DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension, Bus);
2184 
2185             /* Reset flags and set reset timeout to 4 seconds */
2186             DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET;
2187             DeviceExtension->TimerCount = 4;
2188         }
2189 
2190         /* If miniport requested - request a dpc for it */
2191         if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
2192             IoRequestDpc(DeviceExtension->Common.DeviceObject, NULL, NULL);
2193     }
2194 
2195     return TRUE;
2196 }
2197 
2198 
2199 BOOLEAN
2200 NTAPI
2201 SpiResetBus(PVOID ServiceContext)
2202 {
2203     PRESETBUS_PARAMS ResetParams = (PRESETBUS_PARAMS)ServiceContext;
2204     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2205 
2206     /* Perform the bus reset */
2207     DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ResetParams->DeviceExtension;
2208     DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension,
2209                                 ResetParams->PathId);
2210 
2211     /* Set flags and start the timer */
2212     DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET;
2213     DeviceExtension->TimerCount = 4;
2214 
2215     /* If miniport requested - give him a DPC */
2216     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
2217         IoRequestDpc(DeviceExtension->Common.DeviceObject, NULL, NULL);
2218 
2219     return TRUE;
2220 }
2221 
2222 //    ScsiPortIoTimer
2223 //  DESCRIPTION:
2224 //    This function handles timeouts and other time delayed processing
2225 //
2226 //  RUN LEVEL:
2227 //
2228 //  ARGUMENTS:
2229 //    IN  PDEVICE_OBJECT  DeviceObject  Device object registered with timer
2230 //    IN  PVOID           Context       the Controller extension for the
2231 //                                      controller the device is on
2232 //
2233 static VOID NTAPI
2234 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
2235                 PVOID Context)
2236 {
2237     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2238     PSCSI_PORT_LUN_EXTENSION LunExtension;
2239     PIRP Irp;
2240 
2241     DPRINT("ScsiPortIoTimer()\n");
2242 
2243     DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
2244 
2245     /* Protect with the spinlock */
2246     KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
2247 
2248     /* Check timeouts */
2249     if (DeviceExtension->TimerCount > 0)
2250     {
2251         /* Decrease the timeout counter */
2252         DeviceExtension->TimerCount--;
2253 
2254         if (DeviceExtension->TimerCount == 0)
2255         {
2256             /* Timeout, process it */
2257             if (KeSynchronizeExecution(DeviceExtension->Interrupt[0],
2258                                        SpiProcessTimeout,
2259                                        DeviceExtension->Common.DeviceObject))
2260             {
2261                 DPRINT("Error happened during processing timeout, but nothing critical\n");
2262             }
2263         }
2264 
2265         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
2266 
2267         /* We should exit now, since timeout is processed */
2268         return;
2269     }
2270 
2271     /* Per-Lun scanning of timeouts is needed... */
2272     for (UINT8 pathId = 0; pathId < DeviceExtension->NumberOfBuses; pathId++)
2273     {
2274         PSCSI_BUS_INFO bus = &DeviceExtension->Buses[pathId];
2275 
2276         for (PLIST_ENTRY lunEntry = bus->LunsListHead.Flink;
2277              lunEntry != &bus->LunsListHead;
2278              lunEntry = lunEntry->Flink)
2279         {
2280             LunExtension = CONTAINING_RECORD(lunEntry, SCSI_PORT_LUN_EXTENSION, LunEntry);
2281 
2282             if (LunExtension->Flags & LUNEX_BUSY)
2283             {
2284                 if (!(LunExtension->Flags &
2285                     (LUNEX_NEED_REQUEST_SENSE | LUNEX_FROZEN_QUEUE)))
2286                 {
2287                     DPRINT("Retrying busy request\n");
2288 
2289                     /* Clear flags, and retry busy request */
2290                     LunExtension->Flags &= ~(LUNEX_BUSY | LUNEX_FULL_QUEUE);
2291                     Irp = LunExtension->BusyRequest;
2292 
2293                     /* Clearing busy request */
2294                     LunExtension->BusyRequest = NULL;
2295 
2296                     KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
2297 
2298                     IoStartPacket(DeviceObject, Irp, (PULONG)NULL, NULL);
2299 
2300                     KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
2301                 }
2302             }
2303             else if (LunExtension->RequestTimeout == 0)
2304             {
2305                 RESETBUS_PARAMS ResetParams;
2306 
2307                 LunExtension->RequestTimeout = -1;
2308 
2309                 DPRINT("Request timed out, resetting bus\n");
2310 
2311                 /* Pass params to the bus reset routine */
2312                 ResetParams.PathId = LunExtension->PathId;
2313                 ResetParams.DeviceExtension = DeviceExtension;
2314 
2315                 if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0],
2316                                             SpiResetBus,
2317                                             &ResetParams))
2318                 {
2319                     DPRINT1("Reset failed\n");
2320                 }
2321             }
2322             else if (LunExtension->RequestTimeout > 0)
2323             {
2324                 /* Decrement the timeout counter */
2325                 LunExtension->RequestTimeout--;
2326             }
2327         }
2328     }
2329 
2330     /* Release the spinlock */
2331     KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
2332 }
2333 
2334 VOID
2335 NTAPI
2336 SpiMiniportTimerDpc(IN struct _KDPC *Dpc,
2337                     IN PVOID DeviceObject,
2338                     IN PVOID SystemArgument1,
2339                     IN PVOID SystemArgument2)
2340 {
2341     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2342 
2343     DPRINT("Miniport timer DPC\n");
2344 
2345     DeviceExtension = ((PDEVICE_OBJECT)DeviceObject)->DeviceExtension;
2346 
2347     /* Acquire the spinlock */
2348     KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
2349 
2350     /* Call the timer routine */
2351     if (DeviceExtension->HwScsiTimer != NULL)
2352     {
2353         DeviceExtension->HwScsiTimer(&DeviceExtension->MiniPortDeviceExtension);
2354     }
2355 
2356     /* Release the spinlock */
2357     KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
2358 
2359     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
2360     {
2361         ScsiPortDpcForIsr(NULL,
2362                           DeviceExtension->Common.DeviceObject,
2363                           NULL,
2364                           NULL);
2365     }
2366 }
2367 
2368 static NTSTATUS
2369 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
2370                     PHW_INITIALIZATION_DATA HwInitData,
2371                     PCONFIGURATION_INFO InternalConfigInfo,
2372                     PPORT_CONFIGURATION_INFORMATION ConfigInfo,
2373                     BOOLEAN ZeroStruct)
2374 {
2375     UNICODE_STRING UnicodeString;
2376     OBJECT_ATTRIBUTES ObjectAttributes;
2377     PCONFIGURATION_INFORMATION DdkConfigInformation;
2378     HANDLE RootKey, Key;
2379     BOOLEAN Found;
2380     WCHAR DeviceBuffer[16];
2381     WCHAR StrBuffer[512];
2382     ULONG Bus;
2383     NTSTATUS Status;
2384 
2385     /* Zero out the struct if told so */
2386     if (ZeroStruct)
2387     {
2388         /* First zero the portconfig */
2389         RtlZeroMemory(ConfigInfo, sizeof(PORT_CONFIGURATION_INFORMATION));
2390 
2391         /* Then access ranges */
2392         RtlZeroMemory(InternalConfigInfo->AccessRanges,
2393                       HwInitData->NumberOfAccessRanges * sizeof(ACCESS_RANGE));
2394 
2395         /* Initialize the struct */
2396         ConfigInfo->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
2397         ConfigInfo->AdapterInterfaceType = HwInitData->AdapterInterfaceType;
2398         ConfigInfo->InterruptMode = Latched;
2399         ConfigInfo->DmaChannel = SP_UNINITIALIZED_VALUE;
2400         ConfigInfo->DmaPort = SP_UNINITIALIZED_VALUE;
2401         ConfigInfo->DmaChannel2 = SP_UNINITIALIZED_VALUE;
2402         ConfigInfo->DmaPort2 = SP_UNINITIALIZED_VALUE;
2403         ConfigInfo->MaximumTransferLength = SP_UNINITIALIZED_VALUE;
2404         ConfigInfo->NumberOfAccessRanges = HwInitData->NumberOfAccessRanges;
2405         ConfigInfo->MaximumNumberOfTargets = 8;
2406 
2407         /* Store parameters */
2408         ConfigInfo->NeedPhysicalAddresses = HwInitData->NeedPhysicalAddresses;
2409         ConfigInfo->MapBuffers = HwInitData->MapBuffers;
2410         ConfigInfo->AutoRequestSense = HwInitData->AutoRequestSense;
2411         ConfigInfo->ReceiveEvent = HwInitData->ReceiveEvent;
2412         ConfigInfo->TaggedQueuing = HwInitData->TaggedQueuing;
2413         ConfigInfo->MultipleRequestPerLu = HwInitData->MultipleRequestPerLu;
2414 
2415         /* Get the disk usage */
2416         DdkConfigInformation = IoGetConfigurationInformation();
2417         ConfigInfo->AtdiskPrimaryClaimed = DdkConfigInformation->AtDiskPrimaryAddressClaimed;
2418         ConfigInfo->AtdiskSecondaryClaimed = DdkConfigInformation->AtDiskSecondaryAddressClaimed;
2419 
2420         /* Initiator bus id is not set */
2421         for (Bus = 0; Bus < 8; Bus++)
2422             ConfigInfo->InitiatorBusId[Bus] = (CCHAR)SP_UNINITIALIZED_VALUE;
2423     }
2424 
2425     ConfigInfo->NumberOfPhysicalBreaks = 17;
2426 
2427     /* Clear this information */
2428     InternalConfigInfo->DisableTaggedQueueing = FALSE;
2429     InternalConfigInfo->DisableMultipleLun = FALSE;
2430 
2431     /* Store Bus Number */
2432     ConfigInfo->SystemIoBusNumber = InternalConfigInfo->BusNumber;
2433 
2434 TryNextAd:
2435 
2436     if (ConfigInfo->AdapterInterfaceType == Internal)
2437     {
2438         /* Open registry key for HW database */
2439         InitializeObjectAttributes(&ObjectAttributes,
2440                                    DeviceExtension->Common.DeviceObject->DriverObject->HardwareDatabase,
2441                                    OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2442                                    NULL,
2443                                    NULL);
2444 
2445         Status = ZwOpenKey(&RootKey,
2446                            KEY_READ,
2447                            &ObjectAttributes);
2448 
2449         if (NT_SUCCESS(Status))
2450         {
2451             /* Create name for it */
2452             swprintf(StrBuffer, L"ScsiAdapter\\%lu",
2453                 InternalConfigInfo->AdapterNumber);
2454 
2455             RtlInitUnicodeString(&UnicodeString, StrBuffer);
2456 
2457             /* Open device key */
2458             InitializeObjectAttributes(&ObjectAttributes,
2459                                        &UnicodeString,
2460                                        OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2461                                        RootKey,
2462                                        NULL);
2463 
2464             Status = ZwOpenKey(&Key,
2465                                KEY_READ,
2466                                &ObjectAttributes);
2467 
2468             ZwClose(RootKey);
2469 
2470             if (NT_SUCCESS(Status))
2471             {
2472                 if (InternalConfigInfo->LastAdapterNumber != InternalConfigInfo->AdapterNumber)
2473                 {
2474                     DPRINT("Hardware info found at %S\n", StrBuffer);
2475 
2476                     /* Parse it */
2477                     SpiParseDeviceInfo(DeviceExtension,
2478                                        Key,
2479                                        ConfigInfo,
2480                                        InternalConfigInfo,
2481                                        (PUCHAR)StrBuffer);
2482 
2483                      InternalConfigInfo->BusNumber = 0;
2484                 }
2485                 else
2486                 {
2487                     /* Try the next adapter */
2488                     InternalConfigInfo->AdapterNumber++;
2489                     goto TryNextAd;
2490                 }
2491             }
2492             else
2493             {
2494                 /* Info was not found, exit */
2495                 DPRINT("ZwOpenKey() failed with Status=0x%08X\n", Status);
2496                 return STATUS_DEVICE_DOES_NOT_EXIST;
2497             }
2498         }
2499         else
2500         {
2501             DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status);
2502         }
2503     }
2504 
2505     /* Look at device params */
2506     Key = NULL;
2507     if (InternalConfigInfo->Parameter)
2508     {
2509         ExFreePool(InternalConfigInfo->Parameter);
2510         InternalConfigInfo->Parameter = NULL;
2511     }
2512 
2513     if (InternalConfigInfo->ServiceKey != NULL)
2514     {
2515         swprintf(DeviceBuffer, L"Device%lu", InternalConfigInfo->AdapterNumber);
2516         RtlInitUnicodeString(&UnicodeString, DeviceBuffer);
2517 
2518         /* Open the service key */
2519         InitializeObjectAttributes(&ObjectAttributes,
2520                                    &UnicodeString,
2521                                    OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2522                                    InternalConfigInfo->ServiceKey,
2523                                    NULL);
2524 
2525         Status = ZwOpenKey(&Key,
2526                            KEY_READ,
2527                            &ObjectAttributes);
2528     }
2529 
2530     /* Parse device key */
2531     if (InternalConfigInfo->DeviceKey != NULL)
2532     {
2533         SpiParseDeviceInfo(DeviceExtension,
2534                            InternalConfigInfo->DeviceKey,
2535                            ConfigInfo,
2536                            InternalConfigInfo,
2537                            (PUCHAR)StrBuffer);
2538     }
2539 
2540     /* Then parse hw info */
2541     if (Key != NULL)
2542     {
2543         if (InternalConfigInfo->LastAdapterNumber != InternalConfigInfo->AdapterNumber)
2544         {
2545             SpiParseDeviceInfo(DeviceExtension,
2546                                Key,
2547                                ConfigInfo,
2548                                InternalConfigInfo,
2549                                (PUCHAR)StrBuffer);
2550 
2551             /* Close the key */
2552             ZwClose(Key);
2553         }
2554         else
2555         {
2556             /* Adapter not found, go try the next one */
2557             InternalConfigInfo->AdapterNumber++;
2558 
2559             /* Close the key */
2560             ZwClose(Key);
2561 
2562             goto TryNextAd;
2563         }
2564     }
2565 
2566     /* Update the last adapter number */
2567     InternalConfigInfo->LastAdapterNumber = InternalConfigInfo->AdapterNumber;
2568 
2569     /* Do we have this kind of bus at all? */
2570     Found = FALSE;
2571     Status = IoQueryDeviceDescription(&HwInitData->AdapterInterfaceType,
2572                                       &InternalConfigInfo->BusNumber,
2573                                       NULL,
2574                                       NULL,
2575                                       NULL,
2576                                       NULL,
2577                                       SpQueryDeviceCallout,
2578                                       &Found);
2579 
2580     /* This bus was not found */
2581     if (!Found)
2582     {
2583         INTERFACE_TYPE InterfaceType = Eisa;
2584 
2585         /* Check for EISA */
2586         if (HwInitData->AdapterInterfaceType == Isa)
2587         {
2588             Status = IoQueryDeviceDescription(&InterfaceType,
2589                                               &InternalConfigInfo->BusNumber,
2590                                               NULL,
2591                                               NULL,
2592                                               NULL,
2593                                               NULL,
2594                                               SpQueryDeviceCallout,
2595                                               &Found);
2596 
2597             /* Return respectively */
2598             if (Found)
2599                 return STATUS_SUCCESS;
2600             else
2601                 return STATUS_DEVICE_DOES_NOT_EXIST;
2602         }
2603         else
2604         {
2605             return STATUS_DEVICE_DOES_NOT_EXIST;
2606         }
2607     }
2608     else
2609     {
2610         return STATUS_SUCCESS;
2611     }
2612 }
2613 
2614 static VOID
2615 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
2616                    IN HANDLE Key,
2617                    IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
2618                    IN PCONFIGURATION_INFO InternalConfigInfo,
2619                    IN PUCHAR Buffer)
2620 {
2621     PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
2622     PCM_FULL_RESOURCE_DESCRIPTOR FullResource;
2623     PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
2624     PCM_SCSI_DEVICE_DATA ScsiDeviceData;
2625     ULONG Length, Count, Dma = 0, Interrupt = 0;
2626     ULONG Index = 0, RangeCount = 0;
2627     UNICODE_STRING UnicodeString;
2628     ANSI_STRING AnsiString;
2629     NTSTATUS Status = STATUS_SUCCESS;
2630 
2631 
2632     KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION) Buffer;
2633 
2634     /* Loop through all values in the device node */
2635     while(TRUE)
2636     {
2637         Status = ZwEnumerateValueKey(Key,
2638                                      Index,
2639                                      KeyValueFullInformation,
2640                                      Buffer,
2641                                      512,
2642                                      &Length);
2643 
2644         if (!NT_SUCCESS(Status))
2645             return;
2646 
2647         Index++;
2648 
2649         /* Length for DWORD is ok? */
2650         if (KeyValueInformation->Type == REG_DWORD &&
2651             KeyValueInformation->DataLength != sizeof(ULONG))
2652         {
2653             continue;
2654         }
2655 
2656         /* Get MaximumLogicalUnit */
2657         if (_wcsnicmp(KeyValueInformation->Name, L"MaximumLogicalUnit",
2658             KeyValueInformation->NameLength/2) == 0)
2659         {
2660 
2661             if (KeyValueInformation->Type != REG_DWORD)
2662             {
2663                 DPRINT("Bad data type for MaximumLogicalUnit\n");
2664                 continue;
2665             }
2666 
2667             DeviceExtension->MaxLunCount = *((PUCHAR)
2668                 (Buffer + KeyValueInformation->DataOffset));
2669 
2670             /* Check / reset if needed */
2671             if (DeviceExtension->MaxLunCount > SCSI_MAXIMUM_LOGICAL_UNITS)
2672                 DeviceExtension->MaxLunCount = SCSI_MAXIMUM_LOGICAL_UNITS;
2673 
2674             DPRINT("MaximumLogicalUnit = %d\n", DeviceExtension->MaxLunCount);
2675         }
2676 
2677         /* Get InitiatorTargetId */
2678         if (_wcsnicmp(KeyValueInformation->Name, L"InitiatorTargetId",
2679             KeyValueInformation->NameLength / 2) == 0)
2680         {
2681 
2682             if (KeyValueInformation->Type != REG_DWORD)
2683             {
2684                 DPRINT("Bad data type for InitiatorTargetId\n");
2685                 continue;
2686             }
2687 
2688             ConfigInfo->InitiatorBusId[0] = *((PUCHAR)
2689                 (Buffer + KeyValueInformation->DataOffset));
2690 
2691             /* Check / reset if needed */
2692             if (ConfigInfo->InitiatorBusId[0] > ConfigInfo->MaximumNumberOfTargets - 1)
2693                 ConfigInfo->InitiatorBusId[0] = (CCHAR)-1;
2694 
2695             DPRINT("InitiatorTargetId = %d\n", ConfigInfo->InitiatorBusId[0]);
2696         }
2697 
2698         /* Get ScsiDebug */
2699         if (_wcsnicmp(KeyValueInformation->Name, L"ScsiDebug",
2700             KeyValueInformation->NameLength/2) == 0)
2701         {
2702             DPRINT("ScsiDebug key not supported\n");
2703         }
2704 
2705         /* Check for a breakpoint */
2706         if (_wcsnicmp(KeyValueInformation->Name, L"BreakPointOnEntry",
2707             KeyValueInformation->NameLength/2) == 0)
2708         {
2709             DPRINT1("Breakpoint on entry requested!\n");
2710             DbgBreakPoint();
2711         }
2712 
2713         /* Get DisableSynchronousTransfers */
2714         if (_wcsnicmp(KeyValueInformation->Name, L"DisableSynchronousTransfers",
2715             KeyValueInformation->NameLength/2) == 0)
2716         {
2717             DeviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
2718             DPRINT("Synch transfers disabled\n");
2719         }
2720 
2721         /* Get DisableDisconnects */
2722         if (_wcsnicmp(KeyValueInformation->Name, L"DisableDisconnects",
2723             KeyValueInformation->NameLength/2) == 0)
2724         {
2725             DeviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT;
2726             DPRINT("Disconnects disabled\n");
2727         }
2728 
2729         /* Get DisableTaggedQueuing */
2730         if (_wcsnicmp(KeyValueInformation->Name, L"DisableTaggedQueuing",
2731             KeyValueInformation->NameLength/2) == 0)
2732         {
2733             InternalConfigInfo->DisableTaggedQueueing = TRUE;
2734             DPRINT("Tagged queueing disabled\n");
2735         }
2736 
2737         /* Get DisableMultipleRequests */
2738         if (_wcsnicmp(KeyValueInformation->Name, L"DisableMultipleRequests",
2739             KeyValueInformation->NameLength/2) == 0)
2740         {
2741             InternalConfigInfo->DisableMultipleLun = TRUE;
2742             DPRINT("Multiple requests disabled\n");
2743         }
2744 
2745         /* Get DriverParameters */
2746         if (_wcsnicmp(KeyValueInformation->Name, L"DriverParameters",
2747             KeyValueInformation->NameLength/2) == 0)
2748         {
2749             /* Skip if nothing */
2750             if (KeyValueInformation->DataLength == 0)
2751                 continue;
2752 
2753             /* If there was something previously allocated - free it */
2754             if (InternalConfigInfo->Parameter != NULL)
2755                 ExFreePool(InternalConfigInfo->Parameter);
2756 
2757             /* Allocate it */
2758             InternalConfigInfo->Parameter = ExAllocatePoolWithTag(NonPagedPool,
2759                                                            KeyValueInformation->DataLength, TAG_SCSIPORT);
2760 
2761             if (InternalConfigInfo->Parameter != NULL)
2762             {
2763                 if (KeyValueInformation->Type != REG_SZ)
2764                 {
2765                     /* Just copy */
2766                     RtlCopyMemory(
2767                         InternalConfigInfo->Parameter,
2768                         (PCCHAR)KeyValueInformation + KeyValueInformation->DataOffset,
2769                         KeyValueInformation->DataLength);
2770                 }
2771                 else
2772                 {
2773                     /* If it's a unicode string, convert it to ansi */
2774                     UnicodeString.Length = (USHORT)KeyValueInformation->DataLength;
2775                     UnicodeString.MaximumLength = (USHORT)KeyValueInformation->DataLength;
2776                     UnicodeString.Buffer =
2777                         (PWSTR)((PCCHAR)KeyValueInformation + KeyValueInformation->DataOffset);
2778 
2779                     AnsiString.Length = 0;
2780                     AnsiString.MaximumLength = (USHORT)KeyValueInformation->DataLength;
2781                     AnsiString.Buffer = (PCHAR)InternalConfigInfo->Parameter;
2782 
2783                     Status = RtlUnicodeStringToAnsiString(&AnsiString,
2784                                                           &UnicodeString,
2785                                                           FALSE);
2786 
2787                     /* In case of error, free the allocated space */
2788                     if (!NT_SUCCESS(Status))
2789                     {
2790                         ExFreePool(InternalConfigInfo->Parameter);
2791                         InternalConfigInfo->Parameter = NULL;
2792                     }
2793 
2794                 }
2795             }
2796 
2797             DPRINT("Found driver parameter\n");
2798         }
2799 
2800         /* Get MaximumSGList */
2801         if (_wcsnicmp(KeyValueInformation->Name, L"MaximumSGList",
2802             KeyValueInformation->NameLength/2) == 0)
2803         {
2804             if (KeyValueInformation->Type != REG_DWORD)
2805             {
2806                 DPRINT("Bad data type for MaximumSGList\n");
2807                 continue;
2808             }
2809 
2810             ConfigInfo->NumberOfPhysicalBreaks = *((PUCHAR)(Buffer + KeyValueInformation->DataOffset));
2811 
2812             /* Check / fix */
2813             if (ConfigInfo->NumberOfPhysicalBreaks > SCSI_MAXIMUM_PHYSICAL_BREAKS)
2814             {
2815                 ConfigInfo->NumberOfPhysicalBreaks = SCSI_MAXIMUM_PHYSICAL_BREAKS;
2816             }
2817             else if (ConfigInfo->NumberOfPhysicalBreaks < SCSI_MINIMUM_PHYSICAL_BREAKS)
2818             {
2819                 ConfigInfo->NumberOfPhysicalBreaks = SCSI_MINIMUM_PHYSICAL_BREAKS;
2820             }
2821 
2822             DPRINT("MaximumSGList = %d\n", ConfigInfo->NumberOfPhysicalBreaks);
2823         }
2824 
2825         /* Get NumberOfRequests */
2826         if (_wcsnicmp(KeyValueInformation->Name, L"NumberOfRequests",
2827             KeyValueInformation->NameLength/2) == 0)
2828         {
2829             if (KeyValueInformation->Type != REG_DWORD)
2830             {
2831                 DPRINT("NumberOfRequests has wrong data type\n");
2832                 continue;
2833             }
2834 
2835             DeviceExtension->RequestsNumber = *((PUCHAR)(Buffer + KeyValueInformation->DataOffset));
2836 
2837             /* Check / fix */
2838             if (DeviceExtension->RequestsNumber < 16)
2839             {
2840                 DeviceExtension->RequestsNumber = 16;
2841             }
2842             else if (DeviceExtension->RequestsNumber > 512)
2843             {
2844                 DeviceExtension->RequestsNumber = 512;
2845             }
2846 
2847             DPRINT("Number Of Requests = %d\n", DeviceExtension->RequestsNumber);
2848         }
2849 
2850         /* Get resource list */
2851         if (_wcsnicmp(KeyValueInformation->Name, L"ResourceList",
2852                 KeyValueInformation->NameLength/2) == 0 ||
2853             _wcsnicmp(KeyValueInformation->Name, L"Configuration Data",
2854                 KeyValueInformation->NameLength/2) == 0 )
2855         {
2856             if (KeyValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR ||
2857                 KeyValueInformation->DataLength < sizeof(REG_FULL_RESOURCE_DESCRIPTOR))
2858             {
2859                 DPRINT("Bad data type for ResourceList\n");
2860                 continue;
2861             }
2862             else
2863             {
2864                 DPRINT("Found ResourceList\n");
2865             }
2866 
2867             FullResource = (PCM_FULL_RESOURCE_DESCRIPTOR)(Buffer + KeyValueInformation->DataOffset);
2868 
2869             /* Copy some info from it */
2870             InternalConfigInfo->BusNumber = FullResource->BusNumber;
2871             ConfigInfo->SystemIoBusNumber = FullResource->BusNumber;
2872 
2873             /* Loop through it */
2874             for (Count = 0; Count < FullResource->PartialResourceList.Count; Count++)
2875             {
2876                 /* Get partial descriptor */
2877                 PartialDescriptor =
2878                     &FullResource->PartialResourceList.PartialDescriptors[Count];
2879 
2880                 /* Check datalength */
2881                 if ((ULONG)((PCHAR)(PartialDescriptor + 1) -
2882                     (PCHAR)FullResource) > KeyValueInformation->DataLength)
2883                 {
2884                     DPRINT("Resource data is of incorrect size\n");
2885                     break;
2886                 }
2887 
2888                 switch (PartialDescriptor->Type)
2889                 {
2890                 case CmResourceTypePort:
2891                     if (RangeCount >= ConfigInfo->NumberOfAccessRanges)
2892                     {
2893                         DPRINT("Too many access ranges\n");
2894                         continue;
2895                     }
2896 
2897                     InternalConfigInfo->AccessRanges[RangeCount].RangeInMemory = FALSE;
2898                     InternalConfigInfo->AccessRanges[RangeCount].RangeStart = PartialDescriptor->u.Port.Start;
2899                     InternalConfigInfo->AccessRanges[RangeCount].RangeLength = PartialDescriptor->u.Port.Length;
2900                     RangeCount++;
2901 
2902                     break;
2903 
2904                 case CmResourceTypeMemory:
2905                     if (RangeCount >= ConfigInfo->NumberOfAccessRanges)
2906                     {
2907                         DPRINT("Too many access ranges\n");
2908                         continue;
2909                     }
2910 
2911                     InternalConfigInfo->AccessRanges[RangeCount].RangeInMemory = TRUE;
2912                     InternalConfigInfo->AccessRanges[RangeCount].RangeStart = PartialDescriptor->u.Memory.Start;
2913                     InternalConfigInfo->AccessRanges[RangeCount].RangeLength = PartialDescriptor->u.Memory.Length;
2914                     RangeCount++;
2915 
2916                     break;
2917 
2918                 case CmResourceTypeInterrupt:
2919 
2920                     if (Interrupt == 0)
2921                     {
2922                         ConfigInfo->BusInterruptLevel =
2923                             PartialDescriptor->u.Interrupt.Level;
2924 
2925                         ConfigInfo->BusInterruptVector =
2926                             PartialDescriptor->u.Interrupt.Vector;
2927 
2928                         ConfigInfo->InterruptMode = (PartialDescriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive;
2929                     }
2930                     else if (Interrupt == 1)
2931                     {
2932                         ConfigInfo->BusInterruptLevel2 =
2933                         PartialDescriptor->u.Interrupt.Level;
2934 
2935                         ConfigInfo->BusInterruptVector2 =
2936                         PartialDescriptor->u.Interrupt.Vector;
2937 
2938                         ConfigInfo->InterruptMode2 = (PartialDescriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive;
2939                     }
2940 
2941                     Interrupt++;
2942                     break;
2943 
2944                 case CmResourceTypeDma:
2945 
2946                     if (Dma == 0)
2947                     {
2948                         ConfigInfo->DmaChannel = PartialDescriptor->u.Dma.Channel;
2949                         ConfigInfo->DmaPort = PartialDescriptor->u.Dma.Port;
2950 
2951                         if (PartialDescriptor->Flags & CM_RESOURCE_DMA_8)
2952                             ConfigInfo->DmaWidth = Width8Bits;
2953                         else if ((PartialDescriptor->Flags & CM_RESOURCE_DMA_16) ||
2954                                  (PartialDescriptor->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
2955                             ConfigInfo->DmaWidth = Width16Bits;
2956                         else if (PartialDescriptor->Flags & CM_RESOURCE_DMA_32)
2957                             ConfigInfo->DmaWidth = Width32Bits;
2958                     }
2959                     else if (Dma == 1)
2960                     {
2961                         ConfigInfo->DmaChannel2 = PartialDescriptor->u.Dma.Channel;
2962                         ConfigInfo->DmaPort2 = PartialDescriptor->u.Dma.Port;
2963 
2964                         if (PartialDescriptor->Flags & CM_RESOURCE_DMA_8)
2965                             ConfigInfo->DmaWidth2 = Width8Bits;
2966                         else if ((PartialDescriptor->Flags & CM_RESOURCE_DMA_16) ||
2967                                  (PartialDescriptor->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
2968                             ConfigInfo->DmaWidth2 = Width16Bits;
2969                         else if (PartialDescriptor->Flags & CM_RESOURCE_DMA_32)
2970                             ConfigInfo->DmaWidth2 = Width32Bits;
2971                     }
2972 
2973                     Dma++;
2974                     break;
2975 
2976                 case CmResourceTypeDeviceSpecific:
2977                     if (PartialDescriptor->u.DeviceSpecificData.DataSize <
2978                         sizeof(CM_SCSI_DEVICE_DATA) ||
2979                         (PCHAR) (PartialDescriptor + 1) - (PCHAR)FullResource +
2980                         PartialDescriptor->u.DeviceSpecificData.DataSize >
2981                         KeyValueInformation->DataLength)
2982                     {
2983                         DPRINT("Resource data length is incorrect");
2984                         break;
2985                     }
2986 
2987                     /* Set only one field from it */
2988                     ScsiDeviceData = (PCM_SCSI_DEVICE_DATA) (PartialDescriptor+1);
2989                     ConfigInfo->InitiatorBusId[0] = ScsiDeviceData->HostIdentifier;
2990                     break;
2991                 }
2992             }
2993         }
2994     }
2995 }
2996 
2997 NTSTATUS
2998 NTAPI
2999 SpQueryDeviceCallout(IN PVOID  Context,
3000                      IN PUNICODE_STRING  PathName,
3001                      IN INTERFACE_TYPE  BusType,
3002                      IN ULONG  BusNumber,
3003                      IN PKEY_VALUE_FULL_INFORMATION  *BusInformation,
3004                      IN CONFIGURATION_TYPE  ControllerType,
3005                      IN ULONG  ControllerNumber,
3006                      IN PKEY_VALUE_FULL_INFORMATION  *ControllerInformation,
3007                      IN CONFIGURATION_TYPE  PeripheralType,
3008                      IN ULONG  PeripheralNumber,
3009                      IN PKEY_VALUE_FULL_INFORMATION  *PeripheralInformation)
3010 {
3011     PBOOLEAN Found = (PBOOLEAN)Context;
3012     /* We just set our Found variable to TRUE */
3013 
3014     *Found = TRUE;
3015     return STATUS_SUCCESS;
3016 }
3017 
3018 IO_ALLOCATION_ACTION
3019 NTAPI
3020 ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject,
3021                                IN PIRP Irp,
3022                                IN PVOID MapRegisterBase,
3023                                IN PVOID Context)
3024 {
3025     KIRQL Irql;
3026     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
3027 
3028     /* Guard access with the spinlock */
3029     KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
3030 
3031     /* Save MapRegisterBase we've got here */
3032     DeviceExtension->MapRegisterBase = MapRegisterBase;
3033 
3034     /* Start pending request */
3035     KeSynchronizeExecution(DeviceExtension->Interrupt[0],
3036         ScsiPortStartPacket, DeviceObject);
3037 
3038     /* Release spinlock we took */
3039     KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
3040 
3041     return KeepObject;
3042 }
3043 
3044 #undef ScsiPortConvertPhysicalAddressToUlong
3045 /*
3046  * @implemented
3047  */
3048 ULONG NTAPI
3049 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address)
3050 {
3051   DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
3052   return(Address.u.LowPart);
3053 }
3054