1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 2001, 2002 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License along
16  *  with this program; if not, write to the Free Software Foundation, Inc.,
17  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 /*
20  * COPYRIGHT:       See COPYING in the top level directory
21  * PROJECT:         ReactOS Storage Stack
22  * FILE:            drivers/storage/scsiport/scsiport.c
23  * PURPOSE:         SCSI port driver
24  * PROGRAMMER:      Eric Kohl
25  *                  Aleksey Bragin (aleksey reactos org)
26  */
27 
28 /* INCLUDES *****************************************************************/
29 
30 #include "precomp.h"
31 
32 #include <ntddk.h>
33 #include <stdio.h>
34 #include <scsi.h>
35 #include <ntddscsi.h>
36 #include <ntdddisk.h>
37 #include <mountdev.h>
38 
39 #define NDEBUG
40 #include <debug.h>
41 
42 #include "scsiport_int.h"
43 
44 ULONG InternalDebugLevel = 0x00;
45 
46 #undef ScsiPortMoveMemory
47 
48 /* GLOBALS *******************************************************************/
49 
50 static BOOLEAN
51 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject,
52                     IN PDEVICE_OBJECT DeviceObject,
53                     IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
54                     IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,
55                     IN PUNICODE_STRING RegistryPath,
56                     IN ULONG BusNumber,
57                     IN OUT PPCI_SLOT_NUMBER NextSlotNumber);
58 
59 static NTSTATUS NTAPI
60 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
61 		    IN PIRP Irp);
62 
63 static DRIVER_DISPATCH ScsiPortDispatchScsi;
64 static NTSTATUS NTAPI
65 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
66 		     IN PIRP Irp);
67 
68 static NTSTATUS NTAPI
69 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
70 		      IN PIRP Irp);
71 
72 static DRIVER_STARTIO ScsiPortStartIo;
73 static VOID NTAPI
74 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
75 		IN PIRP Irp);
76 
77 static BOOLEAN NTAPI
78 ScsiPortStartPacket(IN OUT PVOID Context);
79 
80 IO_ALLOCATION_ACTION
81 NTAPI
82 SpiAdapterControl(PDEVICE_OBJECT DeviceObject, PIRP Irp,
83                   PVOID MapRegisterBase, PVOID Context);
84 
85 static PSCSI_PORT_LUN_EXTENSION
86 SpiAllocateLunExtension(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
87 
88 static PSCSI_PORT_LUN_EXTENSION
89 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
90 		    IN UCHAR PathId,
91 		    IN UCHAR TargetId,
92 		    IN UCHAR Lun);
93 
94 static PSCSI_REQUEST_BLOCK_INFO
95 SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
96                          PSCSI_PORT_LUN_EXTENSION LunExtension,
97                          PSCSI_REQUEST_BLOCK Srb);
98 
99 static NTSTATUS
100 SpiSendInquiry(IN PDEVICE_OBJECT DeviceObject,
101                IN OUT PSCSI_LUN_INFO LunInfo);
102 
103 static VOID
104 SpiScanAdapter(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
105 
106 static NTSTATUS
107 SpiGetInquiryData (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
108 		   IN PIRP Irp);
109 
110 static PSCSI_REQUEST_BLOCK_INFO
111 SpiGetSrbData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
112               IN UCHAR PathId,
113               IN UCHAR TargetId,
114               IN UCHAR Lun,
115               IN UCHAR QueueTag);
116 
117 static BOOLEAN NTAPI
118 ScsiPortIsr(IN PKINTERRUPT Interrupt,
119 	    IN PVOID ServiceContext);
120 
121 static VOID NTAPI
122 ScsiPortDpcForIsr(IN PKDPC Dpc,
123 		  IN PDEVICE_OBJECT DpcDeviceObject,
124 		  IN PIRP DpcIrp,
125 		  IN PVOID DpcContext);
126 
127 static VOID NTAPI
128 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
129 		PVOID Context);
130 
131 IO_ALLOCATION_ACTION
132 NTAPI
133 ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject,
134                                IN PIRP Irp,
135                                IN PVOID MapRegisterBase,
136                                IN PVOID Context);
137 
138 static NTSTATUS
139 SpiBuildDeviceMap(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
140                   IN PUNICODE_STRING RegistryPath);
141 
142 static NTSTATUS
143 SpiStatusSrbToNt(UCHAR SrbStatus);
144 
145 static VOID
146 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
147                     IN PSCSI_REQUEST_BLOCK Srb);
148 
149 static IO_COMPLETION_ROUTINE SpiCompletionRoutine;
150 NTSTATUS NTAPI
151 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject,
152                      PIRP Irp,
153                      PVOID Context);
154 
155 static VOID
156 NTAPI
157 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
158                            IN PSCSI_REQUEST_BLOCK_INFO SrbInfo,
159                            OUT PBOOLEAN NeedToCallStartIo);
160 
161 VOID NTAPI
162 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
163                          IN PSCSI_PORT_LUN_EXTENSION LunExtension);
164 
165 VOID NTAPI
166 SpiMiniportTimerDpc(IN struct _KDPC *Dpc,
167                     IN PVOID DeviceObject,
168                     IN PVOID SystemArgument1,
169                     IN PVOID SystemArgument2);
170 
171 static NTSTATUS
172 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
173                     PHW_INITIALIZATION_DATA HwInitData,
174                     PCONFIGURATION_INFO InternalConfigInfo,
175                     PPORT_CONFIGURATION_INFORMATION ConfigInfo,
176                     BOOLEAN FirstCall);
177 
178 NTSTATUS NTAPI
179 SpQueryDeviceCallout(IN PVOID  Context,
180                      IN PUNICODE_STRING  PathName,
181                      IN INTERFACE_TYPE  BusType,
182                      IN ULONG  BusNumber,
183                      IN PKEY_VALUE_FULL_INFORMATION  *BusInformation,
184                      IN CONFIGURATION_TYPE  ControllerType,
185                      IN ULONG  ControllerNumber,
186                      IN PKEY_VALUE_FULL_INFORMATION  *ControllerInformation,
187                      IN CONFIGURATION_TYPE  PeripheralType,
188                      IN ULONG  PeripheralNumber,
189                      IN PKEY_VALUE_FULL_INFORMATION  *PeripheralInformation);
190 
191 static VOID
192 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
193                    IN HANDLE Key,
194                    IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
195                    IN PCONFIGURATION_INFO InternalConfigInfo,
196                    IN PUCHAR Buffer);
197 
198 static VOID
199 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData,
200                     IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor,
201                     IN PPORT_CONFIGURATION_INFORMATION PortConfig);
202 
203 static PCM_RESOURCE_LIST
204 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
205                     PPORT_CONFIGURATION_INFORMATION PortConfig);
206 
207 static VOID
208 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
209 
210 static NTSTATUS
211 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
212                        PIRP Irp);
213 
214 static NTSTATUS
215 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, ULONG NonCachedSize);
216 
217 NTHALAPI ULONG NTAPI HalGetBusData(BUS_DATA_TYPE, ULONG, ULONG, PVOID, ULONG);
218 NTHALAPI ULONG NTAPI HalGetInterruptVector(INTERFACE_TYPE, ULONG, ULONG, ULONG, PKIRQL, PKAFFINITY);
219 NTHALAPI NTSTATUS NTAPI HalAssignSlotResources(PUNICODE_STRING, PUNICODE_STRING, PDRIVER_OBJECT, PDEVICE_OBJECT, INTERFACE_TYPE, ULONG, ULONG, PCM_RESOURCE_LIST *);
220 
221 /* FUNCTIONS *****************************************************************/
222 
223 /**********************************************************************
224  * NAME							EXPORTED
225  *	DriverEntry
226  *
227  * DESCRIPTION
228  *	This function initializes the driver.
229  *
230  * RUN LEVEL
231  *	PASSIVE_LEVEL
232  *
233  * ARGUMENTS
234  *	DriverObject
235  *		System allocated Driver Object for this driver.
236  *
237  *	RegistryPath
238  *		Name of registry driver service key.
239  *
240  * RETURN VALUE
241  * 	Status.
242  */
243 
244 NTSTATUS NTAPI
245 DriverEntry(IN PDRIVER_OBJECT DriverObject,
246 	    IN PUNICODE_STRING RegistryPath)
247 {
248     DPRINT("ScsiPort Driver %s\n", VERSION);
249     return(STATUS_SUCCESS);
250 }
251 
252 
253 /**********************************************************************
254  * NAME							EXPORTED
255  *	ScsiDebugPrint
256  *
257  * DESCRIPTION
258  *	Prints debugging messages.
259  *
260  * RUN LEVEL
261  *	PASSIVE_LEVEL
262  *
263  * ARGUMENTS
264  *	DebugPrintLevel
265  *		Debug level of the given message.
266  *
267  *	DebugMessage
268  *		Pointer to printf()-compatible format string.
269  *
270  *	...
271   		Additional output data (see printf()).
272  *
273  * RETURN VALUE
274  * 	None.
275  *
276  * @implemented
277  */
278 
279 VOID
280 ScsiDebugPrint(IN ULONG DebugPrintLevel,
281 	       IN PCHAR DebugMessage,
282 	       ...)
283 {
284     char Buffer[256];
285     va_list ap;
286 
287     if (DebugPrintLevel > InternalDebugLevel)
288         return;
289 
290     va_start(ap, DebugMessage);
291     vsprintf(Buffer, DebugMessage, ap);
292     va_end(ap);
293 
294     DbgPrint(Buffer);
295 }
296 
297 /* An internal helper function for ScsiPortCompleteRequest */
298 VOID
299 NTAPI
300 SpiCompleteRequest(IN PVOID HwDeviceExtension,
301                    IN PSCSI_REQUEST_BLOCK_INFO SrbInfo,
302                    IN UCHAR SrbStatus)
303 {
304     PSCSI_REQUEST_BLOCK Srb;
305 
306     /* Get current SRB */
307     Srb = SrbInfo->Srb;
308 
309     /* Return if there is no SRB or it is not active */
310     if (!Srb || !(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE)) return;
311 
312     /* Set status */
313     Srb->SrbStatus = SrbStatus;
314 
315     /* Set data transfered to 0 */
316     Srb->DataTransferLength = 0;
317 
318     /* Notify */
319     ScsiPortNotification(RequestComplete,
320                          HwDeviceExtension,
321                          Srb);
322 }
323 
324 /*
325  * @unimplemented
326  */
327 VOID NTAPI
328 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension,
329                         IN UCHAR PathId,
330                         IN UCHAR TargetId,
331                         IN UCHAR Lun,
332                         IN UCHAR SrbStatus)
333 {
334     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
335     PSCSI_PORT_LUN_EXTENSION LunExtension;
336     PSCSI_REQUEST_BLOCK_INFO SrbInfo;
337     PLIST_ENTRY ListEntry;
338     ULONG BusNumber;
339     ULONG Target;
340 
341     DPRINT("ScsiPortCompleteRequest() called\n");
342 
343     DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
344                                         SCSI_PORT_DEVICE_EXTENSION,
345                                         MiniPortDeviceExtension);
346 
347     /* Go through all buses */
348     for (BusNumber = 0; BusNumber < 8; BusNumber++)
349     {
350         /* Go through all targets */
351         for (Target = 0; Target < DeviceExtension->MaxTargedIds; Target++)
352         {
353             /* Get logical unit list head */
354             LunExtension = DeviceExtension->LunExtensionList[Target % 8];
355 
356             /* Go through all logical units */
357             while (LunExtension)
358             {
359                 /* Now match what caller asked with what we are at now */
360                 if ((PathId == SP_UNTAGGED || PathId == LunExtension->PathId) &&
361                     (TargetId == SP_UNTAGGED || TargetId == LunExtension->TargetId) &&
362                     (Lun == SP_UNTAGGED || Lun == LunExtension->Lun))
363                 {
364                     /* Yes, that's what caller asked for. Complete abort requests */
365                     if (LunExtension->CompletedAbortRequests)
366                     {
367                         /* TODO: Save SrbStatus in this request */
368                         DPRINT1("Completing abort request without setting SrbStatus!\n");
369 
370                         /* Issue a notification request */
371                         ScsiPortNotification(RequestComplete,
372                                              HwDeviceExtension,
373                                              LunExtension->CompletedAbortRequests);
374                     }
375 
376                     /* Complete the request using our helper */
377                     SpiCompleteRequest(HwDeviceExtension,
378                                        &LunExtension->SrbInfo,
379                                        SrbStatus);
380 
381                     /* Go through the queue and complete everything there too */
382                     ListEntry = LunExtension->SrbInfo.Requests.Flink;
383                     while (ListEntry != &LunExtension->SrbInfo.Requests)
384                     {
385                         /* Get the actual SRB info entry */
386                         SrbInfo = CONTAINING_RECORD(ListEntry,
387                                                     SCSI_REQUEST_BLOCK_INFO,
388                                                     Requests);
389 
390                         /* Complete it */
391                         SpiCompleteRequest(HwDeviceExtension,
392                                            SrbInfo,
393                                            SrbStatus);
394 
395                         /* Advance to the next request in queue */
396                         ListEntry = SrbInfo->Requests.Flink;
397                     }
398                 }
399 
400                 /* Advance to the next one */
401                 LunExtension = LunExtension->Next;
402             }
403         }
404     }
405 }
406 
407 /*
408  * @unimplemented
409  */
410 VOID NTAPI
411 ScsiPortFlushDma(IN PVOID HwDeviceExtension)
412 {
413   DPRINT("ScsiPortFlushDma()\n");
414   UNIMPLEMENTED;
415 }
416 
417 
418 /*
419  * @implemented
420  */
421 VOID NTAPI
422 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension,
423 		       IN PVOID MappedAddress)
424 {
425     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
426     PMAPPED_ADDRESS NextMa, LastMa;
427 
428     //DPRINT("ScsiPortFreeDeviceBase() called\n");
429 
430     DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
431                                         SCSI_PORT_DEVICE_EXTENSION,
432                                         MiniPortDeviceExtension);
433 
434     /* Initialize our pointers */
435     NextMa = DeviceExtension->MappedAddressList;
436     LastMa = NextMa;
437 
438     while (NextMa)
439     {
440         if (NextMa->MappedAddress == MappedAddress)
441         {
442             /* Unmap it first */
443             MmUnmapIoSpace(MappedAddress, NextMa->NumberOfBytes);
444 
445             /* Remove it from the list */
446             if (NextMa == DeviceExtension->MappedAddressList)
447             {
448                 /* Remove the first entry */
449                 DeviceExtension->MappedAddressList = NextMa->NextMappedAddress;
450             }
451             else
452             {
453                 LastMa->NextMappedAddress = NextMa->NextMappedAddress;
454             }
455 
456             /* Free the resources and quit */
457             ExFreePool(NextMa);
458 
459             return;
460         }
461         else
462         {
463             LastMa = NextMa;
464             NextMa = NextMa->NextMappedAddress;
465         }
466     }
467 }
468 
469 
470 /*
471  * @implemented
472  */
473 ULONG NTAPI
474 ScsiPortGetBusData(IN PVOID DeviceExtension,
475 		   IN ULONG BusDataType,
476 		   IN ULONG SystemIoBusNumber,
477 		   IN ULONG SlotNumber,
478 		   IN PVOID Buffer,
479 		   IN ULONG Length)
480 {
481     DPRINT("ScsiPortGetBusData()\n");
482 
483     if (Length)
484     {
485         /* If Length is non-zero, just forward the call to
486         HalGetBusData() function */
487         return HalGetBusData(BusDataType,
488                              SystemIoBusNumber,
489                              SlotNumber,
490                              Buffer,
491                              Length);
492     }
493 
494     /* We have a more complex case here */
495     UNIMPLEMENTED;
496     return 0;
497 }
498 
499 /*
500  * @implemented
501  */
502 ULONG NTAPI
503 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension,
504                            IN ULONG BusDataType,
505                            IN ULONG SystemIoBusNumber,
506                            IN ULONG SlotNumber,
507                            IN PVOID Buffer,
508                            IN ULONG Offset,
509                            IN ULONG Length)
510 {
511     DPRINT("ScsiPortSetBusDataByOffset()\n");
512     return HalSetBusDataByOffset(BusDataType,
513                                  SystemIoBusNumber,
514                                  SlotNumber,
515                                  Buffer,
516                                  Offset,
517                                  Length);
518 }
519 
520 /*
521  * @implemented
522  */
523 PVOID NTAPI
524 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension,
525 		      IN INTERFACE_TYPE BusType,
526 		      IN ULONG SystemIoBusNumber,
527 		      IN SCSI_PHYSICAL_ADDRESS IoAddress,
528 		      IN ULONG NumberOfBytes,
529 		      IN BOOLEAN InIoSpace)
530 {
531     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
532     PHYSICAL_ADDRESS TranslatedAddress;
533     PMAPPED_ADDRESS DeviceBase;
534     ULONG AddressSpace;
535     PVOID MappedAddress;
536 
537     //DPRINT ("ScsiPortGetDeviceBase() called\n");
538 
539     DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
540                                         SCSI_PORT_DEVICE_EXTENSION,
541                                         MiniPortDeviceExtension);
542 
543     AddressSpace = (ULONG)InIoSpace;
544     if (HalTranslateBusAddress(BusType,
545                                SystemIoBusNumber,
546                                IoAddress,
547                                &AddressSpace,
548                                &TranslatedAddress) == FALSE)
549     {
550         return NULL;
551     }
552 
553     /* i/o space */
554     if (AddressSpace != 0)
555         return((PVOID)(ULONG_PTR)TranslatedAddress.QuadPart);
556 
557     MappedAddress = MmMapIoSpace(TranslatedAddress,
558                                  NumberOfBytes,
559                                  FALSE);
560 
561     DeviceBase = ExAllocatePoolWithTag(NonPagedPool,
562                                 sizeof(MAPPED_ADDRESS), TAG_SCSIPORT);
563 
564     if (DeviceBase == NULL)
565         return MappedAddress;
566 
567     DeviceBase->MappedAddress = MappedAddress;
568     DeviceBase->NumberOfBytes = NumberOfBytes;
569     DeviceBase->IoAddress = IoAddress;
570     DeviceBase->BusNumber = SystemIoBusNumber;
571 
572     /* Link it to the Device Extension list */
573     DeviceBase->NextMappedAddress = DeviceExtension->MappedAddressList;
574     DeviceExtension->MappedAddressList = DeviceBase;
575 
576     return MappedAddress;
577 }
578 
579 /*
580  * @unimplemented
581  */
582 PVOID NTAPI
583 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension,
584 		       IN UCHAR PathId,
585 		       IN UCHAR TargetId,
586 		       IN UCHAR Lun)
587 {
588     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
589     PSCSI_PORT_LUN_EXTENSION LunExtension;
590 
591     DPRINT("ScsiPortGetLogicalUnit() called\n");
592 
593     DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
594                                         SCSI_PORT_DEVICE_EXTENSION,
595                                         MiniPortDeviceExtension);
596 
597     /* Check the extension size */
598     if (!DeviceExtension->LunExtensionSize)
599     {
600         /* They didn't want one */
601         return NULL;
602     }
603 
604     LunExtension = SpiGetLunExtension(DeviceExtension,
605                                       PathId,
606                                       TargetId,
607                                       Lun);
608     /* Check that the logical unit exists */
609     if (!LunExtension)
610     {
611         /* Nope, return NULL */
612         return NULL;
613     }
614 
615     /* Return the logical unit miniport extension */
616     return (LunExtension + 1);
617 }
618 
619 
620 /*
621  * @implemented
622  */
623 SCSI_PHYSICAL_ADDRESS NTAPI
624 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension,
625                            IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
626                            IN PVOID VirtualAddress,
627                            OUT ULONG *Length)
628 {
629     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
630     SCSI_PHYSICAL_ADDRESS PhysicalAddress;
631     SIZE_T BufferLength = 0;
632     ULONG_PTR Offset;
633     PSCSI_SG_ADDRESS SGList;
634     PSCSI_REQUEST_BLOCK_INFO SrbInfo;
635 
636     DPRINT("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
637         HwDeviceExtension, Srb, VirtualAddress, Length);
638 
639     DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
640                                         SCSI_PORT_DEVICE_EXTENSION,
641                                         MiniPortDeviceExtension);
642 
643     if (Srb == NULL || Srb->SenseInfoBuffer == VirtualAddress)
644     {
645         /* Simply look it up in the allocated common buffer */
646         Offset = (PUCHAR)VirtualAddress - (PUCHAR)DeviceExtension->SrbExtensionBuffer;
647 
648         BufferLength = DeviceExtension->CommonBufferLength - Offset;
649         PhysicalAddress.QuadPart = DeviceExtension->PhysicalAddress.QuadPart + Offset;
650     }
651     else if (DeviceExtension->MapRegisters)
652     {
653         /* Scatter-gather list must be used */
654         SrbInfo = SpiGetSrbData(DeviceExtension,
655                                Srb->PathId,
656                                Srb->TargetId,
657                                Srb->Lun,
658                                Srb->QueueTag);
659 
660         SGList = SrbInfo->ScatterGather;
661 
662         /* Find needed item in the SG list */
663         Offset = (PCHAR)VirtualAddress - (PCHAR)Srb->DataBuffer;
664         while (Offset >= SGList->Length)
665         {
666             Offset -= SGList->Length;
667             SGList++;
668         }
669 
670         /* We're done, store length and physical address */
671         BufferLength = SGList->Length - Offset;
672         PhysicalAddress.QuadPart = SGList->PhysicalAddress.QuadPart + Offset;
673     }
674     else
675     {
676         /* Nothing */
677         PhysicalAddress.QuadPart = (LONGLONG)(SP_UNINITIALIZED_VALUE);
678     }
679 
680     *Length = (ULONG)BufferLength;
681     return PhysicalAddress;
682 }
683 
684 
685 /*
686  * @unimplemented
687  */
688 PSCSI_REQUEST_BLOCK NTAPI
689 ScsiPortGetSrb(IN PVOID DeviceExtension,
690 	       IN UCHAR PathId,
691 	       IN UCHAR TargetId,
692 	       IN UCHAR Lun,
693 	       IN LONG QueueTag)
694 {
695   DPRINT1("ScsiPortGetSrb() unimplemented\n");
696   UNIMPLEMENTED;
697   return NULL;
698 }
699 
700 
701 /*
702  * @implemented
703  */
704 PVOID NTAPI
705 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension,
706 			     IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
707 			     IN ULONG NumberOfBytes)
708 {
709     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
710     DEVICE_DESCRIPTION DeviceDescription;
711     ULONG MapRegistersCount;
712     NTSTATUS Status;
713 
714     DPRINT("ScsiPortGetUncachedExtension(%p %p %lu)\n",
715         HwDeviceExtension, ConfigInfo, NumberOfBytes);
716 
717     DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
718                                         SCSI_PORT_DEVICE_EXTENSION,
719                                         MiniPortDeviceExtension);
720 
721     /* Check for allocated common DMA buffer */
722     if (DeviceExtension->SrbExtensionBuffer != NULL)
723     {
724         DPRINT1("The HBA has already got a common DMA buffer!\n");
725         return NULL;
726     }
727 
728     /* Check for DMA adapter object */
729     if (DeviceExtension->AdapterObject == NULL)
730     {
731         /* Initialize DMA adapter description */
732         RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
733 
734         DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
735         DeviceDescription.Master = ConfigInfo->Master;
736         DeviceDescription.ScatterGather = ConfigInfo->ScatterGather;
737         DeviceDescription.DemandMode = ConfigInfo->DemandMode;
738         DeviceDescription.Dma32BitAddresses = ConfigInfo->Dma32BitAddresses;
739         DeviceDescription.BusNumber = ConfigInfo->SystemIoBusNumber;
740         DeviceDescription.DmaChannel = ConfigInfo->DmaChannel;
741         DeviceDescription.InterfaceType = ConfigInfo->AdapterInterfaceType;
742         DeviceDescription.DmaWidth = ConfigInfo->DmaWidth;
743         DeviceDescription.DmaSpeed = ConfigInfo->DmaSpeed;
744         DeviceDescription.MaximumLength = ConfigInfo->MaximumTransferLength;
745         DeviceDescription.DmaPort = ConfigInfo->DmaPort;
746 
747         /* Get a DMA adapter object */
748         DeviceExtension->AdapterObject =
749             HalGetAdapter(&DeviceDescription, &MapRegistersCount);
750 
751         /* Fail in case of error */
752         if (DeviceExtension->AdapterObject == NULL)
753         {
754             DPRINT1("HalGetAdapter() failed\n");
755             return NULL;
756         }
757 
758         /* Set number of physical breaks */
759         if (ConfigInfo->NumberOfPhysicalBreaks != 0 &&
760             MapRegistersCount > ConfigInfo->NumberOfPhysicalBreaks)
761         {
762             DeviceExtension->PortCapabilities.MaximumPhysicalPages =
763                 ConfigInfo->NumberOfPhysicalBreaks;
764         }
765         else
766         {
767             DeviceExtension->PortCapabilities.MaximumPhysicalPages = MapRegistersCount;
768         }
769     }
770 
771     /* Update auto request sense feature */
772     DeviceExtension->SupportsAutoSense = ConfigInfo->AutoRequestSense;
773 
774     /* Update Srb extension size */
775     if (DeviceExtension->SrbExtensionSize != ConfigInfo->SrbExtensionSize)
776         DeviceExtension->SrbExtensionSize = ConfigInfo->SrbExtensionSize;
777 
778     /* Update Srb extension alloc flag */
779     if (ConfigInfo->AutoRequestSense || DeviceExtension->SrbExtensionSize)
780         DeviceExtension->NeedSrbExtensionAlloc = TRUE;
781 
782     /* Allocate a common DMA buffer */
783     Status = SpiAllocateCommonBuffer(DeviceExtension, NumberOfBytes);
784 
785     if (!NT_SUCCESS(Status))
786     {
787         DPRINT1("SpiAllocateCommonBuffer() failed with Status = 0x%08X!\n", Status);
788         return NULL;
789     }
790 
791     return DeviceExtension->NonCachedExtension;
792 }
793 
794 static NTSTATUS
795 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, ULONG NonCachedSize)
796 {
797     PVOID *SrbExtension, CommonBuffer;
798     ULONG CommonBufferLength, BufSize;
799 
800     /* If size is 0, set it to 16 */
801     if (!DeviceExtension->SrbExtensionSize)
802         DeviceExtension->SrbExtensionSize = 16;
803 
804     /* Calculate size */
805     BufSize = DeviceExtension->SrbExtensionSize;
806 
807     /* Add autosense data size if needed */
808     if (DeviceExtension->SupportsAutoSense)
809         BufSize += sizeof(SENSE_DATA);
810 
811 
812     /* Round it */
813     BufSize = (BufSize + sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1);
814 
815     /* Sum up into the total common buffer length, and round it to page size */
816     CommonBufferLength =
817         ROUND_TO_PAGES(NonCachedSize + BufSize * DeviceExtension->RequestsNumber);
818 
819     /* Allocate it */
820     if (!DeviceExtension->AdapterObject)
821     {
822         /* From nonpaged pool if there is no DMA */
823         CommonBuffer = ExAllocatePoolWithTag(NonPagedPool, CommonBufferLength, TAG_SCSIPORT);
824     }
825     else
826     {
827         /* Perform a full request since we have a DMA adapter*/
828         CommonBuffer = HalAllocateCommonBuffer(DeviceExtension->AdapterObject,
829             CommonBufferLength,
830             &DeviceExtension->PhysicalAddress,
831             FALSE );
832     }
833 
834     /* Fail in case of error */
835     if (!CommonBuffer)
836         return STATUS_INSUFFICIENT_RESOURCES;
837 
838     /* Zero it */
839     RtlZeroMemory(CommonBuffer, CommonBufferLength);
840 
841     /* Store its size in Device Extension */
842     DeviceExtension->CommonBufferLength = CommonBufferLength;
843 
844     /* SrbExtension buffer is located at the beginning of the buffer */
845     DeviceExtension->SrbExtensionBuffer = CommonBuffer;
846 
847     /* Non-cached extension buffer is located at the end of
848        the common buffer */
849     if (NonCachedSize)
850     {
851         CommonBufferLength -=  NonCachedSize;
852         DeviceExtension->NonCachedExtension = (PUCHAR)CommonBuffer + CommonBufferLength;
853     }
854     else
855     {
856         DeviceExtension->NonCachedExtension = NULL;
857     }
858 
859     if (DeviceExtension->NeedSrbExtensionAlloc)
860     {
861         /* Look up how many SRB data structures we need */
862         DeviceExtension->SrbDataCount = CommonBufferLength / BufSize;
863 
864         /* Initialize the free SRB extensions list */
865         SrbExtension = (PVOID *)CommonBuffer;
866         DeviceExtension->FreeSrbExtensions = SrbExtension;
867 
868         /* Fill the remaining pointers (if we have more than 1 SRB) */
869         while (CommonBufferLength >= 2 * BufSize)
870         {
871             *SrbExtension = (PVOID*)((PCHAR)SrbExtension + BufSize);
872             SrbExtension = *SrbExtension;
873 
874             CommonBufferLength -= BufSize;
875         }
876     }
877 
878     return STATUS_SUCCESS;
879 }
880 
881 
882 
883 /*
884  * @implemented
885  */
886 PVOID NTAPI
887 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension,
888                           IN SCSI_PHYSICAL_ADDRESS PhysicalAddress)
889 {
890     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
891     ULONG Offset;
892 
893     DPRINT("ScsiPortGetVirtualAddress(%p %I64x)\n",
894         HwDeviceExtension, PhysicalAddress.QuadPart);
895 
896     DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
897                                         SCSI_PORT_DEVICE_EXTENSION,
898                                         MiniPortDeviceExtension);
899 
900     if (DeviceExtension->PhysicalAddress.QuadPart > PhysicalAddress.QuadPart)
901         return NULL;
902 
903     Offset = (ULONG)(PhysicalAddress.QuadPart - DeviceExtension->PhysicalAddress.QuadPart);
904 
905     if (Offset >= DeviceExtension->CommonBufferLength)
906         return NULL;
907 
908     return (PVOID)((ULONG_PTR)DeviceExtension->SrbExtensionBuffer + Offset);
909 }
910 
911 static VOID
912 SpiInitOpenKeys(PCONFIGURATION_INFO ConfigInfo, PUNICODE_STRING RegistryPath)
913 {
914     OBJECT_ATTRIBUTES ObjectAttributes;
915     UNICODE_STRING KeyName;
916     NTSTATUS Status;
917 
918     /* Open the service key */
919     InitializeObjectAttributes(&ObjectAttributes,
920                                RegistryPath,
921                                OBJ_CASE_INSENSITIVE,
922                                NULL,
923                                NULL);
924 
925     Status = ZwOpenKey(&ConfigInfo->ServiceKey,
926                        KEY_READ,
927                        &ObjectAttributes);
928 
929     if (!NT_SUCCESS(Status))
930     {
931         DPRINT("Unable to open driver's registry key %wZ, status 0x%08x\n", RegistryPath, Status);
932         ConfigInfo->ServiceKey = NULL;
933     }
934 
935     /* If we could open driver's service key, then proceed to the Parameters key */
936     if (ConfigInfo->ServiceKey != NULL)
937     {
938         RtlInitUnicodeString(&KeyName, L"Parameters");
939         InitializeObjectAttributes(&ObjectAttributes,
940                                    &KeyName,
941                                    OBJ_CASE_INSENSITIVE,
942                                    ConfigInfo->ServiceKey,
943                                    (PSECURITY_DESCRIPTOR) NULL);
944 
945         /* Try to open it */
946         Status = ZwOpenKey(&ConfigInfo->DeviceKey,
947                            KEY_READ,
948                            &ObjectAttributes);
949 
950         if (NT_SUCCESS(Status))
951         {
952             /* Yes, Parameters key exist, and it must be used instead of
953                the Service key */
954             ZwClose(ConfigInfo->ServiceKey);
955             ConfigInfo->ServiceKey = ConfigInfo->DeviceKey;
956             ConfigInfo->DeviceKey = NULL;
957         }
958     }
959 
960     if (ConfigInfo->ServiceKey != NULL)
961     {
962         /* Open the Device key */
963         RtlInitUnicodeString(&KeyName, L"Device");
964         InitializeObjectAttributes(&ObjectAttributes,
965                                    &KeyName,
966                                    OBJ_CASE_INSENSITIVE,
967                                    ConfigInfo->ServiceKey,
968                                    NULL);
969 
970         /* We don't check for failure here - not needed */
971         ZwOpenKey(&ConfigInfo->DeviceKey,
972                   KEY_READ,
973                   &ObjectAttributes);
974     }
975 }
976 
977 
978 /**********************************************************************
979  * NAME							EXPORTED
980  *	ScsiPortInitialize
981  *
982  * DESCRIPTION
983  *	Initializes SCSI port driver specific data.
984  *
985  * RUN LEVEL
986  *	PASSIVE_LEVEL
987  *
988  * ARGUMENTS
989  *	Argument1
990  *		Pointer to the miniport driver's driver object.
991  *
992  *	Argument2
993  *		Pointer to the miniport driver's registry path.
994  *
995  *	HwInitializationData
996  *		Pointer to port driver specific configuration data.
997  *
998  *	HwContext
999   		Miniport driver specific context.
1000  *
1001  * RETURN VALUE
1002  * 	Status.
1003  *
1004  * @implemented
1005  */
1006 
1007 ULONG NTAPI
1008 ScsiPortInitialize(IN PVOID Argument1,
1009 		   IN PVOID Argument2,
1010 		   IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
1011 		   IN PVOID HwContext)
1012 {
1013     PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Argument1;
1014     PUNICODE_STRING RegistryPath = (PUNICODE_STRING)Argument2;
1015     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = NULL;
1016     PCONFIGURATION_INFORMATION SystemConfig;
1017     PPORT_CONFIGURATION_INFORMATION PortConfig;
1018     PORT_CONFIGURATION_INFORMATION InitialPortConfig;
1019     CONFIGURATION_INFO ConfigInfo;
1020     ULONG DeviceExtensionSize;
1021     ULONG PortConfigSize;
1022     BOOLEAN Again;
1023     BOOLEAN DeviceFound = FALSE;
1024     BOOLEAN FirstConfigCall = TRUE;
1025     ULONG Result;
1026     NTSTATUS Status;
1027     ULONG MaxBus;
1028     PCI_SLOT_NUMBER SlotNumber;
1029 
1030     PDEVICE_OBJECT PortDeviceObject;
1031     WCHAR NameBuffer[80];
1032     UNICODE_STRING DeviceName;
1033     WCHAR DosNameBuffer[80];
1034     UNICODE_STRING DosDeviceName;
1035     PIO_SCSI_CAPABILITIES PortCapabilities;
1036 
1037     KIRQL OldIrql;
1038     PCM_RESOURCE_LIST ResourceList;
1039     BOOLEAN Conflict;
1040     SIZE_T BusConfigSize;
1041 
1042 
1043     DPRINT ("ScsiPortInitialize() called!\n");
1044 
1045     /* Check params for validity */
1046     if ((HwInitializationData->HwInitialize == NULL) ||
1047         (HwInitializationData->HwStartIo == NULL) ||
1048         (HwInitializationData->HwInterrupt == NULL) ||
1049         (HwInitializationData->HwFindAdapter == NULL) ||
1050         (HwInitializationData->HwResetBus == NULL))
1051     {
1052         return STATUS_INVALID_PARAMETER;
1053     }
1054 
1055     /* Set handlers */
1056     DriverObject->DriverStartIo = ScsiPortStartIo;
1057     DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiPortCreateClose;
1058     DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiPortCreateClose;
1059     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiPortDeviceControl;
1060     DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiPortDispatchScsi;
1061 
1062     /* Obtain configuration information */
1063     SystemConfig = IoGetConfigurationInformation();
1064 
1065     /* Zero the internal configuration info structure */
1066     RtlZeroMemory(&ConfigInfo, sizeof(CONFIGURATION_INFO));
1067 
1068     /* Zero starting slot number */
1069     SlotNumber.u.AsULONG = 0;
1070 
1071     /* Allocate space for access ranges */
1072     if (HwInitializationData->NumberOfAccessRanges)
1073     {
1074         ConfigInfo.AccessRanges =
1075             ExAllocatePoolWithTag(PagedPool,
1076             HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE), TAG_SCSIPORT);
1077 
1078         /* Fail if failed */
1079         if (ConfigInfo.AccessRanges == NULL)
1080             return STATUS_INSUFFICIENT_RESOURCES;
1081     }
1082 
1083     /* Open registry keys */
1084     SpiInitOpenKeys(&ConfigInfo, (PUNICODE_STRING)Argument2);
1085 
1086     /* Last adapter number = not known */
1087     ConfigInfo.LastAdapterNumber = SP_UNINITIALIZED_VALUE;
1088 
1089     /* Calculate sizes of DeviceExtension and PortConfig */
1090     DeviceExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) +
1091         HwInitializationData->DeviceExtensionSize;
1092 
1093     MaxBus = (HwInitializationData->AdapterInterfaceType == PCIBus) ? 8 : 1;
1094     DPRINT("MaxBus: %lu\n", MaxBus);
1095 
1096     while (TRUE)
1097     {
1098         /* Create a unicode device name */
1099         swprintf(NameBuffer,
1100                  L"\\Device\\ScsiPort%lu",
1101                  SystemConfig->ScsiPortCount);
1102         RtlInitUnicodeString(&DeviceName, NameBuffer);
1103 
1104         DPRINT("Creating device: %wZ\n", &DeviceName);
1105 
1106         /* Create the port device */
1107         Status = IoCreateDevice(DriverObject,
1108                                 DeviceExtensionSize,
1109                                 &DeviceName,
1110                                 FILE_DEVICE_CONTROLLER,
1111                                 0,
1112                                 FALSE,
1113                                 &PortDeviceObject);
1114 
1115         if (!NT_SUCCESS(Status))
1116         {
1117             DPRINT1("IoCreateDevice call failed! (Status 0x%lX)\n", Status);
1118             PortDeviceObject = NULL;
1119             break;
1120         }
1121 
1122         DPRINT ("Created device: %wZ (%p)\n", &DeviceName, PortDeviceObject);
1123 
1124         /* Set the buffering strategy here... */
1125         PortDeviceObject->Flags |= DO_DIRECT_IO;
1126         PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT; /* FIXME: Is this really needed? */
1127 
1128         /* Fill Device Extension */
1129         DeviceExtension = PortDeviceObject->DeviceExtension;
1130         RtlZeroMemory(DeviceExtension, DeviceExtensionSize);
1131         DeviceExtension->Length = DeviceExtensionSize;
1132         DeviceExtension->DeviceObject = PortDeviceObject;
1133         DeviceExtension->PortNumber = SystemConfig->ScsiPortCount;
1134 
1135         /* Driver's routines... */
1136         DeviceExtension->HwInitialize = HwInitializationData->HwInitialize;
1137         DeviceExtension->HwStartIo = HwInitializationData->HwStartIo;
1138         DeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
1139         DeviceExtension->HwResetBus = HwInitializationData->HwResetBus;
1140         DeviceExtension->HwDmaStarted = HwInitializationData->HwDmaStarted;
1141 
1142         /* Extensions sizes */
1143         DeviceExtension->MiniPortExtensionSize = HwInitializationData->DeviceExtensionSize;
1144         DeviceExtension->LunExtensionSize = HwInitializationData->SpecificLuExtensionSize;
1145         DeviceExtension->SrbExtensionSize = HwInitializationData->SrbExtensionSize;
1146 
1147         /* Round Srb extension size to the quadword */
1148         DeviceExtension->SrbExtensionSize =
1149             ~(sizeof(LONGLONG) - 1) & (DeviceExtension->SrbExtensionSize +
1150             sizeof(LONGLONG) - 1);
1151 
1152         /* Fill some numbers (bus count, lun count, etc) */
1153         DeviceExtension->MaxLunCount = SCSI_MAXIMUM_LOGICAL_UNITS;
1154         DeviceExtension->RequestsNumber = 16;
1155 
1156         /* Initialize the spin lock in the controller extension */
1157         KeInitializeSpinLock(&DeviceExtension->IrqLock);
1158         KeInitializeSpinLock(&DeviceExtension->SpinLock);
1159 
1160         /* Initialize the DPC object */
1161         IoInitializeDpcRequest(PortDeviceObject,
1162                                ScsiPortDpcForIsr);
1163 
1164         /* Initialize the device timer */
1165         DeviceExtension->TimerCount = -1;
1166         IoInitializeTimer(PortDeviceObject,
1167                           ScsiPortIoTimer,
1168                           DeviceExtension);
1169 
1170         /* Initialize miniport timer */
1171         KeInitializeTimer(&DeviceExtension->MiniportTimer);
1172         KeInitializeDpc(&DeviceExtension->MiniportTimerDpc,
1173                         SpiMiniportTimerDpc,
1174                         PortDeviceObject);
1175 
1176 CreatePortConfig:
1177 
1178         Status = SpiCreatePortConfig(DeviceExtension,
1179                                      HwInitializationData,
1180                                      &ConfigInfo,
1181                                      &InitialPortConfig,
1182                                      FirstConfigCall);
1183 
1184         if (!NT_SUCCESS(Status))
1185         {
1186             DPRINT("SpiCreatePortConfig() failed with Status 0x%08X\n", Status);
1187             break;
1188         }
1189 
1190         /* Allocate and initialize port configuration info */
1191         PortConfigSize = (sizeof(PORT_CONFIGURATION_INFORMATION) +
1192                           HwInitializationData->NumberOfAccessRanges *
1193                           sizeof(ACCESS_RANGE) + 7) & ~7;
1194         DeviceExtension->PortConfig = ExAllocatePoolWithTag(NonPagedPool, PortConfigSize, TAG_SCSIPORT);
1195 
1196         /* Fail if failed */
1197         if (DeviceExtension->PortConfig == NULL)
1198         {
1199             Status = STATUS_INSUFFICIENT_RESOURCES;
1200             break;
1201         }
1202 
1203         PortConfig = DeviceExtension->PortConfig;
1204 
1205         /* Copy information here */
1206         RtlCopyMemory(PortConfig,
1207                       &InitialPortConfig,
1208                       sizeof(PORT_CONFIGURATION_INFORMATION));
1209 
1210 
1211         /* Copy extension sizes into the PortConfig */
1212         PortConfig->SpecificLuExtensionSize = DeviceExtension->LunExtensionSize;
1213         PortConfig->SrbExtensionSize = DeviceExtension->SrbExtensionSize;
1214 
1215         /* Initialize Access ranges */
1216         if (HwInitializationData->NumberOfAccessRanges != 0)
1217         {
1218             PortConfig->AccessRanges = (PVOID)(PortConfig+1);
1219 
1220             /* Align to LONGLONG */
1221             PortConfig->AccessRanges = (PVOID)((ULONG_PTR)(PortConfig->AccessRanges) + 7);
1222             PortConfig->AccessRanges = (PVOID)((ULONG_PTR)(PortConfig->AccessRanges) & ~7);
1223 
1224             /* Copy the data */
1225             RtlCopyMemory(PortConfig->AccessRanges,
1226                           ConfigInfo.AccessRanges,
1227                           HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE));
1228         }
1229 
1230       /* Search for matching PCI device */
1231       if ((HwInitializationData->AdapterInterfaceType == PCIBus) &&
1232           (HwInitializationData->VendorIdLength > 0) &&
1233           (HwInitializationData->VendorId != NULL) &&
1234           (HwInitializationData->DeviceIdLength > 0) &&
1235           (HwInitializationData->DeviceId != NULL))
1236       {
1237           PortConfig->BusInterruptLevel = 0;
1238 
1239           /* Get PCI device data */
1240           DPRINT("VendorId '%.*s'  DeviceId '%.*s'\n",
1241                  HwInitializationData->VendorIdLength,
1242                  HwInitializationData->VendorId,
1243                  HwInitializationData->DeviceIdLength,
1244                  HwInitializationData->DeviceId);
1245 
1246           if (!SpiGetPciConfigData(DriverObject,
1247                                    PortDeviceObject,
1248                                    HwInitializationData,
1249                                    PortConfig,
1250                                    RegistryPath,
1251                                    ConfigInfo.BusNumber,
1252                                    &SlotNumber))
1253           {
1254               /* Continue to the next bus, nothing here */
1255               ConfigInfo.BusNumber++;
1256               DeviceExtension->PortConfig = NULL;
1257               ExFreePool(PortConfig);
1258               Again = FALSE;
1259               goto CreatePortConfig;
1260           }
1261 
1262           if (!PortConfig->BusInterruptLevel)
1263           {
1264               /* Bypass this slot, because no interrupt was assigned */
1265               DeviceExtension->PortConfig = NULL;
1266               ExFreePool(PortConfig);
1267               goto CreatePortConfig;
1268           }
1269       }
1270       else
1271       {
1272           DPRINT("Non-pci bus\n");
1273       }
1274 
1275       /* Note: HwFindAdapter is called once for each bus */
1276       Again = FALSE;
1277       DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber);
1278       Result = (HwInitializationData->HwFindAdapter)(&DeviceExtension->MiniPortDeviceExtension,
1279                                                      HwContext,
1280                                                      0,  /* BusInformation */
1281                                                      ConfigInfo.Parameter, /* ArgumentString */
1282                                                      PortConfig,
1283                                                      &Again);
1284 
1285       DPRINT("HwFindAdapter() Result: %lu  Again: %s\n",
1286              Result, (Again) ? "True" : "False");
1287 
1288       /* Free MapRegisterBase, it's not needed anymore */
1289       if (DeviceExtension->MapRegisterBase != NULL)
1290       {
1291           ExFreePool(DeviceExtension->MapRegisterBase);
1292           DeviceExtension->MapRegisterBase = NULL;
1293       }
1294 
1295       /* If result is nothing good... */
1296       if (Result != SP_RETURN_FOUND)
1297       {
1298           DPRINT("HwFindAdapter() Result: %lu\n", Result);
1299 
1300           if (Result == SP_RETURN_NOT_FOUND)
1301           {
1302               /* We can continue on the next bus */
1303               ConfigInfo.BusNumber++;
1304               Again = FALSE;
1305 
1306               DeviceExtension->PortConfig = NULL;
1307               ExFreePool(PortConfig);
1308               goto CreatePortConfig;
1309           }
1310 
1311           /* Otherwise, break */
1312           Status = STATUS_INTERNAL_ERROR;
1313           break;
1314       }
1315 
1316       DPRINT("ScsiPortInitialize(): Found HBA! (%x), adapter Id %d\n",
1317           PortConfig->BusInterruptVector, PortConfig->InitiatorBusId[0]);
1318 
1319       /* If the SRB extension size was updated */
1320       if (!DeviceExtension->NonCachedExtension &&
1321           (PortConfig->SrbExtensionSize != DeviceExtension->SrbExtensionSize))
1322       {
1323           /* Set it (rounding to LONGLONG again) */
1324           DeviceExtension->SrbExtensionSize =
1325               (PortConfig->SrbExtensionSize +
1326                sizeof(LONGLONG)) & ~(sizeof(LONGLONG) - 1);
1327       }
1328 
1329       /* The same with LUN extension size */
1330       if (PortConfig->SpecificLuExtensionSize != DeviceExtension->LunExtensionSize)
1331           DeviceExtension->LunExtensionSize = PortConfig->SpecificLuExtensionSize;
1332 
1333 
1334       if (!((HwInitializationData->AdapterInterfaceType == PCIBus) &&
1335           (HwInitializationData->VendorIdLength > 0) &&
1336           (HwInitializationData->VendorId != NULL) &&
1337           (HwInitializationData->DeviceIdLength > 0) &&
1338           (HwInitializationData->DeviceId != NULL)))
1339       {
1340           /* Construct a resource list */
1341           ResourceList = SpiConfigToResource(DeviceExtension,
1342                                              PortConfig);
1343 
1344           if (ResourceList)
1345           {
1346               UNICODE_STRING UnicodeString;
1347               RtlInitUnicodeString(&UnicodeString, L"ScsiAdapter");
1348               DPRINT("Reporting resources\n");
1349               Status = IoReportResourceUsage(&UnicodeString,
1350                                              DriverObject,
1351                                              NULL,
1352                                              0,
1353                                              PortDeviceObject,
1354                                              ResourceList,
1355                                              FIELD_OFFSET(CM_RESOURCE_LIST,
1356                                                  List[0].PartialResourceList.PartialDescriptors) +
1357                                                  ResourceList->List[0].PartialResourceList.Count
1358                                                  * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
1359                                              FALSE,
1360                                              &Conflict);
1361               ExFreePool(ResourceList);
1362 
1363               /* In case of a failure or a conflict, break */
1364               if (Conflict || (!NT_SUCCESS(Status)))
1365               {
1366                   if (Conflict)
1367                       Status = STATUS_CONFLICTING_ADDRESSES;
1368                   break;
1369               }
1370             }
1371       }
1372 
1373       /* Reset the Conflict var */
1374       Conflict = FALSE;
1375 
1376       /* Copy all stuff which we ever need from PortConfig to the DeviceExtension */
1377       if (PortConfig->MaximumNumberOfTargets > SCSI_MAXIMUM_TARGETS_PER_BUS)
1378           DeviceExtension->MaxTargedIds = SCSI_MAXIMUM_TARGETS_PER_BUS;
1379       else
1380           DeviceExtension->MaxTargedIds = PortConfig->MaximumNumberOfTargets;
1381 
1382       DeviceExtension->BusNum = PortConfig->NumberOfBuses;
1383       DeviceExtension->CachesData = PortConfig->CachesData;
1384       DeviceExtension->ReceiveEvent = PortConfig->ReceiveEvent;
1385       DeviceExtension->SupportsTaggedQueuing = PortConfig->TaggedQueuing;
1386       DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu;
1387 
1388       /* If something was disabled via registry - apply it */
1389       if (ConfigInfo.DisableMultipleLun)
1390           DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu = FALSE;
1391 
1392       if (ConfigInfo.DisableTaggedQueueing)
1393           DeviceExtension->SupportsTaggedQueuing = PortConfig->MultipleRequestPerLu = FALSE;
1394 
1395       /* Check if we need to alloc SRB data */
1396       if (DeviceExtension->SupportsTaggedQueuing ||
1397           DeviceExtension->MultipleReqsPerLun)
1398       {
1399           DeviceExtension->NeedSrbDataAlloc = TRUE;
1400       }
1401       else
1402       {
1403           DeviceExtension->NeedSrbDataAlloc = FALSE;
1404       }
1405 
1406       /* Get a pointer to the port capabilities */
1407       PortCapabilities = &DeviceExtension->PortCapabilities;
1408 
1409       /* Copy one field there */
1410       DeviceExtension->MapBuffers = PortConfig->MapBuffers;
1411       PortCapabilities->AdapterUsesPio = PortConfig->MapBuffers;
1412 
1413       if (DeviceExtension->AdapterObject == NULL &&
1414           (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE || PortConfig->Master))
1415       {
1416           DPRINT1("DMA is not supported yet\n");
1417           ASSERT(FALSE);
1418       }
1419 
1420       if (DeviceExtension->SrbExtensionBuffer == NULL &&
1421           (DeviceExtension->SrbExtensionSize != 0  ||
1422           PortConfig->AutoRequestSense))
1423       {
1424           DeviceExtension->SupportsAutoSense = PortConfig->AutoRequestSense;
1425           DeviceExtension->NeedSrbExtensionAlloc = TRUE;
1426 
1427           /* Allocate common buffer */
1428           Status = SpiAllocateCommonBuffer(DeviceExtension, 0);
1429 
1430           /* Check for failure */
1431           if (!NT_SUCCESS(Status))
1432               break;
1433       }
1434 
1435       /* Allocate SrbData, if needed */
1436       if (DeviceExtension->NeedSrbDataAlloc)
1437       {
1438           ULONG Count;
1439           PSCSI_REQUEST_BLOCK_INFO SrbData;
1440 
1441           if (DeviceExtension->SrbDataCount != 0)
1442               Count = DeviceExtension->SrbDataCount;
1443           else
1444               Count = DeviceExtension->RequestsNumber * 2;
1445 
1446           /* Allocate the data */
1447           SrbData = ExAllocatePoolWithTag(NonPagedPool, Count * sizeof(SCSI_REQUEST_BLOCK_INFO), TAG_SCSIPORT);
1448           if (SrbData == NULL)
1449               return STATUS_INSUFFICIENT_RESOURCES;
1450 
1451           RtlZeroMemory(SrbData, Count * sizeof(SCSI_REQUEST_BLOCK_INFO));
1452 
1453           DeviceExtension->SrbInfo = SrbData;
1454           DeviceExtension->FreeSrbInfo = SrbData;
1455           DeviceExtension->SrbDataCount = Count;
1456 
1457           /* Link it to the list */
1458           while (Count > 0)
1459           {
1460               SrbData->Requests.Flink = (PLIST_ENTRY)(SrbData + 1);
1461               SrbData++;
1462               Count--;
1463           }
1464 
1465           /* Mark the last entry of the list */
1466           SrbData--;
1467           SrbData->Requests.Flink = NULL;
1468       }
1469 
1470       /* Initialize port capabilities */
1471       PortCapabilities = &DeviceExtension->PortCapabilities;
1472       PortCapabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
1473       PortCapabilities->MaximumTransferLength = PortConfig->MaximumTransferLength;
1474 
1475       if (PortConfig->ReceiveEvent)
1476           PortCapabilities->SupportedAsynchronousEvents |= SRBEV_SCSI_ASYNC_NOTIFICATION;
1477 
1478       PortCapabilities->TaggedQueuing = DeviceExtension->SupportsTaggedQueuing;
1479       PortCapabilities->AdapterScansDown = PortConfig->AdapterScansDown;
1480 
1481       if (PortConfig->AlignmentMask > PortDeviceObject->AlignmentRequirement)
1482           PortDeviceObject->AlignmentRequirement = PortConfig->AlignmentMask;
1483 
1484       PortCapabilities->AlignmentMask = PortDeviceObject->AlignmentRequirement;
1485 
1486       if (PortCapabilities->MaximumPhysicalPages == 0)
1487       {
1488           PortCapabilities->MaximumPhysicalPages =
1489               BYTES_TO_PAGES(PortCapabilities->MaximumTransferLength);
1490 
1491           /* Apply miniport's limits */
1492           if (PortConfig->NumberOfPhysicalBreaks < PortCapabilities->MaximumPhysicalPages)
1493           {
1494               PortCapabilities->MaximumPhysicalPages = PortConfig->NumberOfPhysicalBreaks;
1495           }
1496       }
1497 
1498       /* Deal with interrupts */
1499       if (DeviceExtension->HwInterrupt == NULL ||
1500           (PortConfig->BusInterruptLevel == 0 && PortConfig->BusInterruptVector == 0))
1501       {
1502           /* No interrupts */
1503           DeviceExtension->InterruptCount = 0;
1504 
1505           DPRINT1("Interrupt Count: 0\n");
1506 
1507           UNIMPLEMENTED;
1508 
1509           /* This code path will ALWAYS crash so stop it now */
1510           while(TRUE);
1511       }
1512       else
1513       {
1514           BOOLEAN InterruptShareable;
1515           KINTERRUPT_MODE InterruptMode[2];
1516           ULONG InterruptVector[2], i, MappedIrq[2];
1517           KIRQL Dirql[2], MaxDirql;
1518           KAFFINITY Affinity[2];
1519 
1520           DeviceExtension->InterruptLevel[0] = PortConfig->BusInterruptLevel;
1521           DeviceExtension->InterruptLevel[1] = PortConfig->BusInterruptLevel2;
1522 
1523           InterruptVector[0] = PortConfig->BusInterruptVector;
1524           InterruptVector[1] = PortConfig->BusInterruptVector2;
1525 
1526           InterruptMode[0] = PortConfig->InterruptMode;
1527           InterruptMode[1] = PortConfig->InterruptMode2;
1528 
1529           DeviceExtension->InterruptCount = (PortConfig->BusInterruptLevel2 != 0 || PortConfig->BusInterruptVector2 != 0) ? 2 : 1;
1530 
1531           for (i = 0; i < DeviceExtension->InterruptCount; i++)
1532           {
1533               /* Register an interrupt handler for this device */
1534               MappedIrq[i] = HalGetInterruptVector(PortConfig->AdapterInterfaceType,
1535                                                    PortConfig->SystemIoBusNumber,
1536                                                    DeviceExtension->InterruptLevel[i],
1537                                                    InterruptVector[i],
1538                                                    &Dirql[i],
1539                                                    &Affinity[i]);
1540           }
1541 
1542           if (DeviceExtension->InterruptCount == 1 || Dirql[0] > Dirql[1])
1543               MaxDirql = Dirql[0];
1544           else
1545               MaxDirql = Dirql[1];
1546 
1547           for (i = 0; i < DeviceExtension->InterruptCount; i++)
1548           {
1549               /* Determine IRQ sharability as usual */
1550               if (PortConfig->AdapterInterfaceType == MicroChannel ||
1551                   InterruptMode[i] == LevelSensitive)
1552               {
1553                   InterruptShareable = TRUE;
1554               }
1555               else
1556               {
1557                   InterruptShareable = FALSE;
1558               }
1559 
1560               Status = IoConnectInterrupt(&DeviceExtension->Interrupt[i],
1561                                           (PKSERVICE_ROUTINE)ScsiPortIsr,
1562                                           DeviceExtension,
1563                                           &DeviceExtension->IrqLock,
1564                                           MappedIrq[i],
1565                                           Dirql[i],
1566                                           MaxDirql,
1567                                           InterruptMode[i],
1568                                           InterruptShareable,
1569                                           Affinity[i],
1570                                           FALSE);
1571 
1572               if (!(NT_SUCCESS(Status)))
1573               {
1574                   DPRINT1("Could not connect interrupt %d\n",
1575                           InterruptVector[i]);
1576                   DeviceExtension->Interrupt[i] = NULL;
1577                   break;
1578               }
1579           }
1580 
1581           if (!NT_SUCCESS(Status))
1582               break;
1583       }
1584 
1585       /* Save IoAddress (from access ranges) */
1586       if (HwInitializationData->NumberOfAccessRanges != 0)
1587       {
1588           DeviceExtension->IoAddress =
1589               ((*(PortConfig->AccessRanges))[0]).RangeStart.LowPart;
1590 
1591           DPRINT("Io Address %x\n", DeviceExtension->IoAddress);
1592       }
1593 
1594       /* Set flag that it's allowed to disconnect during this command */
1595       DeviceExtension->Flags |= SCSI_PORT_DISCONNECT_ALLOWED;
1596 
1597       /* Initialize counter of active requests (-1 means there are none) */
1598       DeviceExtension->ActiveRequestCounter = -1;
1599 
1600       /* Analyze what we have about DMA */
1601       if (DeviceExtension->AdapterObject != NULL &&
1602           PortConfig->Master &&
1603           PortConfig->NeedPhysicalAddresses)
1604       {
1605           DeviceExtension->MapRegisters = TRUE;
1606       }
1607       else
1608       {
1609           DeviceExtension->MapRegisters = FALSE;
1610       }
1611 
1612       /* Call HwInitialize at DISPATCH_LEVEL */
1613       KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
1614 
1615       if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0],
1616                                   DeviceExtension->HwInitialize,
1617                                   DeviceExtension->MiniPortDeviceExtension))
1618       {
1619           DPRINT1("HwInitialize() failed!\n");
1620           KeLowerIrql(OldIrql);
1621           Status = STATUS_ADAPTER_HARDWARE_ERROR;
1622           break;
1623       }
1624 
1625       /* Check if a notification is needed */
1626       if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
1627       {
1628           /* Call DPC right away, because we're already at DISPATCH_LEVEL */
1629           ScsiPortDpcForIsr(NULL,
1630                             DeviceExtension->DeviceObject,
1631                             NULL,
1632                             NULL);
1633       }
1634 
1635       /* Lower irql back to what it was */
1636       KeLowerIrql(OldIrql);
1637 
1638       /* Start our timer */
1639       IoStartTimer(PortDeviceObject);
1640 
1641       /* Initialize bus scanning information */
1642       BusConfigSize = FIELD_OFFSET(BUSES_CONFIGURATION_INFORMATION,
1643                                    BusScanInfo[DeviceExtension->PortConfig->NumberOfBuses]);
1644       DeviceExtension->BusesConfig = ExAllocatePoolWithTag(PagedPool,
1645                                                            BusConfigSize,
1646                                                            TAG_SCSIPORT);
1647       if (!DeviceExtension->BusesConfig)
1648       {
1649           DPRINT1("Out of resources!\n");
1650           Status = STATUS_INSUFFICIENT_RESOURCES;
1651           break;
1652       }
1653 
1654       /* Zero it */
1655       RtlZeroMemory(DeviceExtension->BusesConfig, BusConfigSize);
1656 
1657       /* Store number of buses there */
1658       DeviceExtension->BusesConfig->NumberOfBuses = (UCHAR)DeviceExtension->BusNum;
1659 
1660       /* Scan the adapter for devices */
1661       SpiScanAdapter(DeviceExtension);
1662 
1663       /* Build the registry device map */
1664       SpiBuildDeviceMap(DeviceExtension,
1665                        (PUNICODE_STRING)Argument2);
1666 
1667       /* Create the dos device link */
1668       swprintf(DosNameBuffer,
1669                L"\\??\\Scsi%lu:",
1670               SystemConfig->ScsiPortCount);
1671       RtlInitUnicodeString(&DosDeviceName, DosNameBuffer);
1672       IoCreateSymbolicLink(&DosDeviceName, &DeviceName);
1673 
1674       /* Increase the port count */
1675       SystemConfig->ScsiPortCount++;
1676       FirstConfigCall = FALSE;
1677 
1678       /* Increase adapter number and bus number respectively */
1679       ConfigInfo.AdapterNumber++;
1680 
1681       if (!Again)
1682           ConfigInfo.BusNumber++;
1683 
1684       DPRINT("Bus: %lu  MaxBus: %lu\n", ConfigInfo.BusNumber, MaxBus);
1685 
1686       DeviceFound = TRUE;
1687     }
1688 
1689     /* Clean up the mess */
1690     SpiCleanupAfterInit(DeviceExtension);
1691 
1692     /* Close registry keys */
1693     if (ConfigInfo.ServiceKey != NULL)
1694         ZwClose(ConfigInfo.ServiceKey);
1695 
1696     if (ConfigInfo.DeviceKey != NULL)
1697         ZwClose(ConfigInfo.DeviceKey);
1698 
1699     if (ConfigInfo.BusKey != NULL)
1700         ZwClose(ConfigInfo.BusKey);
1701 
1702     if (ConfigInfo.AccessRanges != NULL)
1703         ExFreePool(ConfigInfo.AccessRanges);
1704 
1705     if (ConfigInfo.Parameter != NULL)
1706         ExFreePool(ConfigInfo.Parameter);
1707 
1708     DPRINT("ScsiPortInitialize() done, Status = 0x%08X, DeviceFound = %d!\n",
1709         Status, DeviceFound);
1710 
1711     return (DeviceFound == FALSE) ? Status : STATUS_SUCCESS;
1712 }
1713 
1714 static VOID
1715 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
1716 {
1717     PSCSI_LUN_INFO LunInfo;
1718     PVOID Ptr;
1719     ULONG Bus, Lun;
1720 
1721     /* Check if we have something to clean up */
1722     if (DeviceExtension == NULL)
1723         return;
1724 
1725     /* Stop the timer */
1726     IoStopTimer(DeviceExtension->DeviceObject);
1727 
1728     /* Disconnect the interrupts */
1729     while (DeviceExtension->InterruptCount)
1730     {
1731         if (DeviceExtension->Interrupt[--DeviceExtension->InterruptCount])
1732             IoDisconnectInterrupt(DeviceExtension->Interrupt[DeviceExtension->InterruptCount]);
1733     }
1734 
1735     /* Delete ConfigInfo */
1736     if (DeviceExtension->BusesConfig)
1737     {
1738         for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
1739         {
1740             if (!DeviceExtension->BusesConfig->BusScanInfo[Bus])
1741                 continue;
1742 
1743             LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
1744 
1745             while (LunInfo)
1746             {
1747                 /* Free current, but save pointer to the next one */
1748                 Ptr = LunInfo->Next;
1749                 ExFreePool(LunInfo);
1750                 LunInfo = Ptr;
1751             }
1752 
1753             ExFreePool(DeviceExtension->BusesConfig->BusScanInfo[Bus]);
1754         }
1755 
1756         ExFreePool(DeviceExtension->BusesConfig);
1757     }
1758 
1759     /* Free PortConfig */
1760     if (DeviceExtension->PortConfig)
1761         ExFreePool(DeviceExtension->PortConfig);
1762 
1763     /* Free LUNs*/
1764     for(Lun = 0; Lun < LUS_NUMBER; Lun++)
1765     {
1766         while (DeviceExtension->LunExtensionList[Lun])
1767         {
1768             Ptr = DeviceExtension->LunExtensionList[Lun];
1769             DeviceExtension->LunExtensionList[Lun] = DeviceExtension->LunExtensionList[Lun]->Next;
1770 
1771             ExFreePool(Ptr);
1772         }
1773     }
1774 
1775     /* Free common buffer (if it exists) */
1776     if (DeviceExtension->SrbExtensionBuffer != NULL &&
1777         DeviceExtension->CommonBufferLength != 0)
1778     {
1779             if (!DeviceExtension->AdapterObject)
1780             {
1781                 ExFreePool(DeviceExtension->SrbExtensionBuffer);
1782             }
1783             else
1784             {
1785                 HalFreeCommonBuffer(DeviceExtension->AdapterObject,
1786                                     DeviceExtension->CommonBufferLength,
1787                                     DeviceExtension->PhysicalAddress,
1788                                     DeviceExtension->SrbExtensionBuffer,
1789                                     FALSE);
1790             }
1791     }
1792 
1793     /* Free SRB info */
1794     if (DeviceExtension->SrbInfo != NULL)
1795         ExFreePool(DeviceExtension->SrbInfo);
1796 
1797     /* Unmap mapped addresses */
1798     while (DeviceExtension->MappedAddressList != NULL)
1799     {
1800         MmUnmapIoSpace(DeviceExtension->MappedAddressList->MappedAddress,
1801                        DeviceExtension->MappedAddressList->NumberOfBytes);
1802 
1803         Ptr = DeviceExtension->MappedAddressList;
1804         DeviceExtension->MappedAddressList = DeviceExtension->MappedAddressList->NextMappedAddress;
1805 
1806         ExFreePool(Ptr);
1807     }
1808 
1809     /* Finally delete the device object */
1810     DPRINT("Deleting device %p\n", DeviceExtension->DeviceObject);
1811     IoDeleteDevice(DeviceExtension->DeviceObject);
1812 }
1813 
1814 /*
1815  * @unimplemented
1816  */
1817 VOID NTAPI
1818 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension,
1819 		      IN PSCSI_REQUEST_BLOCK Srb,
1820 		      IN PVOID LogicalAddress,
1821 		      IN ULONG Length)
1822 {
1823   DPRINT1("ScsiPortIoMapTransfer()\n");
1824   UNIMPLEMENTED;
1825 }
1826 
1827 /*
1828  * @unimplemented
1829  */
1830 VOID NTAPI
1831 ScsiPortLogError(IN PVOID HwDeviceExtension,
1832 		 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
1833 		 IN UCHAR PathId,
1834 		 IN UCHAR TargetId,
1835 		 IN UCHAR Lun,
1836 		 IN ULONG ErrorCode,
1837 		 IN ULONG UniqueId)
1838 {
1839   //PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1840 
1841   DPRINT1("ScsiPortLogError() called\n");
1842   DPRINT1("PathId: 0x%02x  TargetId: 0x%02x  Lun: 0x%02x  ErrorCode: 0x%08lx  UniqueId: 0x%08lx\n",
1843           PathId, TargetId, Lun, ErrorCode, UniqueId);
1844 
1845   //DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, SCSI_PORT_DEVICE_EXTENSION, MiniPortDeviceExtension);
1846 
1847 
1848   DPRINT("ScsiPortLogError() done\n");
1849 }
1850 
1851 /*
1852  * @implemented
1853  */
1854 VOID NTAPI
1855 ScsiPortMoveMemory(OUT PVOID Destination,
1856 		   IN PVOID Source,
1857 		   IN ULONG Length)
1858 {
1859   RtlMoveMemory(Destination,
1860 		Source,
1861 		Length);
1862 }
1863 
1864 
1865 /*
1866  * @implemented
1867  */
1868 VOID
1869 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType,
1870 		     IN PVOID HwDeviceExtension,
1871 		     ...)
1872 {
1873     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1874     va_list ap;
1875 
1876     DPRINT("ScsiPortNotification() called\n");
1877 
1878     DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
1879         SCSI_PORT_DEVICE_EXTENSION,
1880         MiniPortDeviceExtension);
1881 
1882     DPRINT("DeviceExtension %p\n", DeviceExtension);
1883 
1884     va_start(ap, HwDeviceExtension);
1885 
1886     switch (NotificationType)
1887     {
1888     case RequestComplete:
1889         {
1890             PSCSI_REQUEST_BLOCK Srb;
1891             PSCSI_REQUEST_BLOCK_INFO SrbData;
1892 
1893             Srb = (PSCSI_REQUEST_BLOCK) va_arg (ap, PSCSI_REQUEST_BLOCK);
1894 
1895             DPRINT("Notify: RequestComplete (Srb %p)\n", Srb);
1896 
1897             /* Make sure Srb is alright */
1898             ASSERT(Srb->SrbStatus != SRB_STATUS_PENDING);
1899             ASSERT(Srb->Function != SRB_FUNCTION_EXECUTE_SCSI || Srb->SrbStatus != SRB_STATUS_SUCCESS || Srb->ScsiStatus == SCSISTAT_GOOD);
1900 
1901             if (!(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE))
1902             {
1903                 /* It's been already completed */
1904                 va_end(ap);
1905                 return;
1906             }
1907 
1908             /* It's not active anymore */
1909             Srb->SrbFlags &= ~SRB_FLAGS_IS_ACTIVE;
1910 
1911             if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
1912             {
1913                 /* TODO: Treat it specially */
1914                 ASSERT(FALSE);
1915             }
1916             else
1917             {
1918                 /* Get the SRB data */
1919                 SrbData = SpiGetSrbData(DeviceExtension,
1920                                         Srb->PathId,
1921                                         Srb->TargetId,
1922                                         Srb->Lun,
1923                                         Srb->QueueTag);
1924 
1925                 /* Make sure there are no CompletedRequests and there is a Srb */
1926                 ASSERT(SrbData->CompletedRequests == NULL && SrbData->Srb != NULL);
1927 
1928                 /* If it's a read/write request, make sure it has data inside it */
1929                 if ((Srb->SrbStatus == SRB_STATUS_SUCCESS) &&
1930                     ((Srb->Cdb[0] == SCSIOP_READ) || (Srb->Cdb[0] == SCSIOP_WRITE)))
1931                 {
1932                         ASSERT(Srb->DataTransferLength);
1933                 }
1934 
1935                 SrbData->CompletedRequests = DeviceExtension->InterruptData.CompletedRequests;
1936                 DeviceExtension->InterruptData.CompletedRequests = SrbData;
1937             }
1938         }
1939         break;
1940 
1941     case NextRequest:
1942         DPRINT("Notify: NextRequest\n");
1943         DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY;
1944         break;
1945 
1946     case NextLuRequest:
1947         {
1948             UCHAR PathId;
1949             UCHAR TargetId;
1950             UCHAR Lun;
1951             PSCSI_PORT_LUN_EXTENSION LunExtension;
1952 
1953             PathId = (UCHAR) va_arg (ap, int);
1954             TargetId = (UCHAR) va_arg (ap, int);
1955             Lun = (UCHAR) va_arg (ap, int);
1956 
1957             DPRINT("Notify: NextLuRequest(PathId %u  TargetId %u  Lun %u)\n",
1958                 PathId, TargetId, Lun);
1959 
1960             /* Mark it in the flags field */
1961             DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY;
1962 
1963             /* Get the LUN extension */
1964             LunExtension = SpiGetLunExtension(DeviceExtension,
1965                                               PathId,
1966                                               TargetId,
1967                                               Lun);
1968 
1969             /* If returned LunExtension is NULL, break out */
1970             if (!LunExtension) break;
1971 
1972             /* This request should not be processed if */
1973             if ((LunExtension->ReadyLun) ||
1974                 (LunExtension->SrbInfo.Srb))
1975             {
1976                 /* Nothing to do here */
1977                 break;
1978             }
1979 
1980             /* Add this LUN to the list */
1981             LunExtension->ReadyLun = DeviceExtension->InterruptData.ReadyLun;
1982             DeviceExtension->InterruptData.ReadyLun = LunExtension;
1983           }
1984           break;
1985 
1986       case ResetDetected:
1987           DPRINT("Notify: ResetDetected\n");
1988           /* Add RESET flags */
1989           DeviceExtension->InterruptData.Flags |=
1990                 SCSI_PORT_RESET | SCSI_PORT_RESET_REPORTED;
1991           break;
1992 
1993       case CallDisableInterrupts:
1994           DPRINT1("UNIMPLEMENTED SCSI Notification called: CallDisableInterrupts!\n");
1995           break;
1996 
1997       case CallEnableInterrupts:
1998           DPRINT1("UNIMPLEMENTED SCSI Notification called: CallEnableInterrupts!\n");
1999           break;
2000 
2001       case RequestTimerCall:
2002           DPRINT("Notify: RequestTimerCall\n");
2003           DeviceExtension->InterruptData.Flags |= SCSI_PORT_TIMER_NEEDED;
2004           DeviceExtension->InterruptData.HwScsiTimer = (PHW_TIMER)va_arg(ap, PHW_TIMER);
2005           DeviceExtension->InterruptData.MiniportTimerValue = (ULONG)va_arg(ap, ULONG);
2006           break;
2007 
2008       case BusChangeDetected:
2009           DPRINT1("UNIMPLEMENTED SCSI Notification called: BusChangeDetected!\n");
2010           break;
2011 
2012       default:
2013 	DPRINT1 ("Unsupported notification from WMI: %lu\n", NotificationType);
2014 	break;
2015     }
2016 
2017     va_end(ap);
2018 
2019     /* Request a DPC after we're done with the interrupt */
2020     DeviceExtension->InterruptData.Flags |= SCSI_PORT_NOTIFICATION_NEEDED;
2021 }
2022 
2023 /*
2024  * @implemented
2025  */
2026 BOOLEAN NTAPI
2027 ScsiPortValidateRange(IN PVOID HwDeviceExtension,
2028 		      IN INTERFACE_TYPE BusType,
2029 		      IN ULONG SystemIoBusNumber,
2030 		      IN SCSI_PHYSICAL_ADDRESS IoAddress,
2031 		      IN ULONG NumberOfBytes,
2032 		      IN BOOLEAN InIoSpace)
2033 {
2034   DPRINT("ScsiPortValidateRange()\n");
2035   return(TRUE);
2036 }
2037 
2038 
2039 /* INTERNAL FUNCTIONS ********************************************************/
2040 
2041 static VOID
2042 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData,
2043                     IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor,
2044                     IN PPORT_CONFIGURATION_INFORMATION PortConfig)
2045 {
2046     PACCESS_RANGE AccessRange;
2047     PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialData;
2048     ULONG RangeNumber;
2049     ULONG Index;
2050     ULONG Interrupt = 0;
2051     ULONG Dma = 0;
2052 
2053     RangeNumber = 0;
2054 
2055     /* Loop through all entries */
2056     for (Index = 0; Index < ResourceDescriptor->PartialResourceList.Count; Index++)
2057     {
2058         PartialData = &ResourceDescriptor->PartialResourceList.PartialDescriptors[Index];
2059 
2060         switch (PartialData->Type)
2061         {
2062         case CmResourceTypePort:
2063             /* Copy access ranges */
2064             if (RangeNumber < HwInitializationData->NumberOfAccessRanges)
2065             {
2066                 AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]);
2067 
2068                 AccessRange->RangeStart = PartialData->u.Port.Start;
2069                 AccessRange->RangeLength = PartialData->u.Port.Length;
2070 
2071                 AccessRange->RangeInMemory = FALSE;
2072                 RangeNumber++;
2073             }
2074             break;
2075 
2076         case CmResourceTypeMemory:
2077             /* Copy access ranges */
2078             if (RangeNumber < HwInitializationData->NumberOfAccessRanges)
2079             {
2080                 AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]);
2081 
2082                 AccessRange->RangeStart = PartialData->u.Memory.Start;
2083                 AccessRange->RangeLength = PartialData->u.Memory.Length;
2084 
2085                 AccessRange->RangeInMemory = TRUE;
2086                 RangeNumber++;
2087             }
2088             break;
2089 
2090         case CmResourceTypeInterrupt:
2091 
2092             if (Interrupt == 0)
2093             {
2094                 /* Copy interrupt data */
2095                 PortConfig->BusInterruptLevel = PartialData->u.Interrupt.Level;
2096                 PortConfig->BusInterruptVector = PartialData->u.Interrupt.Vector;
2097 
2098                 /* Set interrupt mode accordingly to the resource */
2099                 if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
2100                 {
2101                     PortConfig->InterruptMode = Latched;
2102                 }
2103                 else if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
2104                 {
2105                     PortConfig->InterruptMode = LevelSensitive;
2106                 }
2107             }
2108             else if (Interrupt == 1)
2109             {
2110                 /* Copy interrupt data */
2111                 PortConfig->BusInterruptLevel2 = PartialData->u.Interrupt.Level;
2112                 PortConfig->BusInterruptVector2 = PartialData->u.Interrupt.Vector;
2113 
2114                 /* Set interrupt mode accordingly to the resource */
2115                 if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
2116                 {
2117                     PortConfig->InterruptMode2 = Latched;
2118                 }
2119                 else if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
2120                 {
2121                     PortConfig->InterruptMode2 = LevelSensitive;
2122                 }
2123             }
2124 
2125             Interrupt++;
2126             break;
2127 
2128         case CmResourceTypeDma:
2129 
2130             if (Dma == 0)
2131             {
2132                 PortConfig->DmaChannel = PartialData->u.Dma.Channel;
2133                 PortConfig->DmaPort = PartialData->u.Dma.Port;
2134 
2135                 if (PartialData->Flags & CM_RESOURCE_DMA_8)
2136                     PortConfig->DmaWidth = Width8Bits;
2137                 else if ((PartialData->Flags & CM_RESOURCE_DMA_16) ||
2138                          (PartialData->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
2139                     PortConfig->DmaWidth = Width16Bits;
2140                 else if (PartialData->Flags & CM_RESOURCE_DMA_32)
2141                     PortConfig->DmaWidth = Width32Bits;
2142             }
2143             else if (Dma == 1)
2144             {
2145                 PortConfig->DmaChannel2 = PartialData->u.Dma.Channel;
2146                 PortConfig->DmaPort2 = PartialData->u.Dma.Port;
2147 
2148                 if (PartialData->Flags & CM_RESOURCE_DMA_8)
2149                     PortConfig->DmaWidth2 = Width8Bits;
2150                 else if ((PartialData->Flags & CM_RESOURCE_DMA_16) ||
2151                          (PartialData->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
2152                     PortConfig->DmaWidth2 = Width16Bits;
2153                 else if (PartialData->Flags & CM_RESOURCE_DMA_32)
2154                     PortConfig->DmaWidth2 = Width32Bits;
2155             }
2156             break;
2157         }
2158     }
2159 }
2160 
2161 static PCM_RESOURCE_LIST
2162 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
2163                     PPORT_CONFIGURATION_INFORMATION PortConfig)
2164 {
2165     PCONFIGURATION_INFORMATION ConfigInfo;
2166     PCM_RESOURCE_LIST ResourceList;
2167     PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor;
2168     PACCESS_RANGE AccessRange;
2169     ULONG ListLength = 0, i, FullSize;
2170     ULONG Interrupt, Dma;
2171 
2172     /* Get current Atdisk usage from the system */
2173     ConfigInfo = IoGetConfigurationInformation();
2174 
2175     if (PortConfig->AtdiskPrimaryClaimed)
2176         ConfigInfo->AtDiskPrimaryAddressClaimed = TRUE;
2177 
2178     if (PortConfig->AtdiskSecondaryClaimed)
2179         ConfigInfo->AtDiskSecondaryAddressClaimed = TRUE;
2180 
2181     /* Do we use DMA? */
2182     if (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE ||
2183         PortConfig->DmaPort != SP_UNINITIALIZED_VALUE)
2184     {
2185         Dma = 1;
2186 
2187         if (PortConfig->DmaChannel2 != SP_UNINITIALIZED_VALUE ||
2188             PortConfig->DmaPort2 != SP_UNINITIALIZED_VALUE)
2189             Dma++;
2190     }
2191     else
2192     {
2193         Dma = 0;
2194     }
2195     ListLength += Dma;
2196 
2197     /* How many interrupts to we have? */
2198     Interrupt = DeviceExtension->InterruptCount;
2199     ListLength += Interrupt;
2200 
2201     /* How many access ranges do we use? */
2202     AccessRange = &((*(PortConfig->AccessRanges))[0]);
2203     for (i = 0; i < PortConfig->NumberOfAccessRanges; i++)
2204     {
2205         if (AccessRange->RangeLength != 0)
2206             ListLength++;
2207 
2208         AccessRange++;
2209     }
2210 
2211     /* Allocate the resource list, since we know its size now */
2212     FullSize = sizeof(CM_RESOURCE_LIST) + (ListLength - 1) *
2213         sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
2214 
2215     ResourceList = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(PagedPool, FullSize, TAG_SCSIPORT);
2216 
2217     if (!ResourceList)
2218         return NULL;
2219 
2220     /* Zero it */
2221     RtlZeroMemory(ResourceList, FullSize);
2222 
2223     /* Initialize it */
2224     ResourceList->Count = 1;
2225     ResourceList->List[0].InterfaceType = PortConfig->AdapterInterfaceType;
2226     ResourceList->List[0].BusNumber = PortConfig->SystemIoBusNumber;
2227     ResourceList->List[0].PartialResourceList.Count = ListLength;
2228     ResourceDescriptor = ResourceList->List[0].PartialResourceList.PartialDescriptors;
2229 
2230     /* Copy access ranges array over */
2231     for (i = 0; i < PortConfig->NumberOfAccessRanges; i++)
2232     {
2233         AccessRange = &((*(PortConfig->AccessRanges))[i]);
2234 
2235         /* If the range is empty - skip it */
2236         if (AccessRange->RangeLength == 0)
2237             continue;
2238 
2239         if (AccessRange->RangeInMemory)
2240         {
2241             ResourceDescriptor->Type = CmResourceTypeMemory;
2242             ResourceDescriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
2243         }
2244         else
2245         {
2246             ResourceDescriptor->Type = CmResourceTypePort;
2247             ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
2248         }
2249 
2250         ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
2251 
2252         ResourceDescriptor->u.Memory.Start = AccessRange->RangeStart;
2253         ResourceDescriptor->u.Memory.Length = AccessRange->RangeLength;
2254 
2255         ResourceDescriptor++;
2256     }
2257 
2258     /* If we use interrupt(s), copy them */
2259     while (Interrupt)
2260     {
2261         ResourceDescriptor->Type = CmResourceTypeInterrupt;
2262 
2263         if (PortConfig->AdapterInterfaceType == MicroChannel ||
2264             ((Interrupt == 2) ? PortConfig->InterruptMode2 : PortConfig->InterruptMode) == LevelSensitive)
2265         {
2266             ResourceDescriptor->ShareDisposition = CmResourceShareShared;
2267             ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
2268         }
2269         else
2270         {
2271             ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
2272             ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
2273         }
2274 
2275         ResourceDescriptor->u.Interrupt.Level = (Interrupt == 2) ? PortConfig->BusInterruptLevel2 : PortConfig->BusInterruptLevel;
2276         ResourceDescriptor->u.Interrupt.Vector = (Interrupt == 2) ? PortConfig->BusInterruptVector2 : PortConfig->BusInterruptVector;
2277         ResourceDescriptor->u.Interrupt.Affinity = 0;
2278 
2279         ResourceDescriptor++;
2280         Interrupt--;
2281     }
2282 
2283     /* Copy DMA data */
2284     while (Dma)
2285     {
2286         ResourceDescriptor->Type = CmResourceTypeDma;
2287         ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
2288         ResourceDescriptor->u.Dma.Channel = (Dma == 2) ? PortConfig->DmaChannel2 : PortConfig->DmaChannel;
2289         ResourceDescriptor->u.Dma.Port = (Dma == 2) ? PortConfig->DmaPort2 : PortConfig->DmaPort;
2290         ResourceDescriptor->Flags = 0;
2291 
2292         if (((Dma == 2) ? PortConfig->DmaWidth2 : PortConfig->DmaWidth) == Width8Bits)
2293             ResourceDescriptor->Flags |= CM_RESOURCE_DMA_8;
2294         else if (((Dma == 2) ? PortConfig->DmaWidth2 : PortConfig->DmaWidth) == Width16Bits)
2295             ResourceDescriptor->Flags |= CM_RESOURCE_DMA_16;
2296         else
2297             ResourceDescriptor->Flags |= CM_RESOURCE_DMA_32;
2298 
2299         if (((Dma == 2) ? PortConfig->DmaChannel2 : PortConfig->DmaChannel) == SP_UNINITIALIZED_VALUE)
2300             ResourceDescriptor->u.Dma.Channel = 0;
2301 
2302         if (((Dma == 2) ? PortConfig->DmaPort2 : PortConfig->DmaPort) == SP_UNINITIALIZED_VALUE)
2303             ResourceDescriptor->u.Dma.Port = 0;
2304 
2305         ResourceDescriptor++;
2306         Dma--;
2307     }
2308 
2309     return ResourceList;
2310 }
2311 
2312 
2313 static BOOLEAN
2314 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject,
2315                     IN PDEVICE_OBJECT DeviceObject,
2316                     IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
2317                     IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,
2318                     IN PUNICODE_STRING RegistryPath,
2319                     IN ULONG BusNumber,
2320                     IN OUT PPCI_SLOT_NUMBER NextSlotNumber)
2321 {
2322     PCI_COMMON_CONFIG PciConfig;
2323     PCI_SLOT_NUMBER SlotNumber;
2324     ULONG DataSize;
2325     ULONG DeviceNumber;
2326     ULONG FunctionNumber;
2327     CHAR VendorIdString[8];
2328     CHAR DeviceIdString[8];
2329     UNICODE_STRING UnicodeStr;
2330     PCM_RESOURCE_LIST ResourceList = NULL;
2331     NTSTATUS Status;
2332 
2333     DPRINT ("SpiGetPciConfiguration() called\n");
2334 
2335     SlotNumber.u.AsULONG = 0;
2336 
2337     /* Loop through all devices */
2338     for (DeviceNumber = NextSlotNumber->u.bits.DeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
2339     {
2340         SlotNumber.u.bits.DeviceNumber = DeviceNumber;
2341 
2342         /* Loop through all functions */
2343         for (FunctionNumber = NextSlotNumber->u.bits.FunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
2344         {
2345             SlotNumber.u.bits.FunctionNumber = FunctionNumber;
2346 
2347             /* Get PCI config bytes */
2348             DataSize = HalGetBusData(PCIConfiguration,
2349                                      BusNumber,
2350                                      SlotNumber.u.AsULONG,
2351                                      &PciConfig,
2352                                      sizeof(ULONG));
2353 
2354             /* If result of HalGetBusData is 0, then the bus is wrong */
2355             if (DataSize == 0)
2356                 return FALSE;
2357 
2358             /* Check if result is PCI_INVALID_VENDORID or too small */
2359             if ((DataSize < sizeof(ULONG)) ||
2360                 (PciConfig.VendorID == PCI_INVALID_VENDORID))
2361             {
2362                 /* Continue to try the next function */
2363                 continue;
2364             }
2365 
2366             sprintf (VendorIdString, "%04hx", PciConfig.VendorID);
2367             sprintf (DeviceIdString, "%04hx", PciConfig.DeviceID);
2368 
2369             if (_strnicmp(VendorIdString, HwInitializationData->VendorId, HwInitializationData->VendorIdLength) ||
2370                 _strnicmp(DeviceIdString, HwInitializationData->DeviceId, HwInitializationData->DeviceIdLength))
2371             {
2372                 /* It is not our device */
2373                 continue;
2374             }
2375 
2376             DPRINT("Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n",
2377                    PciConfig.VendorID,
2378                    PciConfig.DeviceID,
2379                    BusNumber,
2380                    SlotNumber.u.bits.DeviceNumber,
2381                    SlotNumber.u.bits.FunctionNumber);
2382 
2383 
2384             RtlInitUnicodeString(&UnicodeStr, L"ScsiAdapter");
2385             Status = HalAssignSlotResources(RegistryPath,
2386                                             &UnicodeStr,
2387                                             DriverObject,
2388                                             DeviceObject,
2389                                             PCIBus,
2390                                             BusNumber,
2391                                             SlotNumber.u.AsULONG,
2392                                             &ResourceList);
2393 
2394             if (!NT_SUCCESS(Status))
2395                 break;
2396 
2397             /* Create configuration information */
2398             SpiResourceToConfig(HwInitializationData,
2399                                 ResourceList->List,
2400                                 PortConfig);
2401 
2402             /* Free the resource list */
2403             ExFreePool(ResourceList);
2404 
2405             /* Set dev & fn numbers */
2406             NextSlotNumber->u.bits.DeviceNumber = DeviceNumber;
2407             NextSlotNumber->u.bits.FunctionNumber = FunctionNumber + 1;
2408 
2409             /* Save the slot number */
2410             PortConfig->SlotNumber = SlotNumber.u.AsULONG;
2411 
2412             return TRUE;
2413         }
2414        NextSlotNumber->u.bits.FunctionNumber = 0;
2415     }
2416 
2417     NextSlotNumber->u.bits.DeviceNumber = 0;
2418     DPRINT ("No device found\n");
2419 
2420     return FALSE;
2421 }
2422 
2423 
2424 
2425 /**********************************************************************
2426  * NAME							INTERNAL
2427  *	ScsiPortCreateClose
2428  *
2429  * DESCRIPTION
2430  *	Answer requests for Create/Close calls: a null operation.
2431  *
2432  * RUN LEVEL
2433  *	PASSIVE_LEVEL
2434  *
2435  * ARGUMENTS
2436  *	DeviceObject
2437  *		Pointer to a device object.
2438  *
2439  *	Irp
2440  *		Pointer to an IRP.
2441  *
2442  * RETURN VALUE
2443  * 	Status.
2444  */
2445 
2446 static NTSTATUS NTAPI
2447 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
2448                    IN PIRP Irp)
2449 {
2450     DPRINT("ScsiPortCreateClose()\n");
2451 
2452     Irp->IoStatus.Status = STATUS_SUCCESS;
2453     IoCompleteRequest(Irp, IO_NO_INCREMENT);
2454 
2455     return STATUS_SUCCESS;
2456 }
2457 
2458 static NTSTATUS
2459 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
2460                        PIRP Irp)
2461 {
2462     PSCSI_LUN_INFO LunInfo;
2463     PIO_STACK_LOCATION IrpStack;
2464     PDEVICE_OBJECT DeviceObject;
2465     PSCSI_REQUEST_BLOCK Srb;
2466     KIRQL Irql;
2467 
2468     /* Get pointer to the SRB */
2469     IrpStack = IoGetCurrentIrpStackLocation(Irp);
2470     Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
2471 
2472     /* Check if PathId matches number of buses */
2473     if (DeviceExtension->BusesConfig == NULL ||
2474         DeviceExtension->BusesConfig->NumberOfBuses <= Srb->PathId)
2475     {
2476         Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
2477         return STATUS_DEVICE_DOES_NOT_EXIST;
2478     }
2479 
2480     /* Get pointer to LunInfo */
2481     LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Srb->PathId]->LunInfo;
2482 
2483     /* Find matching LunInfo */
2484     while (LunInfo)
2485     {
2486         if (LunInfo->PathId == Srb->PathId &&
2487             LunInfo->TargetId == Srb->TargetId &&
2488             LunInfo->Lun == Srb->Lun)
2489         {
2490             break;
2491         }
2492 
2493         LunInfo = LunInfo->Next;
2494     }
2495 
2496     /* If we couldn't find it - exit */
2497     if (LunInfo == NULL)
2498         return STATUS_DEVICE_DOES_NOT_EXIST;
2499 
2500 
2501     /* Get spinlock */
2502     KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
2503 
2504     /* Release, if asked */
2505     if (Srb->Function == SRB_FUNCTION_RELEASE_DEVICE)
2506     {
2507         LunInfo->DeviceClaimed = FALSE;
2508         KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2509         Srb->SrbStatus = SRB_STATUS_SUCCESS;
2510 
2511         return STATUS_SUCCESS;
2512     }
2513 
2514     /* Attach, if not already claimed */
2515     if (LunInfo->DeviceClaimed)
2516     {
2517         KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2518         Srb->SrbStatus = SRB_STATUS_BUSY;
2519 
2520         return STATUS_DEVICE_BUSY;
2521     }
2522 
2523     /* Save the device object */
2524     DeviceObject = LunInfo->DeviceObject;
2525 
2526     if (Srb->Function == SRB_FUNCTION_CLAIM_DEVICE)
2527         LunInfo->DeviceClaimed = TRUE;
2528 
2529     if (Srb->Function == SRB_FUNCTION_ATTACH_DEVICE)
2530         LunInfo->DeviceObject = Srb->DataBuffer;
2531 
2532     Srb->DataBuffer = DeviceObject;
2533 
2534     KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2535     Srb->SrbStatus = SRB_STATUS_SUCCESS;
2536 
2537     return STATUS_SUCCESS;
2538 }
2539 
2540 
2541 /**********************************************************************
2542  * NAME							INTERNAL
2543  *	ScsiPortDispatchScsi
2544  *
2545  * DESCRIPTION
2546  *	Answer requests for SCSI calls
2547  *
2548  * RUN LEVEL
2549  *	PASSIVE_LEVEL
2550  *
2551  * ARGUMENTS
2552  *	Standard dispatch arguments
2553  *
2554  * RETURNS
2555  *	NTSTATUS
2556  */
2557 
2558 static NTSTATUS NTAPI
2559 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
2560 		     IN PIRP Irp)
2561 {
2562     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2563     PSCSI_PORT_LUN_EXTENSION LunExtension;
2564     PIO_STACK_LOCATION Stack;
2565     PSCSI_REQUEST_BLOCK Srb;
2566     KIRQL Irql;
2567     NTSTATUS Status = STATUS_SUCCESS;
2568     PIRP NextIrp, IrpList;
2569     PKDEVICE_QUEUE_ENTRY Entry;
2570 
2571     DPRINT("ScsiPortDispatchScsi(DeviceObject %p  Irp %p)\n",
2572         DeviceObject, Irp);
2573 
2574     DeviceExtension = DeviceObject->DeviceExtension;
2575     Stack = IoGetCurrentIrpStackLocation(Irp);
2576 
2577     Srb = Stack->Parameters.Scsi.Srb;
2578     if (Srb == NULL)
2579     {
2580         DPRINT1("ScsiPortDispatchScsi() called with Srb = NULL!\n");
2581         Status = STATUS_UNSUCCESSFUL;
2582 
2583         Irp->IoStatus.Status = Status;
2584         Irp->IoStatus.Information = 0;
2585 
2586         IoCompleteRequest(Irp, IO_NO_INCREMENT);
2587 
2588         return(Status);
2589     }
2590 
2591     DPRINT("Srb: %p\n", Srb);
2592     DPRINT("Srb->Function: %lu\n", Srb->Function);
2593     DPRINT("PathId: %lu  TargetId: %lu  Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
2594 
2595     LunExtension = SpiGetLunExtension(DeviceExtension,
2596                                       Srb->PathId,
2597                                       Srb->TargetId,
2598                                       Srb->Lun);
2599     if (LunExtension == NULL)
2600     {
2601         DPRINT("ScsiPortDispatchScsi() called with an invalid LUN\n");
2602         Status = STATUS_NO_SUCH_DEVICE;
2603 
2604         Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
2605         Irp->IoStatus.Status = Status;
2606         Irp->IoStatus.Information = 0;
2607 
2608         IoCompleteRequest(Irp, IO_NO_INCREMENT);
2609 
2610         return(Status);
2611     }
2612 
2613     switch (Srb->Function)
2614     {
2615     case SRB_FUNCTION_SHUTDOWN:
2616     case SRB_FUNCTION_FLUSH:
2617         DPRINT ("  SRB_FUNCTION_SHUTDOWN or FLUSH\n");
2618         if (DeviceExtension->CachesData == FALSE)
2619         {
2620             /* All success here */
2621             Srb->SrbStatus = SRB_STATUS_SUCCESS;
2622             Irp->IoStatus.Status = STATUS_SUCCESS;
2623             IoCompleteRequest(Irp, IO_NO_INCREMENT);
2624             return STATUS_SUCCESS;
2625         }
2626         /* Fall through to a usual execute operation */
2627 
2628     case SRB_FUNCTION_EXECUTE_SCSI:
2629     case SRB_FUNCTION_IO_CONTROL:
2630         DPRINT("  SRB_FUNCTION_EXECUTE_SCSI or SRB_FUNCTION_IO_CONTROL\n");
2631         /* Mark IRP as pending in all cases */
2632         IoMarkIrpPending(Irp);
2633 
2634         if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
2635         {
2636             /* Start IO directly */
2637             IoStartPacket(DeviceObject, Irp, NULL, NULL);
2638         }
2639         else
2640         {
2641             KIRQL oldIrql;
2642 
2643             /* We need to be at DISPATCH_LEVEL */
2644             KeRaiseIrql (DISPATCH_LEVEL, &oldIrql);
2645 
2646             /* Insert IRP into the queue */
2647             if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue,
2648                 &Irp->Tail.Overlay.DeviceQueueEntry,
2649                 Srb->QueueSortKey))
2650             {
2651                 /* It means the queue is empty, and we just start this request */
2652                 IoStartPacket(DeviceObject, Irp, NULL, NULL);
2653             }
2654 
2655             /* Back to the old IRQL */
2656             KeLowerIrql (oldIrql);
2657         }
2658         return STATUS_PENDING;
2659 
2660     case SRB_FUNCTION_CLAIM_DEVICE:
2661     case SRB_FUNCTION_ATTACH_DEVICE:
2662         DPRINT ("  SRB_FUNCTION_CLAIM_DEVICE or ATTACH\n");
2663 
2664         /* Reference device object and keep the device object */
2665         Status = SpiHandleAttachRelease(DeviceExtension, Irp);
2666         break;
2667 
2668     case SRB_FUNCTION_RELEASE_DEVICE:
2669         DPRINT ("  SRB_FUNCTION_RELEASE_DEVICE\n");
2670 
2671         /* Dereference device object and clear the device object */
2672         Status = SpiHandleAttachRelease(DeviceExtension, Irp);
2673         break;
2674 
2675     case SRB_FUNCTION_RELEASE_QUEUE:
2676         DPRINT("  SRB_FUNCTION_RELEASE_QUEUE\n");
2677 
2678         /* Guard with the spinlock */
2679         KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
2680 
2681         if (!(LunExtension->Flags & LUNEX_FROZEN_QUEUE))
2682         {
2683             DPRINT("Queue is not frozen really\n");
2684 
2685             KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2686             Srb->SrbStatus = SRB_STATUS_SUCCESS;
2687             Status = STATUS_SUCCESS;
2688             break;
2689 
2690         }
2691 
2692         /* Unfreeze the queue */
2693         LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
2694 
2695         if (LunExtension->SrbInfo.Srb == NULL)
2696         {
2697             /* Get next logical unit request */
2698             SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
2699 
2700             /* SpiGetNextRequestFromLun() releases the spinlock */
2701             KeLowerIrql(Irql);
2702         }
2703         else
2704         {
2705             DPRINT("The queue has active request\n");
2706             KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2707         }
2708 
2709 
2710         Srb->SrbStatus = SRB_STATUS_SUCCESS;
2711         Status = STATUS_SUCCESS;
2712         break;
2713 
2714     case SRB_FUNCTION_FLUSH_QUEUE:
2715         DPRINT("  SRB_FUNCTION_FLUSH_QUEUE\n");
2716 
2717         /* Guard with the spinlock */
2718         KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
2719 
2720         if (!(LunExtension->Flags & LUNEX_FROZEN_QUEUE))
2721         {
2722             DPRINT("Queue is not frozen really\n");
2723 
2724             KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2725             Status = STATUS_INVALID_DEVICE_REQUEST;
2726             break;
2727         }
2728 
2729         /* Make sure there is no active request */
2730         ASSERT(LunExtension->SrbInfo.Srb == NULL);
2731 
2732         /* Compile a list from the device queue */
2733         IrpList = NULL;
2734         while ((Entry = KeRemoveDeviceQueue(&LunExtension->DeviceQueue)) != NULL)
2735         {
2736                 NextIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
2737 
2738                 /* Get the Srb */
2739                 Stack = IoGetCurrentIrpStackLocation(NextIrp);
2740                 Srb = Stack->Parameters.Scsi.Srb;
2741 
2742                 /* Set statuse */
2743                 Srb->SrbStatus = SRB_STATUS_REQUEST_FLUSHED;
2744                 NextIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
2745 
2746                 /* Add then to the list */
2747                 NextIrp->Tail.Overlay.ListEntry.Flink = (PLIST_ENTRY)IrpList;
2748                 IrpList = NextIrp;
2749         }
2750 
2751         /* Unfreeze the queue */
2752         LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
2753 
2754         /* Release the spinlock */
2755         KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2756 
2757         /* Complete those requests */
2758         while (IrpList)
2759         {
2760             NextIrp = IrpList;
2761             IrpList = (PIRP)NextIrp->Tail.Overlay.ListEntry.Flink;
2762 
2763             IoCompleteRequest(NextIrp, 0);
2764         }
2765 
2766         Status = STATUS_SUCCESS;
2767         break;
2768 
2769     default:
2770         DPRINT1("SRB function not implemented (Function %lu)\n", Srb->Function);
2771         Status = STATUS_NOT_IMPLEMENTED;
2772         break;
2773     }
2774 
2775     Irp->IoStatus.Status = Status;
2776 
2777     IoCompleteRequest(Irp, IO_NO_INCREMENT);
2778 
2779     return(Status);
2780 }
2781 
2782 
2783 /**********************************************************************
2784  * NAME							INTERNAL
2785  *	ScsiPortDeviceControl
2786  *
2787  * DESCRIPTION
2788  *	Answer requests for device control calls
2789  *
2790  * RUN LEVEL
2791  *	PASSIVE_LEVEL
2792  *
2793  * ARGUMENTS
2794  *	Standard dispatch arguments
2795  *
2796  * RETURNS
2797  *	NTSTATUS
2798  */
2799 
2800 static NTSTATUS NTAPI
2801 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
2802 		      IN PIRP Irp)
2803 {
2804     PIO_STACK_LOCATION Stack;
2805     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2806     PDUMP_POINTERS DumpPointers;
2807     NTSTATUS Status;
2808 
2809     DPRINT("ScsiPortDeviceControl()\n");
2810 
2811     Irp->IoStatus.Information = 0;
2812 
2813     Stack = IoGetCurrentIrpStackLocation(Irp);
2814     DeviceExtension = DeviceObject->DeviceExtension;
2815 
2816     switch (Stack->Parameters.DeviceIoControl.IoControlCode)
2817     {
2818       case IOCTL_SCSI_GET_DUMP_POINTERS:
2819         DPRINT("  IOCTL_SCSI_GET_DUMP_POINTERS\n");
2820 
2821         if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DUMP_POINTERS))
2822         {
2823           Status = STATUS_BUFFER_OVERFLOW;
2824           Irp->IoStatus.Information = sizeof(DUMP_POINTERS);
2825           break;
2826         }
2827 
2828         DumpPointers = Irp->AssociatedIrp.SystemBuffer;
2829         DumpPointers->DeviceObject = DeviceObject;
2830         /* More data.. ? */
2831 
2832         Status = STATUS_SUCCESS;
2833         Irp->IoStatus.Information = sizeof(DUMP_POINTERS);
2834         break;
2835 
2836       case IOCTL_SCSI_GET_CAPABILITIES:
2837         DPRINT("  IOCTL_SCSI_GET_CAPABILITIES\n");
2838         if (Stack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(PVOID))
2839         {
2840             *((PVOID *)Irp->AssociatedIrp.SystemBuffer) = &DeviceExtension->PortCapabilities;
2841 
2842             Irp->IoStatus.Information = sizeof(PVOID);
2843             Status = STATUS_SUCCESS;
2844             break;
2845         }
2846 
2847         if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(IO_SCSI_CAPABILITIES))
2848         {
2849             Status = STATUS_BUFFER_TOO_SMALL;
2850             break;
2851         }
2852 
2853         RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
2854                       &DeviceExtension->PortCapabilities,
2855                       sizeof(IO_SCSI_CAPABILITIES));
2856 
2857         Irp->IoStatus.Information = sizeof(IO_SCSI_CAPABILITIES);
2858         Status = STATUS_SUCCESS;
2859         break;
2860 
2861       case IOCTL_SCSI_GET_INQUIRY_DATA:
2862           DPRINT("  IOCTL_SCSI_GET_INQUIRY_DATA\n");
2863 
2864           /* Copy inquiry data to the port device extension */
2865           Status = SpiGetInquiryData(DeviceExtension, Irp);
2866           break;
2867 
2868       case IOCTL_SCSI_MINIPORT:
2869           DPRINT1("IOCTL_SCSI_MINIPORT unimplemented!\n");
2870           Status = STATUS_NOT_IMPLEMENTED;
2871           break;
2872 
2873       case IOCTL_SCSI_PASS_THROUGH:
2874           DPRINT1("IOCTL_SCSI_PASS_THROUGH unimplemented!\n");
2875           Status = STATUS_NOT_IMPLEMENTED;
2876           break;
2877 
2878       default:
2879           if (DEVICE_TYPE_FROM_CTL_CODE(Stack->Parameters.DeviceIoControl.IoControlCode) == MOUNTDEVCONTROLTYPE)
2880           {
2881             switch (Stack->Parameters.DeviceIoControl.IoControlCode)
2882             {
2883             case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME:
2884                 DPRINT1("Got unexpected IOCTL_MOUNTDEV_QUERY_DEVICE_NAME\n");
2885                 break;
2886             case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID:
2887                 DPRINT1("Got unexpected IOCTL_MOUNTDEV_QUERY_UNIQUE_ID\n");
2888                 break;
2889             default:
2890                 DPRINT1("  got ioctl intended for the mount manager: 0x%lX\n", Stack->Parameters.DeviceIoControl.IoControlCode);
2891                 break;
2892             }
2893           } else {
2894             DPRINT1("  unknown ioctl code: 0x%lX\n", Stack->Parameters.DeviceIoControl.IoControlCode);
2895           }
2896           Status = STATUS_NOT_IMPLEMENTED;
2897           break;
2898     }
2899 
2900     /* Complete the request with the given status */
2901     Irp->IoStatus.Status = Status;
2902     IoCompleteRequest(Irp, IO_NO_INCREMENT);
2903 
2904     return Status;
2905 }
2906 
2907 
2908 static VOID NTAPI
2909 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
2910 		IN PIRP Irp)
2911 {
2912     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2913     PSCSI_PORT_LUN_EXTENSION LunExtension;
2914     PIO_STACK_LOCATION IrpStack;
2915     PSCSI_REQUEST_BLOCK Srb;
2916     PSCSI_REQUEST_BLOCK_INFO SrbInfo;
2917     LONG CounterResult;
2918     NTSTATUS Status;
2919 
2920     DPRINT("ScsiPortStartIo() called!\n");
2921 
2922     DeviceExtension = DeviceObject->DeviceExtension;
2923     IrpStack = IoGetCurrentIrpStackLocation(Irp);
2924 
2925     DPRINT("DeviceExtension %p\n", DeviceExtension);
2926 
2927     Srb = IrpStack->Parameters.Scsi.Srb;
2928 
2929     /* Apply "default" flags */
2930     Srb->SrbFlags |= DeviceExtension->SrbFlags;
2931 
2932     /* Get LUN extension */
2933     LunExtension = SpiGetLunExtension(DeviceExtension,
2934                                       Srb->PathId,
2935                                       Srb->TargetId,
2936                                       Srb->Lun);
2937 
2938     if (DeviceExtension->NeedSrbDataAlloc ||
2939         DeviceExtension->NeedSrbExtensionAlloc)
2940     {
2941         /* Allocate them */
2942         SrbInfo = SpiAllocateSrbStructures(DeviceExtension,
2943                                            LunExtension,
2944                                            Srb);
2945 
2946         /* Couldn't alloc one or both data structures, return */
2947         if (SrbInfo == NULL)
2948         {
2949             /* We have to call IoStartNextPacket, because this request
2950                was not started */
2951             if (LunExtension->Flags & LUNEX_REQUEST_PENDING)
2952                 IoStartNextPacket(DeviceObject, FALSE);
2953 
2954             return;
2955         }
2956     }
2957     else
2958     {
2959         /* No allocations are needed */
2960         SrbInfo = &LunExtension->SrbInfo;
2961         Srb->SrbExtension = NULL;
2962         Srb->QueueTag = SP_UNTAGGED;
2963     }
2964 
2965     /* Increase sequence number of SRB */
2966     if (!SrbInfo->SequenceNumber)
2967     {
2968         /* Increase global sequence number */
2969         DeviceExtension->SequenceNumber++;
2970 
2971         /* Assign it */
2972         SrbInfo->SequenceNumber = DeviceExtension->SequenceNumber;
2973     }
2974 
2975     /* Check some special SRBs */
2976     if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
2977     {
2978         /* Some special handling */
2979         DPRINT1("Abort command! Unimplemented now\n");
2980     }
2981     else
2982     {
2983         SrbInfo->Srb = Srb;
2984     }
2985 
2986     if (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION)
2987     {
2988         // Store the MDL virtual address in SrbInfo structure
2989         SrbInfo->DataOffset = MmGetMdlVirtualAddress(Irp->MdlAddress);
2990 
2991         if (DeviceExtension->MapBuffers)
2992         {
2993             /* Calculate offset within DataBuffer */
2994             SrbInfo->DataOffset = MmGetSystemAddressForMdl(Irp->MdlAddress);
2995             Srb->DataBuffer = SrbInfo->DataOffset +
2996                 (ULONG)((PUCHAR)Srb->DataBuffer -
2997                 (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress));
2998         }
2999 
3000         if (DeviceExtension->AdapterObject)
3001         {
3002             /* Flush buffers */
3003             KeFlushIoBuffers(Irp->MdlAddress,
3004                              Srb->SrbFlags & SRB_FLAGS_DATA_IN ? TRUE : FALSE,
3005                              TRUE);
3006         }
3007 
3008         if (DeviceExtension->MapRegisters)
3009         {
3010             /* Calculate number of needed map registers */
3011             SrbInfo->NumberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
3012                     Srb->DataBuffer,
3013                     Srb->DataTransferLength);
3014 
3015             /* Allocate adapter channel */
3016             Status = IoAllocateAdapterChannel(DeviceExtension->AdapterObject,
3017                                               DeviceExtension->DeviceObject,
3018                                               SrbInfo->NumberOfMapRegisters,
3019                                               SpiAdapterControl,
3020                                               SrbInfo);
3021 
3022             if (!NT_SUCCESS(Status))
3023             {
3024                 DPRINT1("IoAllocateAdapterChannel() failed!\n");
3025 
3026                 Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
3027                 ScsiPortNotification(RequestComplete,
3028                                      DeviceExtension + 1,
3029                                      Srb);
3030 
3031                 ScsiPortNotification(NextRequest,
3032                                      DeviceExtension + 1);
3033 
3034                 /* Request DPC for that work */
3035                 IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
3036             }
3037 
3038             /* Control goes to SpiAdapterControl */
3039             return;
3040         }
3041     }
3042 
3043     /* Increase active request counter */
3044     CounterResult = InterlockedIncrement(&DeviceExtension->ActiveRequestCounter);
3045 
3046     if (CounterResult == 0 &&
3047         DeviceExtension->AdapterObject != NULL &&
3048         !DeviceExtension->MapRegisters)
3049     {
3050         IoAllocateAdapterChannel(
3051             DeviceExtension->AdapterObject,
3052             DeviceObject,
3053             DeviceExtension->PortCapabilities.MaximumPhysicalPages,
3054             ScsiPortAllocateAdapterChannel,
3055             LunExtension
3056             );
3057 
3058         return;
3059     }
3060 
3061     KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
3062 
3063     if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0],
3064                                 ScsiPortStartPacket,
3065                                 DeviceObject))
3066     {
3067         DPRINT("Synchronization failed!\n");
3068 
3069         Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
3070         Irp->IoStatus.Information = 0;
3071         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3072 
3073         IoCompleteRequest(Irp, IO_NO_INCREMENT);
3074     }
3075     else
3076     {
3077         /* Release the spinlock only */
3078         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3079     }
3080 
3081 
3082     DPRINT("ScsiPortStartIo() done\n");
3083 }
3084 
3085 
3086 static BOOLEAN NTAPI
3087 ScsiPortStartPacket(IN OUT PVOID Context)
3088 {
3089     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
3090     PIO_STACK_LOCATION IrpStack;
3091     PSCSI_REQUEST_BLOCK Srb;
3092     PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)Context;
3093     PSCSI_PORT_LUN_EXTENSION LunExtension;
3094     PSCSI_REQUEST_BLOCK_INFO SrbInfo;
3095     BOOLEAN Result;
3096     BOOLEAN StartTimer;
3097 
3098     DPRINT("ScsiPortStartPacket() called\n");
3099 
3100     DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
3101 
3102     IrpStack = IoGetCurrentIrpStackLocation(DeviceObject->CurrentIrp);
3103     Srb = IrpStack->Parameters.Scsi.Srb;
3104 
3105     /* Get LUN extension */
3106     LunExtension = SpiGetLunExtension(DeviceExtension,
3107                                       Srb->PathId,
3108                                       Srb->TargetId,
3109                                       Srb->Lun);
3110 
3111     /* Check if we are in a reset state */
3112     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET)
3113     {
3114         /* Mark the we've got requests while being in the reset state */
3115         DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET_REQUEST;
3116         return TRUE;
3117     }
3118 
3119     /* Set the time out value */
3120     DeviceExtension->TimerCount = Srb->TimeOutValue;
3121 
3122     /* We are busy */
3123     DeviceExtension->Flags |= SCSI_PORT_DEVICE_BUSY;
3124 
3125     if (LunExtension->RequestTimeout != -1)
3126     {
3127         /* Timer already active */
3128         StartTimer = FALSE;
3129     }
3130     else
3131     {
3132         /* It hasn't been initialized yet */
3133         LunExtension->RequestTimeout = Srb->TimeOutValue;
3134         StartTimer = TRUE;
3135     }
3136 
3137     if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
3138     {
3139         /* Handle bypass-requests */
3140 
3141         /* Is this an abort request? */
3142         if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
3143         {
3144             /* Get pointer to SRB info structure */
3145             SrbInfo = SpiGetSrbData(DeviceExtension,
3146                                     Srb->PathId,
3147                                     Srb->TargetId,
3148                                     Srb->Lun,
3149                                     Srb->QueueTag);
3150 
3151             /* Check if the request is still "active" */
3152             if (SrbInfo == NULL ||
3153                 SrbInfo->Srb == NULL ||
3154                 !(SrbInfo->Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE))
3155             {
3156                 /* It's not, mark it as active then */
3157                 Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
3158 
3159                 if (StartTimer)
3160                     LunExtension->RequestTimeout = -1;
3161 
3162                 DPRINT("Request has been already completed, but abort request came\n");
3163                 Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
3164 
3165                 /* Notify about request complete */
3166                 ScsiPortNotification(RequestComplete,
3167                                      DeviceExtension->MiniPortDeviceExtension,
3168                                      Srb);
3169 
3170                 /* and about readiness for the next request */
3171                 ScsiPortNotification(NextRequest,
3172                                      DeviceExtension->MiniPortDeviceExtension);
3173 
3174                 /* They might ask for some work, so queue the DPC for them */
3175                 IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
3176 
3177                 /* We're done in this branch */
3178                 return TRUE;
3179             }
3180         }
3181         else
3182         {
3183             /* Add number of queued requests */
3184             LunExtension->QueueCount++;
3185         }
3186 
3187         /* Bypass requests don't need request sense */
3188         LunExtension->Flags &= ~LUNEX_NEED_REQUEST_SENSE;
3189 
3190         /* Is disconnect disabled for this request? */
3191         if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
3192         {
3193             /* Set the corresponding flag */
3194             DeviceExtension->Flags &= ~SCSI_PORT_DISCONNECT_ALLOWED;
3195         }
3196 
3197         /* Transfer timeout value from Srb to Lun */
3198         LunExtension->RequestTimeout = Srb->TimeOutValue;
3199     }
3200     else
3201     {
3202         if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
3203         {
3204             /* It's a disconnect, so no more requests can go */
3205             DeviceExtension->Flags &= ~SCSI_PORT_DISCONNECT_ALLOWED;
3206         }
3207 
3208         LunExtension->Flags |= SCSI_PORT_LU_ACTIVE;
3209 
3210         /* Increment queue count */
3211         LunExtension->QueueCount++;
3212 
3213         /* If it's tagged - special thing */
3214         if (Srb->QueueTag != SP_UNTAGGED)
3215         {
3216             SrbInfo = &DeviceExtension->SrbInfo[Srb->QueueTag - 1];
3217 
3218             /* Chek for consistency */
3219             ASSERT(SrbInfo->Requests.Blink == NULL);
3220 
3221             /* Insert it into the list of requests */
3222             InsertTailList(&LunExtension->SrbInfo.Requests, &SrbInfo->Requests);
3223         }
3224     }
3225 
3226     /* Mark this Srb active */
3227     Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
3228 
3229     /* Call HwStartIo routine */
3230     Result = DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
3231                                         Srb);
3232 
3233     /* If notification is needed, then request a DPC */
3234     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
3235         IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
3236 
3237     return Result;
3238 }
3239 
3240 IO_ALLOCATION_ACTION
3241 NTAPI
3242 SpiAdapterControl(PDEVICE_OBJECT DeviceObject,
3243                   PIRP Irp,
3244                   PVOID MapRegisterBase,
3245                   PVOID Context)
3246 {
3247     PSCSI_REQUEST_BLOCK Srb;
3248     PSCSI_SG_ADDRESS ScatterGatherList;
3249     KIRQL CurrentIrql;
3250     PIO_STACK_LOCATION IrpStack;
3251     ULONG TotalLength = 0;
3252     PSCSI_REQUEST_BLOCK_INFO SrbInfo;
3253     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
3254     PUCHAR DataVA;
3255     BOOLEAN WriteToDevice;
3256 
3257     /* Get pointers to SrbInfo and DeviceExtension */
3258     SrbInfo = (PSCSI_REQUEST_BLOCK_INFO)Context;
3259     DeviceExtension = DeviceObject->DeviceExtension;
3260 
3261     /* Get pointer to SRB */
3262     IrpStack = IoGetCurrentIrpStackLocation(Irp);
3263     Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
3264 
3265     /* Depending on the map registers number, we allocate
3266        either from NonPagedPool, or from our static list */
3267     if (SrbInfo->NumberOfMapRegisters > MAX_SG_LIST)
3268     {
3269         SrbInfo->ScatterGather = ExAllocatePoolWithTag(
3270             NonPagedPool, SrbInfo->NumberOfMapRegisters * sizeof(SCSI_SG_ADDRESS), TAG_SCSIPORT);
3271 
3272         if (SrbInfo->ScatterGather == NULL)
3273             ASSERT(FALSE);
3274 
3275         Srb->SrbFlags |= SRB_FLAGS_SGLIST_FROM_POOL;
3276     }
3277     else
3278     {
3279         SrbInfo->ScatterGather = SrbInfo->ScatterGatherList;
3280     }
3281 
3282     /* Use chosen SG list source */
3283     ScatterGatherList = SrbInfo->ScatterGather;
3284 
3285     /* Save map registers base */
3286     SrbInfo->BaseOfMapRegister = MapRegisterBase;
3287 
3288     /* Determine WriteToDevice flag */
3289     WriteToDevice = Srb->SrbFlags & SRB_FLAGS_DATA_OUT ? TRUE : FALSE;
3290 
3291     /* Get virtual address of the data buffer */
3292     DataVA = (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress) +
3293                 ((PCHAR)Srb->DataBuffer - SrbInfo->DataOffset);
3294 
3295     /* Build the actual SG list */
3296     while (TotalLength < Srb->DataTransferLength)
3297     {
3298         if (!ScatterGatherList)
3299             break;
3300 
3301         ScatterGatherList->Length = Srb->DataTransferLength - TotalLength;
3302         ScatterGatherList->PhysicalAddress = IoMapTransfer(DeviceExtension->AdapterObject,
3303                                                            Irp->MdlAddress,
3304                                                            MapRegisterBase,
3305                                                            DataVA + TotalLength,
3306                                                            &ScatterGatherList->Length,
3307                                                            WriteToDevice);
3308 
3309         TotalLength += ScatterGatherList->Length;
3310         ScatterGatherList++;
3311     }
3312 
3313     /* Schedule an active request */
3314     InterlockedIncrement(&DeviceExtension->ActiveRequestCounter );
3315     KeAcquireSpinLock(&DeviceExtension->SpinLock, &CurrentIrql);
3316     KeSynchronizeExecution(DeviceExtension->Interrupt[0],
3317                            ScsiPortStartPacket,
3318                            DeviceObject);
3319     KeReleaseSpinLock(&DeviceExtension->SpinLock, CurrentIrql);
3320 
3321     return DeallocateObjectKeepRegisters;
3322 }
3323 
3324 static PSCSI_PORT_LUN_EXTENSION
3325 SpiAllocateLunExtension(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
3326 {
3327     PSCSI_PORT_LUN_EXTENSION LunExtension;
3328     ULONG LunExtensionSize;
3329 
3330     DPRINT("SpiAllocateLunExtension(%p)\n", DeviceExtension);
3331 
3332     /* Round LunExtensionSize first to the sizeof LONGLONG */
3333     LunExtensionSize = (DeviceExtension->LunExtensionSize +
3334                         sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1);
3335 
3336     LunExtensionSize += sizeof(SCSI_PORT_LUN_EXTENSION);
3337     DPRINT("LunExtensionSize %lu\n", LunExtensionSize);
3338 
3339     LunExtension = ExAllocatePoolWithTag(NonPagedPool, LunExtensionSize, TAG_SCSIPORT);
3340     if (LunExtension == NULL)
3341     {
3342         DPRINT1("Out of resources!\n");
3343         return NULL;
3344     }
3345 
3346     /* Zero everything */
3347     RtlZeroMemory(LunExtension, LunExtensionSize);
3348 
3349     /* Initialize a list of requests */
3350     InitializeListHead(&LunExtension->SrbInfo.Requests);
3351 
3352     /* Initialize timeout counter */
3353     LunExtension->RequestTimeout = -1;
3354 
3355     /* Set maximum queue size */
3356     LunExtension->MaxQueueCount = 256;
3357 
3358     /* Initialize request queue */
3359     KeInitializeDeviceQueue(&LunExtension->DeviceQueue);
3360 
3361     return LunExtension;
3362 }
3363 
3364 static PSCSI_PORT_LUN_EXTENSION
3365 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
3366 		    IN UCHAR PathId,
3367 		    IN UCHAR TargetId,
3368 		    IN UCHAR Lun)
3369 {
3370     PSCSI_PORT_LUN_EXTENSION LunExtension;
3371 
3372     DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
3373         DeviceExtension, PathId, TargetId, Lun);
3374 
3375     /* Get appropriate list */
3376     LunExtension = DeviceExtension->LunExtensionList[(TargetId + Lun) % LUS_NUMBER];
3377 
3378     /* Iterate it until we find what we need */
3379     while (LunExtension)
3380     {
3381         if (LunExtension->TargetId == TargetId &&
3382             LunExtension->Lun == Lun &&
3383             LunExtension->PathId == PathId)
3384         {
3385             /* All matches, return */
3386             return LunExtension;
3387         }
3388 
3389         /* Advance to the next item */
3390         LunExtension = LunExtension->Next;
3391     }
3392 
3393     /* We did not find anything */
3394     DPRINT("Nothing found\n");
3395     return NULL;
3396 }
3397 
3398 static PSCSI_REQUEST_BLOCK_INFO
3399 SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
3400                          PSCSI_PORT_LUN_EXTENSION LunExtension,
3401                          PSCSI_REQUEST_BLOCK Srb)
3402 {
3403     PCHAR SrbExtension;
3404     PSCSI_REQUEST_BLOCK_INFO SrbInfo;
3405 
3406     /* Spinlock must be held while this function executes */
3407     KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
3408 
3409     /* Allocate SRB data structure */
3410     if (DeviceExtension->NeedSrbDataAlloc)
3411     {
3412         /* Treat the abort request in a special way */
3413         if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
3414         {
3415             SrbInfo = SpiGetSrbData(DeviceExtension,
3416                                     Srb->PathId,
3417                                     Srb->TargetId,
3418                                     Srb->Lun,
3419                                     Srb->QueueTag);
3420         }
3421         else if (Srb->SrbFlags &
3422                  (SRB_FLAGS_QUEUE_ACTION_ENABLE | SRB_FLAGS_NO_QUEUE_FREEZE) &&
3423                  !(Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
3424                  )
3425         {
3426             /* Do not process tagged commands if need request sense is set */
3427             if (LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE)
3428             {
3429                 ASSERT(!(LunExtension->Flags & LUNEX_REQUEST_PENDING));
3430 
3431                 LunExtension->PendingRequest = Srb->OriginalRequest;
3432                 LunExtension->Flags |= LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE;
3433 
3434                 /* Release the spinlock and return */
3435                 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3436                 return NULL;
3437             }
3438 
3439             ASSERT(LunExtension->SrbInfo.Srb == NULL);
3440             SrbInfo = DeviceExtension->FreeSrbInfo;
3441 
3442             if (SrbInfo == NULL)
3443             {
3444                 /* No SRB structures left in the list. We have to leave
3445                    and wait while we are called again */
3446 
3447                 DeviceExtension->Flags |= SCSI_PORT_REQUEST_PENDING;
3448                 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3449                 return NULL;
3450             }
3451 
3452             DeviceExtension->FreeSrbInfo = (PSCSI_REQUEST_BLOCK_INFO)SrbInfo->Requests.Flink;
3453 
3454             /* QueueTag must never be 0, so +1 to it */
3455             Srb->QueueTag = (UCHAR)(SrbInfo - DeviceExtension->SrbInfo) + 1;
3456         }
3457         else
3458         {
3459             /* Usual untagged command */
3460             if (
3461                 (!IsListEmpty(&LunExtension->SrbInfo.Requests) ||
3462                 LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE) &&
3463                 !(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
3464                 )
3465             {
3466                 /* Mark it as pending and leave */
3467                 ASSERT(!(LunExtension->Flags & LUNEX_REQUEST_PENDING));
3468                 LunExtension->Flags |= LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE;
3469                 LunExtension->PendingRequest = Srb->OriginalRequest;
3470 
3471                 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3472                 return(NULL);
3473             }
3474 
3475             Srb->QueueTag = SP_UNTAGGED;
3476             SrbInfo = &LunExtension->SrbInfo;
3477         }
3478     }
3479     else
3480     {
3481         Srb->QueueTag = SP_UNTAGGED;
3482         SrbInfo = &LunExtension->SrbInfo;
3483     }
3484 
3485     /* Allocate SRB extension structure */
3486     if (DeviceExtension->NeedSrbExtensionAlloc)
3487     {
3488         /* Check the list of free extensions */
3489         SrbExtension = DeviceExtension->FreeSrbExtensions;
3490 
3491         /* If no free extensions... */
3492         if (SrbExtension == NULL)
3493         {
3494             /* Free SRB data */
3495             if (Srb->Function != SRB_FUNCTION_ABORT_COMMAND &&
3496                 Srb->QueueTag != SP_UNTAGGED)
3497             {
3498                 SrbInfo->Requests.Blink = NULL;
3499                 SrbInfo->Requests.Flink = (PLIST_ENTRY)DeviceExtension->FreeSrbInfo;
3500                 DeviceExtension->FreeSrbInfo = SrbInfo;
3501             }
3502 
3503             /* Return, in order to be called again later */
3504             DeviceExtension->Flags |= SCSI_PORT_REQUEST_PENDING;
3505             KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3506             return NULL;
3507         }
3508 
3509         /* Remove that free SRB extension from the list (since
3510            we're going to use it) */
3511         DeviceExtension->FreeSrbExtensions = *((PVOID *)SrbExtension);
3512 
3513         /* Spinlock can be released now */
3514         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3515 
3516         Srb->SrbExtension = SrbExtension;
3517 
3518         if (Srb->SenseInfoBuffer != NULL &&
3519             DeviceExtension->SupportsAutoSense)
3520         {
3521             /* Store pointer to the SenseInfo buffer */
3522             SrbInfo->SaveSenseRequest = Srb->SenseInfoBuffer;
3523 
3524             /* Does data fit the buffer? */
3525             if (Srb->SenseInfoBufferLength > sizeof(SENSE_DATA))
3526             {
3527                 /* No, disabling autosense at all */
3528                 Srb->SrbFlags |= SRB_FLAGS_DISABLE_AUTOSENSE;
3529             }
3530             else
3531             {
3532                 /* Yes, update the buffer pointer */
3533                 Srb->SenseInfoBuffer = SrbExtension + DeviceExtension->SrbExtensionSize;
3534             }
3535         }
3536     }
3537     else
3538     {
3539         /* Cleanup... */
3540         Srb->SrbExtension = NULL;
3541         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3542     }
3543 
3544     return SrbInfo;
3545 }
3546 
3547 
3548 static NTSTATUS
3549 SpiSendInquiry(IN PDEVICE_OBJECT DeviceObject,
3550                IN OUT PSCSI_LUN_INFO LunInfo)
3551 {
3552     IO_STATUS_BLOCK IoStatusBlock;
3553     PIO_STACK_LOCATION IrpStack;
3554     KEVENT Event;
3555     KIRQL Irql;
3556     PIRP Irp;
3557     NTSTATUS Status;
3558     PINQUIRYDATA InquiryBuffer;
3559     PSENSE_DATA SenseBuffer;
3560     BOOLEAN KeepTrying = TRUE;
3561     ULONG RetryCount = 0;
3562     SCSI_REQUEST_BLOCK Srb;
3563     PCDB Cdb;
3564     PSCSI_PORT_LUN_EXTENSION LunExtension;
3565     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
3566 
3567     DPRINT("SpiSendInquiry() called\n");
3568 
3569     DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
3570 
3571     InquiryBuffer = ExAllocatePoolWithTag(NonPagedPool, INQUIRYDATABUFFERSIZE, TAG_SCSIPORT);
3572     if (InquiryBuffer == NULL)
3573         return STATUS_INSUFFICIENT_RESOURCES;
3574 
3575     SenseBuffer = ExAllocatePoolWithTag(NonPagedPool, SENSE_BUFFER_SIZE, TAG_SCSIPORT);
3576     if (SenseBuffer == NULL)
3577     {
3578         ExFreePoolWithTag(InquiryBuffer, TAG_SCSIPORT);
3579         return STATUS_INSUFFICIENT_RESOURCES;
3580     }
3581 
3582     while (KeepTrying)
3583     {
3584         /* Initialize event for waiting */
3585         KeInitializeEvent(&Event,
3586                           NotificationEvent,
3587                           FALSE);
3588 
3589         /* Create an IRP */
3590         Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_IN,
3591                                             DeviceObject,
3592                                             NULL,
3593                                             0,
3594                                             InquiryBuffer,
3595                                             INQUIRYDATABUFFERSIZE,
3596                                             TRUE,
3597                                             &Event,
3598                                             &IoStatusBlock);
3599         if (Irp == NULL)
3600         {
3601             DPRINT("IoBuildDeviceIoControlRequest() failed\n");
3602 
3603             /* Quit the loop */
3604             Status = STATUS_INSUFFICIENT_RESOURCES;
3605             KeepTrying = FALSE;
3606             continue;
3607         }
3608 
3609         /* Prepare SRB */
3610         RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
3611 
3612         Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
3613         Srb.OriginalRequest = Irp;
3614         Srb.PathId = LunInfo->PathId;
3615         Srb.TargetId = LunInfo->TargetId;
3616         Srb.Lun = LunInfo->Lun;
3617         Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
3618         Srb.SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
3619         Srb.TimeOutValue = 4;
3620         Srb.CdbLength = 6;
3621 
3622         Srb.SenseInfoBuffer = SenseBuffer;
3623         Srb.SenseInfoBufferLength = SENSE_BUFFER_SIZE;
3624 
3625         Srb.DataBuffer = InquiryBuffer;
3626         Srb.DataTransferLength = INQUIRYDATABUFFERSIZE;
3627 
3628         /* Attach Srb to the Irp */
3629         IrpStack = IoGetNextIrpStackLocation (Irp);
3630         IrpStack->Parameters.Scsi.Srb = &Srb;
3631 
3632         /* Fill in CDB */
3633         Cdb = (PCDB)Srb.Cdb;
3634         Cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
3635         Cdb->CDB6INQUIRY.LogicalUnitNumber = LunInfo->Lun;
3636         Cdb->CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE;
3637 
3638         /* Call the driver */
3639         Status = IoCallDriver(DeviceObject, Irp);
3640 
3641         /* Wait for it to complete */
3642         if (Status == STATUS_PENDING)
3643         {
3644             DPRINT("SpiSendInquiry(): Waiting for the driver to process request...\n");
3645             KeWaitForSingleObject(&Event,
3646                                   Executive,
3647                                   KernelMode,
3648                                   FALSE,
3649                                   NULL);
3650             Status = IoStatusBlock.Status;
3651         }
3652 
3653         DPRINT("SpiSendInquiry(): Request processed by driver, status = 0x%08X\n", Status);
3654 
3655         if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_SUCCESS)
3656         {
3657             /* All fine, copy data over */
3658             RtlCopyMemory(LunInfo->InquiryData,
3659                           InquiryBuffer,
3660                           INQUIRYDATABUFFERSIZE);
3661 
3662             /* Quit the loop */
3663             Status = STATUS_SUCCESS;
3664             KeepTrying = FALSE;
3665             continue;
3666         }
3667 
3668         DPRINT("Inquiry SRB failed with SrbStatus 0x%08X\n", Srb.SrbStatus);
3669 
3670         /* Check if the queue is frozen */
3671         if (Srb.SrbStatus & SRB_STATUS_QUEUE_FROZEN)
3672         {
3673             /* Something weird happened, deal with it (unfreeze the queue) */
3674             KeepTrying = FALSE;
3675 
3676             DPRINT("SpiSendInquiry(): the queue is frozen at TargetId %d\n", Srb.TargetId);
3677 
3678             LunExtension = SpiGetLunExtension(DeviceExtension,
3679                                               LunInfo->PathId,
3680                                               LunInfo->TargetId,
3681                                               LunInfo->Lun);
3682 
3683             /* Clear frozen flag */
3684             LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
3685 
3686             /* Acquire the spinlock */
3687             KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
3688 
3689             /* Process the request */
3690             SpiGetNextRequestFromLun(DeviceObject->DeviceExtension, LunExtension);
3691 
3692             /* SpiGetNextRequestFromLun() releases the spinlock,
3693                 so we just lower irql back to what it was before */
3694             KeLowerIrql(Irql);
3695         }
3696 
3697         /* Check if data overrun happened */
3698         if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN)
3699         {
3700             DPRINT("Data overrun at TargetId %d\n", LunInfo->TargetId);
3701 
3702             /* Nothing dramatic, just copy data, but limiting the size */
3703             RtlCopyMemory(LunInfo->InquiryData,
3704                             InquiryBuffer,
3705                             (Srb.DataTransferLength > INQUIRYDATABUFFERSIZE) ?
3706                             INQUIRYDATABUFFERSIZE : Srb.DataTransferLength);
3707 
3708             /* Quit the loop */
3709             Status = STATUS_SUCCESS;
3710             KeepTrying = FALSE;
3711         }
3712         else if ((Srb.SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
3713                  SenseBuffer->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST)
3714         {
3715             /* LUN is not valid, but some device responds there.
3716                 Mark it as invalid anyway */
3717 
3718             /* Quit the loop */
3719             Status = STATUS_INVALID_DEVICE_REQUEST;
3720             KeepTrying = FALSE;
3721         }
3722         else
3723         {
3724             /* Retry a couple of times if no timeout happened */
3725             if ((RetryCount < 2) &&
3726                 (SRB_STATUS(Srb.SrbStatus) != SRB_STATUS_NO_DEVICE) &&
3727                 (SRB_STATUS(Srb.SrbStatus) != SRB_STATUS_SELECTION_TIMEOUT))
3728             {
3729                 RetryCount++;
3730                 KeepTrying = TRUE;
3731             }
3732             else
3733             {
3734                 /* That's all, quit the loop */
3735                 KeepTrying = FALSE;
3736 
3737                 /* Set status according to SRB status */
3738                 if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_BAD_FUNCTION ||
3739                     SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_BAD_SRB_BLOCK_LENGTH)
3740                 {
3741                     Status = STATUS_INVALID_DEVICE_REQUEST;
3742                 }
3743                 else
3744                 {
3745                     Status = STATUS_IO_DEVICE_ERROR;
3746                 }
3747             }
3748         }
3749     }
3750 
3751     /* Free buffers */
3752     ExFreePoolWithTag(InquiryBuffer, TAG_SCSIPORT);
3753     ExFreePoolWithTag(SenseBuffer, TAG_SCSIPORT);
3754 
3755     DPRINT("SpiSendInquiry() done with Status 0x%08X\n", Status);
3756 
3757     return Status;
3758 }
3759 
3760 
3761 /* Scans all SCSI buses */
3762 static VOID
3763 SpiScanAdapter(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
3764 {
3765     PSCSI_PORT_LUN_EXTENSION LunExtension;
3766     ULONG Bus;
3767     ULONG Target;
3768     ULONG Lun;
3769     PSCSI_BUS_SCAN_INFO BusScanInfo;
3770     PSCSI_LUN_INFO LastLunInfo, LunInfo, LunInfoExists;
3771     BOOLEAN DeviceExists;
3772     ULONG Hint;
3773     NTSTATUS Status;
3774     ULONG DevicesFound;
3775 
3776     DPRINT("SpiScanAdapter() called\n");
3777 
3778     /* Scan all buses */
3779     for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
3780     {
3781         DPRINT("    Scanning bus %d\n", Bus);
3782         DevicesFound = 0;
3783 
3784         /* Get pointer to the scan information */
3785         BusScanInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus];
3786 
3787         if (BusScanInfo)
3788         {
3789             /* Find the last LUN info in the list */
3790             LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
3791             LastLunInfo = LunInfo;
3792 
3793             while (LunInfo != NULL)
3794             {
3795                 LastLunInfo = LunInfo;
3796                 LunInfo = LunInfo->Next;
3797             }
3798         }
3799         else
3800         {
3801             /* We need to allocate this buffer */
3802             BusScanInfo = ExAllocatePoolWithTag(NonPagedPool, sizeof(SCSI_BUS_SCAN_INFO), TAG_SCSIPORT);
3803             if (!BusScanInfo)
3804             {
3805                 DPRINT1("Out of resources!\n");
3806                 return;
3807             }
3808 
3809             /* Store the pointer in the BusScanInfo array */
3810             DeviceExtension->BusesConfig->BusScanInfo[Bus] = BusScanInfo;
3811 
3812             /* Fill this struct (length and bus ids for now) */
3813             BusScanInfo->Length = sizeof(SCSI_BUS_SCAN_INFO);
3814             BusScanInfo->LogicalUnitsCount = 0;
3815             BusScanInfo->BusIdentifier = DeviceExtension->PortConfig->InitiatorBusId[Bus];
3816             BusScanInfo->LunInfo = NULL;
3817 
3818             /* Set pointer to the last LUN info to NULL */
3819             LastLunInfo = NULL;
3820         }
3821 
3822         /* Create LUN information structure */
3823         LunInfo = ExAllocatePoolWithTag(PagedPool, sizeof(SCSI_LUN_INFO), TAG_SCSIPORT);
3824         if (!LunInfo)
3825         {
3826             DPRINT1("Out of resources!\n");
3827             return;
3828         }
3829 
3830         RtlZeroMemory(LunInfo, sizeof(SCSI_LUN_INFO));
3831 
3832         /* Create LunExtension */
3833         LunExtension = SpiAllocateLunExtension(DeviceExtension);
3834 
3835         /* And send INQUIRY to every target */
3836         for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
3837         {
3838             /* TODO: Support scan bottom-up */
3839 
3840             /* Skip if it's the same address */
3841             if (Target == BusScanInfo->BusIdentifier)
3842                 continue;
3843 
3844             /* Try to find an existing device here */
3845             DeviceExists = FALSE;
3846             LunInfoExists = BusScanInfo->LunInfo;
3847 
3848             /* Find matching address on this bus */
3849             while (LunInfoExists)
3850             {
3851                 if (LunInfoExists->TargetId == Target)
3852                 {
3853                     DeviceExists = TRUE;
3854                     break;
3855                 }
3856 
3857                 /* Advance to the next one */
3858                 LunInfoExists = LunInfoExists->Next;
3859             }
3860 
3861             /* No need to bother rescanning, since we already did that before */
3862             if (DeviceExists)
3863                 continue;
3864 
3865             /* Scan all logical units */
3866             for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
3867             {
3868                 if ((!LunExtension) || (!LunInfo))
3869                     break;
3870 
3871                 /* Add extension to the list */
3872                 Hint = (Target + Lun) % LUS_NUMBER;
3873                 LunExtension->Next = DeviceExtension->LunExtensionList[Hint];
3874                 DeviceExtension->LunExtensionList[Hint] = LunExtension;
3875 
3876                 /* Fill Path, Target, Lun fields */
3877                 LunExtension->PathId = LunInfo->PathId = (UCHAR)Bus;
3878                 LunExtension->TargetId = LunInfo->TargetId = (UCHAR)Target;
3879                 LunExtension->Lun = LunInfo->Lun = (UCHAR)Lun;
3880 
3881                 /* Set flag to prevent race conditions */
3882                 LunExtension->Flags |= SCSI_PORT_SCAN_IN_PROGRESS;
3883 
3884                 /* Zero LU extension contents */
3885                 if (DeviceExtension->LunExtensionSize)
3886                 {
3887                     RtlZeroMemory(LunExtension + 1,
3888                                   DeviceExtension->LunExtensionSize);
3889                 }
3890 
3891                 /* Finally send the inquiry command */
3892                 Status = SpiSendInquiry(DeviceExtension->DeviceObject, LunInfo);
3893 
3894                 if (NT_SUCCESS(Status))
3895                 {
3896                     /* Let's see if we really found a device */
3897                     PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData;
3898 
3899                     /* Check if this device is unsupported */
3900                     if (InquiryData->DeviceTypeQualifier == DEVICE_QUALIFIER_NOT_SUPPORTED)
3901                     {
3902                         DeviceExtension->LunExtensionList[Hint] =
3903                             DeviceExtension->LunExtensionList[Hint]->Next;
3904 
3905                         continue;
3906                     }
3907 
3908                     /* Clear the "in scan" flag */
3909                     LunExtension->Flags &= ~SCSI_PORT_SCAN_IN_PROGRESS;
3910 
3911                     DPRINT("SpiScanAdapter(): Found device of type %d at bus %d tid %d lun %d\n",
3912                         InquiryData->DeviceType, Bus, Target, Lun);
3913 
3914                     /*
3915                      * Cache the inquiry data into the LUN extension (or alternatively
3916                      * we could save a pointer to LunInfo within the LunExtension?)
3917                      */
3918                     RtlCopyMemory(&LunExtension->InquiryData,
3919                                   InquiryData,
3920                                   INQUIRYDATABUFFERSIZE);
3921 
3922                     /* Add this info to the linked list */
3923                     LunInfo->Next = NULL;
3924                     if (LastLunInfo)
3925                         LastLunInfo->Next = LunInfo;
3926                     else
3927                         BusScanInfo->LunInfo = LunInfo;
3928 
3929                     /* Store the last LUN info */
3930                     LastLunInfo = LunInfo;
3931 
3932                     /* Store DeviceObject */
3933                     LunInfo->DeviceObject = DeviceExtension->DeviceObject;
3934 
3935                     /* Allocate another buffer */
3936                     LunInfo = ExAllocatePoolWithTag(PagedPool, sizeof(SCSI_LUN_INFO), TAG_SCSIPORT);
3937                     if (!LunInfo)
3938                     {
3939                         DPRINT1("Out of resources!\n");
3940                         break;
3941                     }
3942 
3943                     RtlZeroMemory(LunInfo, sizeof(SCSI_LUN_INFO));
3944 
3945                     /* Create a new LU extension */
3946                     LunExtension = SpiAllocateLunExtension(DeviceExtension);
3947 
3948                     DevicesFound++;
3949                 }
3950                 else
3951                 {
3952                     /* Remove this LUN from the list */
3953                     DeviceExtension->LunExtensionList[Hint] =
3954                         DeviceExtension->LunExtensionList[Hint]->Next;
3955 
3956                     /* Decide whether we are continuing or not */
3957                     if (Status == STATUS_INVALID_DEVICE_REQUEST)
3958                         continue;
3959                     else
3960                         break;
3961                 }
3962             }
3963         }
3964 
3965         /* Free allocated buffers */
3966         if (LunExtension)
3967             ExFreePoolWithTag(LunExtension, TAG_SCSIPORT);
3968 
3969         if (LunInfo)
3970             ExFreePoolWithTag(LunInfo, TAG_SCSIPORT);
3971 
3972         /* Sum what we found */
3973         BusScanInfo->LogicalUnitsCount += (UCHAR)DevicesFound;
3974         DPRINT("    Found %d devices on bus %d\n", DevicesFound, Bus);
3975     }
3976 
3977     DPRINT("SpiScanAdapter() done\n");
3978 }
3979 
3980 
3981 static NTSTATUS
3982 SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
3983                   IN PIRP Irp)
3984 {
3985     ULONG InquiryDataSize;
3986     PSCSI_LUN_INFO LunInfo;
3987     ULONG BusCount, LunCount, Length;
3988     PIO_STACK_LOCATION IrpStack;
3989     PSCSI_ADAPTER_BUS_INFO AdapterBusInfo;
3990     PSCSI_INQUIRY_DATA InquiryData;
3991     PSCSI_BUS_DATA BusData;
3992     ULONG Bus;
3993     PUCHAR Buffer;
3994 
3995     DPRINT("SpiGetInquiryData() called\n");
3996 
3997     /* Get pointer to the buffer */
3998     IrpStack = IoGetCurrentIrpStackLocation(Irp);
3999     Buffer = Irp->AssociatedIrp.SystemBuffer;
4000 
4001     /* Initialize bus and LUN counters */
4002     BusCount = DeviceExtension->BusesConfig->NumberOfBuses;
4003     LunCount = 0;
4004 
4005     /* Calculate total number of LUNs */
4006     for (Bus = 0; Bus < BusCount; Bus++)
4007         LunCount += DeviceExtension->BusesConfig->BusScanInfo[Bus]->LogicalUnitsCount;
4008 
4009     /* Calculate size of inquiry data, rounding up to sizeof(ULONG) */
4010     InquiryDataSize =
4011         ((sizeof(SCSI_INQUIRY_DATA) - 1 + INQUIRYDATABUFFERSIZE +
4012         sizeof(ULONG) - 1) & ~(sizeof(ULONG) - 1));
4013 
4014     /* Calculate data size */
4015     Length = sizeof(SCSI_ADAPTER_BUS_INFO) + (BusCount - 1) * sizeof(SCSI_BUS_DATA);
4016 
4017     Length += InquiryDataSize * LunCount;
4018 
4019     /* Check, if all data is going to fit into provided buffer */
4020     if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < Length)
4021     {
4022         Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
4023         return STATUS_BUFFER_TOO_SMALL;
4024     }
4025 
4026     /* Store data size in the IRP */
4027     Irp->IoStatus.Information = Length;
4028 
4029     DPRINT("Data size: %lu\n", Length);
4030 
4031     AdapterBusInfo = (PSCSI_ADAPTER_BUS_INFO)Buffer;
4032 
4033     AdapterBusInfo->NumberOfBuses = (UCHAR)BusCount;
4034 
4035     /* Point InquiryData to the corresponding place inside Buffer */
4036     InquiryData = (PSCSI_INQUIRY_DATA)(Buffer + sizeof(SCSI_ADAPTER_BUS_INFO) +
4037                     (BusCount - 1) * sizeof(SCSI_BUS_DATA));
4038 
4039     /* Loop each bus */
4040     for (Bus = 0; Bus < BusCount; Bus++)
4041     {
4042         BusData = &AdapterBusInfo->BusData[Bus];
4043 
4044         /* Calculate and save an offset of the inquiry data */
4045         BusData->InquiryDataOffset = (ULONG)((PUCHAR)InquiryData - Buffer);
4046 
4047         /* Get a pointer to the LUN information structure */
4048         LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
4049 
4050         /* Store Initiator Bus Id */
4051         BusData->InitiatorBusId =
4052             DeviceExtension->BusesConfig->BusScanInfo[Bus]->BusIdentifier;
4053 
4054         /* Store LUN count */
4055         BusData->NumberOfLogicalUnits =
4056             DeviceExtension->BusesConfig->BusScanInfo[Bus]->LogicalUnitsCount;
4057 
4058         /* Loop all LUNs */
4059         while (LunInfo != NULL)
4060         {
4061             DPRINT("(Bus %lu Target %lu Lun %lu)\n",
4062                    Bus, LunInfo->TargetId, LunInfo->Lun);
4063 
4064             /* Fill InquiryData with values */
4065             InquiryData->PathId = LunInfo->PathId;
4066             InquiryData->TargetId = LunInfo->TargetId;
4067             InquiryData->Lun = LunInfo->Lun;
4068             InquiryData->InquiryDataLength = INQUIRYDATABUFFERSIZE;
4069             InquiryData->DeviceClaimed = LunInfo->DeviceClaimed;
4070             InquiryData->NextInquiryDataOffset =
4071                 (ULONG)((PUCHAR)InquiryData + InquiryDataSize - Buffer);
4072 
4073             /* Copy data in it */
4074             RtlCopyMemory(InquiryData->InquiryData,
4075                           LunInfo->InquiryData,
4076                           INQUIRYDATABUFFERSIZE);
4077 
4078             /* Move to the next LUN */
4079             LunInfo = LunInfo->Next;
4080             InquiryData = (PSCSI_INQUIRY_DATA) ((PCHAR)InquiryData + InquiryDataSize);
4081         }
4082 
4083         /* Either mark the end, or set offset to 0 */
4084         if (BusData->NumberOfLogicalUnits != 0)
4085             ((PSCSI_INQUIRY_DATA) ((PCHAR)InquiryData - InquiryDataSize))->NextInquiryDataOffset = 0;
4086         else
4087             BusData->InquiryDataOffset = 0;
4088     }
4089 
4090     /* Finish with success */
4091     Irp->IoStatus.Status = STATUS_SUCCESS;
4092     return STATUS_SUCCESS;
4093 }
4094 
4095 static PSCSI_REQUEST_BLOCK_INFO
4096 SpiGetSrbData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
4097               IN UCHAR PathId,
4098               IN UCHAR TargetId,
4099               IN UCHAR Lun,
4100               IN UCHAR QueueTag)
4101 {
4102     PSCSI_PORT_LUN_EXTENSION LunExtension;
4103 
4104     if (QueueTag == SP_UNTAGGED)
4105     {
4106         /* Untagged request, get LU and return pointer to SrbInfo */
4107         LunExtension = SpiGetLunExtension(DeviceExtension,
4108                                           PathId,
4109                                           TargetId,
4110                                           Lun);
4111 
4112         /* Return NULL in case of error */
4113         if (!LunExtension)
4114             return(NULL);
4115 
4116         /* Return the pointer to SrbInfo */
4117         return &LunExtension->SrbInfo;
4118     }
4119     else
4120     {
4121         /* Make sure the tag is valid, if it is - return the data */
4122         if (QueueTag > DeviceExtension->SrbDataCount || QueueTag < 1)
4123             return NULL;
4124         else
4125             return &DeviceExtension->SrbInfo[QueueTag -1];
4126     }
4127 }
4128 
4129 static VOID
4130 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
4131                     IN PSCSI_REQUEST_BLOCK InitialSrb)
4132 {
4133     PSCSI_REQUEST_BLOCK Srb;
4134     PCDB Cdb;
4135     PIRP Irp;
4136     PIO_STACK_LOCATION IrpStack;
4137     LARGE_INTEGER LargeInt;
4138     PVOID *Ptr;
4139 
4140     DPRINT("SpiSendRequestSense() entered, InitialSrb %p\n", InitialSrb);
4141 
4142     /* Allocate Srb */
4143     Srb = ExAllocatePoolWithTag(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK) + sizeof(PVOID), TAG_SCSIPORT);
4144     RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
4145 
4146     /* Allocate IRP */
4147     LargeInt.QuadPart = (LONGLONG) 1;
4148     Irp = IoBuildAsynchronousFsdRequest(IRP_MJ_READ,
4149                                         DeviceExtension->DeviceObject,
4150                                         InitialSrb->SenseInfoBuffer,
4151                                         InitialSrb->SenseInfoBufferLength,
4152                                         &LargeInt,
4153                                         NULL);
4154 
4155     IoSetCompletionRoutine(Irp,
4156                            (PIO_COMPLETION_ROUTINE)SpiCompletionRoutine,
4157                            Srb,
4158                            TRUE,
4159                            TRUE,
4160                            TRUE);
4161 
4162     if (!Srb)
4163     {
4164         DPRINT("SpiSendRequestSense() failed, Srb %p\n", Srb);
4165         return;
4166     }
4167 
4168     IrpStack = IoGetNextIrpStackLocation(Irp);
4169     IrpStack->MajorFunction = IRP_MJ_SCSI;
4170 
4171     /* Put Srb address into Irp... */
4172     IrpStack->Parameters.Others.Argument1 = (PVOID)Srb;
4173 
4174     /* ...and vice versa */
4175     Srb->OriginalRequest = Irp;
4176 
4177     /* Save Srb */
4178     Ptr = (PVOID *)(Srb+1);
4179     *Ptr = InitialSrb;
4180 
4181     /* Build CDB for REQUEST SENSE */
4182     Srb->CdbLength = 6;
4183     Cdb = (PCDB)Srb->Cdb;
4184 
4185     Cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE;
4186     Cdb->CDB6INQUIRY.LogicalUnitNumber = 0;
4187     Cdb->CDB6INQUIRY.Reserved1 = 0;
4188     Cdb->CDB6INQUIRY.PageCode = 0;
4189     Cdb->CDB6INQUIRY.IReserved = 0;
4190     Cdb->CDB6INQUIRY.AllocationLength = (UCHAR)InitialSrb->SenseInfoBufferLength;
4191     Cdb->CDB6INQUIRY.Control = 0;
4192 
4193     /* Set address */
4194     Srb->TargetId = InitialSrb->TargetId;
4195     Srb->Lun = InitialSrb->Lun;
4196     Srb->PathId = InitialSrb->PathId;
4197 
4198     Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
4199     Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
4200 
4201     /* Timeout will be 2 seconds */
4202     Srb->TimeOutValue = 2;
4203 
4204     /* No auto request sense */
4205     Srb->SenseInfoBufferLength = 0;
4206     Srb->SenseInfoBuffer = NULL;
4207 
4208     /* Set necessary flags */
4209     Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_BYPASS_FROZEN_QUEUE |
4210                     SRB_FLAGS_DISABLE_DISCONNECT;
4211 
4212     /* Transfer disable synch transfer flag */
4213     if (InitialSrb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER)
4214         Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
4215 
4216     Srb->DataBuffer = InitialSrb->SenseInfoBuffer;
4217 
4218     /* Fill the transfer length */
4219     Srb->DataTransferLength = InitialSrb->SenseInfoBufferLength;
4220 
4221     /* Clear statuses */
4222     Srb->ScsiStatus = Srb->SrbStatus = 0;
4223     Srb->NextSrb = 0;
4224 
4225     /* Call the driver */
4226     (VOID)IoCallDriver(DeviceExtension->DeviceObject, Irp);
4227 
4228     DPRINT("SpiSendRequestSense() done\n");
4229 }
4230 
4231 
4232 static
4233 VOID
4234 NTAPI
4235 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
4236                            IN PSCSI_REQUEST_BLOCK_INFO SrbInfo,
4237                            OUT PBOOLEAN NeedToCallStartIo)
4238 {
4239     PSCSI_REQUEST_BLOCK Srb;
4240     PSCSI_PORT_LUN_EXTENSION LunExtension;
4241     LONG Result;
4242     PIRP Irp;
4243     //ULONG SequenceNumber;
4244 
4245     Srb = SrbInfo->Srb;
4246     Irp = Srb->OriginalRequest;
4247 
4248     /* Get Lun extension */
4249     LunExtension = SpiGetLunExtension(DeviceExtension,
4250                                      Srb->PathId,
4251                                      Srb->TargetId,
4252                                      Srb->Lun);
4253 
4254     if (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION &&
4255         DeviceExtension->MapBuffers &&
4256         Irp->MdlAddress)
4257     {
4258         /* MDL is shared if transfer is broken into smaller parts */
4259         Srb->DataBuffer = (PCCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress) +
4260             ((PCCHAR)Srb->DataBuffer - SrbInfo->DataOffset);
4261 
4262         /* In case of data going in, flush the buffers */
4263         if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
4264         {
4265             KeFlushIoBuffers(Irp->MdlAddress,
4266                              TRUE,
4267                              FALSE);
4268         }
4269     }
4270 
4271     /* Flush adapter if needed */
4272     if (SrbInfo->BaseOfMapRegister)
4273     {
4274         /* TODO: Implement */
4275         ASSERT(FALSE);
4276     }
4277 
4278     /* Clear the request */
4279     SrbInfo->Srb = NULL;
4280 
4281     /* If disconnect is disabled... */
4282     if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
4283     {
4284         /* Acquire the spinlock since we mess with flags */
4285         KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
4286 
4287         /* Set corresponding flag */
4288         DeviceExtension->Flags |= SCSI_PORT_DISCONNECT_ALLOWED;
4289 
4290         /* Clear the timer if needed */
4291         if (!(DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET))
4292             DeviceExtension->TimerCount = -1;
4293 
4294         /* Spinlock is not needed anymore */
4295         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4296 
4297         if (!(DeviceExtension->Flags & SCSI_PORT_REQUEST_PENDING) &&
4298             !(DeviceExtension->Flags & SCSI_PORT_DEVICE_BUSY) &&
4299             !(*NeedToCallStartIo))
4300         {
4301             /* We're not busy, but we have a request pending */
4302             IoStartNextPacket(DeviceExtension->DeviceObject, FALSE);
4303         }
4304     }
4305 
4306     /* Scatter/gather */
4307     if (Srb->SrbFlags & SRB_FLAGS_SGLIST_FROM_POOL)
4308     {
4309         /* TODO: Implement */
4310         ASSERT(FALSE);
4311     }
4312 
4313     /* Acquire spinlock (we're freeing SrbExtension) */
4314     KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
4315 
4316     /* Free it (if needed) */
4317     if (Srb->SrbExtension)
4318     {
4319         if (Srb->SenseInfoBuffer != NULL && DeviceExtension->SupportsAutoSense)
4320         {
4321             ASSERT(Srb->SenseInfoBuffer == NULL || SrbInfo->SaveSenseRequest != NULL);
4322 
4323             if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)
4324             {
4325                 /* Copy sense data to the buffer */
4326                 RtlCopyMemory(SrbInfo->SaveSenseRequest,
4327                               Srb->SenseInfoBuffer,
4328                               Srb->SenseInfoBufferLength);
4329             }
4330 
4331             /* And restore the pointer */
4332             Srb->SenseInfoBuffer = SrbInfo->SaveSenseRequest;
4333         }
4334 
4335         /* Put it into the free srb extensions list */
4336         *((PVOID *)Srb->SrbExtension) = DeviceExtension->FreeSrbExtensions;
4337         DeviceExtension->FreeSrbExtensions = Srb->SrbExtension;
4338     }
4339 
4340     /* Save transfer length in the IRP */
4341     Irp->IoStatus.Information = Srb->DataTransferLength;
4342 
4343     //SequenceNumber = SrbInfo->SequenceNumber;
4344     SrbInfo->SequenceNumber = 0;
4345 
4346     /* Decrement the queue count */
4347     LunExtension->QueueCount--;
4348 
4349     /* Free Srb, if needed*/
4350     if (Srb->QueueTag != SP_UNTAGGED)
4351     {
4352         /* Put it into the free list */
4353         SrbInfo->Requests.Blink = NULL;
4354         SrbInfo->Requests.Flink = (PLIST_ENTRY)DeviceExtension->FreeSrbInfo;
4355         DeviceExtension->FreeSrbInfo = SrbInfo;
4356     }
4357 
4358     /* SrbInfo is not used anymore */
4359     SrbInfo = NULL;
4360 
4361     if (DeviceExtension->Flags & SCSI_PORT_REQUEST_PENDING)
4362     {
4363         /* Clear the flag */
4364         DeviceExtension->Flags &= ~SCSI_PORT_REQUEST_PENDING;
4365 
4366         /* Note the caller about StartIo */
4367         *NeedToCallStartIo = TRUE;
4368     }
4369 
4370     if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
4371     {
4372         /* Start the packet */
4373         Irp->IoStatus.Status = STATUS_SUCCESS;
4374 
4375         if (!(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE) &&
4376             LunExtension->RequestTimeout == -1)
4377         {
4378             /* Start the next packet */
4379             SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
4380         }
4381         else
4382         {
4383             /* Release the spinlock */
4384             KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4385         }
4386 
4387         DPRINT("IoCompleting request IRP 0x%p\n", Irp);
4388 
4389         IoCompleteRequest(Irp, IO_DISK_INCREMENT);
4390 
4391         /* Decrement number of active requests, and analyze the result */
4392         Result = InterlockedDecrement(&DeviceExtension->ActiveRequestCounter);
4393 
4394         if (Result < 0 &&
4395             !DeviceExtension->MapRegisters &&
4396             DeviceExtension->AdapterObject != NULL)
4397         {
4398             /* Nullify map registers */
4399             DeviceExtension->MapRegisterBase = NULL;
4400             IoFreeAdapterChannel(DeviceExtension->AdapterObject);
4401         }
4402 
4403          /* Exit, we're done */
4404         return;
4405     }
4406 
4407     /* Decrement number of active requests, and analyze the result */
4408     Result = InterlockedDecrement(&DeviceExtension->ActiveRequestCounter);
4409 
4410     if (Result < 0 &&
4411         !DeviceExtension->MapRegisters &&
4412         DeviceExtension->AdapterObject != NULL)
4413     {
4414         /* Result is negative, so this is a slave, free map registers */
4415         DeviceExtension->MapRegisterBase = NULL;
4416         IoFreeAdapterChannel(DeviceExtension->AdapterObject);
4417     }
4418 
4419     /* Convert status */
4420     Irp->IoStatus.Status = SpiStatusSrbToNt(Srb->SrbStatus);
4421 
4422     /* It's not a bypass, it's busy or the queue is full? */
4423     if ((Srb->ScsiStatus == SCSISTAT_BUSY ||
4424          Srb->SrbStatus == SRB_STATUS_BUSY ||
4425          Srb->ScsiStatus == SCSISTAT_QUEUE_FULL) &&
4426          !(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE))
4427     {
4428 
4429         DPRINT("Busy SRB status %x\n", Srb->SrbStatus);
4430 
4431         /* Requeue, if needed */
4432         if (LunExtension->Flags & (LUNEX_FROZEN_QUEUE | LUNEX_BUSY))
4433         {
4434             DPRINT("it's being requeued\n");
4435 
4436             Srb->SrbStatus = SRB_STATUS_PENDING;
4437             Srb->ScsiStatus = 0;
4438 
4439             if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue,
4440                                           &Irp->Tail.Overlay.DeviceQueueEntry,
4441                                           Srb->QueueSortKey))
4442             {
4443                 /* It's a big f.ck up if we got here */
4444                 Srb->SrbStatus = SRB_STATUS_ERROR;
4445                 Srb->ScsiStatus = SCSISTAT_BUSY;
4446 
4447                 ASSERT(FALSE);
4448                 goto Error;
4449             }
4450 
4451             /* Release the spinlock */
4452             KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4453 
4454         }
4455         else if (LunExtension->AttemptCount++ < 20)
4456         {
4457             /* LUN is still busy */
4458             Srb->ScsiStatus = 0;
4459             Srb->SrbStatus = SRB_STATUS_PENDING;
4460 
4461             LunExtension->BusyRequest = Irp;
4462             LunExtension->Flags |= LUNEX_BUSY;
4463 
4464             /* Release the spinlock */
4465             KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4466         }
4467         else
4468         {
4469 Error:
4470             /* Freeze the queue*/
4471             Srb->SrbStatus |= SRB_STATUS_QUEUE_FROZEN;
4472             LunExtension->Flags |= LUNEX_FROZEN_QUEUE;
4473 
4474             /* "Unfull" the queue */
4475             LunExtension->Flags &= ~LUNEX_FULL_QUEUE;
4476 
4477             /* Release the spinlock */
4478             KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4479 
4480             /* Return status that the device is not ready */
4481             Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
4482             IoCompleteRequest(Irp, IO_DISK_INCREMENT);
4483         }
4484 
4485         return;
4486     }
4487 
4488     /* Start the next request, if LUN is idle, and this is sense request */
4489     if (((Srb->ScsiStatus != SCSISTAT_CHECK_CONDITION) ||
4490         (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) ||
4491         !Srb->SenseInfoBuffer || !Srb->SenseInfoBufferLength)
4492         && (Srb->SrbFlags & SRB_FLAGS_NO_QUEUE_FREEZE))
4493     {
4494         if (LunExtension->RequestTimeout == -1)
4495             SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
4496         else
4497             KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4498     }
4499     else
4500     {
4501         /* Freeze the queue */
4502         Srb->SrbStatus |= SRB_STATUS_QUEUE_FROZEN;
4503         LunExtension->Flags |= LUNEX_FROZEN_QUEUE;
4504 
4505         /* Do we need a request sense? */
4506         if (Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION &&
4507             !(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
4508             Srb->SenseInfoBuffer && Srb->SenseInfoBufferLength)
4509         {
4510             /* If LUN is busy, we have to requeue it in order to allow request sense */
4511             if (LunExtension->Flags & LUNEX_BUSY)
4512             {
4513                 DPRINT("Requeuing busy request to allow request sense\n");
4514 
4515                 if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue,
4516                     &LunExtension->BusyRequest->Tail.Overlay.DeviceQueueEntry,
4517                     Srb->QueueSortKey))
4518                 {
4519                     /* We should never get here */
4520                     ASSERT(FALSE);
4521 
4522                     KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4523                     IoCompleteRequest(Irp, IO_DISK_INCREMENT);
4524                     return;
4525 
4526                 }
4527 
4528                 /* Clear busy flags */
4529                 LunExtension->Flags &= ~(LUNEX_FULL_QUEUE | LUNEX_BUSY);
4530             }
4531 
4532             /* Release the spinlock */
4533             KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4534 
4535             /* Send RequestSense */
4536             SpiSendRequestSense(DeviceExtension, Srb);
4537 
4538             /* Exit */
4539             return;
4540         }
4541 
4542         /* Release the spinlock */
4543         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4544     }
4545 
4546     /* Complete the request */
4547     IoCompleteRequest(Irp, IO_DISK_INCREMENT);
4548 }
4549 
4550 NTSTATUS
4551 NTAPI
4552 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject,
4553                      PIRP Irp,
4554                      PVOID Context)
4555 {
4556     PSCSI_REQUEST_BLOCK Srb = (PSCSI_REQUEST_BLOCK)Context;
4557     PSCSI_REQUEST_BLOCK InitialSrb;
4558     PIRP InitialIrp;
4559 
4560     DPRINT("SpiCompletionRoutine() entered, IRP %p \n", Irp);
4561 
4562     if ((Srb->Function == SRB_FUNCTION_RESET_BUS) ||
4563         (Srb->Function == SRB_FUNCTION_ABORT_COMMAND))
4564     {
4565         /* Deallocate SRB and IRP and exit */
4566         ExFreePool(Srb);
4567         IoFreeIrp(Irp);
4568 
4569         return STATUS_MORE_PROCESSING_REQUIRED;
4570     }
4571 
4572     /* Get a pointer to the SRB and IRP which were initially sent */
4573     InitialSrb = *((PVOID *)(Srb+1));
4574     InitialIrp = InitialSrb->OriginalRequest;
4575 
4576     if ((SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS) ||
4577         (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN))
4578     {
4579         /* Sense data is OK */
4580         InitialSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
4581 
4582         /* Set length to be the same */
4583         InitialSrb->SenseInfoBufferLength = (UCHAR)Srb->DataTransferLength;
4584     }
4585 
4586     /* Make sure initial SRB's queue is frozen */
4587     ASSERT(InitialSrb->SrbStatus & SRB_STATUS_QUEUE_FROZEN);
4588 
4589     /* Complete this request */
4590     IoCompleteRequest(InitialIrp, IO_DISK_INCREMENT);
4591 
4592     /* Deallocate everything (internal) */
4593     ExFreePool(Srb);
4594 
4595     if (Irp->MdlAddress != NULL)
4596     {
4597 		MmUnlockPages(Irp->MdlAddress);
4598         IoFreeMdl(Irp->MdlAddress);
4599         Irp->MdlAddress = NULL;
4600     }
4601 
4602     IoFreeIrp(Irp);
4603     return STATUS_MORE_PROCESSING_REQUIRED;
4604 }
4605 
4606 static BOOLEAN NTAPI
4607 ScsiPortIsr(IN PKINTERRUPT Interrupt,
4608             IN PVOID ServiceContext)
4609 {
4610     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
4611 
4612     DPRINT("ScsiPortIsr() called!\n");
4613 
4614     DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext;
4615 
4616     /* If interrupts are disabled - we don't expect any */
4617     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_DISABLE_INTERRUPTS)
4618         return FALSE;
4619 
4620     /* Call miniport's HwInterrupt routine */
4621     if (DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension) == FALSE)
4622     {
4623         /* This interrupt doesn't belong to us */
4624         return FALSE;
4625     }
4626 
4627     /* If flag of notification is set - queue a DPC */
4628     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
4629     {
4630         IoRequestDpc(DeviceExtension->DeviceObject,
4631                      DeviceExtension->CurrentIrp,
4632                      DeviceExtension);
4633     }
4634 
4635     return TRUE;
4636 }
4637 
4638 BOOLEAN
4639 NTAPI
4640 SpiSaveInterruptData(IN PVOID Context)
4641 {
4642     PSCSI_PORT_SAVE_INTERRUPT InterruptContext = Context;
4643     PSCSI_PORT_LUN_EXTENSION LunExtension;
4644     PSCSI_REQUEST_BLOCK Srb;
4645     PSCSI_REQUEST_BLOCK_INFO SrbInfo, NextSrbInfo;
4646     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
4647     BOOLEAN IsTimed;
4648 
4649     /* Get pointer to the device extension */
4650     DeviceExtension = InterruptContext->DeviceExtension;
4651 
4652     /* If we don't have anything pending - return */
4653     if (!(DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED))
4654         return FALSE;
4655 
4656     /* Actually save the interrupt data */
4657     *InterruptContext->InterruptData = DeviceExtension->InterruptData;
4658 
4659     /* Clear the data stored in the device extension */
4660     DeviceExtension->InterruptData.Flags &=
4661         (SCSI_PORT_RESET | SCSI_PORT_RESET_REQUEST | SCSI_PORT_DISABLE_INTERRUPTS);
4662     DeviceExtension->InterruptData.CompletedAbort = NULL;
4663     DeviceExtension->InterruptData.ReadyLun = NULL;
4664     DeviceExtension->InterruptData.CompletedRequests = NULL;
4665 
4666     /* Loop through the list of completed requests */
4667     SrbInfo = InterruptContext->InterruptData->CompletedRequests;
4668 
4669     while (SrbInfo)
4670     {
4671         /* Make sure we have SRV */
4672         ASSERT(SrbInfo->Srb);
4673 
4674         /* Get SRB and LunExtension */
4675         Srb = SrbInfo->Srb;
4676 
4677         LunExtension = SpiGetLunExtension(DeviceExtension,
4678                                           Srb->PathId,
4679                                           Srb->TargetId,
4680                                           Srb->Lun);
4681 
4682         /* We have to check special cases if request is unsuccessful*/
4683         if (Srb->SrbStatus != SRB_STATUS_SUCCESS)
4684         {
4685             /* Check if we need request sense by a few conditions */
4686             if (Srb->SenseInfoBuffer && Srb->SenseInfoBufferLength &&
4687                 Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION &&
4688                 !(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID))
4689             {
4690                 if (LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE)
4691                 {
4692                     /* It means: we tried to send REQUEST SENSE, but failed */
4693 
4694                     Srb->ScsiStatus = 0;
4695                     Srb->SrbStatus = SRB_STATUS_REQUEST_SENSE_FAILED;
4696                 }
4697                 else
4698                 {
4699                     /* Set the corresponding flag, so that REQUEST SENSE
4700                        will be sent */
4701                     LunExtension->Flags |= LUNEX_NEED_REQUEST_SENSE;
4702                 }
4703 
4704             }
4705 
4706             /* Check for a full queue */
4707             if (Srb->ScsiStatus == SCSISTAT_QUEUE_FULL)
4708             {
4709                 /* TODO: Implement when it's encountered */
4710                 ASSERT(FALSE);
4711             }
4712         }
4713 
4714         /* Let's decide if we need to watch timeout or not */
4715         if (Srb->QueueTag == SP_UNTAGGED)
4716         {
4717             IsTimed = TRUE;
4718         }
4719         else
4720         {
4721             if (LunExtension->SrbInfo.Requests.Flink == &SrbInfo->Requests)
4722                 IsTimed = TRUE;
4723             else
4724                 IsTimed = FALSE;
4725 
4726             /* Remove it from the queue */
4727             RemoveEntryList(&SrbInfo->Requests);
4728         }
4729 
4730         if (IsTimed)
4731         {
4732             /* We have to maintain timeout counter */
4733             if (IsListEmpty(&LunExtension->SrbInfo.Requests))
4734             {
4735                 LunExtension->RequestTimeout = -1;
4736             }
4737             else
4738             {
4739                 NextSrbInfo = CONTAINING_RECORD(LunExtension->SrbInfo.Requests.Flink,
4740                                                 SCSI_REQUEST_BLOCK_INFO,
4741                                                 Requests);
4742 
4743                 Srb = NextSrbInfo->Srb;
4744 
4745                 /* Update timeout counter */
4746                 LunExtension->RequestTimeout = Srb->TimeOutValue;
4747             }
4748         }
4749 
4750         SrbInfo = SrbInfo->CompletedRequests;
4751     }
4752 
4753     return TRUE;
4754 }
4755 
4756 VOID
4757 NTAPI
4758 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
4759                          IN PSCSI_PORT_LUN_EXTENSION LunExtension)
4760 {
4761     PIO_STACK_LOCATION IrpStack;
4762     PIRP NextIrp;
4763     PKDEVICE_QUEUE_ENTRY Entry;
4764     PSCSI_REQUEST_BLOCK Srb;
4765 
4766 
4767     /* If LUN is not active or queue is more than maximum allowed  */
4768     if (LunExtension->QueueCount >= LunExtension->MaxQueueCount ||
4769         !(LunExtension->Flags & SCSI_PORT_LU_ACTIVE))
4770     {
4771         /* Release the spinlock and exit */
4772         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4773         return;
4774     }
4775 
4776     /* Check if we can get a next request */
4777     if (LunExtension->Flags &
4778         (LUNEX_NEED_REQUEST_SENSE | LUNEX_BUSY |
4779          LUNEX_FULL_QUEUE | LUNEX_FROZEN_QUEUE | LUNEX_REQUEST_PENDING))
4780     {
4781         /* Pending requests can only be started if the queue is empty */
4782         if (IsListEmpty(&LunExtension->SrbInfo.Requests) &&
4783             !(LunExtension->Flags &
4784               (LUNEX_BUSY | LUNEX_FROZEN_QUEUE | LUNEX_FULL_QUEUE | LUNEX_NEED_REQUEST_SENSE)))
4785         {
4786             /* Make sure we have SRB */
4787             ASSERT(LunExtension->SrbInfo.Srb == NULL);
4788 
4789             /* Clear active and pending flags */
4790             LunExtension->Flags &= ~(LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE);
4791 
4792             /* Get next Irp, and clear pending requests list */
4793             NextIrp = LunExtension->PendingRequest;
4794             LunExtension->PendingRequest = NULL;
4795 
4796             /* Set attempt counter to zero */
4797             LunExtension->AttemptCount = 0;
4798 
4799             /* Release the spinlock */
4800             KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4801 
4802             /* Start the next pending request */
4803             IoStartPacket(DeviceExtension->DeviceObject, NextIrp, (PULONG)NULL, NULL);
4804 
4805             return;
4806         }
4807         else
4808         {
4809             /* Release the spinlock, without clearing any flags and exit */
4810             KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4811 
4812             return;
4813         }
4814     }
4815 
4816     /* Reset active flag */
4817     LunExtension->Flags &= ~SCSI_PORT_LU_ACTIVE;
4818 
4819     /* Set attempt counter to zero */
4820     LunExtension->AttemptCount = 0;
4821 
4822     /* Remove packet from the device queue */
4823     Entry = KeRemoveByKeyDeviceQueue(&LunExtension->DeviceQueue, LunExtension->SortKey);
4824 
4825     if (Entry != NULL)
4826     {
4827         /* Get pointer to the next irp */
4828         NextIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
4829 
4830         /* Get point to the SRB */
4831         IrpStack = IoGetCurrentIrpStackLocation(NextIrp);
4832         Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
4833 
4834         /* Set new key*/
4835         LunExtension->SortKey = Srb->QueueSortKey;
4836         LunExtension->SortKey++;
4837 
4838         /* Release the spinlock */
4839         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4840 
4841         /* Start the next pending request */
4842         IoStartPacket(DeviceExtension->DeviceObject, NextIrp, (PULONG)NULL, NULL);
4843     }
4844     else
4845     {
4846         /* Release the spinlock */
4847         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4848     }
4849 }
4850 
4851 
4852 
4853 //    ScsiPortDpcForIsr
4854 //  DESCRIPTION:
4855 //
4856 //  RUN LEVEL:
4857 //
4858 //  ARGUMENTS:
4859 //    IN PKDPC          Dpc
4860 //    IN PDEVICE_OBJECT DpcDeviceObject
4861 //    IN PIRP           DpcIrp
4862 //    IN PVOID          DpcContext
4863 //
4864 static VOID NTAPI
4865 ScsiPortDpcForIsr(IN PKDPC Dpc,
4866 		  IN PDEVICE_OBJECT DpcDeviceObject,
4867 		  IN PIRP DpcIrp,
4868 		  IN PVOID DpcContext)
4869 {
4870     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DpcDeviceObject->DeviceExtension;
4871     SCSI_PORT_INTERRUPT_DATA InterruptData;
4872     SCSI_PORT_SAVE_INTERRUPT Context;
4873     PSCSI_PORT_LUN_EXTENSION LunExtension;
4874     BOOLEAN NeedToStartIo;
4875     PSCSI_REQUEST_BLOCK_INFO SrbInfo;
4876     LARGE_INTEGER TimerValue;
4877 
4878     DPRINT("ScsiPortDpcForIsr(Dpc %p  DpcDeviceObject %p  DpcIrp %p  DpcContext %p)\n",
4879            Dpc, DpcDeviceObject, DpcIrp, DpcContext);
4880 
4881     /* We need to acquire spinlock */
4882     KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
4883 
4884 	RtlZeroMemory(&InterruptData, sizeof(SCSI_PORT_INTERRUPT_DATA));
4885 
4886 TryAgain:
4887 
4888     /* Interrupt structure must be snapshotted, and only then analyzed */
4889     Context.InterruptData = &InterruptData;
4890     Context.DeviceExtension = DeviceExtension;
4891 
4892     if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0],
4893                                 SpiSaveInterruptData,
4894                                 &Context))
4895     {
4896         /* Nothing - just return (don't forget to release the spinlock */
4897         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4898         DPRINT("ScsiPortDpcForIsr() done\n");
4899         return;
4900     }
4901 
4902     /* If flush of adapters is needed - do it */
4903     if (InterruptData.Flags & SCSI_PORT_FLUSH_ADAPTERS)
4904     {
4905         /* TODO: Implement */
4906         ASSERT(FALSE);
4907     }
4908 
4909     /* Check for IoMapTransfer */
4910     if (InterruptData.Flags & SCSI_PORT_MAP_TRANSFER)
4911     {
4912         /* TODO: Implement */
4913         ASSERT(FALSE);
4914     }
4915 
4916     /* Check if timer is needed */
4917     if (InterruptData.Flags & SCSI_PORT_TIMER_NEEDED)
4918     {
4919         /* Save the timer routine */
4920         DeviceExtension->HwScsiTimer = InterruptData.HwScsiTimer;
4921 
4922         if (InterruptData.MiniportTimerValue == 0)
4923         {
4924             /* Cancel the timer */
4925             KeCancelTimer(&DeviceExtension->MiniportTimer);
4926         }
4927         else
4928         {
4929             /* Convert timer value */
4930             TimerValue.QuadPart = Int32x32To64(InterruptData.MiniportTimerValue, -10);
4931 
4932             /* Set the timer */
4933             KeSetTimer(&DeviceExtension->MiniportTimer,
4934                        TimerValue,
4935                        &DeviceExtension->MiniportTimerDpc);
4936         }
4937     }
4938 
4939     /* If it's ready for the next request */
4940     if (InterruptData.Flags & SCSI_PORT_NEXT_REQUEST_READY)
4941     {
4942         /* Check for a duplicate request (NextRequest+NextLuRequest) */
4943         if ((DeviceExtension->Flags &
4944             (SCSI_PORT_DEVICE_BUSY | SCSI_PORT_DISCONNECT_ALLOWED)) ==
4945             (SCSI_PORT_DEVICE_BUSY | SCSI_PORT_DISCONNECT_ALLOWED))
4946         {
4947             /* Clear busy flag set by ScsiPortStartPacket() */
4948             DeviceExtension->Flags &= ~SCSI_PORT_DEVICE_BUSY;
4949 
4950             if (!(InterruptData.Flags & SCSI_PORT_RESET))
4951             {
4952                 /* Ready for next, and no reset is happening */
4953                 DeviceExtension->TimerCount = -1;
4954             }
4955         }
4956         else
4957         {
4958             /* Not busy, but not ready for the next request */
4959             DeviceExtension->Flags &= ~SCSI_PORT_DEVICE_BUSY;
4960             InterruptData.Flags &= ~SCSI_PORT_NEXT_REQUEST_READY;
4961         }
4962     }
4963 
4964     /* Any resets? */
4965     if (InterruptData.Flags & SCSI_PORT_RESET_REPORTED)
4966     {
4967         /* Hold for a bit */
4968         DeviceExtension->TimerCount = 4;
4969     }
4970 
4971     /* Any ready LUN? */
4972     if (InterruptData.ReadyLun != NULL)
4973     {
4974 
4975         /* Process all LUNs from the list*/
4976         while (TRUE)
4977         {
4978             /* Remove it from the list first (as processed) */
4979             LunExtension = InterruptData.ReadyLun;
4980             InterruptData.ReadyLun = LunExtension->ReadyLun;
4981             LunExtension->ReadyLun = NULL;
4982 
4983             /* Get next request for this LUN */
4984             SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
4985 
4986             /* Still ready requests exist?
4987                If yes - get spinlock, if no - stop here */
4988             if (InterruptData.ReadyLun != NULL)
4989                 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
4990             else
4991                 break;
4992         }
4993     }
4994     else
4995     {
4996         /* Release the spinlock */
4997         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4998     }
4999 
5000     /* If we ready for next packet, start it */
5001     if (InterruptData.Flags & SCSI_PORT_NEXT_REQUEST_READY)
5002         IoStartNextPacket(DeviceExtension->DeviceObject, FALSE);
5003 
5004     NeedToStartIo = FALSE;
5005 
5006     /* Loop the completed request list */
5007     while (InterruptData.CompletedRequests)
5008     {
5009         /* Remove the request */
5010         SrbInfo = InterruptData.CompletedRequests;
5011         InterruptData.CompletedRequests = SrbInfo->CompletedRequests;
5012         SrbInfo->CompletedRequests = NULL;
5013 
5014         /* Process it */
5015         SpiProcessCompletedRequest(DeviceExtension,
5016                                   SrbInfo,
5017                                   &NeedToStartIo);
5018     }
5019 
5020     /* Loop abort request list */
5021     while (InterruptData.CompletedAbort)
5022     {
5023         LunExtension = InterruptData.CompletedAbort;
5024 
5025         /* Remove the request */
5026         InterruptData.CompletedAbort = LunExtension->CompletedAbortRequests;
5027 
5028         /* Get spinlock since we're going to change flags */
5029         KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
5030 
5031         /* TODO: Put SrbExtension to the list of free extensions */
5032         ASSERT(FALSE);
5033     }
5034 
5035     /* If we need - call StartIo routine */
5036     if (NeedToStartIo)
5037     {
5038         /* Make sure CurrentIrp is not null! */
5039         ASSERT(DpcDeviceObject->CurrentIrp != NULL);
5040         ScsiPortStartIo(DpcDeviceObject, DpcDeviceObject->CurrentIrp);
5041     }
5042 
5043     /* Everything has been done, check */
5044     if (InterruptData.Flags & SCSI_PORT_ENABLE_INT_REQUEST)
5045     {
5046         /* Synchronize using spinlock */
5047         KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
5048 
5049         /* Request an interrupt */
5050         DeviceExtension->HwInterrupt(DeviceExtension->MiniPortDeviceExtension);
5051 
5052         ASSERT(DeviceExtension->Flags & SCSI_PORT_DISABLE_INT_REQUESET);
5053 
5054         /* Should interrupts be enabled again? */
5055         if (DeviceExtension->Flags & SCSI_PORT_DISABLE_INT_REQUESET)
5056         {
5057             /* Clear this flag */
5058             DeviceExtension->Flags &= ~SCSI_PORT_DISABLE_INT_REQUESET;
5059 
5060             /* Call a special routine to do this */
5061             ASSERT(FALSE);
5062 #if 0
5063             KeSynchronizeExecution(DeviceExtension->Interrupt,
5064                                    SpiEnableInterrupts,
5065                                    DeviceExtension);
5066 #endif
5067         }
5068 
5069         /* If we need a notification again - loop */
5070         if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
5071             goto TryAgain;
5072 
5073         /* Release the spinlock */
5074         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
5075     }
5076 
5077     DPRINT("ScsiPortDpcForIsr() done\n");
5078 }
5079 
5080 BOOLEAN
5081 NTAPI
5082 SpiProcessTimeout(PVOID ServiceContext)
5083 {
5084     PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)ServiceContext;
5085     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
5086     ULONG Bus;
5087 
5088     DPRINT("SpiProcessTimeout() entered\n");
5089 
5090     DeviceExtension->TimerCount = -1;
5091 
5092     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET)
5093     {
5094         DeviceExtension->InterruptData.Flags &= ~SCSI_PORT_RESET;
5095 
5096         if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET_REQUEST)
5097         {
5098             DeviceExtension->InterruptData.Flags &=  ~SCSI_PORT_RESET_REQUEST;
5099             ScsiPortStartPacket(ServiceContext);
5100         }
5101 
5102         return FALSE;
5103     }
5104     else
5105     {
5106         DPRINT("Resetting the bus\n");
5107 
5108         for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
5109         {
5110             DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension, Bus);
5111 
5112             /* Reset flags and set reset timeout to 4 seconds */
5113             DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET;
5114             DeviceExtension->TimerCount = 4;
5115         }
5116 
5117         /* If miniport requested - request a dpc for it */
5118         if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
5119             IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
5120     }
5121 
5122     return TRUE;
5123 }
5124 
5125 
5126 BOOLEAN
5127 NTAPI
5128 SpiResetBus(PVOID ServiceContext)
5129 {
5130     PRESETBUS_PARAMS ResetParams = (PRESETBUS_PARAMS)ServiceContext;
5131     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
5132 
5133     /* Perform the bus reset */
5134     DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ResetParams->DeviceExtension;
5135     DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension,
5136                                 ResetParams->PathId);
5137 
5138     /* Set flags and start the timer */
5139     DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET;
5140     DeviceExtension->TimerCount = 4;
5141 
5142     /* If miniport requested - give him a DPC */
5143     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
5144         IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
5145 
5146     return TRUE;
5147 }
5148 
5149 //    ScsiPortIoTimer
5150 //  DESCRIPTION:
5151 //    This function handles timeouts and other time delayed processing
5152 //
5153 //  RUN LEVEL:
5154 //
5155 //  ARGUMENTS:
5156 //    IN  PDEVICE_OBJECT  DeviceObject  Device object registered with timer
5157 //    IN  PVOID           Context       the Controller extension for the
5158 //                                      controller the device is on
5159 //
5160 static VOID NTAPI
5161 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
5162                 PVOID Context)
5163 {
5164     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
5165     PSCSI_PORT_LUN_EXTENSION LunExtension;
5166     ULONG Lun;
5167     PIRP Irp;
5168 
5169     DPRINT("ScsiPortIoTimer()\n");
5170 
5171     DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
5172 
5173     /* Protect with the spinlock */
5174     KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
5175 
5176     /* Check timeouts */
5177     if (DeviceExtension->TimerCount > 0)
5178     {
5179         /* Decrease the timeout counter */
5180         DeviceExtension->TimerCount--;
5181 
5182         if (DeviceExtension->TimerCount == 0)
5183         {
5184             /* Timeout, process it */
5185             if (KeSynchronizeExecution(DeviceExtension->Interrupt[0],
5186                                        SpiProcessTimeout,
5187                                        DeviceExtension->DeviceObject))
5188             {
5189                 DPRINT("Error happened during processing timeout, but nothing critical\n");
5190             }
5191         }
5192 
5193         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
5194 
5195         /* We should exit now, since timeout is processed */
5196         return;
5197     }
5198 
5199     /* Per-Lun scanning of timeouts is needed... */
5200     for (Lun = 0; Lun < LUS_NUMBER; Lun++)
5201     {
5202         LunExtension = DeviceExtension->LunExtensionList[Lun];
5203 
5204         while (LunExtension)
5205         {
5206             if (LunExtension->Flags & LUNEX_BUSY)
5207             {
5208                 if (!(LunExtension->Flags &
5209                     (LUNEX_NEED_REQUEST_SENSE | LUNEX_FROZEN_QUEUE)))
5210                 {
5211                     DPRINT("Retrying busy request\n");
5212 
5213                     /* Clear flags, and retry busy request */
5214                     LunExtension->Flags &= ~(LUNEX_BUSY | LUNEX_FULL_QUEUE);
5215                     Irp = LunExtension->BusyRequest;
5216 
5217                     /* Clearing busy request */
5218                     LunExtension->BusyRequest = NULL;
5219 
5220                     KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
5221 
5222                     IoStartPacket(DeviceObject, Irp, (PULONG)NULL, NULL);
5223 
5224                     KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
5225                 }
5226             }
5227             else if (LunExtension->RequestTimeout == 0)
5228             {
5229                 RESETBUS_PARAMS ResetParams;
5230 
5231                 LunExtension->RequestTimeout = -1;
5232 
5233                 DPRINT("Request timed out, resetting bus\n");
5234 
5235                 /* Pass params to the bus reset routine */
5236                 ResetParams.PathId = LunExtension->PathId;
5237                 ResetParams.DeviceExtension = DeviceExtension;
5238 
5239                 if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0],
5240                                             SpiResetBus,
5241                                             &ResetParams))
5242                 {
5243                     DPRINT1("Reset failed\n");
5244                 }
5245             }
5246             else if (LunExtension->RequestTimeout > 0)
5247             {
5248                 /* Decrement the timeout counter */
5249                 LunExtension->RequestTimeout--;
5250             }
5251 
5252             LunExtension = LunExtension->Next;
5253         }
5254     }
5255 
5256     /* Release the spinlock */
5257     KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
5258 }
5259 
5260 /**********************************************************************
5261  * NAME                         INTERNAL
5262  *  SpiBuildDeviceMap
5263  *
5264  * DESCRIPTION
5265  *  Builds the registry device map of all device which are attached
5266  *  to the given SCSI HBA port. The device map is located at:
5267  *    \Registry\Machine\DeviceMap\Scsi
5268  *
5269  * RUN LEVEL
5270  *  PASSIVE_LEVEL
5271  *
5272  * ARGUMENTS
5273  *  DeviceExtension
5274  *      ...
5275  *
5276  *  RegistryPath
5277  *      Name of registry driver service key.
5278  *
5279  * RETURNS
5280  *  NTSTATUS
5281  */
5282 
5283 static NTSTATUS
5284 SpiBuildDeviceMap(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
5285                   IN PUNICODE_STRING RegistryPath)
5286 {
5287     PSCSI_PORT_LUN_EXTENSION LunExtension;
5288     OBJECT_ATTRIBUTES ObjectAttributes;
5289     UNICODE_STRING KeyName;
5290     UNICODE_STRING ValueName;
5291     WCHAR NameBuffer[64];
5292     ULONG Disposition;
5293     HANDLE ScsiKey;
5294     HANDLE ScsiPortKey = NULL;
5295     HANDLE ScsiBusKey = NULL;
5296     HANDLE ScsiInitiatorKey = NULL;
5297     HANDLE ScsiTargetKey = NULL;
5298     HANDLE ScsiLunKey = NULL;
5299     ULONG BusNumber;
5300     ULONG Target;
5301     ULONG CurrentTarget;
5302     ULONG Lun;
5303     PWCHAR DriverName;
5304     ULONG UlongData;
5305     PWCHAR TypeName;
5306     NTSTATUS Status;
5307 
5308     DPRINT("SpiBuildDeviceMap() called\n");
5309 
5310     if (DeviceExtension == NULL || RegistryPath == NULL)
5311     {
5312         DPRINT1("Invalid parameter\n");
5313         return STATUS_INVALID_PARAMETER;
5314     }
5315 
5316     /* Open or create the 'Scsi' subkey */
5317     RtlInitUnicodeString(&KeyName,
5318                          L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
5319     InitializeObjectAttributes(&ObjectAttributes,
5320                                &KeyName,
5321                                OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_KERNEL_HANDLE,
5322                                0,
5323                                NULL);
5324     Status = ZwCreateKey(&ScsiKey,
5325                          KEY_ALL_ACCESS,
5326                          &ObjectAttributes,
5327                          0,
5328                          NULL,
5329                          REG_OPTION_VOLATILE,
5330                          &Disposition);
5331     if (!NT_SUCCESS(Status))
5332     {
5333         DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
5334         return Status;
5335     }
5336 
5337     /* Create new 'Scsi Port X' subkey */
5338     DPRINT("Scsi Port %lu\n", DeviceExtension->PortNumber);
5339 
5340     swprintf(NameBuffer,
5341              L"Scsi Port %lu",
5342              DeviceExtension->PortNumber);
5343     RtlInitUnicodeString(&KeyName, NameBuffer);
5344     InitializeObjectAttributes(&ObjectAttributes,
5345                                &KeyName,
5346                                OBJ_KERNEL_HANDLE,
5347                                ScsiKey,
5348                                NULL);
5349     Status = ZwCreateKey(&ScsiPortKey,
5350                          KEY_ALL_ACCESS,
5351                          &ObjectAttributes,
5352                          0,
5353                          NULL,
5354                          REG_OPTION_VOLATILE,
5355                          &Disposition);
5356     ZwClose(ScsiKey);
5357     if (!NT_SUCCESS(Status))
5358     {
5359         DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
5360         return Status;
5361     }
5362 
5363     /*
5364      * Create port-specific values
5365      */
5366 
5367     /* Set 'DMA Enabled' (REG_DWORD) value */
5368     UlongData = (ULONG)!DeviceExtension->PortCapabilities.AdapterUsesPio;
5369     DPRINT("  DMA Enabled = %s\n", UlongData ? "TRUE" : "FALSE");
5370     RtlInitUnicodeString(&ValueName, L"DMA Enabled");
5371     Status = ZwSetValueKey(ScsiPortKey,
5372                            &ValueName,
5373                            0,
5374                            REG_DWORD,
5375                            &UlongData,
5376                            sizeof(UlongData));
5377     if (!NT_SUCCESS(Status))
5378     {
5379         DPRINT("ZwSetValueKey('DMA Enabled') failed (Status %lx)\n", Status);
5380         ZwClose(ScsiPortKey);
5381         return Status;
5382     }
5383 
5384     /* Set 'Driver' (REG_SZ) value */
5385     DriverName = wcsrchr(RegistryPath->Buffer, L'\\') + 1;
5386     RtlInitUnicodeString(&ValueName, L"Driver");
5387     Status = ZwSetValueKey(ScsiPortKey,
5388                            &ValueName,
5389                            0,
5390                            REG_SZ,
5391                            DriverName,
5392                            (ULONG)((wcslen(DriverName) + 1) * sizeof(WCHAR)));
5393     if (!NT_SUCCESS(Status))
5394     {
5395         DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status);
5396         ZwClose(ScsiPortKey);
5397         return Status;
5398     }
5399 
5400     /* Set 'Interrupt' (REG_DWORD) value (NT4 only) */
5401     UlongData = (ULONG)DeviceExtension->PortConfig->BusInterruptLevel;
5402     DPRINT("  Interrupt = %lu\n", UlongData);
5403     RtlInitUnicodeString(&ValueName, L"Interrupt");
5404     Status = ZwSetValueKey(ScsiPortKey,
5405                            &ValueName,
5406                            0,
5407                            REG_DWORD,
5408                            &UlongData,
5409                            sizeof(UlongData));
5410     if (!NT_SUCCESS(Status))
5411     {
5412         DPRINT("ZwSetValueKey('Interrupt') failed (Status %lx)\n", Status);
5413         ZwClose(ScsiPortKey);
5414         return Status;
5415     }
5416 
5417     /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
5418     UlongData = ScsiPortConvertPhysicalAddressToUlong((*DeviceExtension->PortConfig->AccessRanges)[0].RangeStart);
5419     DPRINT("  IOAddress = %lx\n", UlongData);
5420     RtlInitUnicodeString(&ValueName, L"IOAddress");
5421     Status = ZwSetValueKey(ScsiPortKey,
5422                            &ValueName,
5423                            0,
5424                            REG_DWORD,
5425                            &UlongData,
5426                            sizeof(UlongData));
5427     if (!NT_SUCCESS(Status))
5428     {
5429         DPRINT("ZwSetValueKey('IOAddress') failed (Status %lx)\n", Status);
5430         ZwClose(ScsiPortKey);
5431         return Status;
5432     }
5433 
5434     /* Enumerate buses */
5435     for (BusNumber = 0; BusNumber < DeviceExtension->PortConfig->NumberOfBuses; BusNumber++)
5436     {
5437         /* Create 'Scsi Bus X' key */
5438         DPRINT("    Scsi Bus %lu\n", BusNumber);
5439         swprintf(NameBuffer,
5440                  L"Scsi Bus %lu",
5441                  BusNumber);
5442         RtlInitUnicodeString(&KeyName, NameBuffer);
5443         InitializeObjectAttributes(&ObjectAttributes,
5444                                    &KeyName,
5445                                    0,
5446                                    ScsiPortKey,
5447                                    NULL);
5448         Status = ZwCreateKey(&ScsiBusKey,
5449                              KEY_ALL_ACCESS,
5450                              &ObjectAttributes,
5451                              0,
5452                              NULL,
5453                              REG_OPTION_VOLATILE,
5454                              &Disposition);
5455         if (!NT_SUCCESS(Status))
5456         {
5457             DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
5458             goto ByeBye;
5459         }
5460 
5461         /* Create 'Initiator Id X' key */
5462         DPRINT("      Initiator Id %lu\n",
5463                DeviceExtension->PortConfig->InitiatorBusId[BusNumber]);
5464         swprintf(NameBuffer,
5465                  L"Initiator Id %lu",
5466                  (ULONG)(UCHAR)DeviceExtension->PortConfig->InitiatorBusId[BusNumber]);
5467         RtlInitUnicodeString(&KeyName, NameBuffer);
5468         InitializeObjectAttributes(&ObjectAttributes,
5469                                    &KeyName,
5470                                    0,
5471                                    ScsiBusKey,
5472                                    NULL);
5473         Status = ZwCreateKey(&ScsiInitiatorKey,
5474                              KEY_ALL_ACCESS,
5475                              &ObjectAttributes,
5476                              0,
5477                              NULL,
5478                              REG_OPTION_VOLATILE,
5479                              &Disposition);
5480         if (!NT_SUCCESS(Status))
5481         {
5482             DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
5483             goto ByeBye;
5484         }
5485 
5486         /* FIXME: Are there any initiator values (??) */
5487 
5488         ZwClose(ScsiInitiatorKey);
5489         ScsiInitiatorKey = NULL;
5490 
5491 
5492         /* Enumerate targets */
5493         CurrentTarget = (ULONG)-1;
5494         ScsiTargetKey = NULL;
5495         for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
5496         {
5497             for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
5498             {
5499                 LunExtension = SpiGetLunExtension(DeviceExtension,
5500                                                   (UCHAR)BusNumber,
5501                                                   (UCHAR)Target,
5502                                                   (UCHAR)Lun);
5503                 if (LunExtension == NULL)
5504                     continue;
5505 
5506                 if (Target != CurrentTarget)
5507                 {
5508                     /* Close old target key */
5509                     if (ScsiTargetKey != NULL)
5510                     {
5511                         ZwClose(ScsiTargetKey);
5512                         ScsiTargetKey = NULL;
5513                     }
5514 
5515                     /* Create 'Target Id X' key */
5516                     DPRINT("      Target Id %lu\n", Target);
5517                     swprintf(NameBuffer,
5518                              L"Target Id %lu",
5519                              Target);
5520                     RtlInitUnicodeString(&KeyName, NameBuffer);
5521                     InitializeObjectAttributes(&ObjectAttributes,
5522                                                &KeyName,
5523                                                0,
5524                                                ScsiBusKey,
5525                                                NULL);
5526                     Status = ZwCreateKey(&ScsiTargetKey,
5527                                          KEY_ALL_ACCESS,
5528                                          &ObjectAttributes,
5529                                          0,
5530                                          NULL,
5531                                          REG_OPTION_VOLATILE,
5532                                          &Disposition);
5533                     if (!NT_SUCCESS(Status))
5534                     {
5535                         DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
5536                         goto ByeBye;
5537                     }
5538 
5539                     CurrentTarget = Target;
5540                 }
5541 
5542                 /* Create 'Logical Unit Id X' key */
5543                 DPRINT("        Logical Unit Id %lu\n", Lun);
5544                 swprintf(NameBuffer,
5545                          L"Logical Unit Id %lu",
5546                          Lun);
5547                 RtlInitUnicodeString(&KeyName, NameBuffer);
5548                 InitializeObjectAttributes(&ObjectAttributes,
5549                                            &KeyName,
5550                                            0,
5551                                            ScsiTargetKey,
5552                                            NULL);
5553                 Status = ZwCreateKey(&ScsiLunKey,
5554                                      KEY_ALL_ACCESS,
5555                                      &ObjectAttributes,
5556                                      0,
5557                                      NULL,
5558                                      REG_OPTION_VOLATILE,
5559                                      &Disposition);
5560                 if (!NT_SUCCESS(Status))
5561                 {
5562                     DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
5563                     goto ByeBye;
5564                 }
5565 
5566                 /* Set 'Identifier' (REG_SZ) value */
5567                 swprintf(NameBuffer,
5568                          L"%.8S%.16S%.4S",
5569                          LunExtension->InquiryData.VendorId,
5570                          LunExtension->InquiryData.ProductId,
5571                          LunExtension->InquiryData.ProductRevisionLevel);
5572                 DPRINT("          Identifier = '%S'\n", NameBuffer);
5573                 RtlInitUnicodeString(&ValueName, L"Identifier");
5574                 Status = ZwSetValueKey(ScsiLunKey,
5575                                        &ValueName,
5576                                        0,
5577                                        REG_SZ,
5578                                        NameBuffer,
5579                                        (ULONG)((wcslen(NameBuffer) + 1) * sizeof(WCHAR)));
5580                 if (!NT_SUCCESS(Status))
5581                 {
5582                     DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", Status);
5583                     goto ByeBye;
5584                 }
5585 
5586                 /* Set 'Type' (REG_SZ) value */
5587                 /*
5588                  * See https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-ide-devices
5589                  * and https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-scsi-devices
5590                  * for a list of types with their human-readable forms.
5591                  */
5592                 switch (LunExtension->InquiryData.DeviceType)
5593                 {
5594                     case 0:
5595                         TypeName = L"DiskPeripheral";
5596                         break;
5597                     case 1:
5598                         TypeName = L"TapePeripheral";
5599                         break;
5600                     case 2:
5601                         TypeName = L"PrinterPeripheral";
5602                         break;
5603                     // case 3: "ProcessorPeripheral", classified as 'other': fall back to default case.
5604                     case 4:
5605                         TypeName = L"WormPeripheral";
5606                         break;
5607                     case 5:
5608                         TypeName = L"CdRomPeripheral";
5609                         break;
5610                     case 6:
5611                         TypeName = L"ScannerPeripheral";
5612                         break;
5613                     case 7:
5614                         TypeName = L"OpticalDiskPeripheral";
5615                         break;
5616                     case 8:
5617                         TypeName = L"MediumChangerPeripheral";
5618                         break;
5619                     case 9:
5620                         TypeName = L"CommunicationsPeripheral";
5621                         break;
5622 
5623                     /* New peripheral types (SCSI only) */
5624                     case 10: case 11:
5625                         TypeName = L"ASCPrePressGraphicsPeripheral";
5626                         break;
5627                     case 12:
5628                         TypeName = L"ArrayPeripheral";
5629                         break;
5630                     case 13:
5631                         TypeName = L"EnclosurePeripheral";
5632                         break;
5633                     case 14:
5634                         TypeName = L"RBCPeripheral";
5635                         break;
5636                     case 15:
5637                         TypeName = L"CardReaderPeripheral";
5638                         break;
5639                     case 16:
5640                         TypeName = L"BridgePeripheral";
5641                         break;
5642 
5643                     default:
5644                         TypeName = L"OtherPeripheral";
5645                         break;
5646                 }
5647                 DPRINT("          Type = '%S'\n", TypeName);
5648                 RtlInitUnicodeString(&ValueName, L"Type");
5649                 Status = ZwSetValueKey(ScsiLunKey,
5650                                        &ValueName,
5651                                        0,
5652                                        REG_SZ,
5653                                        TypeName,
5654                                        (ULONG)((wcslen(TypeName) + 1) * sizeof(WCHAR)));
5655                 if (!NT_SUCCESS(Status))
5656                 {
5657                     DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status);
5658                     goto ByeBye;
5659                 }
5660 
5661                 ZwClose(ScsiLunKey);
5662                 ScsiLunKey = NULL;
5663             }
5664 
5665             /* Close old target key */
5666             if (ScsiTargetKey != NULL)
5667             {
5668                 ZwClose(ScsiTargetKey);
5669                 ScsiTargetKey = NULL;
5670             }
5671         }
5672 
5673         ZwClose(ScsiBusKey);
5674         ScsiBusKey = NULL;
5675     }
5676 
5677 ByeBye:
5678     if (ScsiLunKey != NULL)
5679         ZwClose(ScsiLunKey);
5680 
5681     if (ScsiInitiatorKey != NULL)
5682         ZwClose(ScsiInitiatorKey);
5683 
5684     if (ScsiTargetKey != NULL)
5685         ZwClose(ScsiTargetKey);
5686 
5687     if (ScsiBusKey != NULL)
5688         ZwClose(ScsiBusKey);
5689 
5690     if (ScsiPortKey != NULL)
5691         ZwClose(ScsiPortKey);
5692 
5693     DPRINT("SpiBuildDeviceMap() done\n");
5694 
5695     return Status;
5696 }
5697 
5698 VOID
5699 NTAPI
5700 SpiMiniportTimerDpc(IN struct _KDPC *Dpc,
5701                     IN PVOID DeviceObject,
5702                     IN PVOID SystemArgument1,
5703                     IN PVOID SystemArgument2)
5704 {
5705     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
5706 
5707     DPRINT("Miniport timer DPC\n");
5708 
5709     DeviceExtension = ((PDEVICE_OBJECT)DeviceObject)->DeviceExtension;
5710 
5711     /* Acquire the spinlock */
5712     KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
5713 
5714     /* Call the timer routine */
5715     if (DeviceExtension->HwScsiTimer != NULL)
5716     {
5717         DeviceExtension->HwScsiTimer(&DeviceExtension->MiniPortDeviceExtension);
5718     }
5719 
5720     /* Release the spinlock */
5721     KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
5722 
5723     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
5724     {
5725         ScsiPortDpcForIsr(NULL,
5726                           DeviceExtension->DeviceObject,
5727                           NULL,
5728                           NULL);
5729     }
5730 }
5731 
5732 static NTSTATUS
5733 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
5734                     PHW_INITIALIZATION_DATA HwInitData,
5735                     PCONFIGURATION_INFO InternalConfigInfo,
5736                     PPORT_CONFIGURATION_INFORMATION ConfigInfo,
5737                     BOOLEAN ZeroStruct)
5738 {
5739     UNICODE_STRING UnicodeString;
5740     OBJECT_ATTRIBUTES ObjectAttributes;
5741     PCONFIGURATION_INFORMATION DdkConfigInformation;
5742     HANDLE RootKey, Key;
5743     BOOLEAN Found;
5744     WCHAR DeviceBuffer[16];
5745     WCHAR StrBuffer[512];
5746     ULONG Bus;
5747     NTSTATUS Status;
5748 
5749     /* Zero out the struct if told so */
5750     if (ZeroStruct)
5751     {
5752         /* First zero the portconfig */
5753         RtlZeroMemory(ConfigInfo, sizeof(PORT_CONFIGURATION_INFORMATION));
5754 
5755         /* Then access ranges */
5756         RtlZeroMemory(InternalConfigInfo->AccessRanges,
5757                       HwInitData->NumberOfAccessRanges * sizeof(ACCESS_RANGE));
5758 
5759         /* Initialize the struct */
5760         ConfigInfo->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
5761         ConfigInfo->AdapterInterfaceType = HwInitData->AdapterInterfaceType;
5762         ConfigInfo->InterruptMode = Latched;
5763         ConfigInfo->DmaChannel = SP_UNINITIALIZED_VALUE;
5764         ConfigInfo->DmaPort = SP_UNINITIALIZED_VALUE;
5765         ConfigInfo->DmaChannel2 = SP_UNINITIALIZED_VALUE;
5766         ConfigInfo->DmaPort2 = SP_UNINITIALIZED_VALUE;
5767         ConfigInfo->MaximumTransferLength = SP_UNINITIALIZED_VALUE;
5768         ConfigInfo->NumberOfAccessRanges = HwInitData->NumberOfAccessRanges;
5769         ConfigInfo->MaximumNumberOfTargets = 8;
5770 
5771         /* Store parameters */
5772         ConfigInfo->NeedPhysicalAddresses = HwInitData->NeedPhysicalAddresses;
5773         ConfigInfo->MapBuffers = HwInitData->MapBuffers;
5774         ConfigInfo->AutoRequestSense = HwInitData->AutoRequestSense;
5775         ConfigInfo->ReceiveEvent = HwInitData->ReceiveEvent;
5776         ConfigInfo->TaggedQueuing = HwInitData->TaggedQueuing;
5777         ConfigInfo->MultipleRequestPerLu = HwInitData->MultipleRequestPerLu;
5778 
5779         /* Get the disk usage */
5780         DdkConfigInformation = IoGetConfigurationInformation();
5781         ConfigInfo->AtdiskPrimaryClaimed = DdkConfigInformation->AtDiskPrimaryAddressClaimed;
5782         ConfigInfo->AtdiskSecondaryClaimed = DdkConfigInformation->AtDiskSecondaryAddressClaimed;
5783 
5784         /* Initiator bus id is not set */
5785         for (Bus = 0; Bus < 8; Bus++)
5786             ConfigInfo->InitiatorBusId[Bus] = (CCHAR)SP_UNINITIALIZED_VALUE;
5787     }
5788 
5789     ConfigInfo->NumberOfPhysicalBreaks = 17;
5790 
5791     /* Clear this information */
5792     InternalConfigInfo->DisableTaggedQueueing = FALSE;
5793     InternalConfigInfo->DisableMultipleLun = FALSE;
5794 
5795     /* Store Bus Number */
5796     ConfigInfo->SystemIoBusNumber = InternalConfigInfo->BusNumber;
5797 
5798 TryNextAd:
5799 
5800     if (ConfigInfo->AdapterInterfaceType == Internal)
5801     {
5802         /* Open registry key for HW database */
5803         InitializeObjectAttributes(&ObjectAttributes,
5804                                    DeviceExtension->DeviceObject->DriverObject->HardwareDatabase,
5805                                    OBJ_CASE_INSENSITIVE,
5806                                    NULL,
5807                                    NULL);
5808 
5809         Status = ZwOpenKey(&RootKey,
5810                            KEY_READ,
5811                            &ObjectAttributes);
5812 
5813         if (NT_SUCCESS(Status))
5814         {
5815             /* Create name for it */
5816             swprintf(StrBuffer, L"ScsiAdapter\\%lu",
5817                 InternalConfigInfo->AdapterNumber);
5818 
5819             RtlInitUnicodeString(&UnicodeString, StrBuffer);
5820 
5821             /* Open device key */
5822             InitializeObjectAttributes(&ObjectAttributes,
5823                                        &UnicodeString,
5824                                        OBJ_CASE_INSENSITIVE,
5825                                        RootKey,
5826                                        NULL);
5827 
5828             Status = ZwOpenKey(&Key,
5829                                KEY_READ,
5830                                &ObjectAttributes);
5831 
5832             ZwClose(RootKey);
5833 
5834             if (NT_SUCCESS(Status))
5835             {
5836                 if (InternalConfigInfo->LastAdapterNumber != InternalConfigInfo->AdapterNumber)
5837                 {
5838                     DPRINT("Hardware info found at %S\n", StrBuffer);
5839 
5840                     /* Parse it */
5841                     SpiParseDeviceInfo(DeviceExtension,
5842                                        Key,
5843                                        ConfigInfo,
5844                                        InternalConfigInfo,
5845                                        (PUCHAR)StrBuffer);
5846 
5847                      InternalConfigInfo->BusNumber = 0;
5848                 }
5849                 else
5850                 {
5851                     /* Try the next adapter */
5852                     InternalConfigInfo->AdapterNumber++;
5853                     goto TryNextAd;
5854                 }
5855             }
5856             else
5857             {
5858                 /* Info was not found, exit */
5859                 DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status);
5860                 return STATUS_DEVICE_DOES_NOT_EXIST;
5861             }
5862         }
5863         else
5864         {
5865             DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status);
5866         }
5867     }
5868 
5869     /* Look at device params */
5870     Key = NULL;
5871     if (InternalConfigInfo->Parameter)
5872     {
5873         ExFreePool(InternalConfigInfo->Parameter);
5874         InternalConfigInfo->Parameter = NULL;
5875     }
5876 
5877     if (InternalConfigInfo->ServiceKey != NULL)
5878     {
5879         swprintf(DeviceBuffer, L"Device%lu", InternalConfigInfo->AdapterNumber);
5880         RtlInitUnicodeString(&UnicodeString, DeviceBuffer);
5881 
5882         /* Open the service key */
5883         InitializeObjectAttributes(&ObjectAttributes,
5884                                    &UnicodeString,
5885                                    OBJ_CASE_INSENSITIVE,
5886                                    InternalConfigInfo->ServiceKey,
5887                                    NULL);
5888 
5889         Status = ZwOpenKey(&Key,
5890                            KEY_READ,
5891                            &ObjectAttributes);
5892     }
5893 
5894     /* Parse device key */
5895     if (InternalConfigInfo->DeviceKey != NULL)
5896     {
5897         SpiParseDeviceInfo(DeviceExtension,
5898                            InternalConfigInfo->DeviceKey,
5899                            ConfigInfo,
5900                            InternalConfigInfo,
5901                            (PUCHAR)StrBuffer);
5902     }
5903 
5904     /* Then parse hw info */
5905     if (Key != NULL)
5906     {
5907         if (InternalConfigInfo->LastAdapterNumber != InternalConfigInfo->AdapterNumber)
5908         {
5909             SpiParseDeviceInfo(DeviceExtension,
5910                                Key,
5911                                ConfigInfo,
5912                                InternalConfigInfo,
5913                                (PUCHAR)StrBuffer);
5914 
5915             /* Close the key */
5916             ZwClose(Key);
5917         }
5918         else
5919         {
5920             /* Adapter not found, go try the next one */
5921             InternalConfigInfo->AdapterNumber++;
5922 
5923             /* Close the key */
5924             ZwClose(Key);
5925 
5926             goto TryNextAd;
5927         }
5928     }
5929 
5930     /* Update the last adapter number */
5931     InternalConfigInfo->LastAdapterNumber = InternalConfigInfo->AdapterNumber;
5932 
5933     /* Do we have this kind of bus at all? */
5934     Found = FALSE;
5935     Status = IoQueryDeviceDescription(&HwInitData->AdapterInterfaceType,
5936                                       &InternalConfigInfo->BusNumber,
5937                                       NULL,
5938                                       NULL,
5939                                       NULL,
5940                                       NULL,
5941                                       SpQueryDeviceCallout,
5942                                       &Found);
5943 
5944     /* This bus was not found */
5945     if (!Found)
5946     {
5947         INTERFACE_TYPE InterfaceType = Eisa;
5948 
5949         /* Check for EISA */
5950         if (HwInitData->AdapterInterfaceType == Isa)
5951         {
5952             Status = IoQueryDeviceDescription(&InterfaceType,
5953                                               &InternalConfigInfo->BusNumber,
5954                                               NULL,
5955                                               NULL,
5956                                               NULL,
5957                                               NULL,
5958                                               SpQueryDeviceCallout,
5959                                               &Found);
5960 
5961             /* Return respectively */
5962             if (Found)
5963                 return STATUS_SUCCESS;
5964             else
5965                 return STATUS_DEVICE_DOES_NOT_EXIST;
5966         }
5967         else
5968         {
5969             return STATUS_DEVICE_DOES_NOT_EXIST;
5970         }
5971     }
5972     else
5973     {
5974         return STATUS_SUCCESS;
5975     }
5976 }
5977 
5978 static VOID
5979 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
5980                    IN HANDLE Key,
5981                    IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
5982                    IN PCONFIGURATION_INFO InternalConfigInfo,
5983                    IN PUCHAR Buffer)
5984 {
5985     PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
5986     PCM_FULL_RESOURCE_DESCRIPTOR FullResource;
5987     PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
5988     PCM_SCSI_DEVICE_DATA ScsiDeviceData;
5989     ULONG Length, Count, Dma = 0, Interrupt = 0;
5990     ULONG Index = 0, RangeCount = 0;
5991     UNICODE_STRING UnicodeString;
5992     ANSI_STRING AnsiString;
5993     NTSTATUS Status = STATUS_SUCCESS;
5994 
5995 
5996     KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION) Buffer;
5997 
5998     /* Loop through all values in the device node */
5999     while(TRUE)
6000     {
6001         Status = ZwEnumerateValueKey(Key,
6002                                      Index,
6003                                      KeyValueFullInformation,
6004                                      Buffer,
6005                                      512,
6006                                      &Length);
6007 
6008         if (!NT_SUCCESS(Status))
6009             return;
6010 
6011         Index++;
6012 
6013         /* Length for DWORD is ok? */
6014         if (KeyValueInformation->Type == REG_DWORD &&
6015             KeyValueInformation->DataLength != sizeof(ULONG))
6016         {
6017             continue;
6018         }
6019 
6020         /* Get MaximumLogicalUnit */
6021         if (_wcsnicmp(KeyValueInformation->Name, L"MaximumLogicalUnit",
6022             KeyValueInformation->NameLength/2) == 0)
6023         {
6024 
6025             if (KeyValueInformation->Type != REG_DWORD)
6026             {
6027                 DPRINT("Bad data type for MaximumLogicalUnit\n");
6028                 continue;
6029             }
6030 
6031             DeviceExtension->MaxLunCount = *((PUCHAR)
6032                 (Buffer + KeyValueInformation->DataOffset));
6033 
6034             /* Check / reset if needed */
6035             if (DeviceExtension->MaxLunCount > SCSI_MAXIMUM_LOGICAL_UNITS)
6036                 DeviceExtension->MaxLunCount = SCSI_MAXIMUM_LOGICAL_UNITS;
6037 
6038             DPRINT("MaximumLogicalUnit = %d\n", DeviceExtension->MaxLunCount);
6039         }
6040 
6041         /* Get InitiatorTargetId */
6042         if (_wcsnicmp(KeyValueInformation->Name, L"InitiatorTargetId",
6043             KeyValueInformation->NameLength / 2) == 0)
6044         {
6045 
6046             if (KeyValueInformation->Type != REG_DWORD)
6047             {
6048                 DPRINT("Bad data type for InitiatorTargetId\n");
6049                 continue;
6050             }
6051 
6052             ConfigInfo->InitiatorBusId[0] = *((PUCHAR)
6053                 (Buffer + KeyValueInformation->DataOffset));
6054 
6055             /* Check / reset if needed */
6056             if (ConfigInfo->InitiatorBusId[0] > ConfigInfo->MaximumNumberOfTargets - 1)
6057                 ConfigInfo->InitiatorBusId[0] = (CCHAR)-1;
6058 
6059             DPRINT("InitiatorTargetId = %d\n", ConfigInfo->InitiatorBusId[0]);
6060         }
6061 
6062         /* Get ScsiDebug */
6063         if (_wcsnicmp(KeyValueInformation->Name, L"ScsiDebug",
6064             KeyValueInformation->NameLength/2) == 0)
6065         {
6066             DPRINT("ScsiDebug key not supported\n");
6067         }
6068 
6069         /* Check for a breakpoint */
6070         if (_wcsnicmp(KeyValueInformation->Name, L"BreakPointOnEntry",
6071             KeyValueInformation->NameLength/2) == 0)
6072         {
6073             DPRINT1("Breakpoint on entry requested!\n");
6074             DbgBreakPoint();
6075         }
6076 
6077         /* Get DisableSynchronousTransfers */
6078         if (_wcsnicmp(KeyValueInformation->Name, L"DisableSynchronousTransfers",
6079             KeyValueInformation->NameLength/2) == 0)
6080         {
6081             DeviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
6082             DPRINT("Synch transfers disabled\n");
6083         }
6084 
6085         /* Get DisableDisconnects */
6086         if (_wcsnicmp(KeyValueInformation->Name, L"DisableDisconnects",
6087             KeyValueInformation->NameLength/2) == 0)
6088         {
6089             DeviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT;
6090             DPRINT("Disconnects disabled\n");
6091         }
6092 
6093         /* Get DisableTaggedQueuing */
6094         if (_wcsnicmp(KeyValueInformation->Name, L"DisableTaggedQueuing",
6095             KeyValueInformation->NameLength/2) == 0)
6096         {
6097             InternalConfigInfo->DisableTaggedQueueing = TRUE;
6098             DPRINT("Tagged queueing disabled\n");
6099         }
6100 
6101         /* Get DisableMultipleRequests */
6102         if (_wcsnicmp(KeyValueInformation->Name, L"DisableMultipleRequests",
6103             KeyValueInformation->NameLength/2) == 0)
6104         {
6105             InternalConfigInfo->DisableMultipleLun = TRUE;
6106             DPRINT("Multiple requests disabled\n");
6107         }
6108 
6109         /* Get DriverParameters */
6110         if (_wcsnicmp(KeyValueInformation->Name, L"DriverParameters",
6111             KeyValueInformation->NameLength/2) == 0)
6112         {
6113             /* Skip if nothing */
6114             if (KeyValueInformation->DataLength == 0)
6115                 continue;
6116 
6117             /* If there was something previously allocated - free it */
6118             if (InternalConfigInfo->Parameter != NULL)
6119                 ExFreePool(InternalConfigInfo->Parameter);
6120 
6121             /* Allocate it */
6122             InternalConfigInfo->Parameter = ExAllocatePoolWithTag(NonPagedPool,
6123                                                            KeyValueInformation->DataLength, TAG_SCSIPORT);
6124 
6125             if (InternalConfigInfo->Parameter != NULL)
6126             {
6127                 if (KeyValueInformation->Type != REG_SZ)
6128                 {
6129                     /* Just copy */
6130                     RtlCopyMemory(
6131                         InternalConfigInfo->Parameter,
6132                         (PCCHAR)KeyValueInformation + KeyValueInformation->DataOffset,
6133                         KeyValueInformation->DataLength);
6134                 }
6135                 else
6136                 {
6137                     /* If it's a unicode string, convert it to ansi */
6138                     UnicodeString.Length = (USHORT)KeyValueInformation->DataLength;
6139                     UnicodeString.MaximumLength = (USHORT)KeyValueInformation->DataLength;
6140                     UnicodeString.Buffer =
6141                         (PWSTR)((PCCHAR)KeyValueInformation + KeyValueInformation->DataOffset);
6142 
6143                     AnsiString.Length = 0;
6144                     AnsiString.MaximumLength = (USHORT)KeyValueInformation->DataLength;
6145                     AnsiString.Buffer = (PCHAR)InternalConfigInfo->Parameter;
6146 
6147                     Status = RtlUnicodeStringToAnsiString(&AnsiString,
6148                                                           &UnicodeString,
6149                                                           FALSE);
6150 
6151                     /* In case of error, free the allocated space */
6152                     if (!NT_SUCCESS(Status))
6153                     {
6154                         ExFreePool(InternalConfigInfo->Parameter);
6155                         InternalConfigInfo->Parameter = NULL;
6156                     }
6157 
6158                 }
6159             }
6160 
6161             DPRINT("Found driver parameter\n");
6162         }
6163 
6164         /* Get MaximumSGList */
6165         if (_wcsnicmp(KeyValueInformation->Name, L"MaximumSGList",
6166             KeyValueInformation->NameLength/2) == 0)
6167         {
6168             if (KeyValueInformation->Type != REG_DWORD)
6169             {
6170                 DPRINT("Bad data type for MaximumSGList\n");
6171                 continue;
6172             }
6173 
6174             ConfigInfo->NumberOfPhysicalBreaks = *((PUCHAR)(Buffer + KeyValueInformation->DataOffset));
6175 
6176             /* Check / fix */
6177             if (ConfigInfo->NumberOfPhysicalBreaks > SCSI_MAXIMUM_PHYSICAL_BREAKS)
6178             {
6179                 ConfigInfo->NumberOfPhysicalBreaks = SCSI_MAXIMUM_PHYSICAL_BREAKS;
6180             }
6181             else if (ConfigInfo->NumberOfPhysicalBreaks < SCSI_MINIMUM_PHYSICAL_BREAKS)
6182             {
6183                 ConfigInfo->NumberOfPhysicalBreaks = SCSI_MINIMUM_PHYSICAL_BREAKS;
6184             }
6185 
6186             DPRINT("MaximumSGList = %d\n", ConfigInfo->NumberOfPhysicalBreaks);
6187         }
6188 
6189         /* Get NumberOfRequests */
6190         if (_wcsnicmp(KeyValueInformation->Name, L"NumberOfRequests",
6191             KeyValueInformation->NameLength/2) == 0)
6192         {
6193             if (KeyValueInformation->Type != REG_DWORD)
6194             {
6195                 DPRINT("NumberOfRequests has wrong data type\n");
6196                 continue;
6197             }
6198 
6199             DeviceExtension->RequestsNumber = *((PUCHAR)(Buffer + KeyValueInformation->DataOffset));
6200 
6201             /* Check / fix */
6202             if (DeviceExtension->RequestsNumber < 16)
6203             {
6204                 DeviceExtension->RequestsNumber = 16;
6205             }
6206             else if (DeviceExtension->RequestsNumber > 512)
6207             {
6208                 DeviceExtension->RequestsNumber = 512;
6209             }
6210 
6211             DPRINT("Number Of Requests = %d\n", DeviceExtension->RequestsNumber);
6212         }
6213 
6214         /* Get resource list */
6215         if (_wcsnicmp(KeyValueInformation->Name, L"ResourceList",
6216                 KeyValueInformation->NameLength/2) == 0 ||
6217             _wcsnicmp(KeyValueInformation->Name, L"Configuration Data",
6218                 KeyValueInformation->NameLength/2) == 0 )
6219         {
6220             if (KeyValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR ||
6221                 KeyValueInformation->DataLength < sizeof(REG_FULL_RESOURCE_DESCRIPTOR))
6222             {
6223                 DPRINT("Bad data type for ResourceList\n");
6224                 continue;
6225             }
6226             else
6227             {
6228                 DPRINT("Found ResourceList\n");
6229             }
6230 
6231             FullResource = (PCM_FULL_RESOURCE_DESCRIPTOR)(Buffer + KeyValueInformation->DataOffset);
6232 
6233             /* Copy some info from it */
6234             InternalConfigInfo->BusNumber = FullResource->BusNumber;
6235             ConfigInfo->SystemIoBusNumber = FullResource->BusNumber;
6236 
6237             /* Loop through it */
6238             for (Count = 0; Count < FullResource->PartialResourceList.Count; Count++)
6239             {
6240                 /* Get partial descriptor */
6241                 PartialDescriptor =
6242                     &FullResource->PartialResourceList.PartialDescriptors[Count];
6243 
6244                 /* Check datalength */
6245                 if ((ULONG)((PCHAR)(PartialDescriptor + 1) -
6246                     (PCHAR)FullResource) > KeyValueInformation->DataLength)
6247                 {
6248                     DPRINT("Resource data is of incorrect size\n");
6249                     break;
6250                 }
6251 
6252                 switch (PartialDescriptor->Type)
6253                 {
6254                 case CmResourceTypePort:
6255                     if (RangeCount >= ConfigInfo->NumberOfAccessRanges)
6256                     {
6257                         DPRINT("Too many access ranges\n");
6258                         continue;
6259                     }
6260 
6261                     InternalConfigInfo->AccessRanges[RangeCount].RangeInMemory = FALSE;
6262                     InternalConfigInfo->AccessRanges[RangeCount].RangeStart = PartialDescriptor->u.Port.Start;
6263                     InternalConfigInfo->AccessRanges[RangeCount].RangeLength = PartialDescriptor->u.Port.Length;
6264                     RangeCount++;
6265 
6266                     break;
6267 
6268                 case CmResourceTypeMemory:
6269                     if (RangeCount >= ConfigInfo->NumberOfAccessRanges)
6270                     {
6271                         DPRINT("Too many access ranges\n");
6272                         continue;
6273                     }
6274 
6275                     InternalConfigInfo->AccessRanges[RangeCount].RangeInMemory = TRUE;
6276                     InternalConfigInfo->AccessRanges[RangeCount].RangeStart = PartialDescriptor->u.Memory.Start;
6277                     InternalConfigInfo->AccessRanges[RangeCount].RangeLength = PartialDescriptor->u.Memory.Length;
6278                     RangeCount++;
6279 
6280                     break;
6281 
6282                 case CmResourceTypeInterrupt:
6283 
6284                     if (Interrupt == 0)
6285                     {
6286                         ConfigInfo->BusInterruptLevel =
6287                             PartialDescriptor->u.Interrupt.Level;
6288 
6289                         ConfigInfo->BusInterruptVector =
6290                             PartialDescriptor->u.Interrupt.Vector;
6291 
6292                         ConfigInfo->InterruptMode = (PartialDescriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive;
6293                     }
6294                     else if (Interrupt == 1)
6295                     {
6296                         ConfigInfo->BusInterruptLevel2 =
6297                         PartialDescriptor->u.Interrupt.Level;
6298 
6299                         ConfigInfo->BusInterruptVector2 =
6300                         PartialDescriptor->u.Interrupt.Vector;
6301 
6302                         ConfigInfo->InterruptMode2 = (PartialDescriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive;
6303                     }
6304 
6305                     Interrupt++;
6306                     break;
6307 
6308                 case CmResourceTypeDma:
6309 
6310                     if (Dma == 0)
6311                     {
6312                         ConfigInfo->DmaChannel = PartialDescriptor->u.Dma.Channel;
6313                         ConfigInfo->DmaPort = PartialDescriptor->u.Dma.Port;
6314 
6315                         if (PartialDescriptor->Flags & CM_RESOURCE_DMA_8)
6316                             ConfigInfo->DmaWidth = Width8Bits;
6317                         else if ((PartialDescriptor->Flags & CM_RESOURCE_DMA_16) ||
6318                                  (PartialDescriptor->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
6319                             ConfigInfo->DmaWidth = Width16Bits;
6320                         else if (PartialDescriptor->Flags & CM_RESOURCE_DMA_32)
6321                             ConfigInfo->DmaWidth = Width32Bits;
6322                     }
6323                     else if (Dma == 1)
6324                     {
6325                         ConfigInfo->DmaChannel2 = PartialDescriptor->u.Dma.Channel;
6326                         ConfigInfo->DmaPort2 = PartialDescriptor->u.Dma.Port;
6327 
6328                         if (PartialDescriptor->Flags & CM_RESOURCE_DMA_8)
6329                             ConfigInfo->DmaWidth2 = Width8Bits;
6330                         else if ((PartialDescriptor->Flags & CM_RESOURCE_DMA_16) ||
6331                                  (PartialDescriptor->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
6332                             ConfigInfo->DmaWidth2 = Width16Bits;
6333                         else if (PartialDescriptor->Flags & CM_RESOURCE_DMA_32)
6334                             ConfigInfo->DmaWidth2 = Width32Bits;
6335                     }
6336 
6337                     Dma++;
6338                     break;
6339 
6340                 case CmResourceTypeDeviceSpecific:
6341                     if (PartialDescriptor->u.DeviceSpecificData.DataSize <
6342                         sizeof(CM_SCSI_DEVICE_DATA) ||
6343                         (PCHAR) (PartialDescriptor + 1) - (PCHAR)FullResource +
6344                         PartialDescriptor->u.DeviceSpecificData.DataSize >
6345                         KeyValueInformation->DataLength)
6346                     {
6347                         DPRINT("Resource data length is incorrect");
6348                         break;
6349                     }
6350 
6351                     /* Set only one field from it */
6352                     ScsiDeviceData = (PCM_SCSI_DEVICE_DATA) (PartialDescriptor+1);
6353                     ConfigInfo->InitiatorBusId[0] = ScsiDeviceData->HostIdentifier;
6354                     break;
6355                 }
6356             }
6357         }
6358     }
6359 }
6360 
6361 NTSTATUS
6362 NTAPI
6363 SpQueryDeviceCallout(IN PVOID  Context,
6364                      IN PUNICODE_STRING  PathName,
6365                      IN INTERFACE_TYPE  BusType,
6366                      IN ULONG  BusNumber,
6367                      IN PKEY_VALUE_FULL_INFORMATION  *BusInformation,
6368                      IN CONFIGURATION_TYPE  ControllerType,
6369                      IN ULONG  ControllerNumber,
6370                      IN PKEY_VALUE_FULL_INFORMATION  *ControllerInformation,
6371                      IN CONFIGURATION_TYPE  PeripheralType,
6372                      IN ULONG  PeripheralNumber,
6373                      IN PKEY_VALUE_FULL_INFORMATION  *PeripheralInformation)
6374 {
6375     PBOOLEAN Found = (PBOOLEAN)Context;
6376     /* We just set our Found variable to TRUE */
6377 
6378     *Found = TRUE;
6379     return STATUS_SUCCESS;
6380 }
6381 
6382 IO_ALLOCATION_ACTION
6383 NTAPI
6384 ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject,
6385                                IN PIRP Irp,
6386                                IN PVOID MapRegisterBase,
6387                                IN PVOID Context)
6388 {
6389     KIRQL Irql;
6390     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
6391 
6392     /* Guard access with the spinlock */
6393     KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
6394 
6395     /* Save MapRegisterBase we've got here */
6396     DeviceExtension->MapRegisterBase = MapRegisterBase;
6397 
6398     /* Start pending request */
6399     KeSynchronizeExecution(DeviceExtension->Interrupt[0],
6400         ScsiPortStartPacket, DeviceObject);
6401 
6402     /* Release spinlock we took */
6403     KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
6404 
6405     return KeepObject;
6406 }
6407 
6408 static
6409 NTSTATUS
6410 SpiStatusSrbToNt(UCHAR SrbStatus)
6411 {
6412     switch (SRB_STATUS(SrbStatus))
6413     {
6414     case SRB_STATUS_TIMEOUT:
6415     case SRB_STATUS_COMMAND_TIMEOUT:
6416         return STATUS_IO_TIMEOUT;
6417 
6418     case SRB_STATUS_BAD_SRB_BLOCK_LENGTH:
6419     case SRB_STATUS_BAD_FUNCTION:
6420         return STATUS_INVALID_DEVICE_REQUEST;
6421 
6422     case SRB_STATUS_NO_DEVICE:
6423     case SRB_STATUS_INVALID_LUN:
6424     case SRB_STATUS_INVALID_TARGET_ID:
6425     case SRB_STATUS_NO_HBA:
6426         return STATUS_DEVICE_DOES_NOT_EXIST;
6427 
6428     case SRB_STATUS_DATA_OVERRUN:
6429         return STATUS_BUFFER_OVERFLOW;
6430 
6431     case SRB_STATUS_SELECTION_TIMEOUT:
6432         return STATUS_DEVICE_NOT_CONNECTED;
6433 
6434     default:
6435         return STATUS_IO_DEVICE_ERROR;
6436     }
6437 
6438     return STATUS_IO_DEVICE_ERROR;
6439 }
6440 
6441 
6442 #undef ScsiPortConvertPhysicalAddressToUlong
6443 /*
6444  * @implemented
6445  */
6446 ULONG NTAPI
6447 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address)
6448 {
6449   DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
6450   return(Address.u.LowPart);
6451 }
6452 
6453 /* EOF */
6454