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