update for HEAD-2003091401
[reactos.git] / drivers / storage / scsiport / scsiport.c
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
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /* $Id$
20  *
21  * COPYRIGHT:       See COPYING in the top level directory
22  * PROJECT:         ReactOS kernel
23  * FILE:            services/storage/scsiport/scsiport.c
24  * PURPOSE:         SCSI port driver
25  * PROGRAMMER:      Eric Kohl (ekohl@rz-online.de)
26  */
27
28 /* INCLUDES *****************************************************************/
29
30 #include <ddk/ntddk.h>
31 #include <ddk/srb.h>
32 #include <ddk/scsi.h>
33 #include <ddk/ntddscsi.h>
34
35 #define NDEBUG
36 #include <debug.h>
37
38
39 #define VERSION "0.0.1"
40
41 #include "scsiport_int.h"
42
43 //#define USE_DEVICE_QUEUES
44
45 /* TYPES *********************************************************************/
46
47 #define IRP_FLAG_COMPLETE       0x00000001
48 #define IRP_FLAG_NEXT           0x00000002
49 #define IRP_FLAG_NEXT_LU        0x00000004
50
51
52 /* GLOBALS *******************************************************************/
53
54 static NTSTATUS STDCALL
55 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
56                     IN PIRP Irp);
57
58 static NTSTATUS STDCALL
59 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
60                      IN PIRP Irp);
61
62 static NTSTATUS STDCALL
63 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
64                       IN PIRP Irp);
65
66 static VOID STDCALL
67 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
68                 IN PIRP Irp);
69
70 static IO_ALLOCATION_ACTION STDCALL
71 ScsiPortAllocateController(IN PDEVICE_OBJECT DeviceObject,
72                            IN PIRP Irp,
73                            IN PVOID MapRegisterBase,
74                            IN PVOID Context);
75
76 static BOOLEAN STDCALL
77 ScsiPortStartPacket(IN OUT PVOID Context);
78
79 static NTSTATUS
80 ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject,
81                          IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension,
82                          IN ULONG PortCount,
83                          IN OUT PSCSI_PORT_DEVICE_EXTENSION *RealDeviceExtension);
84
85 static PSCSI_PORT_LUN_EXTENSION
86 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
87                          IN UCHAR PathId,
88                          IN UCHAR TargetId,
89                          IN UCHAR Lun);
90
91 static PSCSI_PORT_LUN_EXTENSION
92 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
93                     IN UCHAR PathId,
94                     IN UCHAR TargetId,
95                     IN UCHAR Lun);
96
97 static VOID
98 SpiInquirePort (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
99
100 static ULONG
101 SpiGetInquiryData (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
102                    OUT PSCSI_ADAPTER_BUS_INFO AdapterBusInfo);
103
104 static BOOLEAN STDCALL
105 ScsiPortIsr(IN PKINTERRUPT Interrupt,
106             IN PVOID ServiceContext);
107
108 static VOID STDCALL
109 ScsiPortDpcForIsr(IN PKDPC Dpc,
110                   IN PDEVICE_OBJECT DpcDeviceObject,
111                   IN PIRP DpcIrp,
112                   IN PVOID DpcContext);
113
114 static VOID STDCALL
115 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
116                 PVOID Context);
117
118 static PSCSI_REQUEST_BLOCK
119 ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
120                             PSCSI_REQUEST_BLOCK OriginalSrb);
121
122 static NTSTATUS
123 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
124                    PUNICODE_STRING RegistryPath);
125
126
127 /* FUNCTIONS *****************************************************************/
128
129 /**********************************************************************
130  * NAME                                                 EXPORTED
131  *      DriverEntry
132  *
133  * DESCRIPTION
134  *      This function initializes the driver.
135  *
136  * RUN LEVEL
137  *      PASSIVE_LEVEL
138  *
139  * ARGUMENTS
140  *      DriverObject
141  *              System allocated Driver Object for this driver.
142  *
143  *      RegistryPath
144  *              Name of registry driver service key.
145  *
146  * RETURN VALUE
147  *      Status.
148  */
149
150 NTSTATUS STDCALL
151 DriverEntry(IN PDRIVER_OBJECT DriverObject,
152             IN PUNICODE_STRING RegistryPath)
153 {
154   DPRINT("ScsiPort Driver %s\n", VERSION);
155   return(STATUS_SUCCESS);
156 }
157
158
159 /**********************************************************************
160  * NAME                                                 EXPORTED
161  *      ScsiDebugPrint
162  *
163  * DESCRIPTION
164  *      Prints debugging messages.
165  *
166  * RUN LEVEL
167  *      PASSIVE_LEVEL
168  *
169  * ARGUMENTS
170  *      DebugPrintLevel
171  *              Debug level of the given message.
172  *
173  *      DebugMessage
174  *              Pointer to printf()-compatible format string.
175  *
176  *      ...
177                 Additional output data (see printf()).
178  *
179  * RETURN VALUE
180  *      None.
181  *
182  * @implemented
183  */
184
185 VOID
186 ScsiDebugPrint(IN ULONG DebugPrintLevel,
187                IN PCHAR DebugMessage,
188                ...)
189 {
190   char Buffer[256];
191   va_list ap;
192
193 #if 0
194   if (DebugPrintLevel > InternalDebugLevel)
195     return;
196 #endif
197
198   va_start(ap, DebugMessage);
199   vsprintf(Buffer, DebugMessage, ap);
200   va_end(ap);
201
202   DbgPrint(Buffer);
203 }
204
205
206 /*
207  * @unimplemented
208  */
209 VOID STDCALL
210 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension,
211                         IN UCHAR PathId,
212                         IN UCHAR TargetId,
213                         IN UCHAR Lun,
214                         IN UCHAR SrbStatus)
215 {
216   DPRINT("ScsiPortCompleteRequest()\n");
217   UNIMPLEMENTED;
218 }
219
220
221 /*
222  * @implemented
223  */
224 ULONG STDCALL
225 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address)
226 {
227   DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
228   return(Address.u.LowPart);
229 }
230
231
232 /*
233  * @unimplemented
234  */
235 VOID STDCALL
236 ScsiPortFlushDma(IN PVOID HwDeviceExtension)
237 {
238   DPRINT("ScsiPortFlushDma()\n");
239   UNIMPLEMENTED;
240 }
241
242
243 /*
244  * @implemented
245  */
246 VOID STDCALL
247 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension,
248                        IN PVOID MappedAddress)
249 {
250   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
251   PSCSI_PORT_DEVICE_BASE DeviceBase;
252   PLIST_ENTRY Entry;
253
254   DPRINT("ScsiPortFreeDeviceBase() called\n");
255
256   DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
257                                       SCSI_PORT_DEVICE_EXTENSION,
258                                       MiniPortDeviceExtension);
259   if (IsListEmpty(&DeviceExtension->DeviceBaseListHead))
260     return;
261
262   Entry = DeviceExtension->DeviceBaseListHead.Flink;
263   while (Entry != &DeviceExtension->DeviceBaseListHead)
264     {
265       DeviceBase = CONTAINING_RECORD(Entry,
266                                      SCSI_PORT_DEVICE_BASE,
267                                      List);
268       if (DeviceBase->MappedAddress == MappedAddress)
269         {
270           MmUnmapIoSpace(DeviceBase->MappedAddress,
271                          DeviceBase->NumberOfBytes);
272           RemoveEntryList(Entry);
273           ExFreePool(DeviceBase);
274
275           return;
276         }
277
278       Entry = Entry->Flink;
279     }
280 }
281
282
283 /*
284  * @implemented
285  */
286 ULONG STDCALL
287 ScsiPortGetBusData(IN PVOID DeviceExtension,
288                    IN ULONG BusDataType,
289                    IN ULONG SystemIoBusNumber,
290                    IN ULONG SlotNumber,
291                    IN PVOID Buffer,
292                    IN ULONG Length)
293 {
294   return(HalGetBusData(BusDataType,
295                        SystemIoBusNumber,
296                        SlotNumber,
297                        Buffer,
298                        Length));
299 }
300
301
302 /*
303  * @implemented
304  */
305 PVOID STDCALL
306 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension,
307                       IN INTERFACE_TYPE BusType,
308                       IN ULONG SystemIoBusNumber,
309                       IN SCSI_PHYSICAL_ADDRESS IoAddress,
310                       IN ULONG NumberOfBytes,
311                       IN BOOLEAN InIoSpace)
312 {
313   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
314   PHYSICAL_ADDRESS TranslatedAddress;
315   PSCSI_PORT_DEVICE_BASE DeviceBase;
316   ULONG AddressSpace;
317   PVOID MappedAddress;
318
319   DPRINT("ScsiPortGetDeviceBase() called\n");
320
321   AddressSpace = (ULONG)InIoSpace;
322   if (HalTranslateBusAddress(BusType,
323                              SystemIoBusNumber,
324                              IoAddress,
325                              &AddressSpace,
326                              &TranslatedAddress) == FALSE)
327     return NULL;
328
329   /* i/o space */
330   if (AddressSpace != 0)
331     return((PVOID)TranslatedAddress.u.LowPart);
332
333   MappedAddress = MmMapIoSpace(TranslatedAddress,
334                                NumberOfBytes,
335                                FALSE);
336
337   DeviceBase = ExAllocatePool(NonPagedPool,
338                               sizeof(SCSI_PORT_DEVICE_BASE));
339   if (DeviceBase == NULL)
340     return(MappedAddress);
341
342   DeviceBase->MappedAddress = MappedAddress;
343   DeviceBase->NumberOfBytes = NumberOfBytes;
344   DeviceBase->IoAddress = IoAddress;
345   DeviceBase->SystemIoBusNumber = SystemIoBusNumber;
346
347   DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
348                                       SCSI_PORT_DEVICE_EXTENSION,
349                                       MiniPortDeviceExtension);
350
351   InsertHeadList(&DeviceExtension->DeviceBaseListHead,
352                  &DeviceBase->List);
353
354   return(MappedAddress);
355 }
356
357
358 /*
359  * @implemented
360  */
361 PVOID STDCALL
362 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension,
363                        IN UCHAR PathId,
364                        IN UCHAR TargetId,
365                        IN UCHAR Lun)
366 {
367   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
368   PSCSI_PORT_LUN_EXTENSION LunExtension;
369   PLIST_ENTRY Entry;
370
371   DPRINT("ScsiPortGetLogicalUnit() called\n");
372
373   DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
374                                       SCSI_PORT_DEVICE_EXTENSION,
375                                       MiniPortDeviceExtension);
376   if (IsListEmpty(&DeviceExtension->LunExtensionListHead))
377     return NULL;
378
379   Entry = DeviceExtension->LunExtensionListHead.Flink;
380   while (Entry != &DeviceExtension->LunExtensionListHead)
381     {
382       LunExtension = CONTAINING_RECORD(Entry,
383                                        SCSI_PORT_LUN_EXTENSION,
384                                        List);
385       if (LunExtension->PathId == PathId &&
386           LunExtension->TargetId == TargetId &&
387           LunExtension->Lun == Lun)
388         {
389           return (PVOID)&LunExtension->MiniportLunExtension;
390         }
391
392       Entry = Entry->Flink;
393     }
394
395   return NULL;
396 }
397
398
399 /*
400  * @unimplemented
401  */
402 SCSI_PHYSICAL_ADDRESS STDCALL
403 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension,
404                            IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
405                            IN PVOID VirtualAddress,
406                            OUT ULONG *Length)
407 {
408   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
409   SCSI_PHYSICAL_ADDRESS PhysicalAddress;
410   ULONG BufferLength = 0;
411   ULONG Offset;
412
413   DPRINT1("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
414           HwDeviceExtension, Srb, VirtualAddress, Length);
415
416   DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
417                                       SCSI_PORT_DEVICE_EXTENSION,
418                                       MiniPortDeviceExtension);
419
420   *Length = 0;
421
422   if (Srb == NULL)
423     {
424       if ((ULONG_PTR)DeviceExtension->VirtualAddress > (ULONG_PTR)VirtualAddress)
425         {
426           PhysicalAddress.QuadPart = 0ULL;
427           return PhysicalAddress;
428         }
429
430       Offset = (ULONG_PTR)VirtualAddress - (ULONG_PTR)DeviceExtension->VirtualAddress;
431       if (Offset >= DeviceExtension->CommonBufferLength)
432         {
433           PhysicalAddress.QuadPart = 0ULL;
434           return PhysicalAddress;
435         }
436
437       PhysicalAddress.QuadPart =
438         DeviceExtension->PhysicalAddress.QuadPart + (ULONGLONG)Offset;
439       BufferLength = DeviceExtension->CommonBufferLength - Offset;
440     }
441   else
442     {
443       /* FIXME */
444       DPRINT1("Srb != NULL is not implemented yet!\n");
445       UNIMPLEMENTED;
446     }
447
448   *Length = BufferLength;
449
450   return PhysicalAddress;
451 }
452
453
454 /*
455  * @unimplemented
456  */
457 PSCSI_REQUEST_BLOCK STDCALL
458 ScsiPortGetSrb(IN PVOID DeviceExtension,
459                IN UCHAR PathId,
460                IN UCHAR TargetId,
461                IN UCHAR Lun,
462                IN LONG QueueTag)
463 {
464   DPRINT("ScsiPortGetSrb()\n");
465   UNIMPLEMENTED;
466 }
467
468
469 /*
470  * @implemented
471  */
472 PVOID STDCALL
473 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension,
474                              IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
475                              IN ULONG NumberOfBytes)
476 {
477   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
478   DEVICE_DESCRIPTION DeviceDescription;
479
480   DPRINT1("ScsiPortGetUncachedExtension(%p %p %lu)\n",
481           HwDeviceExtension, ConfigInfo, NumberOfBytes);
482
483   DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
484                                       SCSI_PORT_DEVICE_EXTENSION,
485                                       MiniPortDeviceExtension);
486
487   /* Check for allocated common DMA buffer */
488   if (DeviceExtension->VirtualAddress != NULL)
489     {
490       DPRINT1("The HBA has already got a common DMA buffer!\n");
491       return NULL;
492     }
493
494   /* Check for DMA adapter object */
495   if (DeviceExtension->AdapterObject == NULL)
496     {
497       /* Initialize DMA adapter description */
498       RtlZeroMemory(&DeviceDescription,
499                     sizeof(DEVICE_DESCRIPTION));
500       DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
501       DeviceDescription.Master = ConfigInfo->Master;
502       DeviceDescription.ScatterGather = ConfigInfo->ScatterGather;
503       DeviceDescription.DemandMode = ConfigInfo->DemandMode;
504       DeviceDescription.Dma32BitAddresses = ConfigInfo->Dma32BitAddresses;
505       DeviceDescription.BusNumber = ConfigInfo->SystemIoBusNumber;
506       DeviceDescription.DmaChannel = ConfigInfo->DmaChannel;
507       DeviceDescription.InterfaceType = ConfigInfo->AdapterInterfaceType;
508       DeviceDescription.DmaWidth = ConfigInfo->DmaWidth;
509       DeviceDescription.DmaSpeed = ConfigInfo->DmaSpeed;
510       DeviceDescription.MaximumLength = ConfigInfo->MaximumTransferLength;
511       DeviceDescription.DmaPort = ConfigInfo->DmaPort;
512
513       /* Get a DMA adapter object */
514       DeviceExtension->AdapterObject = HalGetAdapter(&DeviceDescription,
515                                                      &DeviceExtension->MapRegisterCount);
516       if (DeviceExtension->AdapterObject == NULL)
517         {
518           DPRINT1("HalGetAdapter() failed\n");
519           return NULL;
520         }
521     }
522
523   /* Allocate a common DMA buffer */
524   DeviceExtension->CommonBufferLength = NumberOfBytes;
525   DeviceExtension->VirtualAddress =
526     HalAllocateCommonBuffer(DeviceExtension->AdapterObject,
527                             DeviceExtension->CommonBufferLength,
528                             &DeviceExtension->PhysicalAddress,
529                             FALSE);
530   if (DeviceExtension->VirtualAddress == NULL)
531     {
532       DPRINT1("HalAllocateCommonBuffer() failed!\n");
533       DeviceExtension->CommonBufferLength = 0;
534       return NULL;
535     }
536
537   return DeviceExtension->VirtualAddress;
538 }
539
540
541 /*
542  * @implemented
543  */
544 PVOID STDCALL
545 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension,
546                           IN SCSI_PHYSICAL_ADDRESS PhysicalAddress)
547 {
548   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
549   ULONG Offset;
550
551   DPRINT("ScsiPortGetVirtualAddress(%p %I64x)\n",
552          HwDeviceExtension, PhysicalAddress.QuadPart);
553
554   DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
555                                       SCSI_PORT_DEVICE_EXTENSION,
556                                       MiniPortDeviceExtension);
557
558   if (DeviceExtension->PhysicalAddress.QuadPart > PhysicalAddress.QuadPart)
559     return NULL;
560
561   Offset = (ULONG)(PhysicalAddress.QuadPart - DeviceExtension->PhysicalAddress.QuadPart);
562   if (Offset >= DeviceExtension->CommonBufferLength)
563     return NULL;
564
565   return (PVOID)((ULONG_PTR)DeviceExtension->VirtualAddress + Offset);
566 }
567
568
569 /**********************************************************************
570  * NAME                                                 EXPORTED
571  *      ScsiPortInitialize
572  *
573  * DESCRIPTION
574  *      Initializes SCSI port driver specific data.
575  *
576  * RUN LEVEL
577  *      PASSIVE_LEVEL
578  *
579  * ARGUMENTS
580  *      Argument1
581  *              Pointer to the miniport driver's driver object.
582  *
583  *      Argument2
584  *              Pointer to the miniport driver's registry path.
585  *
586  *      HwInitializationData
587  *              Pointer to port driver specific configuration data.
588  *
589  *      HwContext
590                 Miniport driver specific context.
591  *
592  * RETURN VALUE
593  *      Status.
594  *
595  * @implemented
596  */
597
598 ULONG STDCALL
599 ScsiPortInitialize(IN PVOID Argument1,
600                    IN PVOID Argument2,
601                    IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
602                    IN PVOID HwContext)
603 {
604   PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Argument1;
605   PUNICODE_STRING RegistryPath = (PUNICODE_STRING)Argument2;
606   PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension;
607   PSCSI_PORT_DEVICE_EXTENSION RealDeviceExtension;
608   PCONFIGURATION_INFORMATION SystemConfig;
609   PPORT_CONFIGURATION_INFORMATION PortConfig;
610   BOOLEAN Again;
611   ULONG i;
612   ULONG Result;
613   NTSTATUS Status;
614   ULONG MaxBus;
615   PACCESS_RANGE AccessRanges;
616   ULONG ExtensionSize;
617
618   DPRINT("ScsiPortInitialize() called!\n");
619
620   if ((HwInitializationData->HwInitialize == NULL) ||
621       (HwInitializationData->HwStartIo == NULL) ||
622       (HwInitializationData->HwInterrupt == NULL) ||
623       (HwInitializationData->HwFindAdapter == NULL) ||
624       (HwInitializationData->HwResetBus == NULL))
625     return(STATUS_INVALID_PARAMETER);
626
627   DriverObject->DriverStartIo = ScsiPortStartIo;
628   DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH)ScsiPortCreateClose;
629   DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH)ScsiPortCreateClose;
630   DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH)ScsiPortDeviceControl;
631   DriverObject->MajorFunction[IRP_MJ_SCSI] = (PDRIVER_DISPATCH)ScsiPortDispatchScsi;
632
633
634   SystemConfig = IoGetConfigurationInformation();
635
636   ExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) +
637                   HwInitializationData->DeviceExtensionSize;
638   PseudoDeviceExtension = ExAllocatePool(PagedPool,
639                                          ExtensionSize);
640   RtlZeroMemory(PseudoDeviceExtension,
641                 ExtensionSize);
642   PseudoDeviceExtension->Length = ExtensionSize;
643   PseudoDeviceExtension->MiniPortExtensionSize = HwInitializationData->DeviceExtensionSize;
644   PseudoDeviceExtension->LunExtensionSize = HwInitializationData->SpecificLuExtensionSize;
645   PseudoDeviceExtension->HwStartIo = HwInitializationData->HwStartIo;
646   PseudoDeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
647
648   PortConfig = &PseudoDeviceExtension->PortConfig;
649
650   PortConfig->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
651   PortConfig->AdapterInterfaceType = HwInitializationData->AdapterInterfaceType;
652   PortConfig->InterruptMode =
653    (PortConfig->AdapterInterfaceType == PCIBus) ? LevelSensitive : Latched;
654   PortConfig->AtdiskPrimaryClaimed = SystemConfig->AtDiskPrimaryAddressClaimed;
655   PortConfig->AtdiskSecondaryClaimed = SystemConfig->AtDiskSecondaryAddressClaimed;
656   PortConfig->NumberOfAccessRanges = HwInitializationData->NumberOfAccessRanges;
657
658   PortConfig->AccessRanges =
659     ExAllocatePool(PagedPool,
660                    sizeof(ACCESS_RANGE) * PortConfig->NumberOfAccessRanges);
661
662   for (i = 0; i < SCSI_MAXIMUM_BUSES; i++)
663     PortConfig->InitiatorBusId[i] = 255;
664
665   PortConfig->SystemIoBusNumber = 0;
666   PortConfig->SlotNumber = 0;
667
668   MaxBus = (PortConfig->AdapterInterfaceType == PCIBus) ? 8 : 1;
669
670   DPRINT("MaxBus: %lu\n", MaxBus);
671
672   while (TRUE)
673     {
674       DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber);
675
676       InitializeListHead(&PseudoDeviceExtension->DeviceBaseListHead);
677
678 //      RtlZeroMemory(AccessRanges,
679 //                  sizeof(ACCESS_RANGE) * PortConfig->NumberOfAccessRanges);
680
681       PseudoDeviceExtension->AdapterObject = NULL;
682       PseudoDeviceExtension->MapRegisterCount = 0;
683       PseudoDeviceExtension->PhysicalAddress.QuadPart = 0ULL;
684       PseudoDeviceExtension->VirtualAddress = NULL;
685       PseudoDeviceExtension->CommonBufferLength = 0;
686
687       RtlZeroMemory(PseudoDeviceExtension->MiniPortDeviceExtension,
688                     PseudoDeviceExtension->MiniPortExtensionSize);
689
690       /* Note: HwFindAdapter is called once for each bus */
691       Result = (HwInitializationData->HwFindAdapter)(&PseudoDeviceExtension->MiniPortDeviceExtension,
692                                                      HwContext,
693                                                      NULL,      /* BusInformation */
694                                                      NULL,      /* ArgumentString */
695                                                      &PseudoDeviceExtension->PortConfig,
696                                                      &Again);
697       DPRINT("HwFindAdapter() result: %lu\n", Result);
698
699       if (Result == SP_RETURN_FOUND)
700         {
701           DPRINT("ScsiPortInitialize(): Found HBA!\n");
702
703           Status = ScsiPortCreatePortDevice(DriverObject,
704                                             PseudoDeviceExtension,
705                                             SystemConfig->ScsiPortCount,
706                                             &RealDeviceExtension);
707
708           if (!NT_SUCCESS(Status))
709             {
710               DbgPrint("ScsiPortCreatePortDevice() failed! (Status 0x%lX)\n", Status);
711
712               ExFreePool(PortConfig->AccessRanges);
713               ExFreePool(PseudoDeviceExtension);
714
715               return(Status);
716             }
717
718           /* Get inquiry data */
719           SpiInquirePort (RealDeviceExtension);
720
721           /* Build the registry device map */
722           SpiBuildDeviceMap (RealDeviceExtension,
723                              (PUNICODE_STRING)Argument2);
724
725           /* Update the configuration info */
726           SystemConfig->AtDiskPrimaryAddressClaimed = PortConfig->AtdiskPrimaryClaimed;
727           SystemConfig->AtDiskSecondaryAddressClaimed = PortConfig->AtdiskSecondaryClaimed;
728           SystemConfig->ScsiPortCount++;
729         }
730
731       if (Again == FALSE)
732         {
733           PortConfig->SystemIoBusNumber++;
734           PortConfig->SlotNumber = 0;
735         }
736
737       DPRINT("Bus: %lu  MaxBus: %lu\n", PortConfig->SystemIoBusNumber, MaxBus);
738       if (PortConfig->SystemIoBusNumber >= MaxBus)
739         {
740           DPRINT("Scanned all buses!\n");
741           break;
742         }
743     }
744
745   ExFreePool(PortConfig->AccessRanges);
746   ExFreePool(PseudoDeviceExtension);
747
748   DPRINT("ScsiPortInitialize() done!\n");
749
750   return(STATUS_SUCCESS);
751 }
752
753
754 /*
755  * @unimplemented
756  */
757 VOID STDCALL
758 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension,
759                       IN PSCSI_REQUEST_BLOCK Srb,
760                       IN ULONG LogicalAddress,
761                       IN ULONG Length)
762 {
763   DPRINT("ScsiPortIoMapTransfer()\n");
764   UNIMPLEMENTED;
765 }
766
767
768 /*
769  * @unimplemented
770  */
771 VOID STDCALL
772 ScsiPortLogError(IN PVOID HwDeviceExtension,
773                  IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
774                  IN UCHAR PathId,
775                  IN UCHAR TargetId,
776                  IN UCHAR Lun,
777                  IN ULONG ErrorCode,
778                  IN ULONG UniqueId)
779 {
780   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
781
782   DPRINT("ScsiPortLogError() called\n");
783
784   DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
785                                       SCSI_PORT_DEVICE_EXTENSION,
786                                       MiniPortDeviceExtension);
787
788
789   DPRINT("ScsiPortLogError() done\n");
790 }
791
792
793 /*
794  * @implemented
795  */
796 VOID STDCALL
797 ScsiPortMoveMemory(OUT PVOID Destination,
798                    IN PVOID Source,
799                    IN ULONG Length)
800 {
801   RtlMoveMemory(Destination,
802                 Source,
803                 Length);
804 }
805
806
807 /*
808  * @implemented
809  */
810 VOID
811 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType,
812                      IN PVOID HwDeviceExtension,
813                      ...)
814 {
815   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
816   va_list ap;
817
818   DPRINT("ScsiPortNotification() called\n");
819
820   DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
821                                       SCSI_PORT_DEVICE_EXTENSION,
822                                       MiniPortDeviceExtension);
823
824   DPRINT("DeviceExtension %p\n", DeviceExtension);
825
826   DPRINT("Initializing = %s\n", (DeviceExtension->Initializing)?"TRUE":"FALSE");
827
828   if (DeviceExtension->Initializing == TRUE)
829     return;
830
831   va_start(ap, HwDeviceExtension);
832
833   switch (NotificationType)
834     {
835       case RequestComplete:
836         {
837           PSCSI_REQUEST_BLOCK Srb;
838
839           Srb = (PSCSI_REQUEST_BLOCK) va_arg (ap, PSCSI_REQUEST_BLOCK);
840
841           DPRINT("Notify: RequestComplete (Srb %p)\n", Srb);
842           DeviceExtension->IrpFlags |= IRP_FLAG_COMPLETE;
843         }
844         break;
845
846       case NextRequest:
847         DPRINT("Notify: NextRequest\n");
848         DeviceExtension->IrpFlags |= IRP_FLAG_NEXT;
849         break;
850
851       case NextLuRequest:
852         {
853           UCHAR PathId;
854           UCHAR TargetId;
855           UCHAR Lun;
856
857           PathId = (UCHAR) va_arg (ap, int);
858           TargetId = (UCHAR) va_arg (ap, int);
859           Lun = (UCHAR) va_arg (ap, int);
860
861           DPRINT1 ("Notify: NextLuRequest(PathId %u  TargetId %u  Lun %u)\n",
862                    PathId, TargetId, Lun);
863           /* FIXME: Implement it! */
864
865 //        DeviceExtension->IrpFlags |= IRP_FLAG_NEXT_LU;
866
867         }
868         break;
869
870       case ResetDetected:
871         DPRINT1("Notify: ResetDetected\n");
872         /* FIXME: ??? */
873         break;
874
875       default:
876         DPRINT1 ("Unsupported notification %lu\n", NotificationType);
877         break;
878     }
879
880   va_end(ap);
881 }
882
883
884 /*
885  * @implemented
886  */
887 ULONG STDCALL
888 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension,
889                            IN ULONG BusDataType,
890                            IN ULONG SystemIoBusNumber,
891                            IN ULONG SlotNumber,
892                            IN PVOID Buffer,
893                            IN ULONG Offset,
894                            IN ULONG Length)
895 {
896   DPRINT("ScsiPortSetBusDataByOffset()\n");
897   return(HalSetBusDataByOffset(BusDataType,
898                                SystemIoBusNumber,
899                                SlotNumber,
900                                Buffer,
901                                Offset,
902                                Length));
903 }
904
905
906 /*
907  * @implemented
908  */
909 BOOLEAN STDCALL
910 ScsiPortValidateRange(IN PVOID HwDeviceExtension,
911                       IN INTERFACE_TYPE BusType,
912                       IN ULONG SystemIoBusNumber,
913                       IN SCSI_PHYSICAL_ADDRESS IoAddress,
914                       IN ULONG NumberOfBytes,
915                       IN BOOLEAN InIoSpace)
916 {
917   DPRINT("ScsiPortValidateRange()\n");
918   return(TRUE);
919 }
920
921
922 /* INTERNAL FUNCTIONS ********************************************************/
923
924 /**********************************************************************
925  * NAME                                                 INTERNAL
926  *      ScsiPortCreateClose
927  *
928  * DESCRIPTION
929  *      Answer requests for Create/Close calls: a null operation.
930  *
931  * RUN LEVEL
932  *      PASSIVE_LEVEL
933  *
934  * ARGUMENTS
935  *      DeviceObject
936  *              Pointer to a device object.
937  *
938  *      Irp
939  *              Pointer to an IRP.
940  *
941  *      ...
942                 Additional output data (see printf()).
943  *
944  * RETURN VALUE
945  *      Status.
946  */
947
948 static NTSTATUS STDCALL
949 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
950                     IN PIRP Irp)
951 {
952   DPRINT("ScsiPortCreateClose()\n");
953
954   Irp->IoStatus.Status = STATUS_SUCCESS;
955   Irp->IoStatus.Information = FILE_OPENED;
956
957   IoCompleteRequest(Irp, IO_NO_INCREMENT);
958
959   return(STATUS_SUCCESS);
960 }
961
962
963 /**********************************************************************
964  * NAME                                                 INTERNAL
965  *      ScsiPortDispatchScsi
966  *
967  * DESCRIPTION
968  *      Answer requests for SCSI calls
969  *
970  * RUN LEVEL
971  *      PASSIVE_LEVEL
972  *
973  * ARGUMENTS
974  *      Standard dispatch arguments
975  *
976  * RETURNS
977  *      NTSTATUS
978  */
979
980 static NTSTATUS STDCALL
981 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
982                      IN PIRP Irp)
983 {
984   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
985   PSCSI_PORT_LUN_EXTENSION LunExtension;
986   PIO_STACK_LOCATION Stack;
987   PSCSI_REQUEST_BLOCK Srb;
988   NTSTATUS Status = STATUS_SUCCESS;
989   ULONG DataSize = 0;
990
991   DPRINT("ScsiPortDispatchScsi(DeviceObject %p  Irp %p)\n",
992          DeviceObject, Irp);
993
994   DeviceExtension = DeviceObject->DeviceExtension;
995   Stack = IoGetCurrentIrpStackLocation(Irp);
996
997   Srb = Stack->Parameters.Scsi.Srb;
998   if (Srb == NULL)
999     {
1000       Status = STATUS_UNSUCCESSFUL;
1001
1002       Irp->IoStatus.Status = Status;
1003       Irp->IoStatus.Information = 0;
1004
1005       IoCompleteRequest(Irp, IO_NO_INCREMENT);
1006
1007       return(Status);
1008     }
1009
1010   DPRINT("Srb: %p\n", Srb);
1011   DPRINT("Srb->Function: %lu\n", Srb->Function);
1012   DPRINT("PathId: %lu  TargetId: %lu  Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
1013
1014   LunExtension = SpiGetLunExtension(DeviceExtension,
1015                                     Srb->PathId,
1016                                     Srb->TargetId,
1017                                     Srb->Lun);
1018   if (LunExtension == NULL)
1019     {
1020       Status = STATUS_NO_SUCH_DEVICE;
1021
1022       Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
1023       Irp->IoStatus.Status = Status;
1024       Irp->IoStatus.Information = 0;
1025
1026       IoCompleteRequest(Irp, IO_NO_INCREMENT);
1027
1028       return(Status);
1029     }
1030
1031   switch (Srb->Function)
1032     {
1033       case SRB_FUNCTION_EXECUTE_SCSI:
1034       case SRB_FUNCTION_IO_CONTROL:
1035 #ifdef USE_DEVICE_QUEUES
1036         if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
1037           {
1038             IoStartPacket (DeviceObject, Irp, NULL, NULL);
1039           }
1040         else
1041           {
1042             KIRQL oldIrql;
1043
1044             KeRaiseIrql (DISPATCH_LEVEL,
1045                          &oldIrql);
1046
1047             if (!KeInsertByKeyDeviceQueue (&LunExtension->DeviceQueue,
1048                                            &Irp->Tail.Overlay.DeviceQueueEntry,
1049                                            Srb->QueueSortKey))
1050               {
1051                 Srb->SrbStatus = SRB_STATUS_SUCCESS;
1052                 IoStartPacket (DeviceObject, Irp, NULL, NULL);
1053               }
1054
1055             KeLowerIrql (oldIrql);
1056           }
1057 #else
1058         IoStartPacket (DeviceObject, Irp, NULL, NULL);
1059 #endif
1060         return(STATUS_PENDING);
1061
1062       case SRB_FUNCTION_SHUTDOWN:
1063       case SRB_FUNCTION_FLUSH:
1064         if (DeviceExtension->PortConfig.CachesData == TRUE)
1065           {
1066             IoStartPacket(DeviceObject, Irp, NULL, NULL);
1067             return(STATUS_PENDING);
1068           }
1069         break;
1070
1071       case SRB_FUNCTION_CLAIM_DEVICE:
1072         DPRINT("  SRB_FUNCTION_CLAIM_DEVICE\n");
1073
1074         /* Reference device object and keep the pointer */
1075         ObReferenceObject(DeviceObject);
1076         LunExtension->DeviceObject = DeviceObject;
1077         LunExtension->DeviceClaimed = TRUE;
1078         Srb->DataBuffer = DeviceObject;
1079         break;
1080
1081       case SRB_FUNCTION_RELEASE_DEVICE:
1082         {
1083           PSCSI_PORT_LUN_EXTENSION LunExtension;
1084
1085           DPRINT("  SRB_FUNCTION_RELEASE_DEVICE\n");
1086           DPRINT("PathId: %lu  TargetId: %lu  Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
1087
1088           LunExtension = SpiGetLunExtension(DeviceExtension,
1089                                             Srb->PathId,
1090                                             Srb->TargetId,
1091                                             Srb->Lun);
1092           if (LunExtension != NULL)
1093             {
1094               /* Dereference device object */
1095               ObDereferenceObject(LunExtension->DeviceObject);
1096               LunExtension->DeviceObject = NULL;
1097               LunExtension->DeviceClaimed = FALSE;
1098             }
1099         }
1100         break;
1101
1102       default:
1103         DPRINT1("SRB function not implemented (Function %lu)\n", Srb->Function);
1104         Status = STATUS_NOT_IMPLEMENTED;
1105         break;
1106     }
1107
1108   Irp->IoStatus.Status = Status;
1109   Irp->IoStatus.Information = DataSize;
1110
1111   IoCompleteRequest(Irp, IO_NO_INCREMENT);
1112
1113   return(Status);
1114 }
1115
1116
1117 /**********************************************************************
1118  * NAME                                                 INTERNAL
1119  *      ScsiPortDeviceControl
1120  *
1121  * DESCRIPTION
1122  *      Answer requests for device control calls
1123  *
1124  * RUN LEVEL
1125  *      PASSIVE_LEVEL
1126  *
1127  * ARGUMENTS
1128  *      Standard dispatch arguments
1129  *
1130  * RETURNS
1131  *      NTSTATUS
1132  */
1133
1134 static NTSTATUS STDCALL
1135 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
1136                       IN PIRP Irp)
1137 {
1138   PIO_STACK_LOCATION Stack;
1139   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1140
1141   DPRINT("ScsiPortDeviceControl()\n");
1142
1143   Irp->IoStatus.Status = STATUS_SUCCESS;
1144   Irp->IoStatus.Information = 0;
1145
1146
1147   Stack = IoGetCurrentIrpStackLocation(Irp);
1148   DeviceExtension = DeviceObject->DeviceExtension;
1149
1150   switch (Stack->Parameters.DeviceIoControl.IoControlCode)
1151     {
1152       case IOCTL_SCSI_GET_DUMP_POINTERS:
1153         {
1154           PDUMP_POINTERS DumpPointers;
1155           DPRINT("  IOCTL_SCSI_GET_DUMP_POINTERS\n");
1156           DumpPointers = (PDUMP_POINTERS)Irp->AssociatedIrp.SystemBuffer;
1157           DumpPointers->DeviceObject = DeviceObject;
1158           
1159           Irp->IoStatus.Information = sizeof(DUMP_POINTERS);
1160         }
1161         break;
1162
1163       case IOCTL_SCSI_GET_CAPABILITIES:
1164         {
1165           DPRINT("  IOCTL_SCSI_GET_CAPABILITIES\n");
1166
1167           *((PIO_SCSI_CAPABILITIES *)Irp->AssociatedIrp.SystemBuffer) =
1168             DeviceExtension->PortCapabilities;
1169
1170           Irp->IoStatus.Information = sizeof(PIO_SCSI_CAPABILITIES);
1171         }
1172         break;
1173
1174       case IOCTL_SCSI_GET_INQUIRY_DATA:
1175         {
1176           DPRINT("  IOCTL_SCSI_GET_INQUIRY_DATA\n");
1177
1178           /* Copy inquiry data to the port device extension */
1179           Irp->IoStatus.Information =
1180             SpiGetInquiryData(DeviceExtension,
1181                               Irp->AssociatedIrp.SystemBuffer);
1182           DPRINT("Inquiry data size: %lu\n", Irp->IoStatus.Information);
1183         }
1184         break;
1185
1186       default:
1187         DPRINT1("  unknown ioctl code: 0x%lX\n",
1188                Stack->Parameters.DeviceIoControl.IoControlCode);
1189         break;
1190     }
1191
1192   IoCompleteRequest(Irp, IO_NO_INCREMENT);
1193
1194   return(STATUS_SUCCESS);
1195 }
1196
1197
1198 static VOID STDCALL
1199 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
1200                 IN PIRP Irp)
1201 {
1202   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1203   PSCSI_PORT_LUN_EXTENSION LunExtension;
1204   PIO_STACK_LOCATION IrpStack;
1205   PSCSI_REQUEST_BLOCK Srb;
1206   KIRQL oldIrql;
1207   BOOLEAN Result;
1208
1209   DPRINT("ScsiPortStartIo() called!\n");
1210
1211   DeviceExtension = DeviceObject->DeviceExtension;
1212   IrpStack = IoGetCurrentIrpStackLocation(Irp);
1213
1214   DPRINT("DeviceExtension %p\n", DeviceExtension);
1215
1216   if (IrpStack->MajorFunction != IRP_MJ_SCSI)
1217     {
1218       DPRINT("No IRP_MJ_SCSI!\n");
1219       Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
1220       Irp->IoStatus.Information = 0;
1221       IoCompleteRequest (Irp,
1222                          IO_NO_INCREMENT);
1223       IoStartNextPacket (DeviceObject,
1224                          FALSE);
1225       return;
1226     }
1227
1228   Srb = IrpStack->Parameters.Scsi.Srb;
1229
1230   LunExtension = SpiGetLunExtension(DeviceExtension,
1231                                     Srb->PathId,
1232                                     Srb->TargetId,
1233                                     Srb->Lun);
1234   if (LunExtension == NULL)
1235     {
1236       DPRINT("No IRP_MJ_SCSI!\n");
1237       Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
1238       Irp->IoStatus.Information = 0;
1239       IoCompleteRequest (Irp,
1240                          IO_NO_INCREMENT);
1241       IoStartNextPacket (DeviceObject,
1242                          FALSE);
1243       return;
1244     }
1245
1246   Irp->IoStatus.Status = STATUS_SUCCESS;
1247   Irp->IoStatus.Information = Srb->DataTransferLength;
1248
1249   DeviceExtension->CurrentIrp = Irp;
1250
1251   if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
1252                               ScsiPortStartPacket,
1253                               DeviceExtension))
1254     {
1255       DPRINT("Synchronization failed!\n");
1256
1257       Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
1258       Irp->IoStatus.Information = 0;
1259       IoCompleteRequest(Irp,
1260                         IO_NO_INCREMENT);
1261       IoStartNextPacket(DeviceObject,
1262                         FALSE);
1263     }
1264
1265   KeAcquireSpinLock(&DeviceExtension->IrpLock, &oldIrql);
1266   if (DeviceExtension->IrpFlags & IRP_FLAG_COMPLETE)
1267     {
1268       DeviceExtension->IrpFlags &= ~IRP_FLAG_COMPLETE;
1269       IoCompleteRequest(Irp,
1270                         IO_NO_INCREMENT);
1271     }
1272
1273   if (DeviceExtension->IrpFlags & IRP_FLAG_NEXT)
1274     {
1275       DeviceExtension->IrpFlags &= ~IRP_FLAG_NEXT;
1276       KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1277       IoStartNextPacket(DeviceObject,
1278                         FALSE);
1279     }
1280   else
1281     {
1282       KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1283     }
1284
1285   DPRINT("ScsiPortStartIo() done\n");
1286 }
1287
1288
1289 static BOOLEAN STDCALL
1290 ScsiPortStartPacket(IN OUT PVOID Context)
1291 {
1292   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1293   PIO_STACK_LOCATION IrpStack;
1294   PSCSI_REQUEST_BLOCK Srb;
1295
1296   DPRINT("ScsiPortStartPacket() called\n");
1297
1298   DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)Context;
1299
1300   IrpStack = IoGetCurrentIrpStackLocation(DeviceExtension->CurrentIrp);
1301   Srb = IrpStack->Parameters.Scsi.Srb;
1302
1303   return(DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
1304                                     Srb));
1305 }
1306
1307
1308 /**********************************************************************
1309  * NAME                                                 INTERNAL
1310  *      ScsiPortCreatePortDevice
1311  *
1312  * DESCRIPTION
1313  *      Creates and initializes a SCSI port device object.
1314  *
1315  * RUN LEVEL
1316  *      PASSIVE_LEVEL
1317  *
1318  * ARGUMENTS
1319  *      DriverObject
1320  *              ...
1321  *
1322  *      PseudoDeviceExtension
1323  *              ...
1324  *
1325  *      PortNumber
1326  *              ...
1327  *
1328  * RETURNS
1329  *      NTSTATUS
1330  */
1331
1332 static NTSTATUS
1333 ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject,
1334                          IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension,
1335                          IN ULONG PortNumber,
1336                          IN OUT PSCSI_PORT_DEVICE_EXTENSION *RealDeviceExtension)
1337 {
1338   PSCSI_PORT_DEVICE_EXTENSION PortDeviceExtension;
1339   PIO_SCSI_CAPABILITIES PortCapabilities;
1340   PDEVICE_OBJECT PortDeviceObject;
1341   WCHAR NameBuffer[80];
1342   UNICODE_STRING DeviceName;
1343   WCHAR DosNameBuffer[80];
1344   UNICODE_STRING DosDeviceName;
1345   NTSTATUS Status;
1346   ULONG AccessRangeSize;
1347   ULONG MappedIrq;
1348   KIRQL Dirql;
1349   KAFFINITY Affinity;
1350
1351   DPRINT("ScsiPortCreatePortDevice() called\n");
1352
1353   *RealDeviceExtension = NULL;
1354
1355   MappedIrq = HalGetInterruptVector(PseudoDeviceExtension->PortConfig.AdapterInterfaceType,
1356                                     PseudoDeviceExtension->PortConfig.SystemIoBusNumber,
1357                                     PseudoDeviceExtension->PortConfig.BusInterruptLevel,
1358                                     PseudoDeviceExtension->PortConfig.BusInterruptVector,
1359                                     &Dirql,
1360                                     &Affinity);
1361
1362   /* Create a unicode device name */
1363   swprintf(NameBuffer,
1364            L"\\Device\\ScsiPort%lu",
1365            PortNumber);
1366   RtlInitUnicodeString(&DeviceName,
1367                        NameBuffer);
1368
1369   DPRINT("Creating device: %wZ\n", &DeviceName);
1370
1371   /* Create the port device */
1372   Status = IoCreateDevice(DriverObject,
1373                           PseudoDeviceExtension->Length,
1374                           &DeviceName,
1375                           FILE_DEVICE_CONTROLLER,
1376                           0,
1377                           FALSE,
1378                           &PortDeviceObject);
1379   if (!NT_SUCCESS(Status))
1380     {
1381       DbgPrint("IoCreateDevice call failed! (Status 0x%lX)\n", Status);
1382       return(Status);
1383     }
1384
1385   DPRINT("Created device: %wZ\n", &DeviceName);
1386
1387   /* Set the buffering strategy here... */
1388   PortDeviceObject->Flags |= DO_DIRECT_IO;
1389   PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
1390
1391   PortDeviceExtension = PortDeviceObject->DeviceExtension;
1392
1393   /* Copy pseudo device extension into the real device extension */
1394   memcpy(PortDeviceExtension,
1395          PseudoDeviceExtension,
1396          PseudoDeviceExtension->Length);
1397
1398   /* Copy access ranges */
1399   AccessRangeSize =
1400     sizeof(ACCESS_RANGE) * PseudoDeviceExtension->PortConfig.NumberOfAccessRanges;
1401   PortDeviceExtension->PortConfig.AccessRanges = ExAllocatePool(NonPagedPool,
1402                                                                 AccessRangeSize);
1403   memcpy(PortDeviceExtension->PortConfig.AccessRanges,
1404          PseudoDeviceExtension->PortConfig.AccessRanges,
1405          AccessRangeSize);
1406
1407   /* Copy device base list */
1408   if (IsListEmpty(&PseudoDeviceExtension->DeviceBaseListHead))
1409     {
1410       InitializeListHead(&PortDeviceExtension->DeviceBaseListHead);
1411     }
1412   else
1413     {
1414       PseudoDeviceExtension->DeviceBaseListHead.Flink =
1415         PortDeviceExtension->DeviceBaseListHead.Flink;
1416       PseudoDeviceExtension->DeviceBaseListHead.Blink =
1417         PortDeviceExtension->DeviceBaseListHead.Blink;
1418       PortDeviceExtension->DeviceBaseListHead.Blink->Flink =
1419         &PortDeviceExtension->DeviceBaseListHead;
1420       PortDeviceExtension->DeviceBaseListHead.Flink->Blink =
1421         &PortDeviceExtension->DeviceBaseListHead;
1422     }
1423
1424   PortDeviceExtension->DeviceObject = PortDeviceObject;
1425   PortDeviceExtension->PortNumber = PortNumber;
1426
1427   /* Initialize the spin lock in the controller extension */
1428   KeInitializeSpinLock(&PortDeviceExtension->IrpLock);
1429   KeInitializeSpinLock(&PortDeviceExtension->SpinLock);
1430
1431   /* Register an interrupt handler for this device */
1432   Status = IoConnectInterrupt(&PortDeviceExtension->Interrupt,
1433                               ScsiPortIsr,
1434                               PortDeviceExtension,
1435                               &PortDeviceExtension->SpinLock,
1436                               MappedIrq,
1437                               Dirql,
1438                               Dirql,
1439                               PortDeviceExtension->PortConfig.InterruptMode,
1440                               TRUE,
1441                               Affinity,
1442                               FALSE);
1443   if (!NT_SUCCESS(Status))
1444     {
1445       DbgPrint("Could not Connect Interrupt %d\n",
1446                PortDeviceExtension->PortConfig.BusInterruptVector);
1447       IoDeleteDevice(PortDeviceObject);
1448       return(Status);
1449     }
1450
1451   /* Initialize the DPC object */
1452   IoInitializeDpcRequest(PortDeviceExtension->DeviceObject,
1453                          ScsiPortDpcForIsr);
1454
1455   /* Initialize the device timer */
1456   PortDeviceExtension->TimerState = IDETimerIdle;
1457   PortDeviceExtension->TimerCount = 0;
1458   IoInitializeTimer(PortDeviceExtension->DeviceObject,
1459                     ScsiPortIoTimer,
1460                     PortDeviceExtension);
1461
1462   /* Initialize port capabilities */
1463   PortCapabilities = ExAllocatePool(NonPagedPool,
1464                                     sizeof(IO_SCSI_CAPABILITIES));
1465   PortDeviceExtension->PortCapabilities = PortCapabilities;
1466   PortCapabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
1467   PortCapabilities->MaximumTransferLength =
1468     PortDeviceExtension->PortConfig.MaximumTransferLength;
1469   PortCapabilities->MaximumPhysicalPages =
1470     PortCapabilities->MaximumTransferLength / PAGE_SIZE;
1471   PortCapabilities->SupportedAsynchronousEvents = 0; /* FIXME */
1472   PortCapabilities->AlignmentMask =
1473     PortDeviceExtension->PortConfig.AlignmentMask;
1474   PortCapabilities->TaggedQueuing =
1475     PortDeviceExtension->PortConfig.TaggedQueuing;
1476   PortCapabilities->AdapterScansDown =
1477     PortDeviceExtension->PortConfig.AdapterScansDown;
1478   PortCapabilities->AdapterUsesPio = TRUE; /* FIXME */
1479
1480   /* Initialize LUN-Extension list */
1481   InitializeListHead(&PortDeviceExtension->LunExtensionListHead);
1482
1483   DPRINT("DeviceExtension %p\n", PortDeviceExtension);
1484
1485   /* FIXME: Copy more configuration data? */
1486
1487
1488   /* Create the dos device link */
1489   swprintf(DosNameBuffer,
1490            L"\\??\\Scsi%lu:",
1491            PortNumber);
1492   RtlInitUnicodeString(&DosDeviceName,
1493                        DosNameBuffer);
1494
1495   IoCreateSymbolicLink(&DosDeviceName,
1496                        &DeviceName);
1497
1498   *RealDeviceExtension = PortDeviceExtension;
1499
1500   DPRINT("ScsiPortCreatePortDevice() done\n");
1501
1502   return(STATUS_SUCCESS);
1503 }
1504
1505
1506 static PSCSI_PORT_LUN_EXTENSION
1507 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1508                          IN UCHAR PathId,
1509                          IN UCHAR TargetId,
1510                          IN UCHAR Lun)
1511 {
1512   PSCSI_PORT_LUN_EXTENSION LunExtension;
1513   ULONG LunExtensionSize;
1514
1515   DPRINT("SpiAllocateLunExtension (%p %u %u %u)\n",
1516          DeviceExtension, PathId, TargetId, Lun);
1517
1518   LunExtensionSize =
1519     sizeof(SCSI_PORT_LUN_EXTENSION) + DeviceExtension->LunExtensionSize;
1520   DPRINT("LunExtensionSize %lu\n", LunExtensionSize);
1521
1522   LunExtension = ExAllocatePool(NonPagedPool,
1523                                 LunExtensionSize);
1524   if (LunExtension == NULL)
1525     {
1526       return NULL;
1527     }
1528
1529   RtlZeroMemory(LunExtension,
1530                 LunExtensionSize);
1531
1532   InsertTailList(&DeviceExtension->LunExtensionListHead,
1533                  &LunExtension->List);
1534
1535   LunExtension->PathId = PathId;
1536   LunExtension->TargetId = TargetId;
1537   LunExtension->Lun = Lun;
1538
1539   KeInitializeDeviceQueue (&LunExtension->DeviceQueue);
1540
1541   return LunExtension;
1542 }
1543
1544
1545 static PSCSI_PORT_LUN_EXTENSION
1546 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1547                     IN UCHAR PathId,
1548                     IN UCHAR TargetId,
1549                     IN UCHAR Lun)
1550 {
1551   PSCSI_PORT_LUN_EXTENSION LunExtension;
1552   PLIST_ENTRY Entry;
1553
1554   DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
1555          DeviceExtension, PathId, TargetId, Lun);
1556
1557   if (IsListEmpty(&DeviceExtension->LunExtensionListHead))
1558     return NULL;
1559
1560   Entry = DeviceExtension->LunExtensionListHead.Flink;
1561   while (Entry != &DeviceExtension->LunExtensionListHead)
1562     {
1563       LunExtension = CONTAINING_RECORD(Entry,
1564                                        SCSI_PORT_LUN_EXTENSION,
1565                                        List);
1566       if (LunExtension->PathId == PathId &&
1567           LunExtension->TargetId == TargetId &&
1568           LunExtension->Lun == Lun)
1569         {
1570           return LunExtension;
1571         }
1572
1573       Entry = Entry->Flink;
1574     }
1575
1576   return NULL;
1577 }
1578
1579
1580 static VOID
1581 SpiInquirePort(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
1582 {
1583   PSCSI_PORT_LUN_EXTENSION LunExtension;
1584   SCSI_REQUEST_BLOCK Srb;
1585   ULONG Bus;
1586   ULONG Target;
1587   ULONG Lun;
1588   BOOLEAN Result;
1589
1590   DPRINT("SpiInquirePort() called\n");
1591
1592   DeviceExtension->Initializing = TRUE;
1593
1594   RtlZeroMemory(&Srb,
1595                 sizeof(SCSI_REQUEST_BLOCK));
1596   Srb.SrbFlags = SRB_FLAGS_DATA_IN;
1597   Srb.DataBuffer = ExAllocatePool(NonPagedPool, 256);
1598   Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
1599   Srb.DataTransferLength = 256;
1600   Srb.Cdb[0] = SCSIOP_INQUIRY;
1601
1602   for (Bus = 0; Bus < DeviceExtension->PortConfig.NumberOfBuses; Bus++)
1603     {
1604       Srb.PathId = Bus;
1605
1606       for (Target = 0; Target < DeviceExtension->PortConfig.MaximumNumberOfTargets; Target++)
1607         {
1608           Srb.TargetId = Target;
1609
1610           for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
1611             {
1612               Srb.Lun = Lun;
1613               Srb.SrbStatus = SRB_STATUS_SUCCESS;
1614
1615               Result = DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
1616                                                   &Srb);
1617               DPRINT("Result %s  Srb.SrbStatus %lx\n", (Result) ? "TRUE" : "FALSE", Srb.SrbStatus);
1618
1619               if (Result == TRUE && Srb.SrbStatus == SRB_STATUS_SUCCESS)
1620                 {
1621                   LunExtension = SpiAllocateLunExtension(DeviceExtension,
1622                                                          Bus,
1623                                                          Target,
1624                                                          Lun);
1625                   if (LunExtension != NULL)
1626                     {
1627                       /* Copy inquiry data */
1628                       memcpy(&LunExtension->InquiryData,
1629                              Srb.DataBuffer,
1630                              sizeof(INQUIRYDATA));
1631                     }
1632                 }
1633             }
1634         }
1635     }
1636
1637   ExFreePool(Srb.DataBuffer);
1638
1639   DeviceExtension->Initializing = FALSE;
1640
1641   DPRINT("SpiInquirePort() done\n");
1642 }
1643
1644
1645 static ULONG
1646 SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1647                   OUT PSCSI_ADAPTER_BUS_INFO AdapterBusInfo)
1648 {
1649   PSCSI_PORT_LUN_EXTENSION LunExtension;
1650   PSCSI_INQUIRY_DATA UnitInfo, PrevUnit;
1651   ULONG Bus;
1652   ULONG Target;
1653   ULONG Lun;
1654   ULONG UnitCount;
1655
1656   DPRINT("SpiGetInquiryData() called\n");
1657
1658   /* Copy inquiry data to the port device extension */
1659   AdapterBusInfo->NumberOfBuses = DeviceExtension->PortConfig.NumberOfBuses;
1660
1661   UnitInfo = (PSCSI_INQUIRY_DATA)
1662         ((PUCHAR)AdapterBusInfo + sizeof(SCSI_ADAPTER_BUS_INFO) +
1663          (sizeof(SCSI_BUS_DATA) * (AdapterBusInfo->NumberOfBuses - 1)));
1664
1665   for (Bus = 0; Bus < AdapterBusInfo->NumberOfBuses; Bus++)
1666     {
1667       AdapterBusInfo->BusData[Bus].InitiatorBusId =
1668         DeviceExtension->PortConfig.InitiatorBusId[Bus];
1669       AdapterBusInfo->BusData[Bus].InquiryDataOffset =
1670         (ULONG)((PUCHAR)UnitInfo - (PUCHAR)AdapterBusInfo);
1671
1672       PrevUnit = NULL;
1673       UnitCount = 0;
1674
1675       for (Target = 0; Target < DeviceExtension->PortConfig.MaximumNumberOfTargets; Target++)
1676         {
1677           for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
1678             {
1679               LunExtension = SpiGetLunExtension(DeviceExtension,
1680                                                 Bus,
1681                                                 Target,
1682                                                 Lun);
1683               if (LunExtension != NULL)
1684                 {
1685                   DPRINT("(Bus %lu Target %lu Lun %lu)\n",
1686                          Bus, Target, Lun);
1687
1688                   UnitInfo->PathId = Bus;
1689                   UnitInfo->TargetId = Target;
1690                   UnitInfo->Lun = Lun;
1691                   UnitInfo->InquiryDataLength = INQUIRYDATABUFFERSIZE;
1692                   memcpy(&UnitInfo->InquiryData,
1693                          &LunExtension->InquiryData,
1694                          INQUIRYDATABUFFERSIZE);
1695                   if (PrevUnit != NULL)
1696                     PrevUnit->NextInquiryDataOffset = (ULONG)((PUCHAR)UnitInfo-(PUCHAR)AdapterBusInfo);
1697                   PrevUnit = UnitInfo;
1698                   UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)UnitInfo + sizeof(SCSI_INQUIRY_DATA)+INQUIRYDATABUFFERSIZE-1);
1699                   UnitCount++;
1700                 }
1701             }
1702         }
1703       DPRINT("UnitCount: %lu\n", UnitCount);
1704       AdapterBusInfo->BusData[Bus].NumberOfLogicalUnits = UnitCount;
1705       if (UnitCount == 0)
1706         AdapterBusInfo->BusData[Bus].InquiryDataOffset = 0;
1707     }
1708
1709   DPRINT("Data size: %lu\n", (ULONG)UnitInfo - (ULONG)AdapterBusInfo);
1710
1711   return (ULONG)((PUCHAR)UnitInfo-(PUCHAR)AdapterBusInfo);
1712 }
1713
1714
1715 static BOOLEAN STDCALL
1716 ScsiPortIsr(IN PKINTERRUPT Interrupt,
1717             IN PVOID ServiceContext)
1718 {
1719   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1720   BOOLEAN Result;
1721
1722   DPRINT("ScsiPortIsr() called!\n");
1723
1724   DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext;
1725
1726   Result = DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension);
1727   if (Result == FALSE)
1728     {
1729       return(FALSE);
1730     }
1731
1732   if (DeviceExtension->IrpFlags)
1733     {
1734       IoRequestDpc(DeviceExtension->DeviceObject,
1735                    DeviceExtension->CurrentIrp,
1736                    DeviceExtension);
1737     }
1738
1739   return(TRUE);
1740 }
1741
1742
1743 //    ScsiPortDpcForIsr
1744 //  DESCRIPTION:
1745 //
1746 //  RUN LEVEL:
1747 //
1748 //  ARGUMENTS:
1749 //    IN PKDPC          Dpc
1750 //    IN PDEVICE_OBJECT DpcDeviceObject
1751 //    IN PIRP           DpcIrp
1752 //    IN PVOID          DpcContext
1753 //
1754 static VOID STDCALL
1755 ScsiPortDpcForIsr(IN PKDPC Dpc,
1756                   IN PDEVICE_OBJECT DpcDeviceObject,
1757                   IN PIRP DpcIrp,
1758                   IN PVOID DpcContext)
1759 {
1760   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1761   PIO_STACK_LOCATION IrpStack;
1762   PSCSI_REQUEST_BLOCK Srb;
1763   KIRQL oldIrql;
1764
1765   DPRINT("ScsiPortDpcForIsr(Dpc %p  DpcDeviceObject %p  DpcIrp %p  DpcContext %p)\n",
1766          Dpc, DpcDeviceObject, DpcIrp, DpcContext);
1767
1768   DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DpcContext;
1769
1770   KeAcquireSpinLock(&DeviceExtension->IrpLock, &oldIrql);
1771   if (DeviceExtension->IrpFlags)
1772     {
1773       IrpStack = IoGetCurrentIrpStackLocation(DeviceExtension->CurrentIrp);
1774       Srb = IrpStack->Parameters.Scsi.Srb;
1775
1776       if (DeviceExtension->OriginalSrb != NULL)
1777         {
1778           DPRINT("Got sense data!\n");
1779
1780           DPRINT("Valid: %x\n", DeviceExtension->InternalSenseData.Valid);
1781           DPRINT("ErrorCode: %x\n", DeviceExtension->InternalSenseData.ErrorCode);
1782           DPRINT("SenseKey: %x\n", DeviceExtension->InternalSenseData.SenseKey);
1783           DPRINT("SenseCode: %x\n", DeviceExtension->InternalSenseData.AdditionalSenseCode);
1784
1785           /* Copy sense data */
1786           if (DeviceExtension->OriginalSrb->SenseInfoBufferLength != 0)
1787             {
1788               RtlCopyMemory(DeviceExtension->OriginalSrb->SenseInfoBuffer,
1789                             &DeviceExtension->InternalSenseData,
1790                             sizeof(SENSE_DATA));
1791               DeviceExtension->OriginalSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
1792             }
1793
1794           /* Clear current sense data */
1795           RtlZeroMemory(&DeviceExtension->InternalSenseData, sizeof(SENSE_DATA));
1796
1797           IrpStack->Parameters.Scsi.Srb = DeviceExtension->OriginalSrb;
1798           DeviceExtension->OriginalSrb = NULL;
1799         }
1800       else if ((SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) &&
1801                (Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION))
1802         {
1803           DPRINT("SCSIOP_REQUEST_SENSE required!\n");
1804
1805           DeviceExtension->OriginalSrb = Srb;
1806           IrpStack->Parameters.Scsi.Srb = ScsiPortInitSenseRequestSrb(DeviceExtension,
1807                                                                       Srb);
1808           KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1809           if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
1810                                       ScsiPortStartPacket,
1811                                       DeviceExtension))
1812             {
1813               DPRINT1("Synchronization failed!\n");
1814
1815               DpcIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
1816               DpcIrp->IoStatus.Information = 0;
1817               IoCompleteRequest(DpcIrp,
1818                                 IO_NO_INCREMENT);
1819               IoStartNextPacket(DpcDeviceObject,
1820                                 FALSE);
1821             }
1822
1823           return;
1824         }
1825
1826       DeviceExtension->CurrentIrp = NULL;
1827
1828 //      DpcIrp->IoStatus.Information = 0;
1829 //      DpcIrp->IoStatus.Status = STATUS_SUCCESS;
1830
1831       if (DeviceExtension->IrpFlags & IRP_FLAG_COMPLETE)
1832         {
1833           DeviceExtension->IrpFlags &= ~IRP_FLAG_COMPLETE;
1834           IoCompleteRequest(DpcIrp, IO_NO_INCREMENT);
1835         }
1836
1837       if (DeviceExtension->IrpFlags & IRP_FLAG_NEXT)
1838         {
1839           DeviceExtension->IrpFlags &= ~IRP_FLAG_NEXT;
1840           KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1841           IoStartNextPacket(DpcDeviceObject, FALSE);
1842         }
1843       else
1844         {
1845           KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1846         }
1847     }
1848   else
1849     {
1850       KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1851     }
1852
1853   DPRINT("ScsiPortDpcForIsr() done\n");
1854 }
1855
1856
1857 //    ScsiPortIoTimer
1858 //  DESCRIPTION:
1859 //    This function handles timeouts and other time delayed processing
1860 //
1861 //  RUN LEVEL:
1862 //
1863 //  ARGUMENTS:
1864 //    IN  PDEVICE_OBJECT  DeviceObject  Device object registered with timer
1865 //    IN  PVOID           Context       the Controller extension for the
1866 //                                      controller the device is on
1867 //
1868 static VOID STDCALL
1869 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
1870                 PVOID Context)
1871 {
1872   DPRINT1("ScsiPortIoTimer()\n");
1873 }
1874
1875
1876 static PSCSI_REQUEST_BLOCK
1877 ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1878                             PSCSI_REQUEST_BLOCK OriginalSrb)
1879 {
1880   PSCSI_REQUEST_BLOCK Srb;
1881   PCDB Cdb;
1882
1883   Srb = &DeviceExtension->InternalSrb;
1884
1885   RtlZeroMemory(Srb,
1886                 sizeof(SCSI_REQUEST_BLOCK));
1887
1888   Srb->PathId = OriginalSrb->PathId;
1889   Srb->TargetId = OriginalSrb->TargetId;
1890   Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1891   Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
1892   Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
1893
1894   Srb->TimeOutValue = 4;
1895
1896   Srb->CdbLength = 6;
1897   Srb->DataBuffer = &DeviceExtension->InternalSenseData;
1898   Srb->DataTransferLength = sizeof(SENSE_DATA);
1899
1900   Cdb = (PCDB)Srb->Cdb;
1901   Cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE;
1902   Cdb->CDB6INQUIRY.AllocationLength = sizeof(SENSE_DATA);
1903
1904   return(Srb);
1905 }
1906
1907
1908 static VOID
1909 ScsiPortFreeSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
1910 {
1911   DeviceExtension->OriginalSrb = NULL;
1912 }
1913
1914
1915 /**********************************************************************
1916  * NAME                                                 INTERNAL
1917  *      SpiBuildDeviceMap
1918  *
1919  * DESCRIPTION
1920  *      Builds the registry device map of all device which are attached
1921  *      to the given SCSI HBA port. The device map is located at:
1922  *        \Registry\Machine\DeviceMap\Scsi
1923  *
1924  * RUN LEVEL
1925  *      PASSIVE_LEVEL
1926  *
1927  * ARGUMENTS
1928  *      DeviceExtension
1929  *              ...
1930  *
1931  *      RegistryPath
1932  *              Name of registry driver service key.
1933  *
1934  * RETURNS
1935  *      NTSTATUS
1936  */
1937
1938 static NTSTATUS
1939 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1940                    PUNICODE_STRING RegistryPath)
1941 {
1942   PSCSI_PORT_LUN_EXTENSION LunExtension;
1943   OBJECT_ATTRIBUTES ObjectAttributes;
1944   UNICODE_STRING KeyName;
1945   UNICODE_STRING ValueName;
1946   WCHAR NameBuffer[64];
1947   ULONG Disposition;
1948   HANDLE ScsiKey;
1949   HANDLE ScsiPortKey = NULL;
1950   HANDLE ScsiBusKey = NULL;
1951   HANDLE ScsiInitiatorKey = NULL;
1952   HANDLE ScsiTargetKey = NULL;
1953   HANDLE ScsiLunKey = NULL;
1954   ULONG BusNumber;
1955   ULONG Target;
1956   ULONG CurrentTarget;
1957   ULONG Lun;
1958   PWCHAR DriverName;
1959   ULONG UlongData;
1960   PWCHAR TypeName;
1961   NTSTATUS Status;
1962
1963   DPRINT("SpiBuildDeviceMap() called\n");
1964
1965   if (DeviceExtension == NULL || RegistryPath == NULL)
1966     {
1967       DPRINT1("Invalid parameter\n");
1968       return(STATUS_INVALID_PARAMETER);
1969     }
1970
1971   /* Open or create the 'Scsi' subkey */
1972   RtlInitUnicodeStringFromLiteral(&KeyName,
1973                                   L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
1974   InitializeObjectAttributes(&ObjectAttributes,
1975                              &KeyName,
1976                              OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
1977                              0,
1978                              NULL);
1979   Status = ZwCreateKey(&ScsiKey,
1980                        KEY_ALL_ACCESS,
1981                        &ObjectAttributes,
1982                        0,
1983                        NULL,
1984                        REG_OPTION_VOLATILE,
1985                        &Disposition);
1986   if (!NT_SUCCESS(Status))
1987     {
1988       DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
1989       return(Status);
1990     }
1991
1992   /* Create new 'Scsi Port X' subkey */
1993   DPRINT("Scsi Port %lu\n",
1994          DeviceExtension->PortNumber);
1995
1996   swprintf(NameBuffer,
1997            L"Scsi Port %lu",
1998            DeviceExtension->PortNumber);
1999   RtlInitUnicodeString(&KeyName,
2000                        NameBuffer);
2001   InitializeObjectAttributes(&ObjectAttributes,
2002                              &KeyName,
2003                              0,
2004                              ScsiKey,
2005                              NULL);
2006   Status = ZwCreateKey(&ScsiPortKey,
2007                        KEY_ALL_ACCESS,
2008                        &ObjectAttributes,
2009                        0,
2010                        NULL,
2011                        REG_OPTION_VOLATILE,
2012                        &Disposition);
2013   ZwClose(ScsiKey);
2014   if (!NT_SUCCESS(Status))
2015     {
2016       DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
2017       return(Status);
2018     }
2019
2020   /*
2021    * Create port-specific values
2022    */
2023
2024   /* Set 'DMA Enabled' (REG_DWORD) value */
2025   UlongData = (ULONG)!DeviceExtension->PortCapabilities->AdapterUsesPio;
2026   DPRINT("  DMA Enabled = %s\n", (UlongData) ? "TRUE" : "FALSE");
2027   RtlInitUnicodeString(&ValueName,
2028                        L"DMA Enabled");
2029   Status = ZwSetValueKey(ScsiPortKey,
2030                          &ValueName,
2031                          0,
2032                          REG_DWORD,
2033                          &UlongData,
2034                          sizeof(ULONG));
2035   if (!NT_SUCCESS(Status))
2036     {
2037       DPRINT("ZwSetValueKey('DMA Enabled') failed (Status %lx)\n", Status);
2038       ZwClose(ScsiPortKey);
2039       return(Status);
2040     }
2041
2042   /* Set 'Driver' (REG_SZ) value */
2043   DriverName = wcsrchr(RegistryPath->Buffer, L'\\') + 1;
2044   RtlInitUnicodeString(&ValueName,
2045                        L"Driver");
2046   Status = ZwSetValueKey(ScsiPortKey,
2047                          &ValueName,
2048                          0,
2049                          REG_SZ,
2050                          DriverName,
2051                          (wcslen(DriverName) + 1) * sizeof(WCHAR));
2052   if (!NT_SUCCESS(Status))
2053     {
2054       DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status);
2055       ZwClose(ScsiPortKey);
2056       return(Status);
2057     }
2058
2059   /* Set 'Interrupt' (REG_DWORD) value (NT4 only) */
2060   UlongData = (ULONG)DeviceExtension->PortConfig.BusInterruptLevel;
2061   DPRINT("  Interrupt = %lu\n", UlongData);
2062   RtlInitUnicodeString(&ValueName,
2063                        L"Interrupt");
2064   Status = ZwSetValueKey(ScsiPortKey,
2065                          &ValueName,
2066                          0,
2067                          REG_DWORD,
2068                          &UlongData,
2069                          sizeof(ULONG));
2070   if (!NT_SUCCESS(Status))
2071     {
2072       DPRINT("ZwSetValueKey('Interrupt') failed (Status %lx)\n", Status);
2073       ZwClose(ScsiPortKey);
2074       return(Status);
2075     }
2076
2077   /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
2078   UlongData = ScsiPortConvertPhysicalAddressToUlong(DeviceExtension->PortConfig.AccessRanges[0].RangeStart);
2079   DPRINT("  IOAddress = %lx\n", UlongData);
2080   RtlInitUnicodeString(&ValueName,
2081                        L"IOAddress");
2082   Status = ZwSetValueKey(ScsiPortKey,
2083                          &ValueName,
2084                          0,
2085                          REG_DWORD,
2086                          &UlongData,
2087                          sizeof(ULONG));
2088   if (!NT_SUCCESS(Status))
2089     {
2090       DPRINT("ZwSetValueKey('IOAddress') failed (Status %lx)\n", Status);
2091       ZwClose(ScsiPortKey);
2092       return(Status);
2093     }
2094
2095   /* Enumerate buses */
2096   for (BusNumber = 0; BusNumber < DeviceExtension->PortConfig.NumberOfBuses; BusNumber++)
2097     {
2098       /* Create 'Scsi Bus X' key */
2099       DPRINT("    Scsi Bus %lu\n", BusNumber);
2100       swprintf(NameBuffer,
2101                L"Scsi Bus %lu",
2102                BusNumber);
2103       RtlInitUnicodeString(&KeyName,
2104                            NameBuffer);
2105       InitializeObjectAttributes(&ObjectAttributes,
2106                                  &KeyName,
2107                                  0,
2108                                  ScsiPortKey,
2109                                  NULL);
2110       Status = ZwCreateKey(&ScsiBusKey,
2111                            KEY_ALL_ACCESS,
2112                            &ObjectAttributes,
2113                            0,
2114                            NULL,
2115                            REG_OPTION_VOLATILE,
2116                            &Disposition);
2117       if (!NT_SUCCESS(Status))
2118         {
2119           DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
2120           goto ByeBye;
2121         }
2122
2123       /* Create 'Initiator Id X' key */
2124       DPRINT("      Initiator Id %u\n",
2125               DeviceExtension->PortConfig.InitiatorBusId[BusNumber]);
2126       swprintf(NameBuffer,
2127                L"Initiator Id %u",
2128                DeviceExtension->PortConfig.InitiatorBusId[BusNumber]);
2129       RtlInitUnicodeString(&KeyName,
2130                            NameBuffer);
2131       InitializeObjectAttributes(&ObjectAttributes,
2132                                  &KeyName,
2133                                  0,
2134                                  ScsiBusKey,
2135                                  NULL);
2136       Status = ZwCreateKey(&ScsiInitiatorKey,
2137                            KEY_ALL_ACCESS,
2138                            &ObjectAttributes,
2139                            0,
2140                            NULL,
2141                            REG_OPTION_VOLATILE,
2142                            &Disposition);
2143       if (!NT_SUCCESS(Status))
2144         {
2145           DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
2146           goto ByeBye;
2147         }
2148
2149       /* FIXME: Are there any initiator values (??) */
2150
2151       ZwClose(ScsiInitiatorKey);
2152       ScsiInitiatorKey = NULL;
2153
2154
2155       /* Enumerate targets */
2156       CurrentTarget = (ULONG)-1;
2157       ScsiTargetKey = NULL;
2158       for (Target = 0; Target < DeviceExtension->PortConfig.MaximumNumberOfTargets; Target++)
2159         {
2160           for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
2161             {
2162               LunExtension = SpiGetLunExtension(DeviceExtension,
2163                                                 BusNumber,
2164                                                 Target,
2165                                                 Lun);
2166               if (LunExtension != NULL)
2167                 {
2168                   if (Target != CurrentTarget)
2169                     {
2170                       /* Close old target key */
2171                       if (ScsiTargetKey != NULL)
2172                         {
2173                           ZwClose(ScsiTargetKey);
2174                           ScsiTargetKey = NULL;
2175                         }
2176
2177                       /* Create 'Target Id X' key */
2178                       DPRINT("      Target Id %lu\n", Target);
2179                       swprintf(NameBuffer,
2180                                L"Target Id %lu",
2181                                Target);
2182                       RtlInitUnicodeString(&KeyName,
2183                                            NameBuffer);
2184                       InitializeObjectAttributes(&ObjectAttributes,
2185                                                  &KeyName,
2186                                                  0,
2187                                                  ScsiBusKey,
2188                                                  NULL);
2189                       Status = ZwCreateKey(&ScsiTargetKey,
2190                                            KEY_ALL_ACCESS,
2191                                            &ObjectAttributes,
2192                                            0,
2193                                            NULL,
2194                                            REG_OPTION_VOLATILE,
2195                                            &Disposition);
2196                       if (!NT_SUCCESS(Status))
2197                         {
2198                           DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
2199                           goto ByeBye;
2200                         }
2201
2202                       CurrentTarget = Target;
2203                     }
2204
2205                   /* Create 'Logical Unit Id X' key */
2206                   DPRINT("        Logical Unit Id %lu\n", Lun);
2207                   swprintf(NameBuffer,
2208                            L"Logical Unit Id %lu",
2209                            Lun);
2210                   RtlInitUnicodeString(&KeyName,
2211                                        NameBuffer);
2212                   InitializeObjectAttributes(&ObjectAttributes,
2213                                              &KeyName,
2214                                              0,
2215                                              ScsiTargetKey,
2216                                              NULL);
2217                   Status = ZwCreateKey(&ScsiLunKey,
2218                                        KEY_ALL_ACCESS,
2219                                        &ObjectAttributes,
2220                                        0,
2221                                        NULL,
2222                                        REG_OPTION_VOLATILE,
2223                                        &Disposition);
2224                   if (!NT_SUCCESS(Status))
2225                     {
2226                       DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
2227                       goto ByeBye;
2228                     }
2229
2230                   /* Set 'Identifier' (REG_SZ) value */
2231                   swprintf(NameBuffer,
2232                            L"%.8S%.16S%.4S",
2233                            LunExtension->InquiryData.VendorId,
2234                            LunExtension->InquiryData.ProductId,
2235                            LunExtension->InquiryData.ProductRevisionLevel);
2236                   DPRINT("          Identifier = '%S'\n", NameBuffer);
2237                   RtlInitUnicodeString(&ValueName,
2238                                        L"Identifier");
2239                   Status = ZwSetValueKey(ScsiLunKey,
2240                                          &ValueName,
2241                                          0,
2242                                          REG_SZ,
2243                                          NameBuffer,
2244                                          (wcslen(NameBuffer) + 1) * sizeof(WCHAR));
2245                   if (!NT_SUCCESS(Status))
2246                     {
2247                       DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", Status);
2248                       goto ByeBye;
2249                     }
2250
2251                   /* Set 'Type' (REG_SZ) value */
2252                   switch (LunExtension->InquiryData.DeviceType)
2253                     {
2254                       case 0:
2255                         TypeName = L"DiskPeripheral";
2256                         break;
2257                       case 1:
2258                         TypeName = L"TapePeripheral";
2259                         break;
2260                       case 2:
2261                         TypeName = L"PrinterPeripheral";
2262                         break;
2263                       case 4:
2264                         TypeName = L"WormPeripheral";
2265                         break;
2266                       case 5:
2267                         TypeName = L"CdRomPeripheral";
2268                         break;
2269                       case 6:
2270                         TypeName = L"ScannerPeripheral";
2271                         break;
2272                       case 7:
2273                         TypeName = L"OpticalDiskPeripheral";
2274                         break;
2275                       case 8:
2276                         TypeName = L"MediumChangerPeripheral";
2277                         break;
2278                       case 9:
2279                         TypeName = L"CommunicationPeripheral";
2280                         break;
2281                       default:
2282                         TypeName = L"OtherPeripheral";
2283                         break;
2284                     }
2285                   DPRINT("          Type = '%S'\n", TypeName);
2286                   RtlInitUnicodeString(&ValueName,
2287                                        L"Type");
2288                   Status = ZwSetValueKey(ScsiLunKey,
2289                                          &ValueName,
2290                                          0,
2291                                          REG_SZ,
2292                                          TypeName,
2293                                          (wcslen(TypeName) + 1) * sizeof(WCHAR));
2294                   if (!NT_SUCCESS(Status))
2295                     {
2296                       DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status);
2297                       goto ByeBye;
2298                     }
2299
2300                   ZwClose(ScsiLunKey);
2301                   ScsiLunKey = NULL;
2302                 }
2303             }
2304
2305           /* Close old target key */
2306           if (ScsiTargetKey != NULL)
2307             {
2308               ZwClose(ScsiTargetKey);
2309               ScsiTargetKey = NULL;
2310             }
2311         }
2312
2313       ZwClose(ScsiBusKey);
2314       ScsiBusKey = NULL;
2315     }
2316
2317 ByeBye:
2318   if (ScsiLunKey != NULL)
2319     ZwClose (ScsiLunKey);
2320
2321   if (ScsiInitiatorKey != NULL)
2322     ZwClose (ScsiInitiatorKey);
2323
2324   if (ScsiTargetKey != NULL)
2325     ZwClose (ScsiTargetKey);
2326
2327   if (ScsiBusKey != NULL)
2328     ZwClose (ScsiBusKey);
2329
2330   if (ScsiPortKey != NULL)
2331     ZwClose (ScsiPortKey);
2332
2333   DPRINT("SpiBuildDeviceMap() done\n");
2334
2335   return Status;
2336 }
2337
2338 /* EOF */