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         DPRINT1("Created device: %wZ (%p)\n", &DeviceName, PortDeviceObject);
985 
986         /* Set the buffering strategy here... */
987         PortDeviceObject->Flags |= DO_DIRECT_IO;
988         PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT; /* FIXME: Is this really needed? */
989 
990         /* Fill Device Extension */
991         DeviceExtension = PortDeviceObject->DeviceExtension;
992         RtlZeroMemory(DeviceExtension, DeviceExtensionSize);
993         DeviceExtension->Common.DeviceObject = PortDeviceObject;
994         DeviceExtension->Common.IsFDO = TRUE;
995         DeviceExtension->Length = DeviceExtensionSize;
996         DeviceExtension->PortNumber = SystemConfig->ScsiPortCount;
997         DeviceExtension->DeviceName = DeviceName;
998 
999         /* Driver's routines... */
1000         DeviceExtension->HwInitialize = HwInitializationData->HwInitialize;
1001         DeviceExtension->HwStartIo = HwInitializationData->HwStartIo;
1002         DeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
1003         DeviceExtension->HwResetBus = HwInitializationData->HwResetBus;
1004         DeviceExtension->HwDmaStarted = HwInitializationData->HwDmaStarted;
1005 
1006         /* Extensions sizes */
1007         DeviceExtension->MiniPortExtensionSize = HwInitializationData->DeviceExtensionSize;
1008         DeviceExtension->LunExtensionSize =
1009             ALIGN_UP(HwInitializationData->SpecificLuExtensionSize, INT64);
1010         DeviceExtension->SrbExtensionSize =
1011             ALIGN_UP(HwInitializationData->SrbExtensionSize, INT64);
1012 
1013         /* Fill some numbers (bus count, lun count, etc) */
1014         DeviceExtension->MaxLunCount = SCSI_MAXIMUM_LOGICAL_UNITS;
1015         DeviceExtension->RequestsNumber = 16;
1016 
1017         /* Initialize the spin lock in the controller extension */
1018         KeInitializeSpinLock(&DeviceExtension->IrqLock);
1019         KeInitializeSpinLock(&DeviceExtension->SpinLock);
1020 
1021         /* Initialize the DPC object */
1022         IoInitializeDpcRequest(PortDeviceObject,
1023                                ScsiPortDpcForIsr);
1024 
1025         /* Initialize the device timer */
1026         DeviceExtension->TimerCount = -1;
1027         IoInitializeTimer(PortDeviceObject,
1028                           ScsiPortIoTimer,
1029                           DeviceExtension);
1030 
1031         /* Initialize miniport timer */
1032         KeInitializeTimer(&DeviceExtension->MiniportTimer);
1033         KeInitializeDpc(&DeviceExtension->MiniportTimerDpc,
1034                         SpiMiniportTimerDpc,
1035                         PortDeviceObject);
1036 
1037 CreatePortConfig:
1038 
1039         /* Allocate and initialize port configuration info */
1040         PortConfigSize = sizeof(PORT_CONFIGURATION_INFORMATION) +
1041                          HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE);
1042         PortConfigSize = ALIGN_UP(PortConfigSize, INT64);
1043         DeviceExtension->PortConfig = ExAllocatePoolWithTag(NonPagedPool, PortConfigSize, TAG_SCSIPORT);
1044 
1045         /* Fail if failed */
1046         if (DeviceExtension->PortConfig == NULL)
1047         {
1048             Status = STATUS_INSUFFICIENT_RESOURCES;
1049             break;
1050         }
1051 
1052         Status = SpiCreatePortConfig(DeviceExtension,
1053                                      HwInitializationData,
1054                                      &ConfigInfo,
1055                                      DeviceExtension->PortConfig,
1056                                      FirstConfigCall);
1057 
1058         if (!NT_SUCCESS(Status))
1059         {
1060             DPRINT("SpiCreatePortConfig() failed with Status 0x%08X\n", Status);
1061             break;
1062         }
1063 
1064         PortConfig = DeviceExtension->PortConfig;
1065 
1066         /* Copy extension sizes into the PortConfig */
1067         PortConfig->SpecificLuExtensionSize = DeviceExtension->LunExtensionSize;
1068         PortConfig->SrbExtensionSize = DeviceExtension->SrbExtensionSize;
1069 
1070         /* Initialize Access ranges */
1071         if (HwInitializationData->NumberOfAccessRanges != 0)
1072         {
1073             PortConfig->AccessRanges = ALIGN_UP_POINTER(PortConfig + 1, INT64);
1074 
1075             /* Copy the data */
1076             RtlCopyMemory(PortConfig->AccessRanges,
1077                           ConfigInfo.AccessRanges,
1078                           HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE));
1079         }
1080 
1081         /* Search for matching PCI device */
1082         if ((HwInitializationData->AdapterInterfaceType == PCIBus) &&
1083             (HwInitializationData->VendorIdLength > 0) &&
1084             (HwInitializationData->VendorId != NULL) &&
1085             (HwInitializationData->DeviceIdLength > 0) && (HwInitializationData->DeviceId != NULL))
1086         {
1087             PortConfig->BusInterruptLevel = 0;
1088 
1089             /* Get PCI device data */
1090             DPRINT(
1091                 "VendorId '%.*s'  DeviceId '%.*s'\n", HwInitializationData->VendorIdLength,
1092                 HwInitializationData->VendorId, HwInitializationData->DeviceIdLength,
1093                 HwInitializationData->DeviceId);
1094 
1095             if (!SpiGetPciConfigData(
1096                     DriverObject, PortDeviceObject, HwInitializationData, PortConfig, RegistryPath,
1097                     ConfigInfo.BusNumber, &SlotNumber))
1098             {
1099                 /* Continue to the next bus, nothing here */
1100                 ConfigInfo.BusNumber++;
1101                 DeviceExtension->PortConfig = NULL;
1102                 ExFreePool(PortConfig);
1103                 Again = FALSE;
1104                 goto CreatePortConfig;
1105             }
1106 
1107             if (!PortConfig->BusInterruptLevel)
1108             {
1109                 /* Bypass this slot, because no interrupt was assigned */
1110                 DeviceExtension->PortConfig = NULL;
1111                 ExFreePool(PortConfig);
1112                 goto CreatePortConfig;
1113             }
1114         }
1115         else
1116         {
1117             DPRINT("Non-pci bus\n");
1118         }
1119 
1120         /* Note: HwFindAdapter is called once for each bus */
1121         Again = FALSE;
1122         DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber);
1123         Result = (HwInitializationData->HwFindAdapter)(
1124             &DeviceExtension->MiniPortDeviceExtension, HwContext, 0, /* BusInformation */
1125             ConfigInfo.Parameter,                                    /* ArgumentString */
1126             PortConfig, &Again);
1127 
1128         DPRINT("HwFindAdapter() Result: %lu  Again: %s\n", Result, (Again) ? "True" : "False");
1129 
1130         /* Free MapRegisterBase, it's not needed anymore */
1131         if (DeviceExtension->MapRegisterBase != NULL)
1132         {
1133             ExFreePool(DeviceExtension->MapRegisterBase);
1134             DeviceExtension->MapRegisterBase = NULL;
1135         }
1136 
1137         /* If result is nothing good... */
1138         if (Result != SP_RETURN_FOUND)
1139         {
1140             DPRINT("HwFindAdapter() Result: %lu\n", Result);
1141 
1142             if (Result == SP_RETURN_NOT_FOUND)
1143             {
1144                 /* We can continue on the next bus */
1145                 ConfigInfo.BusNumber++;
1146                 Again = FALSE;
1147 
1148                 DeviceExtension->PortConfig = NULL;
1149                 ExFreePool(PortConfig);
1150                 goto CreatePortConfig;
1151             }
1152 
1153             /* Otherwise, break */
1154             Status = STATUS_INTERNAL_ERROR;
1155             break;
1156         }
1157 
1158         DPRINT(
1159             "ScsiPortInitialize(): Found HBA! (%x), adapter Id %d\n",
1160             PortConfig->BusInterruptVector, PortConfig->InitiatorBusId[0]);
1161 
1162         /* If the SRB extension size was updated */
1163         if (!DeviceExtension->NonCachedExtension &&
1164             (PortConfig->SrbExtensionSize != DeviceExtension->SrbExtensionSize))
1165         {
1166             /* Set it (rounding to LONGLONG again) */
1167             DeviceExtension->SrbExtensionSize = ALIGN_UP(PortConfig->SrbExtensionSize, INT64);
1168         }
1169 
1170         /* The same with LUN extension size */
1171         if (PortConfig->SpecificLuExtensionSize != DeviceExtension->LunExtensionSize)
1172             DeviceExtension->LunExtensionSize = PortConfig->SpecificLuExtensionSize;
1173 
1174         /* Construct a resource list */
1175         ResourceList = SpiConfigToResource(DeviceExtension, PortConfig);
1176 
1177         PDEVICE_OBJECT LowerPDO = NULL;
1178 
1179         Status = IoReportDetectedDevice(DriverObject,
1180                                         HwInitializationData->AdapterInterfaceType,
1181                                         ConfigInfo.BusNumber,
1182                                         PortConfig->SlotNumber,
1183                                         ResourceList,
1184                                         NULL,
1185                                         TRUE,
1186                                         &LowerPDO);
1187 
1188         if (!NT_SUCCESS(Status))
1189         {
1190             DPRINT1("IoReportDetectedDevice failed. Status: 0x%x\n", Status);
1191             __debugbreak();
1192             break;
1193         }
1194 
1195         DeviceExtension->Common.LowerDevice = IoAttachDeviceToDeviceStack(PortDeviceObject, LowerPDO);
1196 
1197         ASSERT(DeviceExtension->Common.LowerDevice);
1198 
1199         PortDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1200 
1201         if (ResourceList)
1202         {
1203             ExFreePoolWithTag(ResourceList, TAG_SCSIPORT);
1204         }
1205 
1206         /* Copy all stuff which we ever need from PortConfig to the DeviceExtension */
1207         if (PortConfig->MaximumNumberOfTargets > SCSI_MAXIMUM_TARGETS_PER_BUS)
1208             DeviceExtension->MaxTargedIds = SCSI_MAXIMUM_TARGETS_PER_BUS;
1209         else
1210             DeviceExtension->MaxTargedIds = PortConfig->MaximumNumberOfTargets;
1211 
1212         DeviceExtension->NumberOfBuses = PortConfig->NumberOfBuses;
1213         DeviceExtension->CachesData = PortConfig->CachesData;
1214         DeviceExtension->ReceiveEvent = PortConfig->ReceiveEvent;
1215         DeviceExtension->SupportsTaggedQueuing = PortConfig->TaggedQueuing;
1216         DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu;
1217 
1218         /* Initialize bus scanning information */
1219         size_t BusConfigSize = DeviceExtension->NumberOfBuses * sizeof(*DeviceExtension->Buses);
1220         DeviceExtension->Buses = ExAllocatePoolZero(NonPagedPool, BusConfigSize, TAG_SCSIPORT);
1221         if (!DeviceExtension->Buses)
1222         {
1223             DPRINT1("Out of resources!\n");
1224             Status = STATUS_INSUFFICIENT_RESOURCES;
1225             break;
1226         }
1227 
1228         // initialize bus data
1229         for (UINT8 pathId = 0; pathId < DeviceExtension->NumberOfBuses; pathId++)
1230         {
1231             DeviceExtension->Buses[pathId].BusIdentifier =
1232                 DeviceExtension->PortConfig->InitiatorBusId[pathId];
1233             InitializeListHead(&DeviceExtension->Buses[pathId].LunsListHead);
1234         }
1235 
1236         /* If something was disabled via registry - apply it */
1237         if (ConfigInfo.DisableMultipleLun)
1238             DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu = FALSE;
1239 
1240         if (ConfigInfo.DisableTaggedQueueing)
1241             DeviceExtension->SupportsTaggedQueuing = PortConfig->MultipleRequestPerLu = FALSE;
1242 
1243         /* Check if we need to alloc SRB data */
1244         if (DeviceExtension->SupportsTaggedQueuing || DeviceExtension->MultipleReqsPerLun)
1245         {
1246             DeviceExtension->NeedSrbDataAlloc = TRUE;
1247         }
1248         else
1249         {
1250             DeviceExtension->NeedSrbDataAlloc = FALSE;
1251         }
1252 
1253         /* Get a pointer to the port capabilities */
1254         PortCapabilities = &DeviceExtension->PortCapabilities;
1255 
1256         /* Copy one field there */
1257         DeviceExtension->MapBuffers = PortConfig->MapBuffers;
1258         PortCapabilities->AdapterUsesPio = PortConfig->MapBuffers;
1259 
1260         if (DeviceExtension->AdapterObject == NULL &&
1261             (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE || PortConfig->Master))
1262         {
1263             DPRINT1("DMA is not supported yet\n");
1264             ASSERT(FALSE);
1265         }
1266 
1267         if (DeviceExtension->SrbExtensionBuffer == NULL &&
1268             (DeviceExtension->SrbExtensionSize != 0 || PortConfig->AutoRequestSense))
1269         {
1270             DeviceExtension->SupportsAutoSense = PortConfig->AutoRequestSense;
1271             DeviceExtension->NeedSrbExtensionAlloc = TRUE;
1272 
1273             /* Allocate common buffer */
1274             Status = SpiAllocateCommonBuffer(DeviceExtension, 0);
1275 
1276             /* Check for failure */
1277             if (!NT_SUCCESS(Status))
1278                 break;
1279         }
1280 
1281         /* Allocate SrbData, if needed */
1282         if (DeviceExtension->NeedSrbDataAlloc)
1283         {
1284             ULONG Count;
1285             PSCSI_REQUEST_BLOCK_INFO SrbData;
1286 
1287             if (DeviceExtension->SrbDataCount != 0)
1288                 Count = DeviceExtension->SrbDataCount;
1289             else
1290                 Count = DeviceExtension->RequestsNumber * 2;
1291 
1292             /* Allocate the data */
1293             SrbData = ExAllocatePoolWithTag(
1294                 NonPagedPool, Count * sizeof(SCSI_REQUEST_BLOCK_INFO), TAG_SCSIPORT);
1295             if (SrbData == NULL)
1296                 return STATUS_INSUFFICIENT_RESOURCES;
1297 
1298             RtlZeroMemory(SrbData, Count * sizeof(SCSI_REQUEST_BLOCK_INFO));
1299 
1300             DeviceExtension->SrbInfo = SrbData;
1301             DeviceExtension->FreeSrbInfo = SrbData;
1302             DeviceExtension->SrbDataCount = Count;
1303 
1304             /* Link it to the list */
1305             while (Count > 0)
1306             {
1307                 SrbData->Requests.Flink = (PLIST_ENTRY)(SrbData + 1);
1308                 SrbData++;
1309                 Count--;
1310             }
1311 
1312             /* Mark the last entry of the list */
1313             SrbData--;
1314             SrbData->Requests.Flink = NULL;
1315         }
1316 
1317         /* Initialize port capabilities */
1318         PortCapabilities = &DeviceExtension->PortCapabilities;
1319         PortCapabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
1320         PortCapabilities->MaximumTransferLength = PortConfig->MaximumTransferLength;
1321 
1322         if (PortConfig->ReceiveEvent)
1323             PortCapabilities->SupportedAsynchronousEvents |= SRBEV_SCSI_ASYNC_NOTIFICATION;
1324 
1325         PortCapabilities->TaggedQueuing = DeviceExtension->SupportsTaggedQueuing;
1326         PortCapabilities->AdapterScansDown = PortConfig->AdapterScansDown;
1327 
1328         if (PortConfig->AlignmentMask > PortDeviceObject->AlignmentRequirement)
1329             PortDeviceObject->AlignmentRequirement = PortConfig->AlignmentMask;
1330 
1331         PortCapabilities->AlignmentMask = PortDeviceObject->AlignmentRequirement;
1332 
1333         if (PortCapabilities->MaximumPhysicalPages == 0)
1334         {
1335             PortCapabilities->MaximumPhysicalPages =
1336                 BYTES_TO_PAGES(PortCapabilities->MaximumTransferLength);
1337 
1338             /* Apply miniport's limits */
1339             if (PortConfig->NumberOfPhysicalBreaks < PortCapabilities->MaximumPhysicalPages)
1340             {
1341                 PortCapabilities->MaximumPhysicalPages = PortConfig->NumberOfPhysicalBreaks;
1342             }
1343         }
1344 
1345         FdoCallHWInitialize(DeviceExtension);
1346 
1347         Status = FdoStartAdapter(DeviceExtension);
1348 
1349         if (!NT_SUCCESS(Status))
1350         {
1351             DPRINT1("Failed to start the legacy adapter. Status 0x%x\n", Status);
1352             break;
1353         }
1354 
1355         FdoScanAdapter(DeviceExtension);
1356 
1357         FirstConfigCall = FALSE;
1358 
1359         /* Increase adapter number and bus number respectively */
1360         ConfigInfo.AdapterNumber++;
1361 
1362         if (!Again)
1363             ConfigInfo.BusNumber++;
1364 
1365         DPRINT("Bus: %lu  MaxBus: %lu\n", ConfigInfo.BusNumber, MaxBus);
1366 
1367         DeviceFound = TRUE;
1368     }
1369 
1370     /* Clean up the mess */
1371     if (!NT_SUCCESS(Status) && PortDeviceObject)
1372     {
1373         FdoRemoveAdapter(DeviceExtension);
1374     }
1375 
1376     /* Close registry keys */
1377     if (ConfigInfo.ServiceKey != NULL)
1378         ZwClose(ConfigInfo.ServiceKey);
1379 
1380     if (ConfigInfo.DeviceKey != NULL)
1381         ZwClose(ConfigInfo.DeviceKey);
1382 
1383     if (ConfigInfo.BusKey != NULL)
1384         ZwClose(ConfigInfo.BusKey);
1385 
1386     if (ConfigInfo.AccessRanges != NULL)
1387         ExFreePool(ConfigInfo.AccessRanges);
1388 
1389     if (ConfigInfo.Parameter != NULL)
1390         ExFreePool(ConfigInfo.Parameter);
1391 
1392     DPRINT("ScsiPortInitialize() done, Status = 0x%08X, DeviceFound = %d!\n",
1393         Status, DeviceFound);
1394 
1395     return (DeviceFound == FALSE) ? Status : STATUS_SUCCESS;
1396 }
1397 
1398 /*
1399  * @unimplemented
1400  */
1401 VOID NTAPI
1402 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension,
1403               IN PSCSI_REQUEST_BLOCK Srb,
1404               IN PVOID LogicalAddress,
1405               IN ULONG Length)
1406 {
1407   DPRINT1("ScsiPortIoMapTransfer()\n");
1408   UNIMPLEMENTED;
1409 }
1410 
1411 /*
1412  * @unimplemented
1413  */
1414 VOID NTAPI
1415 ScsiPortLogError(IN PVOID HwDeviceExtension,
1416          IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
1417          IN UCHAR PathId,
1418          IN UCHAR TargetId,
1419          IN UCHAR Lun,
1420          IN ULONG ErrorCode,
1421          IN ULONG UniqueId)
1422 {
1423   //PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1424 
1425   DPRINT1("ScsiPortLogError() called\n");
1426   DPRINT1("PathId: 0x%02x  TargetId: 0x%02x  Lun: 0x%02x  ErrorCode: 0x%08lx  UniqueId: 0x%08lx\n",
1427           PathId, TargetId, Lun, ErrorCode, UniqueId);
1428 
1429   //DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, SCSI_PORT_DEVICE_EXTENSION, MiniPortDeviceExtension);
1430 
1431 
1432   DPRINT("ScsiPortLogError() done\n");
1433 }
1434 
1435 /*
1436  * @implemented
1437  */
1438 VOID NTAPI
1439 ScsiPortMoveMemory(OUT PVOID Destination,
1440            IN PVOID Source,
1441            IN ULONG Length)
1442 {
1443   RtlMoveMemory(Destination,
1444         Source,
1445         Length);
1446 }
1447 
1448 
1449 /*
1450  * @implemented
1451  */
1452 VOID
1453 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType, IN PVOID HwDeviceExtension, ...)
1454 {
1455     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1456     va_list ap;
1457 
1458     DPRINT("ScsiPortNotification() called\n");
1459 
1460     DeviceExtension =
1461         CONTAINING_RECORD(HwDeviceExtension, SCSI_PORT_DEVICE_EXTENSION, MiniPortDeviceExtension);
1462 
1463     DPRINT("DeviceExtension %p\n", DeviceExtension);
1464 
1465     va_start(ap, HwDeviceExtension);
1466 
1467     switch (NotificationType)
1468     {
1469         case RequestComplete:
1470         {
1471             PSCSI_REQUEST_BLOCK Srb;
1472             PSCSI_REQUEST_BLOCK_INFO SrbData;
1473 
1474             Srb = (PSCSI_REQUEST_BLOCK)va_arg(ap, PSCSI_REQUEST_BLOCK);
1475 
1476             DPRINT("Notify: RequestComplete (Srb %p)\n", Srb);
1477 
1478             /* Make sure Srb is alright */
1479             ASSERT(Srb->SrbStatus != SRB_STATUS_PENDING);
1480             ASSERT(
1481                 Srb->Function != SRB_FUNCTION_EXECUTE_SCSI ||
1482                 Srb->SrbStatus != SRB_STATUS_SUCCESS || Srb->ScsiStatus == SCSISTAT_GOOD);
1483 
1484             if (!(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE))
1485             {
1486                 /* It's been already completed */
1487                 va_end(ap);
1488                 return;
1489             }
1490 
1491             /* It's not active anymore */
1492             Srb->SrbFlags &= ~SRB_FLAGS_IS_ACTIVE;
1493 
1494             if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
1495             {
1496                 /* TODO: Treat it specially */
1497                 ASSERT(FALSE);
1498             }
1499             else
1500             {
1501                 PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Srb->OriginalRequest);
1502                 PSCSI_PORT_LUN_EXTENSION LunExtension = IoStack->DeviceObject->DeviceExtension;
1503                 ASSERT(LunExtension && !LunExtension->Common.IsFDO);
1504 
1505                 /* Get the SRB data */
1506                 SrbData = SpiGetSrbData(DeviceExtension, LunExtension, Srb->QueueTag);
1507 
1508                 /* Make sure there are no CompletedRequests and there is a Srb */
1509                 ASSERT(SrbData->CompletedRequests == NULL && SrbData->Srb != NULL);
1510 
1511                 /* If it's a read/write request, make sure it has data inside it */
1512                 if ((Srb->SrbStatus == SRB_STATUS_SUCCESS) &&
1513                     ((Srb->Cdb[0] == SCSIOP_READ) || (Srb->Cdb[0] == SCSIOP_WRITE)))
1514                 {
1515                     ASSERT(Srb->DataTransferLength);
1516                 }
1517 
1518                 SrbData->CompletedRequests = DeviceExtension->InterruptData.CompletedRequests;
1519                 DeviceExtension->InterruptData.CompletedRequests = SrbData;
1520             }
1521         }
1522         break;
1523 
1524         case NextRequest:
1525             DPRINT("Notify: NextRequest\n");
1526             DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY;
1527             break;
1528 
1529         case NextLuRequest:
1530         {
1531             UCHAR PathId;
1532             UCHAR TargetId;
1533             UCHAR Lun;
1534             PSCSI_PORT_LUN_EXTENSION LunExtension;
1535 
1536             PathId = (UCHAR)va_arg(ap, int);
1537             TargetId = (UCHAR)va_arg(ap, int);
1538             Lun = (UCHAR)va_arg(ap, int);
1539 
1540             DPRINT(
1541                 "Notify: NextLuRequest(PathId %u  TargetId %u  Lun %u)\n", PathId, TargetId, Lun);
1542 
1543             /* Mark it in the flags field */
1544             DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY;
1545 
1546             /* Get the LUN extension */
1547             LunExtension = GetLunByPath(DeviceExtension, PathId, TargetId, Lun);
1548 
1549             /* If returned LunExtension is NULL, break out */
1550             if (!LunExtension)
1551                 break;
1552 
1553             /* This request should not be processed if */
1554             if ((LunExtension->ReadyLun) || (LunExtension->SrbInfo.Srb))
1555             {
1556                 /* Nothing to do here */
1557                 break;
1558             }
1559 
1560             /* Add this LUN to the list */
1561             LunExtension->ReadyLun = DeviceExtension->InterruptData.ReadyLun;
1562             DeviceExtension->InterruptData.ReadyLun = LunExtension;
1563         }
1564         break;
1565 
1566         case ResetDetected:
1567             DPRINT("Notify: ResetDetected\n");
1568             /* Add RESET flags */
1569             DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET | SCSI_PORT_RESET_REPORTED;
1570             break;
1571 
1572         case CallDisableInterrupts:
1573             DPRINT1("UNIMPLEMENTED SCSI Notification called: CallDisableInterrupts!\n");
1574             break;
1575 
1576         case CallEnableInterrupts:
1577             DPRINT1("UNIMPLEMENTED SCSI Notification called: CallEnableInterrupts!\n");
1578             break;
1579 
1580         case RequestTimerCall:
1581             DPRINT("Notify: RequestTimerCall\n");
1582             DeviceExtension->InterruptData.Flags |= SCSI_PORT_TIMER_NEEDED;
1583             DeviceExtension->InterruptData.HwScsiTimer = (PHW_TIMER)va_arg(ap, PHW_TIMER);
1584             DeviceExtension->InterruptData.MiniportTimerValue = (ULONG)va_arg(ap, ULONG);
1585             break;
1586 
1587         case BusChangeDetected:
1588             DPRINT1("UNIMPLEMENTED SCSI Notification called: BusChangeDetected!\n");
1589             break;
1590 
1591         default:
1592             DPRINT1("Unsupported notification from WMI: %lu\n", NotificationType);
1593             break;
1594     }
1595 
1596     va_end(ap);
1597 
1598     /* Request a DPC after we're done with the interrupt */
1599     DeviceExtension->InterruptData.Flags |= SCSI_PORT_NOTIFICATION_NEEDED;
1600 }
1601 
1602 /*
1603  * @implemented
1604  */
1605 BOOLEAN NTAPI
1606 ScsiPortValidateRange(IN PVOID HwDeviceExtension,
1607               IN INTERFACE_TYPE BusType,
1608               IN ULONG SystemIoBusNumber,
1609               IN SCSI_PHYSICAL_ADDRESS IoAddress,
1610               IN ULONG NumberOfBytes,
1611               IN BOOLEAN InIoSpace)
1612 {
1613   DPRINT("ScsiPortValidateRange()\n");
1614   return(TRUE);
1615 }
1616 
1617 
1618 /* INTERNAL FUNCTIONS ********************************************************/
1619 
1620 static VOID
1621 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData,
1622                     IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor,
1623                     IN PPORT_CONFIGURATION_INFORMATION PortConfig)
1624 {
1625     PACCESS_RANGE AccessRange;
1626     PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialData;
1627     ULONG RangeNumber;
1628     ULONG Index;
1629     ULONG Interrupt = 0;
1630     ULONG Dma = 0;
1631 
1632     RangeNumber = 0;
1633 
1634     /* Loop through all entries */
1635     for (Index = 0; Index < ResourceDescriptor->PartialResourceList.Count; Index++)
1636     {
1637         PartialData = &ResourceDescriptor->PartialResourceList.PartialDescriptors[Index];
1638 
1639         switch (PartialData->Type)
1640         {
1641         case CmResourceTypePort:
1642             /* Copy access ranges */
1643             if (RangeNumber < HwInitializationData->NumberOfAccessRanges)
1644             {
1645                 AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]);
1646 
1647                 AccessRange->RangeStart = PartialData->u.Port.Start;
1648                 AccessRange->RangeLength = PartialData->u.Port.Length;
1649 
1650                 AccessRange->RangeInMemory = FALSE;
1651                 RangeNumber++;
1652             }
1653             break;
1654 
1655         case CmResourceTypeMemory:
1656             /* Copy access ranges */
1657             if (RangeNumber < HwInitializationData->NumberOfAccessRanges)
1658             {
1659                 AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]);
1660 
1661                 AccessRange->RangeStart = PartialData->u.Memory.Start;
1662                 AccessRange->RangeLength = PartialData->u.Memory.Length;
1663 
1664                 AccessRange->RangeInMemory = TRUE;
1665                 RangeNumber++;
1666             }
1667             break;
1668 
1669         case CmResourceTypeInterrupt:
1670 
1671             if (Interrupt == 0)
1672             {
1673                 /* Copy interrupt data */
1674                 PortConfig->BusInterruptLevel = PartialData->u.Interrupt.Level;
1675                 PortConfig->BusInterruptVector = PartialData->u.Interrupt.Vector;
1676 
1677                 /* Set interrupt mode accordingly to the resource */
1678                 if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
1679                 {
1680                     PortConfig->InterruptMode = Latched;
1681                 }
1682                 else if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
1683                 {
1684                     PortConfig->InterruptMode = LevelSensitive;
1685                 }
1686             }
1687             else if (Interrupt == 1)
1688             {
1689                 /* Copy interrupt data */
1690                 PortConfig->BusInterruptLevel2 = PartialData->u.Interrupt.Level;
1691                 PortConfig->BusInterruptVector2 = PartialData->u.Interrupt.Vector;
1692 
1693                 /* Set interrupt mode accordingly to the resource */
1694                 if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
1695                 {
1696                     PortConfig->InterruptMode2 = Latched;
1697                 }
1698                 else if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
1699                 {
1700                     PortConfig->InterruptMode2 = LevelSensitive;
1701                 }
1702             }
1703 
1704             Interrupt++;
1705             break;
1706 
1707         case CmResourceTypeDma:
1708 
1709             if (Dma == 0)
1710             {
1711                 PortConfig->DmaChannel = PartialData->u.Dma.Channel;
1712                 PortConfig->DmaPort = PartialData->u.Dma.Port;
1713 
1714                 if (PartialData->Flags & CM_RESOURCE_DMA_8)
1715                     PortConfig->DmaWidth = Width8Bits;
1716                 else if ((PartialData->Flags & CM_RESOURCE_DMA_16) ||
1717                          (PartialData->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
1718                     PortConfig->DmaWidth = Width16Bits;
1719                 else if (PartialData->Flags & CM_RESOURCE_DMA_32)
1720                     PortConfig->DmaWidth = Width32Bits;
1721             }
1722             else if (Dma == 1)
1723             {
1724                 PortConfig->DmaChannel2 = PartialData->u.Dma.Channel;
1725                 PortConfig->DmaPort2 = PartialData->u.Dma.Port;
1726 
1727                 if (PartialData->Flags & CM_RESOURCE_DMA_8)
1728                     PortConfig->DmaWidth2 = Width8Bits;
1729                 else if ((PartialData->Flags & CM_RESOURCE_DMA_16) ||
1730                          (PartialData->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
1731                     PortConfig->DmaWidth2 = Width16Bits;
1732                 else if (PartialData->Flags & CM_RESOURCE_DMA_32)
1733                     PortConfig->DmaWidth2 = Width32Bits;
1734             }
1735             break;
1736         }
1737     }
1738 }
1739 
1740 static PCM_RESOURCE_LIST
1741 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1742                     PPORT_CONFIGURATION_INFORMATION PortConfig)
1743 {
1744     PCONFIGURATION_INFORMATION ConfigInfo;
1745     PCM_RESOURCE_LIST ResourceList;
1746     PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor;
1747     PACCESS_RANGE AccessRange;
1748     ULONG ListLength = 0, i, FullSize;
1749     ULONG Interrupt, Dma;
1750 
1751     /* Get current Atdisk usage from the system */
1752     ConfigInfo = IoGetConfigurationInformation();
1753 
1754     if (PortConfig->AtdiskPrimaryClaimed)
1755         ConfigInfo->AtDiskPrimaryAddressClaimed = TRUE;
1756 
1757     if (PortConfig->AtdiskSecondaryClaimed)
1758         ConfigInfo->AtDiskSecondaryAddressClaimed = TRUE;
1759 
1760     /* Do we use DMA? */
1761     if (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE ||
1762         PortConfig->DmaPort != SP_UNINITIALIZED_VALUE)
1763     {
1764         Dma = 1;
1765 
1766         if (PortConfig->DmaChannel2 != SP_UNINITIALIZED_VALUE ||
1767             PortConfig->DmaPort2 != SP_UNINITIALIZED_VALUE)
1768             Dma++;
1769     }
1770     else
1771     {
1772         Dma = 0;
1773     }
1774     ListLength += Dma;
1775 
1776     /* How many interrupts to we have? */
1777     Interrupt = DeviceExtension->InterruptCount;
1778     ListLength += Interrupt;
1779 
1780     /* How many access ranges do we use? */
1781     AccessRange = &((*(PortConfig->AccessRanges))[0]);
1782     for (i = 0; i < PortConfig->NumberOfAccessRanges; i++)
1783     {
1784         if (AccessRange->RangeLength != 0)
1785             ListLength++;
1786 
1787         AccessRange++;
1788     }
1789 
1790     /* Allocate the resource list, since we know its size now */
1791     FullSize = sizeof(CM_RESOURCE_LIST) + (ListLength - 1) *
1792         sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1793 
1794     ResourceList = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(PagedPool, FullSize, TAG_SCSIPORT);
1795 
1796     if (!ResourceList)
1797         return NULL;
1798 
1799     /* Zero it */
1800     RtlZeroMemory(ResourceList, FullSize);
1801 
1802     /* Initialize it */
1803     ResourceList->Count = 1;
1804     ResourceList->List[0].InterfaceType = PortConfig->AdapterInterfaceType;
1805     ResourceList->List[0].BusNumber = PortConfig->SystemIoBusNumber;
1806     ResourceList->List[0].PartialResourceList.Count = ListLength;
1807     ResourceDescriptor = ResourceList->List[0].PartialResourceList.PartialDescriptors;
1808 
1809     /* Copy access ranges array over */
1810     for (i = 0; i < PortConfig->NumberOfAccessRanges; i++)
1811     {
1812         AccessRange = &((*(PortConfig->AccessRanges))[i]);
1813 
1814         /* If the range is empty - skip it */
1815         if (AccessRange->RangeLength == 0)
1816             continue;
1817 
1818         if (AccessRange->RangeInMemory)
1819         {
1820             ResourceDescriptor->Type = CmResourceTypeMemory;
1821             ResourceDescriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
1822         }
1823         else
1824         {
1825             ResourceDescriptor->Type = CmResourceTypePort;
1826             ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
1827         }
1828 
1829         ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1830 
1831         ResourceDescriptor->u.Memory.Start = AccessRange->RangeStart;
1832         ResourceDescriptor->u.Memory.Length = AccessRange->RangeLength;
1833 
1834         ResourceDescriptor++;
1835     }
1836 
1837     /* If we use interrupt(s), copy them */
1838     while (Interrupt)
1839     {
1840         ResourceDescriptor->Type = CmResourceTypeInterrupt;
1841 
1842         if (PortConfig->AdapterInterfaceType == MicroChannel ||
1843             ((Interrupt == 2) ? PortConfig->InterruptMode2 : PortConfig->InterruptMode) == LevelSensitive)
1844         {
1845             ResourceDescriptor->ShareDisposition = CmResourceShareShared;
1846             ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
1847         }
1848         else
1849         {
1850             ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1851             ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
1852         }
1853 
1854         ResourceDescriptor->u.Interrupt.Level = (Interrupt == 2) ? PortConfig->BusInterruptLevel2 : PortConfig->BusInterruptLevel;
1855         ResourceDescriptor->u.Interrupt.Vector = (Interrupt == 2) ? PortConfig->BusInterruptVector2 : PortConfig->BusInterruptVector;
1856         ResourceDescriptor->u.Interrupt.Affinity = 0;
1857 
1858         ResourceDescriptor++;
1859         Interrupt--;
1860     }
1861 
1862     /* Copy DMA data */
1863     while (Dma)
1864     {
1865         ResourceDescriptor->Type = CmResourceTypeDma;
1866         ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1867         ResourceDescriptor->u.Dma.Channel = (Dma == 2) ? PortConfig->DmaChannel2 : PortConfig->DmaChannel;
1868         ResourceDescriptor->u.Dma.Port = (Dma == 2) ? PortConfig->DmaPort2 : PortConfig->DmaPort;
1869         ResourceDescriptor->Flags = 0;
1870 
1871         if (((Dma == 2) ? PortConfig->DmaWidth2 : PortConfig->DmaWidth) == Width8Bits)
1872             ResourceDescriptor->Flags |= CM_RESOURCE_DMA_8;
1873         else if (((Dma == 2) ? PortConfig->DmaWidth2 : PortConfig->DmaWidth) == Width16Bits)
1874             ResourceDescriptor->Flags |= CM_RESOURCE_DMA_16;
1875         else
1876             ResourceDescriptor->Flags |= CM_RESOURCE_DMA_32;
1877 
1878         if (((Dma == 2) ? PortConfig->DmaChannel2 : PortConfig->DmaChannel) == SP_UNINITIALIZED_VALUE)
1879             ResourceDescriptor->u.Dma.Channel = 0;
1880 
1881         if (((Dma == 2) ? PortConfig->DmaPort2 : PortConfig->DmaPort) == SP_UNINITIALIZED_VALUE)
1882             ResourceDescriptor->u.Dma.Port = 0;
1883 
1884         ResourceDescriptor++;
1885         Dma--;
1886     }
1887 
1888     return ResourceList;
1889 }
1890 
1891 
1892 static BOOLEAN
1893 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject,
1894                     IN PDEVICE_OBJECT DeviceObject,
1895                     IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
1896                     IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,
1897                     IN PUNICODE_STRING RegistryPath,
1898                     IN ULONG BusNumber,
1899                     IN OUT PPCI_SLOT_NUMBER NextSlotNumber)
1900 {
1901     PCI_COMMON_CONFIG PciConfig;
1902     PCI_SLOT_NUMBER SlotNumber;
1903     ULONG DataSize;
1904     ULONG DeviceNumber;
1905     ULONG FunctionNumber;
1906     CHAR VendorIdString[8];
1907     CHAR DeviceIdString[8];
1908     UNICODE_STRING UnicodeStr;
1909     PCM_RESOURCE_LIST ResourceList = NULL;
1910     NTSTATUS Status;
1911 
1912     DPRINT ("SpiGetPciConfiguration() called\n");
1913 
1914     SlotNumber.u.AsULONG = 0;
1915 
1916     /* Loop through all devices */
1917     for (DeviceNumber = NextSlotNumber->u.bits.DeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
1918     {
1919         SlotNumber.u.bits.DeviceNumber = DeviceNumber;
1920 
1921         /* Loop through all functions */
1922         for (FunctionNumber = NextSlotNumber->u.bits.FunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
1923         {
1924             SlotNumber.u.bits.FunctionNumber = FunctionNumber;
1925 
1926             /* Get PCI config bytes */
1927             DataSize = HalGetBusData(PCIConfiguration,
1928                                      BusNumber,
1929                                      SlotNumber.u.AsULONG,
1930                                      &PciConfig,
1931                                      sizeof(ULONG));
1932 
1933             /* If result of HalGetBusData is 0, then the bus is wrong */
1934             if (DataSize == 0)
1935                 return FALSE;
1936 
1937             /* Check if result is PCI_INVALID_VENDORID or too small */
1938             if ((DataSize < sizeof(ULONG)) ||
1939                 (PciConfig.VendorID == PCI_INVALID_VENDORID))
1940             {
1941                 /* Continue to try the next function */
1942                 continue;
1943             }
1944 
1945             sprintf (VendorIdString, "%04hx", PciConfig.VendorID);
1946             sprintf (DeviceIdString, "%04hx", PciConfig.DeviceID);
1947 
1948             if (_strnicmp(VendorIdString, HwInitializationData->VendorId, HwInitializationData->VendorIdLength) ||
1949                 _strnicmp(DeviceIdString, HwInitializationData->DeviceId, HwInitializationData->DeviceIdLength))
1950             {
1951                 /* It is not our device */
1952                 continue;
1953             }
1954 
1955             DPRINT("Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n",
1956                    PciConfig.VendorID,
1957                    PciConfig.DeviceID,
1958                    BusNumber,
1959                    SlotNumber.u.bits.DeviceNumber,
1960                    SlotNumber.u.bits.FunctionNumber);
1961 
1962 
1963             RtlInitUnicodeString(&UnicodeStr, L"ScsiAdapter");
1964             Status = HalAssignSlotResources(RegistryPath,
1965                                             &UnicodeStr,
1966                                             DriverObject,
1967                                             DeviceObject,
1968                                             PCIBus,
1969                                             BusNumber,
1970                                             SlotNumber.u.AsULONG,
1971                                             &ResourceList);
1972 
1973             if (!NT_SUCCESS(Status))
1974                 break;
1975 
1976             /* Create configuration information */
1977             SpiResourceToConfig(HwInitializationData,
1978                                 ResourceList->List,
1979                                 PortConfig);
1980 
1981             /* Free the resource list */
1982             ExFreePool(ResourceList);
1983 
1984             /* Set dev & fn numbers */
1985             NextSlotNumber->u.bits.DeviceNumber = DeviceNumber;
1986             NextSlotNumber->u.bits.FunctionNumber = FunctionNumber + 1;
1987 
1988             /* Save the slot number */
1989             PortConfig->SlotNumber = SlotNumber.u.AsULONG;
1990 
1991             return TRUE;
1992         }
1993        NextSlotNumber->u.bits.FunctionNumber = 0;
1994     }
1995 
1996     NextSlotNumber->u.bits.DeviceNumber = 0;
1997     DPRINT ("No device found\n");
1998 
1999     return FALSE;
2000 }
2001 
2002 
2003 
2004 /**********************************************************************
2005  * NAME                         INTERNAL
2006  *  ScsiPortCreateClose
2007  *
2008  * DESCRIPTION
2009  *  Answer requests for Create/Close calls: a null operation.
2010  *
2011  * RUN LEVEL
2012  *  PASSIVE_LEVEL
2013  *
2014  * ARGUMENTS
2015  *  DeviceObject
2016  *      Pointer to a device object.
2017  *
2018  *  Irp
2019  *      Pointer to an IRP.
2020  *
2021  * RETURN VALUE
2022  *  Status.
2023  */
2024 
2025 static NTSTATUS NTAPI
2026 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
2027                    IN PIRP Irp)
2028 {
2029     DPRINT("ScsiPortCreateClose()\n");
2030 
2031     Irp->IoStatus.Status = STATUS_SUCCESS;
2032     IoCompleteRequest(Irp, IO_NO_INCREMENT);
2033 
2034     return STATUS_SUCCESS;
2035 }
2036 
2037 IO_ALLOCATION_ACTION
2038 NTAPI
2039 SpiAdapterControl(PDEVICE_OBJECT DeviceObject,
2040                   PIRP Irp,
2041                   PVOID MapRegisterBase,
2042                   PVOID Context)
2043 {
2044     PSCSI_REQUEST_BLOCK Srb;
2045     PSCSI_SG_ADDRESS ScatterGatherList;
2046     KIRQL CurrentIrql;
2047     PIO_STACK_LOCATION IrpStack;
2048     ULONG TotalLength = 0;
2049     PSCSI_REQUEST_BLOCK_INFO SrbInfo;
2050     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2051     PUCHAR DataVA;
2052     BOOLEAN WriteToDevice;
2053 
2054     /* Get pointers to SrbInfo and DeviceExtension */
2055     SrbInfo = (PSCSI_REQUEST_BLOCK_INFO)Context;
2056     DeviceExtension = DeviceObject->DeviceExtension;
2057 
2058     /* Get pointer to SRB */
2059     IrpStack = IoGetCurrentIrpStackLocation(Irp);
2060     Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
2061 
2062     /* Depending on the map registers number, we allocate
2063        either from NonPagedPool, or from our static list */
2064     if (SrbInfo->NumberOfMapRegisters > MAX_SG_LIST)
2065     {
2066         SrbInfo->ScatterGather = ExAllocatePoolWithTag(
2067             NonPagedPool, SrbInfo->NumberOfMapRegisters * sizeof(SCSI_SG_ADDRESS), TAG_SCSIPORT);
2068 
2069         if (SrbInfo->ScatterGather == NULL)
2070             ASSERT(FALSE);
2071 
2072         Srb->SrbFlags |= SRB_FLAGS_SGLIST_FROM_POOL;
2073     }
2074     else
2075     {
2076         SrbInfo->ScatterGather = SrbInfo->ScatterGatherList;
2077     }
2078 
2079     /* Use chosen SG list source */
2080     ScatterGatherList = SrbInfo->ScatterGather;
2081 
2082     /* Save map registers base */
2083     SrbInfo->BaseOfMapRegister = MapRegisterBase;
2084 
2085     /* Determine WriteToDevice flag */
2086     WriteToDevice = Srb->SrbFlags & SRB_FLAGS_DATA_OUT ? TRUE : FALSE;
2087 
2088     /* Get virtual address of the data buffer */
2089     DataVA = (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress) +
2090                 ((PCHAR)Srb->DataBuffer - SrbInfo->DataOffset);
2091 
2092     /* Build the actual SG list */
2093     while (TotalLength < Srb->DataTransferLength)
2094     {
2095         if (!ScatterGatherList)
2096             break;
2097 
2098         ScatterGatherList->Length = Srb->DataTransferLength - TotalLength;
2099         ScatterGatherList->PhysicalAddress = IoMapTransfer(DeviceExtension->AdapterObject,
2100                                                            Irp->MdlAddress,
2101                                                            MapRegisterBase,
2102                                                            DataVA + TotalLength,
2103                                                            &ScatterGatherList->Length,
2104                                                            WriteToDevice);
2105 
2106         TotalLength += ScatterGatherList->Length;
2107         ScatterGatherList++;
2108     }
2109 
2110     /* Schedule an active request */
2111     InterlockedIncrement(&DeviceExtension->ActiveRequestCounter );
2112     KeAcquireSpinLock(&DeviceExtension->SpinLock, &CurrentIrql);
2113     KeSynchronizeExecution(DeviceExtension->Interrupt[0],
2114                            ScsiPortStartPacket,
2115                            DeviceObject);
2116     KeReleaseSpinLock(&DeviceExtension->SpinLock, CurrentIrql);
2117 
2118     return DeallocateObjectKeepRegisters;
2119 }
2120 
2121 BOOLEAN
2122 NTAPI
2123 ScsiPortIsr(
2124     _In_ PKINTERRUPT Interrupt,
2125     _In_ PVOID ServiceContext)
2126 {
2127     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2128 
2129     DPRINT("ScsiPortIsr() called!\n");
2130 
2131     DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext;
2132 
2133     /* If interrupts are disabled - we don't expect any */
2134     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_DISABLE_INTERRUPTS)
2135         return FALSE;
2136 
2137     /* Call miniport's HwInterrupt routine */
2138     if (DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension) == FALSE)
2139     {
2140         /* This interrupt doesn't belong to us */
2141         return FALSE;
2142     }
2143 
2144     /* If flag of notification is set - queue a DPC */
2145     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
2146     {
2147         IoRequestDpc(DeviceExtension->Common.DeviceObject,
2148                      DeviceExtension->CurrentIrp,
2149                      DeviceExtension);
2150     }
2151 
2152     return TRUE;
2153 }
2154 
2155 BOOLEAN
2156 NTAPI
2157 SpiProcessTimeout(PVOID ServiceContext)
2158 {
2159     PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)ServiceContext;
2160     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
2161     ULONG Bus;
2162 
2163     DPRINT("SpiProcessTimeout() entered\n");
2164 
2165     DeviceExtension->TimerCount = -1;
2166 
2167     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET)
2168     {
2169         DeviceExtension->InterruptData.Flags &= ~SCSI_PORT_RESET;
2170 
2171         if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET_REQUEST)
2172         {
2173             DeviceExtension->InterruptData.Flags &=  ~SCSI_PORT_RESET_REQUEST;
2174             ScsiPortStartPacket(ServiceContext);
2175         }
2176 
2177         return FALSE;
2178     }
2179     else
2180     {
2181         DPRINT("Resetting the bus\n");
2182 
2183         for (Bus = 0; Bus < DeviceExtension->NumberOfBuses; Bus++)
2184         {
2185             DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension, Bus);
2186 
2187             /* Reset flags and set reset timeout to 4 seconds */
2188             DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET;
2189             DeviceExtension->TimerCount = 4;
2190         }
2191 
2192         /* If miniport requested - request a dpc for it */
2193         if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
2194             IoRequestDpc(DeviceExtension->Common.DeviceObject, NULL, NULL);
2195     }
2196 
2197     return TRUE;
2198 }
2199 
2200 
2201 BOOLEAN
2202 NTAPI
2203 SpiResetBus(PVOID ServiceContext)
2204 {
2205     PRESETBUS_PARAMS ResetParams = (PRESETBUS_PARAMS)ServiceContext;
2206     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2207 
2208     /* Perform the bus reset */
2209     DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ResetParams->DeviceExtension;
2210     DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension,
2211                                 ResetParams->PathId);
2212 
2213     /* Set flags and start the timer */
2214     DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET;
2215     DeviceExtension->TimerCount = 4;
2216 
2217     /* If miniport requested - give him a DPC */
2218     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
2219         IoRequestDpc(DeviceExtension->Common.DeviceObject, NULL, NULL);
2220 
2221     return TRUE;
2222 }
2223 
2224 //    ScsiPortIoTimer
2225 //  DESCRIPTION:
2226 //    This function handles timeouts and other time delayed processing
2227 //
2228 //  RUN LEVEL:
2229 //
2230 //  ARGUMENTS:
2231 //    IN  PDEVICE_OBJECT  DeviceObject  Device object registered with timer
2232 //    IN  PVOID           Context       the Controller extension for the
2233 //                                      controller the device is on
2234 //
2235 static VOID NTAPI
2236 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
2237                 PVOID Context)
2238 {
2239     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2240     PSCSI_PORT_LUN_EXTENSION LunExtension;
2241     PIRP Irp;
2242 
2243     DPRINT("ScsiPortIoTimer()\n");
2244 
2245     DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
2246 
2247     /* Protect with the spinlock */
2248     KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
2249 
2250     /* Check timeouts */
2251     if (DeviceExtension->TimerCount > 0)
2252     {
2253         /* Decrease the timeout counter */
2254         DeviceExtension->TimerCount--;
2255 
2256         if (DeviceExtension->TimerCount == 0)
2257         {
2258             /* Timeout, process it */
2259             if (KeSynchronizeExecution(DeviceExtension->Interrupt[0],
2260                                        SpiProcessTimeout,
2261                                        DeviceExtension->Common.DeviceObject))
2262             {
2263                 DPRINT("Error happened during processing timeout, but nothing critical\n");
2264             }
2265         }
2266 
2267         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
2268 
2269         /* We should exit now, since timeout is processed */
2270         return;
2271     }
2272 
2273     /* Per-Lun scanning of timeouts is needed... */
2274     for (UINT8 pathId = 0; pathId < DeviceExtension->NumberOfBuses; pathId++)
2275     {
2276         PSCSI_BUS_INFO bus = &DeviceExtension->Buses[pathId];
2277 
2278         for (PLIST_ENTRY lunEntry = bus->LunsListHead.Flink;
2279              lunEntry != &bus->LunsListHead;
2280              lunEntry = lunEntry->Flink)
2281         {
2282             LunExtension = CONTAINING_RECORD(lunEntry, SCSI_PORT_LUN_EXTENSION, LunEntry);
2283 
2284             if (LunExtension->Flags & LUNEX_BUSY)
2285             {
2286                 if (!(LunExtension->Flags &
2287                     (LUNEX_NEED_REQUEST_SENSE | LUNEX_FROZEN_QUEUE)))
2288                 {
2289                     DPRINT("Retrying busy request\n");
2290 
2291                     /* Clear flags, and retry busy request */
2292                     LunExtension->Flags &= ~(LUNEX_BUSY | LUNEX_FULL_QUEUE);
2293                     Irp = LunExtension->BusyRequest;
2294 
2295                     /* Clearing busy request */
2296                     LunExtension->BusyRequest = NULL;
2297 
2298                     KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
2299 
2300                     IoStartPacket(DeviceObject, Irp, (PULONG)NULL, NULL);
2301 
2302                     KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
2303                 }
2304             }
2305             else if (LunExtension->RequestTimeout == 0)
2306             {
2307                 RESETBUS_PARAMS ResetParams;
2308 
2309                 LunExtension->RequestTimeout = -1;
2310 
2311                 DPRINT("Request timed out, resetting bus\n");
2312 
2313                 /* Pass params to the bus reset routine */
2314                 ResetParams.PathId = LunExtension->PathId;
2315                 ResetParams.DeviceExtension = DeviceExtension;
2316 
2317                 if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0],
2318                                             SpiResetBus,
2319                                             &ResetParams))
2320                 {
2321                     DPRINT1("Reset failed\n");
2322                 }
2323             }
2324             else if (LunExtension->RequestTimeout > 0)
2325             {
2326                 /* Decrement the timeout counter */
2327                 LunExtension->RequestTimeout--;
2328             }
2329         }
2330     }
2331 
2332     /* Release the spinlock */
2333     KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
2334 }
2335 
2336 VOID
2337 NTAPI
2338 SpiMiniportTimerDpc(IN struct _KDPC *Dpc,
2339                     IN PVOID DeviceObject,
2340                     IN PVOID SystemArgument1,
2341                     IN PVOID SystemArgument2)
2342 {
2343     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2344 
2345     DPRINT("Miniport timer DPC\n");
2346 
2347     DeviceExtension = ((PDEVICE_OBJECT)DeviceObject)->DeviceExtension;
2348 
2349     /* Acquire the spinlock */
2350     KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
2351 
2352     /* Call the timer routine */
2353     if (DeviceExtension->HwScsiTimer != NULL)
2354     {
2355         DeviceExtension->HwScsiTimer(&DeviceExtension->MiniPortDeviceExtension);
2356     }
2357 
2358     /* Release the spinlock */
2359     KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
2360 
2361     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
2362     {
2363         ScsiPortDpcForIsr(NULL,
2364                           DeviceExtension->Common.DeviceObject,
2365                           NULL,
2366                           NULL);
2367     }
2368 }
2369 
2370 static NTSTATUS
2371 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
2372                     PHW_INITIALIZATION_DATA HwInitData,
2373                     PCONFIGURATION_INFO InternalConfigInfo,
2374                     PPORT_CONFIGURATION_INFORMATION ConfigInfo,
2375                     BOOLEAN ZeroStruct)
2376 {
2377     UNICODE_STRING UnicodeString;
2378     OBJECT_ATTRIBUTES ObjectAttributes;
2379     PCONFIGURATION_INFORMATION DdkConfigInformation;
2380     HANDLE RootKey, Key;
2381     BOOLEAN Found;
2382     WCHAR DeviceBuffer[16];
2383     WCHAR StrBuffer[512];
2384     ULONG Bus;
2385     NTSTATUS Status;
2386 
2387     /* Zero out the struct if told so */
2388     if (ZeroStruct)
2389     {
2390         /* First zero the portconfig */
2391         RtlZeroMemory(ConfigInfo, sizeof(PORT_CONFIGURATION_INFORMATION));
2392 
2393         /* Then access ranges */
2394         RtlZeroMemory(InternalConfigInfo->AccessRanges,
2395                       HwInitData->NumberOfAccessRanges * sizeof(ACCESS_RANGE));
2396 
2397         /* Initialize the struct */
2398         ConfigInfo->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
2399         ConfigInfo->AdapterInterfaceType = HwInitData->AdapterInterfaceType;
2400         ConfigInfo->InterruptMode = Latched;
2401         ConfigInfo->DmaChannel = SP_UNINITIALIZED_VALUE;
2402         ConfigInfo->DmaPort = SP_UNINITIALIZED_VALUE;
2403         ConfigInfo->DmaChannel2 = SP_UNINITIALIZED_VALUE;
2404         ConfigInfo->DmaPort2 = SP_UNINITIALIZED_VALUE;
2405         ConfigInfo->MaximumTransferLength = SP_UNINITIALIZED_VALUE;
2406         ConfigInfo->NumberOfAccessRanges = HwInitData->NumberOfAccessRanges;
2407         ConfigInfo->MaximumNumberOfTargets = 8;
2408 
2409         /* Store parameters */
2410         ConfigInfo->NeedPhysicalAddresses = HwInitData->NeedPhysicalAddresses;
2411         ConfigInfo->MapBuffers = HwInitData->MapBuffers;
2412         ConfigInfo->AutoRequestSense = HwInitData->AutoRequestSense;
2413         ConfigInfo->ReceiveEvent = HwInitData->ReceiveEvent;
2414         ConfigInfo->TaggedQueuing = HwInitData->TaggedQueuing;
2415         ConfigInfo->MultipleRequestPerLu = HwInitData->MultipleRequestPerLu;
2416 
2417         /* Get the disk usage */
2418         DdkConfigInformation = IoGetConfigurationInformation();
2419         ConfigInfo->AtdiskPrimaryClaimed = DdkConfigInformation->AtDiskPrimaryAddressClaimed;
2420         ConfigInfo->AtdiskSecondaryClaimed = DdkConfigInformation->AtDiskSecondaryAddressClaimed;
2421 
2422         /* Initiator bus id is not set */
2423         for (Bus = 0; Bus < 8; Bus++)
2424             ConfigInfo->InitiatorBusId[Bus] = (CCHAR)SP_UNINITIALIZED_VALUE;
2425     }
2426 
2427     ConfigInfo->NumberOfPhysicalBreaks = 17;
2428 
2429     /* Clear this information */
2430     InternalConfigInfo->DisableTaggedQueueing = FALSE;
2431     InternalConfigInfo->DisableMultipleLun = FALSE;
2432 
2433     /* Store Bus Number */
2434     ConfigInfo->SystemIoBusNumber = InternalConfigInfo->BusNumber;
2435 
2436 TryNextAd:
2437 
2438     if (ConfigInfo->AdapterInterfaceType == Internal)
2439     {
2440         /* Open registry key for HW database */
2441         InitializeObjectAttributes(&ObjectAttributes,
2442                                    DeviceExtension->Common.DeviceObject->DriverObject->HardwareDatabase,
2443                                    OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2444                                    NULL,
2445                                    NULL);
2446 
2447         Status = ZwOpenKey(&RootKey,
2448                            KEY_READ,
2449                            &ObjectAttributes);
2450 
2451         if (NT_SUCCESS(Status))
2452         {
2453             /* Create name for it */
2454             swprintf(StrBuffer, L"ScsiAdapter\\%lu",
2455                 InternalConfigInfo->AdapterNumber);
2456 
2457             RtlInitUnicodeString(&UnicodeString, StrBuffer);
2458 
2459             /* Open device key */
2460             InitializeObjectAttributes(&ObjectAttributes,
2461                                        &UnicodeString,
2462                                        OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2463                                        RootKey,
2464                                        NULL);
2465 
2466             Status = ZwOpenKey(&Key,
2467                                KEY_READ,
2468                                &ObjectAttributes);
2469 
2470             ZwClose(RootKey);
2471 
2472             if (NT_SUCCESS(Status))
2473             {
2474                 if (InternalConfigInfo->LastAdapterNumber != InternalConfigInfo->AdapterNumber)
2475                 {
2476                     DPRINT("Hardware info found at %S\n", StrBuffer);
2477 
2478                     /* Parse it */
2479                     SpiParseDeviceInfo(DeviceExtension,
2480                                        Key,
2481                                        ConfigInfo,
2482                                        InternalConfigInfo,
2483                                        (PUCHAR)StrBuffer);
2484 
2485                      InternalConfigInfo->BusNumber = 0;
2486                 }
2487                 else
2488                 {
2489                     /* Try the next adapter */
2490                     InternalConfigInfo->AdapterNumber++;
2491                     goto TryNextAd;
2492                 }
2493             }
2494             else
2495             {
2496                 /* Info was not found, exit */
2497                 DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status);
2498                 return STATUS_DEVICE_DOES_NOT_EXIST;
2499             }
2500         }
2501         else
2502         {
2503             DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status);
2504         }
2505     }
2506 
2507     /* Look at device params */
2508     Key = NULL;
2509     if (InternalConfigInfo->Parameter)
2510     {
2511         ExFreePool(InternalConfigInfo->Parameter);
2512         InternalConfigInfo->Parameter = NULL;
2513     }
2514 
2515     if (InternalConfigInfo->ServiceKey != NULL)
2516     {
2517         swprintf(DeviceBuffer, L"Device%lu", InternalConfigInfo->AdapterNumber);
2518         RtlInitUnicodeString(&UnicodeString, DeviceBuffer);
2519 
2520         /* Open the service key */
2521         InitializeObjectAttributes(&ObjectAttributes,
2522                                    &UnicodeString,
2523                                    OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2524                                    InternalConfigInfo->ServiceKey,
2525                                    NULL);
2526 
2527         Status = ZwOpenKey(&Key,
2528                            KEY_READ,
2529                            &ObjectAttributes);
2530     }
2531 
2532     /* Parse device key */
2533     if (InternalConfigInfo->DeviceKey != NULL)
2534     {
2535         SpiParseDeviceInfo(DeviceExtension,
2536                            InternalConfigInfo->DeviceKey,
2537                            ConfigInfo,
2538                            InternalConfigInfo,
2539                            (PUCHAR)StrBuffer);
2540     }
2541 
2542     /* Then parse hw info */
2543     if (Key != NULL)
2544     {
2545         if (InternalConfigInfo->LastAdapterNumber != InternalConfigInfo->AdapterNumber)
2546         {
2547             SpiParseDeviceInfo(DeviceExtension,
2548                                Key,
2549                                ConfigInfo,
2550                                InternalConfigInfo,
2551                                (PUCHAR)StrBuffer);
2552 
2553             /* Close the key */
2554             ZwClose(Key);
2555         }
2556         else
2557         {
2558             /* Adapter not found, go try the next one */
2559             InternalConfigInfo->AdapterNumber++;
2560 
2561             /* Close the key */
2562             ZwClose(Key);
2563 
2564             goto TryNextAd;
2565         }
2566     }
2567 
2568     /* Update the last adapter number */
2569     InternalConfigInfo->LastAdapterNumber = InternalConfigInfo->AdapterNumber;
2570 
2571     /* Do we have this kind of bus at all? */
2572     Found = FALSE;
2573     Status = IoQueryDeviceDescription(&HwInitData->AdapterInterfaceType,
2574                                       &InternalConfigInfo->BusNumber,
2575                                       NULL,
2576                                       NULL,
2577                                       NULL,
2578                                       NULL,
2579                                       SpQueryDeviceCallout,
2580                                       &Found);
2581 
2582     /* This bus was not found */
2583     if (!Found)
2584     {
2585         INTERFACE_TYPE InterfaceType = Eisa;
2586 
2587         /* Check for EISA */
2588         if (HwInitData->AdapterInterfaceType == Isa)
2589         {
2590             Status = IoQueryDeviceDescription(&InterfaceType,
2591                                               &InternalConfigInfo->BusNumber,
2592                                               NULL,
2593                                               NULL,
2594                                               NULL,
2595                                               NULL,
2596                                               SpQueryDeviceCallout,
2597                                               &Found);
2598 
2599             /* Return respectively */
2600             if (Found)
2601                 return STATUS_SUCCESS;
2602             else
2603                 return STATUS_DEVICE_DOES_NOT_EXIST;
2604         }
2605         else
2606         {
2607             return STATUS_DEVICE_DOES_NOT_EXIST;
2608         }
2609     }
2610     else
2611     {
2612         return STATUS_SUCCESS;
2613     }
2614 }
2615 
2616 static VOID
2617 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
2618                    IN HANDLE Key,
2619                    IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
2620                    IN PCONFIGURATION_INFO InternalConfigInfo,
2621                    IN PUCHAR Buffer)
2622 {
2623     PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
2624     PCM_FULL_RESOURCE_DESCRIPTOR FullResource;
2625     PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
2626     PCM_SCSI_DEVICE_DATA ScsiDeviceData;
2627     ULONG Length, Count, Dma = 0, Interrupt = 0;
2628     ULONG Index = 0, RangeCount = 0;
2629     UNICODE_STRING UnicodeString;
2630     ANSI_STRING AnsiString;
2631     NTSTATUS Status = STATUS_SUCCESS;
2632 
2633 
2634     KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION) Buffer;
2635 
2636     /* Loop through all values in the device node */
2637     while(TRUE)
2638     {
2639         Status = ZwEnumerateValueKey(Key,
2640                                      Index,
2641                                      KeyValueFullInformation,
2642                                      Buffer,
2643                                      512,
2644                                      &Length);
2645 
2646         if (!NT_SUCCESS(Status))
2647             return;
2648 
2649         Index++;
2650 
2651         /* Length for DWORD is ok? */
2652         if (KeyValueInformation->Type == REG_DWORD &&
2653             KeyValueInformation->DataLength != sizeof(ULONG))
2654         {
2655             continue;
2656         }
2657 
2658         /* Get MaximumLogicalUnit */
2659         if (_wcsnicmp(KeyValueInformation->Name, L"MaximumLogicalUnit",
2660             KeyValueInformation->NameLength/2) == 0)
2661         {
2662 
2663             if (KeyValueInformation->Type != REG_DWORD)
2664             {
2665                 DPRINT("Bad data type for MaximumLogicalUnit\n");
2666                 continue;
2667             }
2668 
2669             DeviceExtension->MaxLunCount = *((PUCHAR)
2670                 (Buffer + KeyValueInformation->DataOffset));
2671 
2672             /* Check / reset if needed */
2673             if (DeviceExtension->MaxLunCount > SCSI_MAXIMUM_LOGICAL_UNITS)
2674                 DeviceExtension->MaxLunCount = SCSI_MAXIMUM_LOGICAL_UNITS;
2675 
2676             DPRINT("MaximumLogicalUnit = %d\n", DeviceExtension->MaxLunCount);
2677         }
2678 
2679         /* Get InitiatorTargetId */
2680         if (_wcsnicmp(KeyValueInformation->Name, L"InitiatorTargetId",
2681             KeyValueInformation->NameLength / 2) == 0)
2682         {
2683 
2684             if (KeyValueInformation->Type != REG_DWORD)
2685             {
2686                 DPRINT("Bad data type for InitiatorTargetId\n");
2687                 continue;
2688             }
2689 
2690             ConfigInfo->InitiatorBusId[0] = *((PUCHAR)
2691                 (Buffer + KeyValueInformation->DataOffset));
2692 
2693             /* Check / reset if needed */
2694             if (ConfigInfo->InitiatorBusId[0] > ConfigInfo->MaximumNumberOfTargets - 1)
2695                 ConfigInfo->InitiatorBusId[0] = (CCHAR)-1;
2696 
2697             DPRINT("InitiatorTargetId = %d\n", ConfigInfo->InitiatorBusId[0]);
2698         }
2699 
2700         /* Get ScsiDebug */
2701         if (_wcsnicmp(KeyValueInformation->Name, L"ScsiDebug",
2702             KeyValueInformation->NameLength/2) == 0)
2703         {
2704             DPRINT("ScsiDebug key not supported\n");
2705         }
2706 
2707         /* Check for a breakpoint */
2708         if (_wcsnicmp(KeyValueInformation->Name, L"BreakPointOnEntry",
2709             KeyValueInformation->NameLength/2) == 0)
2710         {
2711             DPRINT1("Breakpoint on entry requested!\n");
2712             DbgBreakPoint();
2713         }
2714 
2715         /* Get DisableSynchronousTransfers */
2716         if (_wcsnicmp(KeyValueInformation->Name, L"DisableSynchronousTransfers",
2717             KeyValueInformation->NameLength/2) == 0)
2718         {
2719             DeviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
2720             DPRINT("Synch transfers disabled\n");
2721         }
2722 
2723         /* Get DisableDisconnects */
2724         if (_wcsnicmp(KeyValueInformation->Name, L"DisableDisconnects",
2725             KeyValueInformation->NameLength/2) == 0)
2726         {
2727             DeviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT;
2728             DPRINT("Disconnects disabled\n");
2729         }
2730 
2731         /* Get DisableTaggedQueuing */
2732         if (_wcsnicmp(KeyValueInformation->Name, L"DisableTaggedQueuing",
2733             KeyValueInformation->NameLength/2) == 0)
2734         {
2735             InternalConfigInfo->DisableTaggedQueueing = TRUE;
2736             DPRINT("Tagged queueing disabled\n");
2737         }
2738 
2739         /* Get DisableMultipleRequests */
2740         if (_wcsnicmp(KeyValueInformation->Name, L"DisableMultipleRequests",
2741             KeyValueInformation->NameLength/2) == 0)
2742         {
2743             InternalConfigInfo->DisableMultipleLun = TRUE;
2744             DPRINT("Multiple requests disabled\n");
2745         }
2746 
2747         /* Get DriverParameters */
2748         if (_wcsnicmp(KeyValueInformation->Name, L"DriverParameters",
2749             KeyValueInformation->NameLength/2) == 0)
2750         {
2751             /* Skip if nothing */
2752             if (KeyValueInformation->DataLength == 0)
2753                 continue;
2754 
2755             /* If there was something previously allocated - free it */
2756             if (InternalConfigInfo->Parameter != NULL)
2757                 ExFreePool(InternalConfigInfo->Parameter);
2758 
2759             /* Allocate it */
2760             InternalConfigInfo->Parameter = ExAllocatePoolWithTag(NonPagedPool,
2761                                                            KeyValueInformation->DataLength, TAG_SCSIPORT);
2762 
2763             if (InternalConfigInfo->Parameter != NULL)
2764             {
2765                 if (KeyValueInformation->Type != REG_SZ)
2766                 {
2767                     /* Just copy */
2768                     RtlCopyMemory(
2769                         InternalConfigInfo->Parameter,
2770                         (PCCHAR)KeyValueInformation + KeyValueInformation->DataOffset,
2771                         KeyValueInformation->DataLength);
2772                 }
2773                 else
2774                 {
2775                     /* If it's a unicode string, convert it to ansi */
2776                     UnicodeString.Length = (USHORT)KeyValueInformation->DataLength;
2777                     UnicodeString.MaximumLength = (USHORT)KeyValueInformation->DataLength;
2778                     UnicodeString.Buffer =
2779                         (PWSTR)((PCCHAR)KeyValueInformation + KeyValueInformation->DataOffset);
2780 
2781                     AnsiString.Length = 0;
2782                     AnsiString.MaximumLength = (USHORT)KeyValueInformation->DataLength;
2783                     AnsiString.Buffer = (PCHAR)InternalConfigInfo->Parameter;
2784 
2785                     Status = RtlUnicodeStringToAnsiString(&AnsiString,
2786                                                           &UnicodeString,
2787                                                           FALSE);
2788 
2789                     /* In case of error, free the allocated space */
2790                     if (!NT_SUCCESS(Status))
2791                     {
2792                         ExFreePool(InternalConfigInfo->Parameter);
2793                         InternalConfigInfo->Parameter = NULL;
2794                     }
2795 
2796                 }
2797             }
2798 
2799             DPRINT("Found driver parameter\n");
2800         }
2801 
2802         /* Get MaximumSGList */
2803         if (_wcsnicmp(KeyValueInformation->Name, L"MaximumSGList",
2804             KeyValueInformation->NameLength/2) == 0)
2805         {
2806             if (KeyValueInformation->Type != REG_DWORD)
2807             {
2808                 DPRINT("Bad data type for MaximumSGList\n");
2809                 continue;
2810             }
2811 
2812             ConfigInfo->NumberOfPhysicalBreaks = *((PUCHAR)(Buffer + KeyValueInformation->DataOffset));
2813 
2814             /* Check / fix */
2815             if (ConfigInfo->NumberOfPhysicalBreaks > SCSI_MAXIMUM_PHYSICAL_BREAKS)
2816             {
2817                 ConfigInfo->NumberOfPhysicalBreaks = SCSI_MAXIMUM_PHYSICAL_BREAKS;
2818             }
2819             else if (ConfigInfo->NumberOfPhysicalBreaks < SCSI_MINIMUM_PHYSICAL_BREAKS)
2820             {
2821                 ConfigInfo->NumberOfPhysicalBreaks = SCSI_MINIMUM_PHYSICAL_BREAKS;
2822             }
2823 
2824             DPRINT("MaximumSGList = %d\n", ConfigInfo->NumberOfPhysicalBreaks);
2825         }
2826 
2827         /* Get NumberOfRequests */
2828         if (_wcsnicmp(KeyValueInformation->Name, L"NumberOfRequests",
2829             KeyValueInformation->NameLength/2) == 0)
2830         {
2831             if (KeyValueInformation->Type != REG_DWORD)
2832             {
2833                 DPRINT("NumberOfRequests has wrong data type\n");
2834                 continue;
2835             }
2836 
2837             DeviceExtension->RequestsNumber = *((PUCHAR)(Buffer + KeyValueInformation->DataOffset));
2838 
2839             /* Check / fix */
2840             if (DeviceExtension->RequestsNumber < 16)
2841             {
2842                 DeviceExtension->RequestsNumber = 16;
2843             }
2844             else if (DeviceExtension->RequestsNumber > 512)
2845             {
2846                 DeviceExtension->RequestsNumber = 512;
2847             }
2848 
2849             DPRINT("Number Of Requests = %d\n", DeviceExtension->RequestsNumber);
2850         }
2851 
2852         /* Get resource list */
2853         if (_wcsnicmp(KeyValueInformation->Name, L"ResourceList",
2854                 KeyValueInformation->NameLength/2) == 0 ||
2855             _wcsnicmp(KeyValueInformation->Name, L"Configuration Data",
2856                 KeyValueInformation->NameLength/2) == 0 )
2857         {
2858             if (KeyValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR ||
2859                 KeyValueInformation->DataLength < sizeof(REG_FULL_RESOURCE_DESCRIPTOR))
2860             {
2861                 DPRINT("Bad data type for ResourceList\n");
2862                 continue;
2863             }
2864             else
2865             {
2866                 DPRINT("Found ResourceList\n");
2867             }
2868 
2869             FullResource = (PCM_FULL_RESOURCE_DESCRIPTOR)(Buffer + KeyValueInformation->DataOffset);
2870 
2871             /* Copy some info from it */
2872             InternalConfigInfo->BusNumber = FullResource->BusNumber;
2873             ConfigInfo->SystemIoBusNumber = FullResource->BusNumber;
2874 
2875             /* Loop through it */
2876             for (Count = 0; Count < FullResource->PartialResourceList.Count; Count++)
2877             {
2878                 /* Get partial descriptor */
2879                 PartialDescriptor =
2880                     &FullResource->PartialResourceList.PartialDescriptors[Count];
2881 
2882                 /* Check datalength */
2883                 if ((ULONG)((PCHAR)(PartialDescriptor + 1) -
2884                     (PCHAR)FullResource) > KeyValueInformation->DataLength)
2885                 {
2886                     DPRINT("Resource data is of incorrect size\n");
2887                     break;
2888                 }
2889 
2890                 switch (PartialDescriptor->Type)
2891                 {
2892                 case CmResourceTypePort:
2893                     if (RangeCount >= ConfigInfo->NumberOfAccessRanges)
2894                     {
2895                         DPRINT("Too many access ranges\n");
2896                         continue;
2897                     }
2898 
2899                     InternalConfigInfo->AccessRanges[RangeCount].RangeInMemory = FALSE;
2900                     InternalConfigInfo->AccessRanges[RangeCount].RangeStart = PartialDescriptor->u.Port.Start;
2901                     InternalConfigInfo->AccessRanges[RangeCount].RangeLength = PartialDescriptor->u.Port.Length;
2902                     RangeCount++;
2903 
2904                     break;
2905 
2906                 case CmResourceTypeMemory:
2907                     if (RangeCount >= ConfigInfo->NumberOfAccessRanges)
2908                     {
2909                         DPRINT("Too many access ranges\n");
2910                         continue;
2911                     }
2912 
2913                     InternalConfigInfo->AccessRanges[RangeCount].RangeInMemory = TRUE;
2914                     InternalConfigInfo->AccessRanges[RangeCount].RangeStart = PartialDescriptor->u.Memory.Start;
2915                     InternalConfigInfo->AccessRanges[RangeCount].RangeLength = PartialDescriptor->u.Memory.Length;
2916                     RangeCount++;
2917 
2918                     break;
2919 
2920                 case CmResourceTypeInterrupt:
2921 
2922                     if (Interrupt == 0)
2923                     {
2924                         ConfigInfo->BusInterruptLevel =
2925                             PartialDescriptor->u.Interrupt.Level;
2926 
2927                         ConfigInfo->BusInterruptVector =
2928                             PartialDescriptor->u.Interrupt.Vector;
2929 
2930                         ConfigInfo->InterruptMode = (PartialDescriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive;
2931                     }
2932                     else if (Interrupt == 1)
2933                     {
2934                         ConfigInfo->BusInterruptLevel2 =
2935                         PartialDescriptor->u.Interrupt.Level;
2936 
2937                         ConfigInfo->BusInterruptVector2 =
2938                         PartialDescriptor->u.Interrupt.Vector;
2939 
2940                         ConfigInfo->InterruptMode2 = (PartialDescriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive;
2941                     }
2942 
2943                     Interrupt++;
2944                     break;
2945 
2946                 case CmResourceTypeDma:
2947 
2948                     if (Dma == 0)
2949                     {
2950                         ConfigInfo->DmaChannel = PartialDescriptor->u.Dma.Channel;
2951                         ConfigInfo->DmaPort = PartialDescriptor->u.Dma.Port;
2952 
2953                         if (PartialDescriptor->Flags & CM_RESOURCE_DMA_8)
2954                             ConfigInfo->DmaWidth = Width8Bits;
2955                         else if ((PartialDescriptor->Flags & CM_RESOURCE_DMA_16) ||
2956                                  (PartialDescriptor->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
2957                             ConfigInfo->DmaWidth = Width16Bits;
2958                         else if (PartialDescriptor->Flags & CM_RESOURCE_DMA_32)
2959                             ConfigInfo->DmaWidth = Width32Bits;
2960                     }
2961                     else if (Dma == 1)
2962                     {
2963                         ConfigInfo->DmaChannel2 = PartialDescriptor->u.Dma.Channel;
2964                         ConfigInfo->DmaPort2 = PartialDescriptor->u.Dma.Port;
2965 
2966                         if (PartialDescriptor->Flags & CM_RESOURCE_DMA_8)
2967                             ConfigInfo->DmaWidth2 = Width8Bits;
2968                         else if ((PartialDescriptor->Flags & CM_RESOURCE_DMA_16) ||
2969                                  (PartialDescriptor->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
2970                             ConfigInfo->DmaWidth2 = Width16Bits;
2971                         else if (PartialDescriptor->Flags & CM_RESOURCE_DMA_32)
2972                             ConfigInfo->DmaWidth2 = Width32Bits;
2973                     }
2974 
2975                     Dma++;
2976                     break;
2977 
2978                 case CmResourceTypeDeviceSpecific:
2979                     if (PartialDescriptor->u.DeviceSpecificData.DataSize <
2980                         sizeof(CM_SCSI_DEVICE_DATA) ||
2981                         (PCHAR) (PartialDescriptor + 1) - (PCHAR)FullResource +
2982                         PartialDescriptor->u.DeviceSpecificData.DataSize >
2983                         KeyValueInformation->DataLength)
2984                     {
2985                         DPRINT("Resource data length is incorrect");
2986                         break;
2987                     }
2988 
2989                     /* Set only one field from it */
2990                     ScsiDeviceData = (PCM_SCSI_DEVICE_DATA) (PartialDescriptor+1);
2991                     ConfigInfo->InitiatorBusId[0] = ScsiDeviceData->HostIdentifier;
2992                     break;
2993                 }
2994             }
2995         }
2996     }
2997 }
2998 
2999 NTSTATUS
3000 NTAPI
3001 SpQueryDeviceCallout(IN PVOID  Context,
3002                      IN PUNICODE_STRING  PathName,
3003                      IN INTERFACE_TYPE  BusType,
3004                      IN ULONG  BusNumber,
3005                      IN PKEY_VALUE_FULL_INFORMATION  *BusInformation,
3006                      IN CONFIGURATION_TYPE  ControllerType,
3007                      IN ULONG  ControllerNumber,
3008                      IN PKEY_VALUE_FULL_INFORMATION  *ControllerInformation,
3009                      IN CONFIGURATION_TYPE  PeripheralType,
3010                      IN ULONG  PeripheralNumber,
3011                      IN PKEY_VALUE_FULL_INFORMATION  *PeripheralInformation)
3012 {
3013     PBOOLEAN Found = (PBOOLEAN)Context;
3014     /* We just set our Found variable to TRUE */
3015 
3016     *Found = TRUE;
3017     return STATUS_SUCCESS;
3018 }
3019 
3020 IO_ALLOCATION_ACTION
3021 NTAPI
3022 ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject,
3023                                IN PIRP Irp,
3024                                IN PVOID MapRegisterBase,
3025                                IN PVOID Context)
3026 {
3027     KIRQL Irql;
3028     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
3029 
3030     /* Guard access with the spinlock */
3031     KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
3032 
3033     /* Save MapRegisterBase we've got here */
3034     DeviceExtension->MapRegisterBase = MapRegisterBase;
3035 
3036     /* Start pending request */
3037     KeSynchronizeExecution(DeviceExtension->Interrupt[0],
3038         ScsiPortStartPacket, DeviceObject);
3039 
3040     /* Release spinlock we took */
3041     KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
3042 
3043     return KeepObject;
3044 }
3045 
3046 #undef ScsiPortConvertPhysicalAddressToUlong
3047 /*
3048  * @implemented
3049  */
3050 ULONG NTAPI
3051 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address)
3052 {
3053   DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
3054   return(Address.u.LowPart);
3055 }
3056