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
DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)113 DriverEntry(IN PDRIVER_OBJECT DriverObject,
114         IN PUNICODE_STRING RegistryPath)
115 {
116     return STATUS_SUCCESS;
117 }
118 
119 VOID
120 NTAPI
ScsiPortUnload(_In_ PDRIVER_OBJECT DriverObject)121 ScsiPortUnload(
122     _In_ PDRIVER_OBJECT DriverObject)
123 {
124     // no-op
125 }
126 
127 NTSTATUS
128 NTAPI
ScsiPortDispatchPnp(PDEVICE_OBJECT DeviceObject,PIRP Irp)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
ScsiPortAddDevice(_In_ PDRIVER_OBJECT DriverObject,_In_ PDEVICE_OBJECT PhysicalDeviceObject)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
ScsiDebugPrint(IN ULONG DebugPrintLevel,IN PCHAR DebugMessage,...)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
SpiCompleteRequest(IN PVOID HwDeviceExtension,IN PSCSI_REQUEST_BLOCK_INFO SrbInfo,IN UCHAR SrbStatus)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
ScsiPortCompleteRequest(IN PVOID HwDeviceExtension,IN UCHAR PathId,IN UCHAR TargetId,IN UCHAR Lun,IN UCHAR SrbStatus)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
ScsiPortFlushDma(IN PVOID HwDeviceExtension)308 ScsiPortFlushDma(IN PVOID HwDeviceExtension)
309 {
310   DPRINT("ScsiPortFlushDma()\n");
311   UNIMPLEMENTED;
312 }
313 
314 
315 /*
316  * @implemented
317  */
318 VOID NTAPI
ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension,IN PVOID MappedAddress)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
ScsiPortGetBusData(IN PVOID DeviceExtension,IN ULONG BusDataType,IN ULONG SystemIoBusNumber,IN ULONG SlotNumber,IN PVOID Buffer,IN ULONG Length)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
ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension,IN ULONG BusDataType,IN ULONG SystemIoBusNumber,IN ULONG SlotNumber,IN PVOID Buffer,IN ULONG Offset,IN ULONG Length)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
ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension,IN INTERFACE_TYPE BusType,IN ULONG SystemIoBusNumber,IN SCSI_PHYSICAL_ADDRESS IoAddress,IN ULONG NumberOfBytes,IN BOOLEAN InIoSpace)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
ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension,IN UCHAR PathId,IN UCHAR TargetId,IN UCHAR Lun)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
ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension,IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,IN PVOID VirtualAddress,OUT ULONG * Length)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
ScsiPortGetSrb(IN PVOID DeviceExtension,IN UCHAR PathId,IN UCHAR TargetId,IN UCHAR Lun,IN LONG QueueTag)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
ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension,IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,IN ULONG NumberOfBytes)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
SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,ULONG NonCachedSize)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
ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension,IN SCSI_PHYSICAL_ADDRESS PhysicalAddress)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
ScsiPortInitialize(IN PVOID Argument1,IN PVOID Argument2,IN struct _HW_INITIALIZATION_DATA * HwInitializationData,IN PVOID HwContext)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     PCI_SLOT_NUMBER SlotNumber;
856 
857     PDEVICE_OBJECT PortDeviceObject;
858     UNICODE_STRING DeviceName;
859     PIO_SCSI_CAPABILITIES PortCapabilities;
860 
861     PCM_RESOURCE_LIST ResourceList;
862 
863     DPRINT("ScsiPortInitialize() called!\n");
864 
865     /* Check params for validity */
866     if ((HwInitializationData->HwInitialize == NULL) ||
867         (HwInitializationData->HwStartIo == NULL) ||
868         (HwInitializationData->HwInterrupt == NULL) ||
869         (HwInitializationData->HwFindAdapter == NULL) ||
870         (HwInitializationData->HwResetBus == NULL))
871     {
872         return STATUS_REVISION_MISMATCH;
873     }
874 
875     PSCSI_PORT_DRIVER_EXTENSION driverExtension;
876 
877     // ScsiPortInitialize may be called multiple times by the same driver
878     driverExtension = IoGetDriverObjectExtension(DriverObject, HwInitializationData->HwInitialize);
879 
880     if (!driverExtension)
881     {
882         Status = IoAllocateDriverObjectExtension(DriverObject,
883                                                  HwInitializationData->HwInitialize,
884                                                  sizeof(SCSI_PORT_DRIVER_EXTENSION),
885                                                  (PVOID *)&driverExtension);
886 
887         if (!NT_SUCCESS(Status))
888         {
889             DPRINT1("Failed to allocate the driver extension! Status 0x%x\n", Status);
890             return Status;
891         }
892     }
893 
894     // set up the driver extension
895     driverExtension->RegistryPath.Buffer =
896         ExAllocatePoolWithTag(PagedPool, RegistryPath->MaximumLength, TAG_SCSIPORT);
897     driverExtension->RegistryPath.MaximumLength = RegistryPath->MaximumLength;
898     RtlCopyUnicodeString(&driverExtension->RegistryPath, RegistryPath);
899 
900     driverExtension->DriverObject = DriverObject;
901 
902     /* Set handlers */
903     DriverObject->DriverUnload = ScsiPortUnload;
904     DriverObject->DriverStartIo = ScsiPortStartIo;
905     DriverObject->DriverExtension->AddDevice = ScsiPortAddDevice;
906     DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiPortCreateClose;
907     DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiPortCreateClose;
908     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiPortDeviceControl;
909     DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiPortDispatchScsi;
910     DriverObject->MajorFunction[IRP_MJ_PNP] = ScsiPortDispatchPnp;
911     DriverObject->MajorFunction[IRP_MJ_POWER] = ScsiPortDispatchPower;
912 
913     /* Obtain configuration information */
914     SystemConfig = IoGetConfigurationInformation();
915 
916     /* Zero the internal configuration info structure */
917     RtlZeroMemory(&ConfigInfo, sizeof(CONFIGURATION_INFO));
918 
919     /* Zero starting slot number */
920     SlotNumber.u.AsULONG = 0;
921 
922     /* Allocate space for access ranges */
923     if (HwInitializationData->NumberOfAccessRanges)
924     {
925         ConfigInfo.AccessRanges =
926             ExAllocatePoolWithTag(PagedPool,
927             HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE), TAG_SCSIPORT);
928 
929         /* Fail if failed */
930         if (ConfigInfo.AccessRanges == NULL)
931             return STATUS_INSUFFICIENT_RESOURCES;
932     }
933 
934     /* Open registry keys and fill the driverExtension */
935     SpiInitOpenKeys(&ConfigInfo, driverExtension);
936 
937     // FIXME: PnP miniports are not supported
938     ASSERT(driverExtension->IsLegacyDriver);
939 
940     /* Last adapter number = not known */
941     ConfigInfo.LastAdapterNumber = SP_UNINITIALIZED_VALUE;
942 
943     /* Calculate sizes of DeviceExtension and PortConfig */
944     DeviceExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) +
945         HwInitializationData->DeviceExtensionSize;
946 
947     DPRINT("AdapterInterfaceType: %lu\n",
948            HwInitializationData->AdapterInterfaceType);
949 
950     while (TRUE)
951     {
952         WCHAR NameBuffer[27];
953         /* Create a unicode device name */
954         swprintf(NameBuffer,
955                  L"\\Device\\ScsiPort%lu",
956                  SystemConfig->ScsiPortCount);
957         if (!RtlCreateUnicodeString(&DeviceName, NameBuffer))
958         {
959             DPRINT1("Failed to allocate memory for device name!\n");
960             Status = STATUS_INSUFFICIENT_RESOURCES;
961             PortDeviceObject = NULL;
962             break;
963         }
964 
965         DPRINT("Creating device: %wZ\n", &DeviceName);
966 
967         /* Create the port device */
968         Status = IoCreateDevice(DriverObject,
969                                 DeviceExtensionSize,
970                                 &DeviceName,
971                                 FILE_DEVICE_CONTROLLER,
972                                 FILE_DEVICE_SECURE_OPEN,
973                                 FALSE,
974                                 &PortDeviceObject);
975 
976         if (!NT_SUCCESS(Status))
977         {
978             DPRINT1("IoCreateDevice call failed! (Status 0x%lX)\n", Status);
979             PortDeviceObject = NULL;
980             break;
981         }
982 
983         /* Set the buffering strategy here... */
984         PortDeviceObject->Flags |= DO_DIRECT_IO;
985         PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT; /* FIXME: Is this really needed? */
986 
987         /* Fill Device Extension */
988         DeviceExtension = PortDeviceObject->DeviceExtension;
989         RtlZeroMemory(DeviceExtension, DeviceExtensionSize);
990         DeviceExtension->Common.DeviceObject = PortDeviceObject;
991         DeviceExtension->Common.IsFDO = TRUE;
992         DeviceExtension->Length = DeviceExtensionSize;
993         DeviceExtension->PortNumber = SystemConfig->ScsiPortCount;
994         DeviceExtension->DeviceName = DeviceName;
995 
996         /* Driver's routines... */
997         DeviceExtension->HwInitialize = HwInitializationData->HwInitialize;
998         DeviceExtension->HwStartIo = HwInitializationData->HwStartIo;
999         DeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
1000         DeviceExtension->HwResetBus = HwInitializationData->HwResetBus;
1001         DeviceExtension->HwDmaStarted = HwInitializationData->HwDmaStarted;
1002 
1003         /* Extensions sizes */
1004         DeviceExtension->MiniPortExtensionSize = HwInitializationData->DeviceExtensionSize;
1005         DeviceExtension->LunExtensionSize =
1006             ALIGN_UP(HwInitializationData->SpecificLuExtensionSize, INT64);
1007         DeviceExtension->SrbExtensionSize =
1008             ALIGN_UP(HwInitializationData->SrbExtensionSize, INT64);
1009 
1010         /* Fill some numbers (bus count, lun count, etc) */
1011         DeviceExtension->MaxLunCount = SCSI_MAXIMUM_LOGICAL_UNITS;
1012         DeviceExtension->RequestsNumber = 16;
1013 
1014         /* Initialize the spin lock in the controller extension */
1015         KeInitializeSpinLock(&DeviceExtension->IrqLock);
1016         KeInitializeSpinLock(&DeviceExtension->SpinLock);
1017 
1018         /* Initialize the DPC object */
1019         IoInitializeDpcRequest(PortDeviceObject,
1020                                ScsiPortDpcForIsr);
1021 
1022         /* Initialize the device timer */
1023         DeviceExtension->TimerCount = -1;
1024         IoInitializeTimer(PortDeviceObject,
1025                           ScsiPortIoTimer,
1026                           DeviceExtension);
1027 
1028         /* Initialize miniport timer */
1029         KeInitializeTimer(&DeviceExtension->MiniportTimer);
1030         KeInitializeDpc(&DeviceExtension->MiniportTimerDpc,
1031                         SpiMiniportTimerDpc,
1032                         PortDeviceObject);
1033 
1034 CreatePortConfig:
1035 
1036         /* Allocate and initialize port configuration info */
1037         PortConfigSize = sizeof(PORT_CONFIGURATION_INFORMATION) +
1038                          HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE);
1039         PortConfigSize = ALIGN_UP(PortConfigSize, INT64);
1040         DeviceExtension->PortConfig = ExAllocatePoolWithTag(NonPagedPool, PortConfigSize, TAG_SCSIPORT);
1041 
1042         /* Fail if failed */
1043         if (DeviceExtension->PortConfig == NULL)
1044         {
1045             Status = STATUS_INSUFFICIENT_RESOURCES;
1046             break;
1047         }
1048 
1049         Status = SpiCreatePortConfig(DeviceExtension,
1050                                      HwInitializationData,
1051                                      &ConfigInfo,
1052                                      DeviceExtension->PortConfig,
1053                                      FirstConfigCall);
1054 
1055         if (!NT_SUCCESS(Status))
1056         {
1057             DPRINT("SpiCreatePortConfig() failed with Status 0x%08X\n", Status);
1058             break;
1059         }
1060 
1061         PortConfig = DeviceExtension->PortConfig;
1062 
1063         /* Copy extension sizes into the PortConfig */
1064         PortConfig->SpecificLuExtensionSize = DeviceExtension->LunExtensionSize;
1065         PortConfig->SrbExtensionSize = DeviceExtension->SrbExtensionSize;
1066 
1067         /* Initialize Access ranges */
1068         if (HwInitializationData->NumberOfAccessRanges != 0)
1069         {
1070             PortConfig->AccessRanges = ALIGN_UP_POINTER(PortConfig + 1, INT64);
1071 
1072             /* Copy the data */
1073             RtlCopyMemory(PortConfig->AccessRanges,
1074                           ConfigInfo.AccessRanges,
1075                           HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE));
1076         }
1077 
1078         /* Search for matching PCI device */
1079         if ((HwInitializationData->AdapterInterfaceType == PCIBus) &&
1080             (HwInitializationData->VendorIdLength > 0) &&
1081             (HwInitializationData->VendorId != NULL) &&
1082             (HwInitializationData->DeviceIdLength > 0) &&
1083             (HwInitializationData->DeviceId != NULL))
1084         {
1085             PortConfig->BusInterruptLevel = 0;
1086 
1087             /* Get PCI device data */
1088             DPRINT(
1089                 "VendorId '%.*s'  DeviceId '%.*s'\n", HwInitializationData->VendorIdLength,
1090                 HwInitializationData->VendorId, HwInitializationData->DeviceIdLength,
1091                 HwInitializationData->DeviceId);
1092 
1093             if (!SpiGetPciConfigData(
1094                     DriverObject, PortDeviceObject, HwInitializationData, PortConfig, RegistryPath,
1095                     ConfigInfo.BusNumber, &SlotNumber))
1096             {
1097                 /* Continue to the next bus, nothing here */
1098                 ConfigInfo.BusNumber++;
1099                 DeviceExtension->PortConfig = NULL;
1100                 ExFreePool(PortConfig);
1101                 Again = FALSE;
1102                 goto CreatePortConfig;
1103             }
1104 
1105             if (!PortConfig->BusInterruptLevel)
1106             {
1107                 /* Bypass this slot, because no interrupt was assigned */
1108                 DeviceExtension->PortConfig = NULL;
1109                 ExFreePool(PortConfig);
1110                 goto CreatePortConfig;
1111             }
1112         }
1113         else
1114         {
1115             DPRINT("Non-pci bus\n");
1116         }
1117 
1118         /* Note: HwFindAdapter is called once for each bus */
1119         Again = FALSE;
1120         DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber);
1121         Result = (HwInitializationData->HwFindAdapter)(
1122             &DeviceExtension->MiniPortDeviceExtension, HwContext, 0, /* BusInformation */
1123             ConfigInfo.Parameter,                                    /* ArgumentString */
1124             PortConfig, &Again);
1125 
1126         DPRINT("HwFindAdapter() Result: %lu  Again: %s\n", Result, (Again) ? "True" : "False");
1127 
1128         /* Free MapRegisterBase, it's not needed anymore */
1129         if (DeviceExtension->MapRegisterBase != NULL)
1130         {
1131             ExFreePool(DeviceExtension->MapRegisterBase);
1132             DeviceExtension->MapRegisterBase = NULL;
1133         }
1134 
1135         /* If result is nothing good... */
1136         if (Result != SP_RETURN_FOUND)
1137         {
1138             DPRINT("HwFindAdapter() Result: %lu\n", Result);
1139 
1140             if (Result == SP_RETURN_NOT_FOUND)
1141             {
1142                 /* We can continue on the next bus */
1143                 ConfigInfo.BusNumber++;
1144                 Again = FALSE;
1145 
1146                 DeviceExtension->PortConfig = NULL;
1147                 ExFreePool(PortConfig);
1148                 goto CreatePortConfig;
1149             }
1150 
1151             /* Otherwise, break */
1152             Status = STATUS_INTERNAL_ERROR;
1153             break;
1154         }
1155 
1156         DPRINT(
1157             "ScsiPortInitialize(): Found HBA! (%x), adapter Id %d\n",
1158             PortConfig->BusInterruptVector, PortConfig->InitiatorBusId[0]);
1159 
1160         /* If the SRB extension size was updated */
1161         if (!DeviceExtension->NonCachedExtension &&
1162             (PortConfig->SrbExtensionSize != DeviceExtension->SrbExtensionSize))
1163         {
1164             /* Set it (rounding to LONGLONG again) */
1165             DeviceExtension->SrbExtensionSize = ALIGN_UP(PortConfig->SrbExtensionSize, INT64);
1166         }
1167 
1168         /* The same with LUN extension size */
1169         if (PortConfig->SpecificLuExtensionSize != DeviceExtension->LunExtensionSize)
1170             DeviceExtension->LunExtensionSize = PortConfig->SpecificLuExtensionSize;
1171 
1172         /* Construct a resource list */
1173         ResourceList = SpiConfigToResource(DeviceExtension, PortConfig);
1174 
1175         PDEVICE_OBJECT LowerPDO = NULL;
1176 
1177         Status = IoReportDetectedDevice(DriverObject,
1178                                         HwInitializationData->AdapterInterfaceType,
1179                                         ConfigInfo.BusNumber,
1180                                         PortConfig->SlotNumber,
1181                                         ResourceList,
1182                                         NULL,
1183                                         TRUE,
1184                                         &LowerPDO);
1185 
1186         if (!NT_SUCCESS(Status))
1187         {
1188             DPRINT1("IoReportDetectedDevice failed. Status: 0x%x\n", Status);
1189             __debugbreak();
1190             break;
1191         }
1192 
1193         DeviceExtension->Common.LowerDevice = IoAttachDeviceToDeviceStack(PortDeviceObject, LowerPDO);
1194 
1195         ASSERT(DeviceExtension->Common.LowerDevice);
1196 
1197         PortDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1198 
1199         if (ResourceList)
1200         {
1201             ExFreePoolWithTag(ResourceList, TAG_SCSIPORT);
1202         }
1203 
1204         /* Copy all stuff which we ever need from PortConfig to the DeviceExtension */
1205         if (PortConfig->MaximumNumberOfTargets > SCSI_MAXIMUM_TARGETS_PER_BUS)
1206             DeviceExtension->MaxTargedIds = SCSI_MAXIMUM_TARGETS_PER_BUS;
1207         else
1208             DeviceExtension->MaxTargedIds = PortConfig->MaximumNumberOfTargets;
1209 
1210         DeviceExtension->NumberOfBuses = PortConfig->NumberOfBuses;
1211         DeviceExtension->CachesData = PortConfig->CachesData;
1212         DeviceExtension->ReceiveEvent = PortConfig->ReceiveEvent;
1213         DeviceExtension->SupportsTaggedQueuing = PortConfig->TaggedQueuing;
1214         DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu;
1215 
1216         /* Initialize bus scanning information */
1217         size_t BusConfigSize = DeviceExtension->NumberOfBuses * sizeof(*DeviceExtension->Buses);
1218         DeviceExtension->Buses = ExAllocatePoolZero(NonPagedPool, BusConfigSize, TAG_SCSIPORT);
1219         if (!DeviceExtension->Buses)
1220         {
1221             DPRINT1("Out of resources!\n");
1222             Status = STATUS_INSUFFICIENT_RESOURCES;
1223             break;
1224         }
1225 
1226         // initialize bus data
1227         for (UINT8 pathId = 0; pathId < DeviceExtension->NumberOfBuses; pathId++)
1228         {
1229             DeviceExtension->Buses[pathId].BusIdentifier =
1230                 DeviceExtension->PortConfig->InitiatorBusId[pathId];
1231             InitializeListHead(&DeviceExtension->Buses[pathId].LunsListHead);
1232         }
1233 
1234         /* If something was disabled via registry - apply it */
1235         if (ConfigInfo.DisableMultipleLun)
1236             DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu = FALSE;
1237 
1238         if (ConfigInfo.DisableTaggedQueueing)
1239             DeviceExtension->SupportsTaggedQueuing = PortConfig->MultipleRequestPerLu = FALSE;
1240 
1241         /* Check if we need to alloc SRB data */
1242         if (DeviceExtension->SupportsTaggedQueuing || DeviceExtension->MultipleReqsPerLun)
1243         {
1244             DeviceExtension->NeedSrbDataAlloc = TRUE;
1245         }
1246         else
1247         {
1248             DeviceExtension->NeedSrbDataAlloc = FALSE;
1249         }
1250 
1251         /* Get a pointer to the port capabilities */
1252         PortCapabilities = &DeviceExtension->PortCapabilities;
1253 
1254         /* Copy one field there */
1255         DeviceExtension->MapBuffers = PortConfig->MapBuffers;
1256         PortCapabilities->AdapterUsesPio = PortConfig->MapBuffers;
1257 
1258         if (DeviceExtension->AdapterObject == NULL &&
1259             (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE || PortConfig->Master))
1260         {
1261             DPRINT1("DMA is not supported yet\n");
1262             ASSERT(FALSE);
1263         }
1264 
1265         if (DeviceExtension->SrbExtensionBuffer == NULL &&
1266             (DeviceExtension->SrbExtensionSize != 0 || PortConfig->AutoRequestSense))
1267         {
1268             DeviceExtension->SupportsAutoSense = PortConfig->AutoRequestSense;
1269             DeviceExtension->NeedSrbExtensionAlloc = TRUE;
1270 
1271             /* Allocate common buffer */
1272             Status = SpiAllocateCommonBuffer(DeviceExtension, 0);
1273 
1274             /* Check for failure */
1275             if (!NT_SUCCESS(Status))
1276                 break;
1277         }
1278 
1279         /* Allocate SrbData, if needed */
1280         if (DeviceExtension->NeedSrbDataAlloc)
1281         {
1282             ULONG Count;
1283             PSCSI_REQUEST_BLOCK_INFO SrbData;
1284 
1285             if (DeviceExtension->SrbDataCount != 0)
1286                 Count = DeviceExtension->SrbDataCount;
1287             else
1288                 Count = DeviceExtension->RequestsNumber * 2;
1289 
1290             /* Allocate the data */
1291             SrbData = ExAllocatePoolWithTag(
1292                 NonPagedPool, Count * sizeof(SCSI_REQUEST_BLOCK_INFO), TAG_SCSIPORT);
1293             if (SrbData == NULL)
1294                 return STATUS_INSUFFICIENT_RESOURCES;
1295 
1296             RtlZeroMemory(SrbData, Count * sizeof(SCSI_REQUEST_BLOCK_INFO));
1297 
1298             DeviceExtension->SrbInfo = SrbData;
1299             DeviceExtension->FreeSrbInfo = SrbData;
1300             DeviceExtension->SrbDataCount = Count;
1301 
1302             /* Link it to the list */
1303             while (Count > 0)
1304             {
1305                 SrbData->Requests.Flink = (PLIST_ENTRY)(SrbData + 1);
1306                 SrbData++;
1307                 Count--;
1308             }
1309 
1310             /* Mark the last entry of the list */
1311             SrbData--;
1312             SrbData->Requests.Flink = NULL;
1313         }
1314 
1315         /* Initialize port capabilities */
1316         PortCapabilities = &DeviceExtension->PortCapabilities;
1317         PortCapabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
1318         PortCapabilities->MaximumTransferLength = PortConfig->MaximumTransferLength;
1319 
1320         if (PortConfig->ReceiveEvent)
1321             PortCapabilities->SupportedAsynchronousEvents |= SRBEV_SCSI_ASYNC_NOTIFICATION;
1322 
1323         PortCapabilities->TaggedQueuing = DeviceExtension->SupportsTaggedQueuing;
1324         PortCapabilities->AdapterScansDown = PortConfig->AdapterScansDown;
1325 
1326         if (PortConfig->AlignmentMask > PortDeviceObject->AlignmentRequirement)
1327             PortDeviceObject->AlignmentRequirement = PortConfig->AlignmentMask;
1328 
1329         PortCapabilities->AlignmentMask = PortDeviceObject->AlignmentRequirement;
1330 
1331         if (PortCapabilities->MaximumPhysicalPages == 0)
1332         {
1333             PortCapabilities->MaximumPhysicalPages =
1334                 BYTES_TO_PAGES(PortCapabilities->MaximumTransferLength);
1335 
1336             /* Apply miniport's limits */
1337             if (PortConfig->NumberOfPhysicalBreaks < PortCapabilities->MaximumPhysicalPages)
1338             {
1339                 PortCapabilities->MaximumPhysicalPages = PortConfig->NumberOfPhysicalBreaks;
1340             }
1341         }
1342 
1343         FdoCallHWInitialize(DeviceExtension);
1344 
1345         Status = FdoStartAdapter(DeviceExtension);
1346 
1347         if (!NT_SUCCESS(Status))
1348         {
1349             DPRINT1("Failed to start the legacy adapter. Status 0x%x\n", Status);
1350             break;
1351         }
1352 
1353         FdoScanAdapter(DeviceExtension);
1354 
1355         FirstConfigCall = FALSE;
1356 
1357         /* Increase adapter number and bus number respectively */
1358         ConfigInfo.AdapterNumber++;
1359 
1360         if (!Again)
1361             ConfigInfo.BusNumber++;
1362 
1363         DPRINT("  Bus: %lu\n", ConfigInfo.BusNumber);
1364 
1365         DeviceFound = TRUE;
1366     }
1367 
1368     /* Clean up the mess */
1369     if (!NT_SUCCESS(Status) && PortDeviceObject)
1370     {
1371         FdoRemoveAdapter(DeviceExtension);
1372     }
1373 
1374     /* Close registry keys */
1375     if (ConfigInfo.ServiceKey != NULL)
1376         ZwClose(ConfigInfo.ServiceKey);
1377 
1378     if (ConfigInfo.DeviceKey != NULL)
1379         ZwClose(ConfigInfo.DeviceKey);
1380 
1381     if (ConfigInfo.BusKey != NULL)
1382         ZwClose(ConfigInfo.BusKey);
1383 
1384     if (ConfigInfo.AccessRanges != NULL)
1385         ExFreePool(ConfigInfo.AccessRanges);
1386 
1387     if (ConfigInfo.Parameter != NULL)
1388         ExFreePool(ConfigInfo.Parameter);
1389 
1390     DPRINT("ScsiPortInitialize() done, Status = 0x%08X, DeviceFound = %d!\n",
1391         Status, DeviceFound);
1392 
1393     return (DeviceFound == FALSE) ? Status : STATUS_SUCCESS;
1394 }
1395 
1396 /*
1397  * @unimplemented
1398  */
1399 VOID NTAPI
ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension,IN PSCSI_REQUEST_BLOCK Srb,IN PVOID LogicalAddress,IN ULONG Length)1400 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension,
1401               IN PSCSI_REQUEST_BLOCK Srb,
1402               IN PVOID LogicalAddress,
1403               IN ULONG Length)
1404 {
1405   DPRINT1("ScsiPortIoMapTransfer()\n");
1406   UNIMPLEMENTED;
1407 }
1408 
1409 /*
1410  * @unimplemented
1411  */
1412 VOID NTAPI
ScsiPortLogError(IN PVOID HwDeviceExtension,IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,IN UCHAR PathId,IN UCHAR TargetId,IN UCHAR Lun,IN ULONG ErrorCode,IN ULONG UniqueId)1413 ScsiPortLogError(IN PVOID HwDeviceExtension,
1414          IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
1415          IN UCHAR PathId,
1416          IN UCHAR TargetId,
1417          IN UCHAR Lun,
1418          IN ULONG ErrorCode,
1419          IN ULONG UniqueId)
1420 {
1421   //PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1422 
1423   DPRINT1("ScsiPortLogError() called\n");
1424   DPRINT1("PathId: 0x%02x  TargetId: 0x%02x  Lun: 0x%02x  ErrorCode: 0x%08lx  UniqueId: 0x%08lx\n",
1425           PathId, TargetId, Lun, ErrorCode, UniqueId);
1426 
1427   //DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, SCSI_PORT_DEVICE_EXTENSION, MiniPortDeviceExtension);
1428 
1429 
1430   DPRINT("ScsiPortLogError() done\n");
1431 }
1432 
1433 /*
1434  * @implemented
1435  */
1436 VOID NTAPI
ScsiPortMoveMemory(OUT PVOID Destination,IN PVOID Source,IN ULONG Length)1437 ScsiPortMoveMemory(OUT PVOID Destination,
1438            IN PVOID Source,
1439            IN ULONG Length)
1440 {
1441   RtlMoveMemory(Destination,
1442         Source,
1443         Length);
1444 }
1445 
1446 
1447 /*
1448  * @implemented
1449  */
1450 VOID
ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType,IN PVOID HwDeviceExtension,...)1451 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType, IN PVOID HwDeviceExtension, ...)
1452 {
1453     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1454     va_list ap;
1455 
1456     DPRINT("ScsiPortNotification() called\n");
1457 
1458     DeviceExtension =
1459         CONTAINING_RECORD(HwDeviceExtension, SCSI_PORT_DEVICE_EXTENSION, MiniPortDeviceExtension);
1460 
1461     DPRINT("DeviceExtension %p\n", DeviceExtension);
1462 
1463     va_start(ap, HwDeviceExtension);
1464 
1465     switch (NotificationType)
1466     {
1467         case RequestComplete:
1468         {
1469             PSCSI_REQUEST_BLOCK Srb;
1470             PSCSI_REQUEST_BLOCK_INFO SrbData;
1471 
1472             Srb = (PSCSI_REQUEST_BLOCK)va_arg(ap, PSCSI_REQUEST_BLOCK);
1473 
1474             DPRINT("Notify: RequestComplete (Srb %p)\n", Srb);
1475 
1476             /* Make sure Srb is alright */
1477             ASSERT(Srb->SrbStatus != SRB_STATUS_PENDING);
1478             ASSERT(
1479                 Srb->Function != SRB_FUNCTION_EXECUTE_SCSI ||
1480                 Srb->SrbStatus != SRB_STATUS_SUCCESS || Srb->ScsiStatus == SCSISTAT_GOOD);
1481 
1482             if (!(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE))
1483             {
1484                 /* It's been already completed */
1485                 va_end(ap);
1486                 return;
1487             }
1488 
1489             /* It's not active anymore */
1490             Srb->SrbFlags &= ~SRB_FLAGS_IS_ACTIVE;
1491 
1492             if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
1493             {
1494                 /* TODO: Treat it specially */
1495                 ASSERT(FALSE);
1496             }
1497             else
1498             {
1499                 PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Srb->OriginalRequest);
1500                 PSCSI_PORT_LUN_EXTENSION LunExtension = IoStack->DeviceObject->DeviceExtension;
1501                 ASSERT(LunExtension && !LunExtension->Common.IsFDO);
1502 
1503                 /* Get the SRB data */
1504                 SrbData = SpiGetSrbData(DeviceExtension, LunExtension, Srb->QueueTag);
1505 
1506                 /* Make sure there are no CompletedRequests and there is a Srb */
1507                 ASSERT(SrbData->CompletedRequests == NULL && SrbData->Srb != NULL);
1508 
1509                 /* If it's a read/write request, make sure it has data inside it */
1510                 if ((Srb->SrbStatus == SRB_STATUS_SUCCESS) &&
1511                     ((Srb->Cdb[0] == SCSIOP_READ) || (Srb->Cdb[0] == SCSIOP_WRITE)))
1512                 {
1513                     ASSERT(Srb->DataTransferLength);
1514                 }
1515 
1516                 SrbData->CompletedRequests = DeviceExtension->InterruptData.CompletedRequests;
1517                 DeviceExtension->InterruptData.CompletedRequests = SrbData;
1518             }
1519         }
1520         break;
1521 
1522         case NextRequest:
1523             DPRINT("Notify: NextRequest\n");
1524             DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY;
1525             break;
1526 
1527         case NextLuRequest:
1528         {
1529             UCHAR PathId;
1530             UCHAR TargetId;
1531             UCHAR Lun;
1532             PSCSI_PORT_LUN_EXTENSION LunExtension;
1533 
1534             PathId = (UCHAR)va_arg(ap, int);
1535             TargetId = (UCHAR)va_arg(ap, int);
1536             Lun = (UCHAR)va_arg(ap, int);
1537 
1538             DPRINT(
1539                 "Notify: NextLuRequest(PathId %u  TargetId %u  Lun %u)\n", PathId, TargetId, Lun);
1540 
1541             /* Mark it in the flags field */
1542             DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY;
1543 
1544             /* Get the LUN extension */
1545             LunExtension = GetLunByPath(DeviceExtension, PathId, TargetId, Lun);
1546 
1547             /* If returned LunExtension is NULL, break out */
1548             if (!LunExtension)
1549                 break;
1550 
1551             /* This request should not be processed if */
1552             if ((LunExtension->ReadyLun) || (LunExtension->SrbInfo.Srb))
1553             {
1554                 /* Nothing to do here */
1555                 break;
1556             }
1557 
1558             /* Add this LUN to the list */
1559             LunExtension->ReadyLun = DeviceExtension->InterruptData.ReadyLun;
1560             DeviceExtension->InterruptData.ReadyLun = LunExtension;
1561         }
1562         break;
1563 
1564         case ResetDetected:
1565             DPRINT("Notify: ResetDetected\n");
1566             /* Add RESET flags */
1567             DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET | SCSI_PORT_RESET_REPORTED;
1568             break;
1569 
1570         case CallDisableInterrupts:
1571             DPRINT1("UNIMPLEMENTED SCSI Notification called: CallDisableInterrupts!\n");
1572             break;
1573 
1574         case CallEnableInterrupts:
1575             DPRINT1("UNIMPLEMENTED SCSI Notification called: CallEnableInterrupts!\n");
1576             break;
1577 
1578         case RequestTimerCall:
1579             DPRINT("Notify: RequestTimerCall\n");
1580             DeviceExtension->InterruptData.Flags |= SCSI_PORT_TIMER_NEEDED;
1581             DeviceExtension->InterruptData.HwScsiTimer = (PHW_TIMER)va_arg(ap, PHW_TIMER);
1582             DeviceExtension->InterruptData.MiniportTimerValue = (ULONG)va_arg(ap, ULONG);
1583             break;
1584 
1585         case BusChangeDetected:
1586             DPRINT1("UNIMPLEMENTED SCSI Notification called: BusChangeDetected!\n");
1587             break;
1588 
1589         default:
1590             DPRINT1("Unsupported notification from WMI: %lu\n", NotificationType);
1591             break;
1592     }
1593 
1594     va_end(ap);
1595 
1596     /* Request a DPC after we're done with the interrupt */
1597     DeviceExtension->InterruptData.Flags |= SCSI_PORT_NOTIFICATION_NEEDED;
1598 }
1599 
1600 /*
1601  * @implemented
1602  */
1603 BOOLEAN NTAPI
ScsiPortValidateRange(IN PVOID HwDeviceExtension,IN INTERFACE_TYPE BusType,IN ULONG SystemIoBusNumber,IN SCSI_PHYSICAL_ADDRESS IoAddress,IN ULONG NumberOfBytes,IN BOOLEAN InIoSpace)1604 ScsiPortValidateRange(IN PVOID HwDeviceExtension,
1605               IN INTERFACE_TYPE BusType,
1606               IN ULONG SystemIoBusNumber,
1607               IN SCSI_PHYSICAL_ADDRESS IoAddress,
1608               IN ULONG NumberOfBytes,
1609               IN BOOLEAN InIoSpace)
1610 {
1611   DPRINT("ScsiPortValidateRange()\n");
1612   return(TRUE);
1613 }
1614 
1615 
1616 /* INTERNAL FUNCTIONS ********************************************************/
1617 
1618 static VOID
SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData,IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor,IN PPORT_CONFIGURATION_INFORMATION PortConfig)1619 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData,
1620                     IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor,
1621                     IN PPORT_CONFIGURATION_INFORMATION PortConfig)
1622 {
1623     PACCESS_RANGE AccessRange;
1624     PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialData;
1625     ULONG RangeNumber;
1626     ULONG Index;
1627     ULONG Interrupt = 0;
1628     ULONG Dma = 0;
1629 
1630     RangeNumber = 0;
1631 
1632     /* Loop through all entries */
1633     for (Index = 0; Index < ResourceDescriptor->PartialResourceList.Count; Index++)
1634     {
1635         PartialData = &ResourceDescriptor->PartialResourceList.PartialDescriptors[Index];
1636 
1637         switch (PartialData->Type)
1638         {
1639         case CmResourceTypePort:
1640             /* Copy access ranges */
1641             if (RangeNumber < HwInitializationData->NumberOfAccessRanges)
1642             {
1643                 AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]);
1644 
1645                 AccessRange->RangeStart = PartialData->u.Port.Start;
1646                 AccessRange->RangeLength = PartialData->u.Port.Length;
1647 
1648                 AccessRange->RangeInMemory = FALSE;
1649                 RangeNumber++;
1650             }
1651             break;
1652 
1653         case CmResourceTypeMemory:
1654             /* Copy access ranges */
1655             if (RangeNumber < HwInitializationData->NumberOfAccessRanges)
1656             {
1657                 AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]);
1658 
1659                 AccessRange->RangeStart = PartialData->u.Memory.Start;
1660                 AccessRange->RangeLength = PartialData->u.Memory.Length;
1661 
1662                 AccessRange->RangeInMemory = TRUE;
1663                 RangeNumber++;
1664             }
1665             break;
1666 
1667         case CmResourceTypeInterrupt:
1668 
1669             if (Interrupt == 0)
1670             {
1671                 /* Copy interrupt data */
1672                 PortConfig->BusInterruptLevel = PartialData->u.Interrupt.Level;
1673                 PortConfig->BusInterruptVector = PartialData->u.Interrupt.Vector;
1674 
1675                 /* Set interrupt mode accordingly to the resource */
1676                 if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
1677                 {
1678                     PortConfig->InterruptMode = Latched;
1679                 }
1680                 else if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
1681                 {
1682                     PortConfig->InterruptMode = LevelSensitive;
1683                 }
1684             }
1685             else if (Interrupt == 1)
1686             {
1687                 /* Copy interrupt data */
1688                 PortConfig->BusInterruptLevel2 = PartialData->u.Interrupt.Level;
1689                 PortConfig->BusInterruptVector2 = PartialData->u.Interrupt.Vector;
1690 
1691                 /* Set interrupt mode accordingly to the resource */
1692                 if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
1693                 {
1694                     PortConfig->InterruptMode2 = Latched;
1695                 }
1696                 else if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
1697                 {
1698                     PortConfig->InterruptMode2 = LevelSensitive;
1699                 }
1700             }
1701 
1702             Interrupt++;
1703             break;
1704 
1705         case CmResourceTypeDma:
1706 
1707             if (Dma == 0)
1708             {
1709                 PortConfig->DmaChannel = PartialData->u.Dma.Channel;
1710                 PortConfig->DmaPort = PartialData->u.Dma.Port;
1711 
1712                 if (PartialData->Flags & CM_RESOURCE_DMA_8)
1713                     PortConfig->DmaWidth = Width8Bits;
1714                 else if ((PartialData->Flags & CM_RESOURCE_DMA_16) ||
1715                          (PartialData->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
1716                     PortConfig->DmaWidth = Width16Bits;
1717                 else if (PartialData->Flags & CM_RESOURCE_DMA_32)
1718                     PortConfig->DmaWidth = Width32Bits;
1719             }
1720             else if (Dma == 1)
1721             {
1722                 PortConfig->DmaChannel2 = PartialData->u.Dma.Channel;
1723                 PortConfig->DmaPort2 = PartialData->u.Dma.Port;
1724 
1725                 if (PartialData->Flags & CM_RESOURCE_DMA_8)
1726                     PortConfig->DmaWidth2 = Width8Bits;
1727                 else if ((PartialData->Flags & CM_RESOURCE_DMA_16) ||
1728                          (PartialData->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
1729                     PortConfig->DmaWidth2 = Width16Bits;
1730                 else if (PartialData->Flags & CM_RESOURCE_DMA_32)
1731                     PortConfig->DmaWidth2 = Width32Bits;
1732             }
1733             break;
1734         }
1735     }
1736 }
1737 
1738 static PCM_RESOURCE_LIST
SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,PPORT_CONFIGURATION_INFORMATION PortConfig)1739 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1740                     PPORT_CONFIGURATION_INFORMATION PortConfig)
1741 {
1742     PCONFIGURATION_INFORMATION ConfigInfo;
1743     PCM_RESOURCE_LIST ResourceList;
1744     PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor;
1745     PACCESS_RANGE AccessRange;
1746     ULONG ListLength = 0, i, FullSize;
1747     ULONG Interrupt, Dma;
1748 
1749     /* Get current Atdisk usage from the system */
1750     ConfigInfo = IoGetConfigurationInformation();
1751 
1752     if (PortConfig->AtdiskPrimaryClaimed)
1753         ConfigInfo->AtDiskPrimaryAddressClaimed = TRUE;
1754 
1755     if (PortConfig->AtdiskSecondaryClaimed)
1756         ConfigInfo->AtDiskSecondaryAddressClaimed = TRUE;
1757 
1758     /* Do we use DMA? */
1759     if (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE ||
1760         PortConfig->DmaPort != SP_UNINITIALIZED_VALUE)
1761     {
1762         Dma = 1;
1763 
1764         if (PortConfig->DmaChannel2 != SP_UNINITIALIZED_VALUE ||
1765             PortConfig->DmaPort2 != SP_UNINITIALIZED_VALUE)
1766             Dma++;
1767     }
1768     else
1769     {
1770         Dma = 0;
1771     }
1772     ListLength += Dma;
1773 
1774     /* How many interrupts to we have? */
1775     Interrupt = DeviceExtension->InterruptCount;
1776     ListLength += Interrupt;
1777 
1778     /* How many access ranges do we use? */
1779     AccessRange = &((*(PortConfig->AccessRanges))[0]);
1780     for (i = 0; i < PortConfig->NumberOfAccessRanges; i++)
1781     {
1782         if (AccessRange->RangeLength != 0)
1783             ListLength++;
1784 
1785         AccessRange++;
1786     }
1787 
1788     /* Allocate the resource list, since we know its size now */
1789     FullSize = sizeof(CM_RESOURCE_LIST) + (ListLength - 1) *
1790         sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1791 
1792     ResourceList = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(PagedPool, FullSize, TAG_SCSIPORT);
1793 
1794     if (!ResourceList)
1795         return NULL;
1796 
1797     /* Zero it */
1798     RtlZeroMemory(ResourceList, FullSize);
1799 
1800     /* Initialize it */
1801     ResourceList->Count = 1;
1802     ResourceList->List[0].InterfaceType = PortConfig->AdapterInterfaceType;
1803     ResourceList->List[0].BusNumber = PortConfig->SystemIoBusNumber;
1804     ResourceList->List[0].PartialResourceList.Count = ListLength;
1805     ResourceDescriptor = ResourceList->List[0].PartialResourceList.PartialDescriptors;
1806 
1807     /* Copy access ranges array over */
1808     for (i = 0; i < PortConfig->NumberOfAccessRanges; i++)
1809     {
1810         AccessRange = &((*(PortConfig->AccessRanges))[i]);
1811 
1812         /* If the range is empty - skip it */
1813         if (AccessRange->RangeLength == 0)
1814             continue;
1815 
1816         if (AccessRange->RangeInMemory)
1817         {
1818             ResourceDescriptor->Type = CmResourceTypeMemory;
1819             ResourceDescriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
1820         }
1821         else
1822         {
1823             ResourceDescriptor->Type = CmResourceTypePort;
1824             ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
1825         }
1826 
1827         ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1828 
1829         ResourceDescriptor->u.Memory.Start = AccessRange->RangeStart;
1830         ResourceDescriptor->u.Memory.Length = AccessRange->RangeLength;
1831 
1832         ResourceDescriptor++;
1833     }
1834 
1835     /* If we use interrupt(s), copy them */
1836     while (Interrupt)
1837     {
1838         ResourceDescriptor->Type = CmResourceTypeInterrupt;
1839 
1840         if (PortConfig->AdapterInterfaceType == MicroChannel ||
1841             ((Interrupt == 2) ? PortConfig->InterruptMode2 : PortConfig->InterruptMode) == LevelSensitive)
1842         {
1843             ResourceDescriptor->ShareDisposition = CmResourceShareShared;
1844             ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
1845         }
1846         else
1847         {
1848             ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1849             ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
1850         }
1851 
1852         ResourceDescriptor->u.Interrupt.Level = (Interrupt == 2) ? PortConfig->BusInterruptLevel2 : PortConfig->BusInterruptLevel;
1853         ResourceDescriptor->u.Interrupt.Vector = (Interrupt == 2) ? PortConfig->BusInterruptVector2 : PortConfig->BusInterruptVector;
1854         ResourceDescriptor->u.Interrupt.Affinity = 0;
1855 
1856         ResourceDescriptor++;
1857         Interrupt--;
1858     }
1859 
1860     /* Copy DMA data */
1861     while (Dma)
1862     {
1863         ResourceDescriptor->Type = CmResourceTypeDma;
1864         ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1865         ResourceDescriptor->u.Dma.Channel = (Dma == 2) ? PortConfig->DmaChannel2 : PortConfig->DmaChannel;
1866         ResourceDescriptor->u.Dma.Port = (Dma == 2) ? PortConfig->DmaPort2 : PortConfig->DmaPort;
1867         ResourceDescriptor->Flags = 0;
1868 
1869         if (((Dma == 2) ? PortConfig->DmaWidth2 : PortConfig->DmaWidth) == Width8Bits)
1870             ResourceDescriptor->Flags |= CM_RESOURCE_DMA_8;
1871         else if (((Dma == 2) ? PortConfig->DmaWidth2 : PortConfig->DmaWidth) == Width16Bits)
1872             ResourceDescriptor->Flags |= CM_RESOURCE_DMA_16;
1873         else
1874             ResourceDescriptor->Flags |= CM_RESOURCE_DMA_32;
1875 
1876         if (((Dma == 2) ? PortConfig->DmaChannel2 : PortConfig->DmaChannel) == SP_UNINITIALIZED_VALUE)
1877             ResourceDescriptor->u.Dma.Channel = 0;
1878 
1879         if (((Dma == 2) ? PortConfig->DmaPort2 : PortConfig->DmaPort) == SP_UNINITIALIZED_VALUE)
1880             ResourceDescriptor->u.Dma.Port = 0;
1881 
1882         ResourceDescriptor++;
1883         Dma--;
1884     }
1885 
1886     return ResourceList;
1887 }
1888 
1889 
1890 static BOOLEAN
SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT DeviceObject,IN struct _HW_INITIALIZATION_DATA * HwInitializationData,IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,IN PUNICODE_STRING RegistryPath,IN ULONG BusNumber,IN OUT PPCI_SLOT_NUMBER NextSlotNumber)1891 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject,
1892                     IN PDEVICE_OBJECT DeviceObject,
1893                     IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
1894                     IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,
1895                     IN PUNICODE_STRING RegistryPath,
1896                     IN ULONG BusNumber,
1897                     IN OUT PPCI_SLOT_NUMBER NextSlotNumber)
1898 {
1899     PCI_COMMON_CONFIG PciConfig;
1900     PCI_SLOT_NUMBER SlotNumber;
1901     ULONG DataSize;
1902     ULONG DeviceNumber;
1903     ULONG FunctionNumber;
1904     CHAR VendorIdString[8];
1905     CHAR DeviceIdString[8];
1906     UNICODE_STRING UnicodeStr;
1907     PCM_RESOURCE_LIST ResourceList = NULL;
1908     NTSTATUS Status;
1909 
1910     DPRINT ("SpiGetPciConfiguration() called\n");
1911 
1912     SlotNumber.u.AsULONG = 0;
1913 
1914     /* Loop through all devices */
1915     for (DeviceNumber = NextSlotNumber->u.bits.DeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
1916     {
1917         SlotNumber.u.bits.DeviceNumber = DeviceNumber;
1918 
1919         /* Loop through all functions */
1920         for (FunctionNumber = NextSlotNumber->u.bits.FunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
1921         {
1922             SlotNumber.u.bits.FunctionNumber = FunctionNumber;
1923 
1924             /* Get PCI config bytes */
1925             DataSize = HalGetBusData(PCIConfiguration,
1926                                      BusNumber,
1927                                      SlotNumber.u.AsULONG,
1928                                      &PciConfig,
1929                                      sizeof(ULONG));
1930 
1931             /* If result of HalGetBusData is 0, then the bus is wrong */
1932             if (DataSize == 0)
1933                 return FALSE;
1934 
1935             /* Check if result is PCI_INVALID_VENDORID or too small */
1936             if ((DataSize < sizeof(ULONG)) ||
1937                 (PciConfig.VendorID == PCI_INVALID_VENDORID))
1938             {
1939                 /* Continue to try the next function */
1940                 continue;
1941             }
1942 
1943             sprintf (VendorIdString, "%04hx", PciConfig.VendorID);
1944             sprintf (DeviceIdString, "%04hx", PciConfig.DeviceID);
1945 
1946             if (_strnicmp(VendorIdString, HwInitializationData->VendorId, HwInitializationData->VendorIdLength) ||
1947                 _strnicmp(DeviceIdString, HwInitializationData->DeviceId, HwInitializationData->DeviceIdLength))
1948             {
1949                 /* It is not our device */
1950                 continue;
1951             }
1952 
1953             DPRINT("Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n",
1954                    PciConfig.VendorID,
1955                    PciConfig.DeviceID,
1956                    BusNumber,
1957                    SlotNumber.u.bits.DeviceNumber,
1958                    SlotNumber.u.bits.FunctionNumber);
1959 
1960 
1961             RtlInitUnicodeString(&UnicodeStr, L"ScsiAdapter");
1962             Status = HalAssignSlotResources(RegistryPath,
1963                                             &UnicodeStr,
1964                                             DriverObject,
1965                                             DeviceObject,
1966                                             PCIBus,
1967                                             BusNumber,
1968                                             SlotNumber.u.AsULONG,
1969                                             &ResourceList);
1970 
1971             if (!NT_SUCCESS(Status))
1972                 break;
1973 
1974             /* Create configuration information */
1975             SpiResourceToConfig(HwInitializationData,
1976                                 ResourceList->List,
1977                                 PortConfig);
1978 
1979             /* Free the resource list */
1980             ExFreePool(ResourceList);
1981 
1982             /* Set dev & fn numbers */
1983             NextSlotNumber->u.bits.DeviceNumber = DeviceNumber;
1984             NextSlotNumber->u.bits.FunctionNumber = FunctionNumber + 1;
1985 
1986             /* Save the slot number */
1987             PortConfig->SlotNumber = SlotNumber.u.AsULONG;
1988 
1989             return TRUE;
1990         }
1991        NextSlotNumber->u.bits.FunctionNumber = 0;
1992     }
1993 
1994     NextSlotNumber->u.bits.DeviceNumber = 0;
1995     DPRINT ("No device found\n");
1996 
1997     return FALSE;
1998 }
1999 
2000 
2001 
2002 /**********************************************************************
2003  * NAME                         INTERNAL
2004  *  ScsiPortCreateClose
2005  *
2006  * DESCRIPTION
2007  *  Answer requests for Create/Close calls: a null operation.
2008  *
2009  * RUN LEVEL
2010  *  PASSIVE_LEVEL
2011  *
2012  * ARGUMENTS
2013  *  DeviceObject
2014  *      Pointer to a device object.
2015  *
2016  *  Irp
2017  *      Pointer to an IRP.
2018  *
2019  * RETURN VALUE
2020  *  Status.
2021  */
2022 
2023 static NTSTATUS NTAPI
ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)2024 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
2025                    IN PIRP Irp)
2026 {
2027     DPRINT("ScsiPortCreateClose()\n");
2028 
2029     Irp->IoStatus.Status = STATUS_SUCCESS;
2030     IoCompleteRequest(Irp, IO_NO_INCREMENT);
2031 
2032     return STATUS_SUCCESS;
2033 }
2034 
2035 IO_ALLOCATION_ACTION
2036 NTAPI
SpiAdapterControl(PDEVICE_OBJECT DeviceObject,PIRP Irp,PVOID MapRegisterBase,PVOID Context)2037 SpiAdapterControl(PDEVICE_OBJECT DeviceObject,
2038                   PIRP Irp,
2039                   PVOID MapRegisterBase,
2040                   PVOID Context)
2041 {
2042     PSCSI_REQUEST_BLOCK Srb;
2043     PSCSI_SG_ADDRESS ScatterGatherList;
2044     KIRQL CurrentIrql;
2045     PIO_STACK_LOCATION IrpStack;
2046     ULONG TotalLength = 0;
2047     PSCSI_REQUEST_BLOCK_INFO SrbInfo;
2048     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2049     PUCHAR DataVA;
2050     BOOLEAN WriteToDevice;
2051 
2052     /* Get pointers to SrbInfo and DeviceExtension */
2053     SrbInfo = (PSCSI_REQUEST_BLOCK_INFO)Context;
2054     DeviceExtension = DeviceObject->DeviceExtension;
2055 
2056     /* Get pointer to SRB */
2057     IrpStack = IoGetCurrentIrpStackLocation(Irp);
2058     Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
2059 
2060     /* Depending on the map registers number, we allocate
2061        either from NonPagedPool, or from our static list */
2062     if (SrbInfo->NumberOfMapRegisters > MAX_SG_LIST)
2063     {
2064         SrbInfo->ScatterGather = ExAllocatePoolWithTag(
2065             NonPagedPool, SrbInfo->NumberOfMapRegisters * sizeof(SCSI_SG_ADDRESS), TAG_SCSIPORT);
2066 
2067         if (SrbInfo->ScatterGather == NULL)
2068             ASSERT(FALSE);
2069 
2070         Srb->SrbFlags |= SRB_FLAGS_SGLIST_FROM_POOL;
2071     }
2072     else
2073     {
2074         SrbInfo->ScatterGather = SrbInfo->ScatterGatherList;
2075     }
2076 
2077     /* Use chosen SG list source */
2078     ScatterGatherList = SrbInfo->ScatterGather;
2079 
2080     /* Save map registers base */
2081     SrbInfo->BaseOfMapRegister = MapRegisterBase;
2082 
2083     /* Determine WriteToDevice flag */
2084     WriteToDevice = Srb->SrbFlags & SRB_FLAGS_DATA_OUT ? TRUE : FALSE;
2085 
2086     /* Get virtual address of the data buffer */
2087     DataVA = (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress) +
2088                 ((PCHAR)Srb->DataBuffer - SrbInfo->DataOffset);
2089 
2090     /* Build the actual SG list */
2091     while (TotalLength < Srb->DataTransferLength)
2092     {
2093         if (!ScatterGatherList)
2094             break;
2095 
2096         ScatterGatherList->Length = Srb->DataTransferLength - TotalLength;
2097         ScatterGatherList->PhysicalAddress = IoMapTransfer(DeviceExtension->AdapterObject,
2098                                                            Irp->MdlAddress,
2099                                                            MapRegisterBase,
2100                                                            DataVA + TotalLength,
2101                                                            &ScatterGatherList->Length,
2102                                                            WriteToDevice);
2103 
2104         TotalLength += ScatterGatherList->Length;
2105         ScatterGatherList++;
2106     }
2107 
2108     /* Schedule an active request */
2109     InterlockedIncrement(&DeviceExtension->ActiveRequestCounter );
2110     KeAcquireSpinLock(&DeviceExtension->SpinLock, &CurrentIrql);
2111     KeSynchronizeExecution(DeviceExtension->Interrupt[0],
2112                            ScsiPortStartPacket,
2113                            DeviceObject);
2114     KeReleaseSpinLock(&DeviceExtension->SpinLock, CurrentIrql);
2115 
2116     return DeallocateObjectKeepRegisters;
2117 }
2118 
2119 BOOLEAN
2120 NTAPI
ScsiPortIsr(_In_ PKINTERRUPT Interrupt,_In_ PVOID ServiceContext)2121 ScsiPortIsr(
2122     _In_ PKINTERRUPT Interrupt,
2123     _In_ PVOID ServiceContext)
2124 {
2125     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2126 
2127     DPRINT("ScsiPortIsr() called!\n");
2128 
2129     DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext;
2130 
2131     /* If interrupts are disabled - we don't expect any */
2132     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_DISABLE_INTERRUPTS)
2133         return FALSE;
2134 
2135     /* Call miniport's HwInterrupt routine */
2136     if (DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension) == FALSE)
2137     {
2138         /* This interrupt doesn't belong to us */
2139         return FALSE;
2140     }
2141 
2142     /* If flag of notification is set - queue a DPC */
2143     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
2144     {
2145         IoRequestDpc(DeviceExtension->Common.DeviceObject,
2146                      DeviceExtension->CurrentIrp,
2147                      DeviceExtension);
2148     }
2149 
2150     return TRUE;
2151 }
2152 
2153 BOOLEAN
2154 NTAPI
SpiProcessTimeout(PVOID ServiceContext)2155 SpiProcessTimeout(PVOID ServiceContext)
2156 {
2157     PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)ServiceContext;
2158     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
2159     ULONG Bus;
2160 
2161     DPRINT("SpiProcessTimeout() entered\n");
2162 
2163     DeviceExtension->TimerCount = -1;
2164 
2165     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET)
2166     {
2167         DeviceExtension->InterruptData.Flags &= ~SCSI_PORT_RESET;
2168 
2169         if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET_REQUEST)
2170         {
2171             DeviceExtension->InterruptData.Flags &=  ~SCSI_PORT_RESET_REQUEST;
2172             ScsiPortStartPacket(ServiceContext);
2173         }
2174 
2175         return FALSE;
2176     }
2177     else
2178     {
2179         DPRINT("Resetting the bus\n");
2180 
2181         for (Bus = 0; Bus < DeviceExtension->NumberOfBuses; Bus++)
2182         {
2183             DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension, Bus);
2184 
2185             /* Reset flags and set reset timeout to 4 seconds */
2186             DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET;
2187             DeviceExtension->TimerCount = 4;
2188         }
2189 
2190         /* If miniport requested - request a dpc for it */
2191         if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
2192             IoRequestDpc(DeviceExtension->Common.DeviceObject, NULL, NULL);
2193     }
2194 
2195     return TRUE;
2196 }
2197 
2198 
2199 BOOLEAN
2200 NTAPI
SpiResetBus(PVOID ServiceContext)2201 SpiResetBus(PVOID ServiceContext)
2202 {
2203     PRESETBUS_PARAMS ResetParams = (PRESETBUS_PARAMS)ServiceContext;
2204     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2205 
2206     /* Perform the bus reset */
2207     DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ResetParams->DeviceExtension;
2208     DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension,
2209                                 ResetParams->PathId);
2210 
2211     /* Set flags and start the timer */
2212     DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET;
2213     DeviceExtension->TimerCount = 4;
2214 
2215     /* If miniport requested - give him a DPC */
2216     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
2217         IoRequestDpc(DeviceExtension->Common.DeviceObject, NULL, NULL);
2218 
2219     return TRUE;
2220 }
2221 
2222 //    ScsiPortIoTimer
2223 //  DESCRIPTION:
2224 //    This function handles timeouts and other time delayed processing
2225 //
2226 //  RUN LEVEL:
2227 //
2228 //  ARGUMENTS:
2229 //    IN  PDEVICE_OBJECT  DeviceObject  Device object registered with timer
2230 //    IN  PVOID           Context       the Controller extension for the
2231 //                                      controller the device is on
2232 //
2233 static VOID NTAPI
ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,PVOID Context)2234 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
2235                 PVOID Context)
2236 {
2237     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2238     PSCSI_PORT_LUN_EXTENSION LunExtension;
2239     PIRP Irp;
2240 
2241     DPRINT("ScsiPortIoTimer()\n");
2242 
2243     DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
2244 
2245     /* Protect with the spinlock */
2246     KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
2247 
2248     /* Check timeouts */
2249     if (DeviceExtension->TimerCount > 0)
2250     {
2251         /* Decrease the timeout counter */
2252         DeviceExtension->TimerCount--;
2253 
2254         if (DeviceExtension->TimerCount == 0)
2255         {
2256             /* Timeout, process it */
2257             if (KeSynchronizeExecution(DeviceExtension->Interrupt[0],
2258                                        SpiProcessTimeout,
2259                                        DeviceExtension->Common.DeviceObject))
2260             {
2261                 DPRINT("Error happened during processing timeout, but nothing critical\n");
2262             }
2263         }
2264 
2265         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
2266 
2267         /* We should exit now, since timeout is processed */
2268         return;
2269     }
2270 
2271     /* Per-Lun scanning of timeouts is needed... */
2272     for (UINT8 pathId = 0; pathId < DeviceExtension->NumberOfBuses; pathId++)
2273     {
2274         PSCSI_BUS_INFO bus = &DeviceExtension->Buses[pathId];
2275 
2276         for (PLIST_ENTRY lunEntry = bus->LunsListHead.Flink;
2277              lunEntry != &bus->LunsListHead;
2278              lunEntry = lunEntry->Flink)
2279         {
2280             LunExtension = CONTAINING_RECORD(lunEntry, SCSI_PORT_LUN_EXTENSION, LunEntry);
2281 
2282             if (LunExtension->Flags & LUNEX_BUSY)
2283             {
2284                 if (!(LunExtension->Flags &
2285                     (LUNEX_NEED_REQUEST_SENSE | LUNEX_FROZEN_QUEUE)))
2286                 {
2287                     DPRINT("Retrying busy request\n");
2288 
2289                     /* Clear flags, and retry busy request */
2290                     LunExtension->Flags &= ~(LUNEX_BUSY | LUNEX_FULL_QUEUE);
2291                     Irp = LunExtension->BusyRequest;
2292 
2293                     /* Clearing busy request */
2294                     LunExtension->BusyRequest = NULL;
2295 
2296                     KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
2297 
2298                     IoStartPacket(DeviceObject, Irp, (PULONG)NULL, NULL);
2299 
2300                     KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
2301                 }
2302             }
2303             else if (LunExtension->RequestTimeout == 0)
2304             {
2305                 RESETBUS_PARAMS ResetParams;
2306 
2307                 LunExtension->RequestTimeout = -1;
2308 
2309                 DPRINT("Request timed out, resetting bus\n");
2310 
2311                 /* Pass params to the bus reset routine */
2312                 ResetParams.PathId = LunExtension->PathId;
2313                 ResetParams.DeviceExtension = DeviceExtension;
2314 
2315                 if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0],
2316                                             SpiResetBus,
2317                                             &ResetParams))
2318                 {
2319                     DPRINT1("Reset failed\n");
2320                 }
2321             }
2322             else if (LunExtension->RequestTimeout > 0)
2323             {
2324                 /* Decrement the timeout counter */
2325                 LunExtension->RequestTimeout--;
2326             }
2327         }
2328     }
2329 
2330     /* Release the spinlock */
2331     KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
2332 }
2333 
2334 VOID
2335 NTAPI
SpiMiniportTimerDpc(IN struct _KDPC * Dpc,IN PVOID DeviceObject,IN PVOID SystemArgument1,IN PVOID SystemArgument2)2336 SpiMiniportTimerDpc(IN struct _KDPC *Dpc,
2337                     IN PVOID DeviceObject,
2338                     IN PVOID SystemArgument1,
2339                     IN PVOID SystemArgument2)
2340 {
2341     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2342 
2343     DPRINT("Miniport timer DPC\n");
2344 
2345     DeviceExtension = ((PDEVICE_OBJECT)DeviceObject)->DeviceExtension;
2346 
2347     /* Acquire the spinlock */
2348     KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
2349 
2350     /* Call the timer routine */
2351     if (DeviceExtension->HwScsiTimer != NULL)
2352     {
2353         DeviceExtension->HwScsiTimer(&DeviceExtension->MiniPortDeviceExtension);
2354     }
2355 
2356     /* Release the spinlock */
2357     KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
2358 
2359     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
2360     {
2361         ScsiPortDpcForIsr(NULL,
2362                           DeviceExtension->Common.DeviceObject,
2363                           NULL,
2364                           NULL);
2365     }
2366 }
2367 
2368 static NTSTATUS
SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,PHW_INITIALIZATION_DATA HwInitData,PCONFIGURATION_INFO InternalConfigInfo,PPORT_CONFIGURATION_INFORMATION ConfigInfo,BOOLEAN ZeroStruct)2369 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
2370                     PHW_INITIALIZATION_DATA HwInitData,
2371                     PCONFIGURATION_INFO InternalConfigInfo,
2372                     PPORT_CONFIGURATION_INFORMATION ConfigInfo,
2373                     BOOLEAN ZeroStruct)
2374 {
2375     UNICODE_STRING UnicodeString;
2376     OBJECT_ATTRIBUTES ObjectAttributes;
2377     PCONFIGURATION_INFORMATION DdkConfigInformation;
2378     HANDLE RootKey, Key;
2379     BOOLEAN Found;
2380     WCHAR DeviceBuffer[16];
2381     WCHAR StrBuffer[512];
2382     ULONG Bus;
2383     NTSTATUS Status;
2384 
2385     /* Zero out the struct if told so */
2386     if (ZeroStruct)
2387     {
2388         /* First zero the portconfig */
2389         RtlZeroMemory(ConfigInfo, sizeof(PORT_CONFIGURATION_INFORMATION));
2390 
2391         /* Then access ranges */
2392         RtlZeroMemory(InternalConfigInfo->AccessRanges,
2393                       HwInitData->NumberOfAccessRanges * sizeof(ACCESS_RANGE));
2394 
2395         /* Initialize the struct */
2396         ConfigInfo->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
2397         ConfigInfo->AdapterInterfaceType = HwInitData->AdapterInterfaceType;
2398         ConfigInfo->InterruptMode = Latched;
2399         ConfigInfo->DmaChannel = SP_UNINITIALIZED_VALUE;
2400         ConfigInfo->DmaPort = SP_UNINITIALIZED_VALUE;
2401         ConfigInfo->DmaChannel2 = SP_UNINITIALIZED_VALUE;
2402         ConfigInfo->DmaPort2 = SP_UNINITIALIZED_VALUE;
2403         ConfigInfo->MaximumTransferLength = SP_UNINITIALIZED_VALUE;
2404         ConfigInfo->NumberOfAccessRanges = HwInitData->NumberOfAccessRanges;
2405         ConfigInfo->MaximumNumberOfTargets = SCSI_MAXIMUM_TARGETS; // NOTE: Using legacy value.
2406 
2407         /* Store parameters */
2408         ConfigInfo->NeedPhysicalAddresses = HwInitData->NeedPhysicalAddresses;
2409         ConfigInfo->MapBuffers = HwInitData->MapBuffers;
2410         ConfigInfo->AutoRequestSense = HwInitData->AutoRequestSense;
2411         ConfigInfo->ReceiveEvent = HwInitData->ReceiveEvent;
2412         ConfigInfo->TaggedQueuing = HwInitData->TaggedQueuing;
2413         ConfigInfo->MultipleRequestPerLu = HwInitData->MultipleRequestPerLu;
2414 
2415         /* Get the disk usage */
2416         DdkConfigInformation = IoGetConfigurationInformation();
2417         ConfigInfo->AtdiskPrimaryClaimed = DdkConfigInformation->AtDiskPrimaryAddressClaimed;
2418         ConfigInfo->AtdiskSecondaryClaimed = DdkConfigInformation->AtDiskSecondaryAddressClaimed;
2419 
2420         /* Initiator bus id is not set */
2421         for (Bus = 0; Bus < RTL_NUMBER_OF(ConfigInfo->InitiatorBusId); Bus++)
2422         {
2423             ConfigInfo->InitiatorBusId[Bus] = (CCHAR)SP_UNINITIALIZED_VALUE;
2424         }
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                 DPRINT("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
SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,IN HANDLE Key,IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,IN PCONFIGURATION_INFO InternalConfigInfo,IN PUCHAR Buffer)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)SP_UNINITIALIZED_VALUE;
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
SpQueryDeviceCallout(IN PVOID Context,IN PUNICODE_STRING PathName,IN INTERFACE_TYPE BusType,IN ULONG BusNumber,IN PKEY_VALUE_FULL_INFORMATION * BusInformation,IN CONFIGURATION_TYPE ControllerType,IN ULONG ControllerNumber,IN PKEY_VALUE_FULL_INFORMATION * ControllerInformation,IN CONFIGURATION_TYPE PeripheralType,IN ULONG PeripheralNumber,IN PKEY_VALUE_FULL_INFORMATION * PeripheralInformation)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
ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID MapRegisterBase,IN PVOID Context)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
ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address)3051 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address)
3052 {
3053   DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
3054   return(Address.u.LowPart);
3055 }
3056