update for HEAD-2003021201
[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   DPRINT("ScsiPortLogError()\n");
638   UNIMPLEMENTED;
639 }
640
641
642 VOID STDCALL
643 ScsiPortMoveMemory(OUT PVOID Destination,
644                    IN PVOID Source,
645                    IN ULONG Length)
646 {
647   RtlMoveMemory(Destination,
648                 Source,
649                 Length);
650 }
651
652
653 VOID
654 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType,
655                      IN PVOID HwDeviceExtension,
656                      ...)
657 {
658   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
659
660   DPRINT("ScsiPortNotification() called\n");
661
662   DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
663                                       SCSI_PORT_DEVICE_EXTENSION,
664                                       MiniPortDeviceExtension);
665
666   DPRINT("DeviceExtension %p\n", DeviceExtension);
667
668   DPRINT("Initializing = %s\n", (DeviceExtension->Initializing)?"TRUE":"FALSE");
669
670   if (DeviceExtension->Initializing == TRUE)
671     return;
672
673   switch (NotificationType)
674     {
675       case RequestComplete:
676         DPRINT("Notify: RequestComplete\n");
677         DeviceExtension->IrpFlags |= IRP_FLAG_COMPLETE;
678         break;
679
680       case NextRequest:
681         DPRINT("Notify: NextRequest\n");
682         DeviceExtension->IrpFlags |= IRP_FLAG_NEXT;
683         break;
684
685       default:
686         break;
687     }
688 }
689
690
691 ULONG STDCALL
692 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension,
693                            IN ULONG BusDataType,
694                            IN ULONG SystemIoBusNumber,
695                            IN ULONG SlotNumber,
696                            IN PVOID Buffer,
697                            IN ULONG Offset,
698                            IN ULONG Length)
699 {
700   DPRINT("ScsiPortSetBusDataByOffset()\n");
701   return(HalSetBusDataByOffset(BusDataType,
702                                SystemIoBusNumber,
703                                SlotNumber,
704                                Buffer,
705                                Offset,
706                                Length));
707 }
708
709
710 BOOLEAN STDCALL
711 ScsiPortValidateRange(IN PVOID HwDeviceExtension,
712                       IN INTERFACE_TYPE BusType,
713                       IN ULONG SystemIoBusNumber,
714                       IN SCSI_PHYSICAL_ADDRESS IoAddress,
715                       IN ULONG NumberOfBytes,
716                       IN BOOLEAN InIoSpace)
717 {
718   DPRINT("ScsiPortValidateRange()\n");
719   return(TRUE);
720 }
721
722
723 /* INTERNAL FUNCTIONS ********************************************************/
724
725 /**********************************************************************
726  * NAME                                                 INTERNAL
727  *      ScsiPortCreateClose
728  *
729  * DESCRIPTION
730  *      Answer requests for Create/Close calls: a null operation.
731  *
732  * RUN LEVEL
733  *      PASSIVE_LEVEL
734  *
735  * ARGUMENTS
736  *      DeviceObject
737  *              Pointer to a device object.
738  *
739  *      Irp
740  *              Pointer to an IRP.
741  *
742  *      ...
743                 Additional output data (see printf()).
744  *
745  * RETURN VALUE
746  *      Status.
747  */
748
749 static NTSTATUS STDCALL
750 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
751                     IN PIRP Irp)
752 {
753   DPRINT("ScsiPortCreateClose()\n");
754
755   Irp->IoStatus.Status = STATUS_SUCCESS;
756   Irp->IoStatus.Information = FILE_OPENED;
757
758   IoCompleteRequest(Irp, IO_NO_INCREMENT);
759
760   return(STATUS_SUCCESS);
761 }
762
763
764 /**********************************************************************
765  * NAME                                                 INTERNAL
766  *      ScsiPortDispatchScsi
767  *
768  * DESCRIPTION
769  *      Answer requests for SCSI calls
770  *
771  * RUN LEVEL
772  *      PASSIVE_LEVEL
773  *
774  * ARGUMENTS
775  *      Standard dispatch arguments
776  *
777  * RETURNS
778  *      NTSTATUS
779  */
780
781 static NTSTATUS STDCALL
782 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
783                      IN PIRP Irp)
784 {
785   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
786   PIO_STACK_LOCATION Stack;
787   PSCSI_REQUEST_BLOCK Srb;
788   NTSTATUS Status = STATUS_SUCCESS;
789   ULONG DataSize = 0;
790
791   DPRINT("ScsiPortDispatchScsi(DeviceObject %p  Irp %p)\n",
792          DeviceObject, Irp);
793
794   DeviceExtension = DeviceObject->DeviceExtension;
795   Stack = IoGetCurrentIrpStackLocation(Irp);
796
797   Srb = Stack->Parameters.Scsi.Srb;
798   if (Srb == NULL)
799     {
800       Status = STATUS_UNSUCCESSFUL;
801
802       Irp->IoStatus.Status = Status;
803       Irp->IoStatus.Information = 0;
804
805       IoCompleteRequest(Irp, IO_NO_INCREMENT);
806
807       return(Status);
808     }
809
810   DPRINT("Srb: %p\n", Srb);
811   DPRINT("Srb->Function: %lu\n", Srb->Function);
812   DPRINT("PathId: %lu  TargetId: %lu  Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
813
814   switch (Srb->Function)
815     {
816       case SRB_FUNCTION_EXECUTE_SCSI:
817         IoStartPacket(DeviceObject, Irp, NULL, NULL);
818         return(STATUS_PENDING);
819
820       case SRB_FUNCTION_SHUTDOWN:
821       case SRB_FUNCTION_FLUSH:
822         if (DeviceExtension->PortConfig.CachesData == TRUE)
823           {
824             IoStartPacket(DeviceObject, Irp, NULL, NULL);
825             return(STATUS_PENDING);
826           }
827         break;
828
829       case SRB_FUNCTION_CLAIM_DEVICE:
830         {
831           PSCSI_ADAPTER_BUS_INFO AdapterInfo;
832           PSCSI_INQUIRY_DATA UnitInfo;
833           PINQUIRYDATA InquiryData;
834
835           DPRINT("  SRB_FUNCTION_CLAIM_DEVICE\n");
836           DPRINT("PathId: %lu  TargetId: %lu  Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
837
838           Srb->DataBuffer = NULL;
839
840           if (DeviceExtension->PortBusInfo != NULL)
841             {
842               AdapterInfo = (PSCSI_ADAPTER_BUS_INFO)DeviceExtension->PortBusInfo;
843
844               if (AdapterInfo->BusData[Srb->PathId].NumberOfLogicalUnits == 0)
845                 break;
846
847               UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo +
848                 AdapterInfo->BusData[Srb->PathId].InquiryDataOffset);
849
850               while (AdapterInfo->BusData[Srb->PathId].InquiryDataOffset)
851                 {
852                   InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
853
854                   if ((UnitInfo->TargetId == Srb->TargetId) &&
855                       (UnitInfo->Lun == Srb->Lun) &&
856                       (UnitInfo->DeviceClaimed == FALSE))
857                     {
858                       UnitInfo->DeviceClaimed = TRUE;
859                       DPRINT("Claimed device!\n");
860
861                       /* FIXME: Hack!!!!! */
862                       Srb->DataBuffer = DeviceObject;
863
864                       break;
865                     }
866
867                   if (UnitInfo->NextInquiryDataOffset == 0)
868                     break;
869
870                   UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo + UnitInfo->NextInquiryDataOffset);
871                 }
872             }
873         }
874         break;
875
876       case SRB_FUNCTION_RELEASE_DEVICE:
877         {
878           PSCSI_ADAPTER_BUS_INFO AdapterInfo;
879           PSCSI_INQUIRY_DATA UnitInfo;
880           PINQUIRYDATA InquiryData;
881
882           DPRINT("  SRB_FUNCTION_RELEASE_DEVICE\n");
883           DPRINT("PathId: %lu  TargetId: %lu  Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
884
885           if (DeviceExtension->PortBusInfo != NULL)
886             {
887               AdapterInfo = (PSCSI_ADAPTER_BUS_INFO)DeviceExtension->PortBusInfo;
888
889               if (AdapterInfo->BusData[Srb->PathId].NumberOfLogicalUnits == 0)
890                 break;
891
892               UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo +
893                 AdapterInfo->BusData[Srb->PathId].InquiryDataOffset);
894
895               while (AdapterInfo->BusData[Srb->PathId].InquiryDataOffset)
896                 {
897                   InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
898
899                   if ((UnitInfo->TargetId == Srb->TargetId) &&
900                       (UnitInfo->Lun == Srb->Lun) &&
901                       (UnitInfo->DeviceClaimed == TRUE))
902                     {
903                       UnitInfo->DeviceClaimed = FALSE;
904                       DPRINT("Released device!\n");
905                       break;
906                     }
907
908                   if (UnitInfo->NextInquiryDataOffset == 0)
909                     break;
910
911                   UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo + UnitInfo->NextInquiryDataOffset);
912                 }
913             }
914         }
915         break;
916
917       default:
918         DPRINT1("SRB function not implemented (Function %lu)\n", Srb->Function);
919         Status = STATUS_NOT_IMPLEMENTED;
920         break;
921     }
922
923   Irp->IoStatus.Status = Status;
924   Irp->IoStatus.Information = DataSize;
925
926   IoCompleteRequest(Irp, IO_NO_INCREMENT);
927
928   return(Status);
929 }
930
931
932 /**********************************************************************
933  * NAME                                                 INTERNAL
934  *      ScsiPortDeviceControl
935  *
936  * DESCRIPTION
937  *      Answer requests for device control calls
938  *
939  * RUN LEVEL
940  *      PASSIVE_LEVEL
941  *
942  * ARGUMENTS
943  *      Standard dispatch arguments
944  *
945  * RETURNS
946  *      NTSTATUS
947  */
948
949 static NTSTATUS STDCALL
950 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
951                       IN PIRP Irp)
952 {
953   PIO_STACK_LOCATION Stack;
954   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
955
956   DPRINT("ScsiPortDeviceControl()\n");
957
958   Irp->IoStatus.Status = STATUS_SUCCESS;
959   Irp->IoStatus.Information = 0;
960
961
962   Stack = IoGetCurrentIrpStackLocation(Irp);
963   DeviceExtension = DeviceObject->DeviceExtension;
964
965   switch (Stack->Parameters.DeviceIoControl.IoControlCode)
966     {
967
968       case IOCTL_SCSI_GET_CAPABILITIES:
969         {
970           DPRINT("  IOCTL_SCSI_GET_CAPABILITIES\n");
971
972           *((PIO_SCSI_CAPABILITIES *)Irp->AssociatedIrp.SystemBuffer) =
973             DeviceExtension->PortCapabilities;
974
975           Irp->IoStatus.Information = sizeof(PIO_SCSI_CAPABILITIES);
976         }
977         break;
978
979       case IOCTL_SCSI_GET_INQUIRY_DATA:
980         {
981           DPRINT("  IOCTL_SCSI_GET_INQUIRY_DATA\n");
982
983           /* Copy inquiry data to the port device extension */
984           memcpy(Irp->AssociatedIrp.SystemBuffer,
985                  DeviceExtension->PortBusInfo,
986                  DeviceExtension->PortBusInfoSize);
987
988           DPRINT("BufferSize: %lu\n", DeviceExtension->PortBusInfoSize);
989           Irp->IoStatus.Information = DeviceExtension->PortBusInfoSize;
990         }
991         break;
992
993       default:
994         DPRINT1("  unknown ioctl code: 0x%lX\n",
995                Stack->Parameters.DeviceIoControl.IoControlCode);
996         break;
997     }
998
999   IoCompleteRequest(Irp, IO_NO_INCREMENT);
1000
1001   return(STATUS_SUCCESS);
1002 }
1003
1004
1005 static VOID STDCALL
1006 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
1007                 IN PIRP Irp)
1008 {
1009   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1010   PIO_STACK_LOCATION IrpStack;
1011   KIRQL OldIrql;
1012
1013   DPRINT("ScsiPortStartIo() called!\n");
1014
1015   DeviceExtension = DeviceObject->DeviceExtension;
1016   IrpStack = IoGetCurrentIrpStackLocation(Irp);
1017
1018   // FIXME: implement the supported functions
1019
1020   switch (IrpStack->MajorFunction)
1021     {
1022       case IRP_MJ_SCSI:
1023         {
1024           BOOLEAN Result;
1025           PSCSI_REQUEST_BLOCK Srb;
1026           KIRQL oldIrql;
1027
1028           DPRINT("IRP_MJ_SCSI\n");
1029
1030           Srb = IrpStack->Parameters.Scsi.Srb;
1031
1032           DPRINT("DeviceExtension %p\n", DeviceExtension);
1033
1034           Irp->IoStatus.Status = STATUS_SUCCESS;
1035           Irp->IoStatus.Information = Srb->DataTransferLength;
1036
1037           DeviceExtension->CurrentIrp = Irp;
1038
1039           if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
1040                                       ScsiPortStartPacket,
1041                                       DeviceExtension))
1042             {
1043                 DPRINT("Synchronization failed!\n");
1044
1045                 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
1046                 Irp->IoStatus.Information = 0;
1047                 IoCompleteRequest(Irp,
1048                                   IO_NO_INCREMENT);
1049                 IoStartNextPacket(DeviceObject,
1050                                   FALSE);
1051             }
1052           KeAcquireSpinLock(&DeviceExtension->IrpLock, &oldIrql);
1053           if (DeviceExtension->IrpFlags & IRP_FLAG_COMPLETE)
1054             {
1055                 DeviceExtension->IrpFlags &= ~IRP_FLAG_COMPLETE;
1056                 IoCompleteRequest(Irp,
1057                                   IO_NO_INCREMENT);
1058             }
1059
1060           if (DeviceExtension->IrpFlags & IRP_FLAG_NEXT)
1061             {
1062                 DeviceExtension->IrpFlags &= ~IRP_FLAG_NEXT;
1063                 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1064                 IoStartNextPacket(DeviceObject,
1065                                   FALSE);
1066             }
1067           else
1068             {
1069                 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1070             }
1071         }
1072         break;
1073
1074       default:
1075         Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
1076         Irp->IoStatus.Information = 0;
1077         IoCompleteRequest(Irp,
1078                           IO_NO_INCREMENT);
1079         IoStartNextPacket(DeviceObject,
1080                           FALSE);
1081         break;
1082     }
1083   DPRINT("ScsiPortStartIo() done\n");
1084 }
1085
1086
1087 static BOOLEAN STDCALL
1088 ScsiPortStartPacket(IN OUT PVOID Context)
1089 {
1090   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1091   PIO_STACK_LOCATION IrpStack;
1092   PSCSI_REQUEST_BLOCK Srb;
1093
1094   DPRINT("ScsiPortStartPacket() called\n");
1095
1096   DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)Context;
1097
1098   IrpStack = IoGetCurrentIrpStackLocation(DeviceExtension->CurrentIrp);
1099   Srb = IrpStack->Parameters.Scsi.Srb;
1100
1101   return(DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
1102                                     Srb));
1103 }
1104
1105
1106 /**********************************************************************
1107  * NAME                                                 INTERNAL
1108  *      ScsiPortCreatePortDevice
1109  *
1110  * DESCRIPTION
1111  *      Creates and initializes a SCSI port device object.
1112  *
1113  * RUN LEVEL
1114  *      PASSIVE_LEVEL
1115  *
1116  * ARGUMENTS
1117  *      DriverObject
1118  *              ...
1119  *
1120  *      PseudoDeviceExtension
1121  *              ...
1122  *
1123  *      PortNumber
1124  *              ...
1125  *
1126  * RETURNS
1127  *      NTSTATUS
1128  */
1129
1130 static NTSTATUS
1131 ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject,
1132                          IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension,
1133                          IN ULONG PortNumber,
1134                          IN OUT PSCSI_PORT_DEVICE_EXTENSION *RealDeviceExtension)
1135 {
1136   PSCSI_PORT_DEVICE_EXTENSION PortDeviceExtension;
1137   PIO_SCSI_CAPABILITIES PortCapabilities;
1138   PDEVICE_OBJECT PortDeviceObject;
1139   WCHAR NameBuffer[80];
1140   UNICODE_STRING DeviceName;
1141   WCHAR DosNameBuffer[80];
1142   UNICODE_STRING DosDeviceName;
1143   NTSTATUS Status;
1144   ULONG AccessRangeSize;
1145   ULONG MappedIrq;
1146   KIRQL Dirql;
1147   KAFFINITY Affinity;
1148
1149   DPRINT("ScsiPortCreatePortDevice() called\n");
1150
1151   *RealDeviceExtension = NULL;
1152
1153   MappedIrq = HalGetInterruptVector(PseudoDeviceExtension->PortConfig.AdapterInterfaceType,
1154                                     PseudoDeviceExtension->PortConfig.SystemIoBusNumber,
1155                                     PseudoDeviceExtension->PortConfig.BusInterruptLevel,
1156                                     PseudoDeviceExtension->PortConfig.BusInterruptVector,
1157                                     &Dirql,
1158                                     &Affinity);
1159
1160   /* Create a unicode device name */
1161   swprintf(NameBuffer,
1162            L"\\Device\\ScsiPort%lu",
1163            PortNumber);
1164   RtlInitUnicodeString(&DeviceName,
1165                        NameBuffer);
1166
1167   DPRINT("Creating device: %wZ\n", &DeviceName);
1168
1169   /* Create the port device */
1170   Status = IoCreateDevice(DriverObject,
1171                           PseudoDeviceExtension->Length,
1172                           &DeviceName,
1173                           FILE_DEVICE_CONTROLLER,
1174                           0,
1175                           FALSE,
1176                           &PortDeviceObject);
1177   if (!NT_SUCCESS(Status))
1178     {
1179       DbgPrint("IoCreateDevice call failed! (Status 0x%lX)\n", Status);
1180       return(Status);
1181     }
1182
1183   DPRINT("Created device: %wZ\n", &DeviceName);
1184
1185   /* Set the buffering strategy here... */
1186   PortDeviceObject->Flags |= DO_DIRECT_IO;
1187   PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
1188
1189   PortDeviceExtension = PortDeviceObject->DeviceExtension;
1190
1191   /* Copy pseudo device extension into the real device extension */
1192   memcpy(PortDeviceExtension,
1193          PseudoDeviceExtension,
1194          PseudoDeviceExtension->Length);
1195
1196   /* Copy access ranges */
1197   AccessRangeSize =
1198     sizeof(ACCESS_RANGE) * PseudoDeviceExtension->PortConfig.NumberOfAccessRanges;
1199   PortDeviceExtension->PortConfig.AccessRanges = ExAllocatePool(NonPagedPool,
1200                                                                 AccessRangeSize);
1201   memcpy(PortDeviceExtension->PortConfig.AccessRanges,
1202          PseudoDeviceExtension->PortConfig.AccessRanges,
1203          AccessRangeSize);
1204
1205   /* Copy device base list */
1206   if (IsListEmpty(&PseudoDeviceExtension->DeviceBaseListHead))
1207     {
1208       InitializeListHead(&PortDeviceExtension->DeviceBaseListHead);
1209     }
1210   else
1211     {
1212       PseudoDeviceExtension->DeviceBaseListHead.Flink =
1213         PortDeviceExtension->DeviceBaseListHead.Flink;
1214       PseudoDeviceExtension->DeviceBaseListHead.Blink =
1215         PortDeviceExtension->DeviceBaseListHead.Blink;
1216       PortDeviceExtension->DeviceBaseListHead.Blink->Flink =
1217         &PortDeviceExtension->DeviceBaseListHead;
1218       PortDeviceExtension->DeviceBaseListHead.Flink->Blink =
1219         &PortDeviceExtension->DeviceBaseListHead;
1220     }
1221
1222   PortDeviceExtension->DeviceObject = PortDeviceObject;
1223   PortDeviceExtension->PortNumber = PortNumber;
1224
1225   /* Initialize the spin lock in the controller extension */
1226   KeInitializeSpinLock(&PortDeviceExtension->IrpLock);
1227   KeInitializeSpinLock(&PortDeviceExtension->SpinLock);
1228
1229   /* Register an interrupt handler for this device */
1230   Status = IoConnectInterrupt(&PortDeviceExtension->Interrupt,
1231                               ScsiPortIsr,
1232                               PortDeviceExtension,
1233                               &PortDeviceExtension->SpinLock,
1234                               MappedIrq,
1235                               Dirql,
1236                               Dirql,
1237                               PortDeviceExtension->PortConfig.InterruptMode,
1238                               TRUE,
1239                               Affinity,
1240                               FALSE);
1241   if (!NT_SUCCESS(Status))
1242     {
1243       DbgPrint("Could not Connect Interrupt %d\n",
1244                PortDeviceExtension->PortConfig.BusInterruptVector);
1245       return(Status);
1246     }
1247
1248   /* Initialize the DPC object */
1249   IoInitializeDpcRequest(PortDeviceExtension->DeviceObject,
1250                          ScsiPortDpcForIsr);
1251
1252   /* Initialize the device timer */
1253   PortDeviceExtension->TimerState = IDETimerIdle;
1254   PortDeviceExtension->TimerCount = 0;
1255   IoInitializeTimer(PortDeviceExtension->DeviceObject,
1256                     ScsiPortIoTimer,
1257                     PortDeviceExtension);
1258
1259   /* Initialize port capabilities */
1260   PortCapabilities = ExAllocatePool(NonPagedPool,
1261                                     sizeof(IO_SCSI_CAPABILITIES));
1262   PortDeviceExtension->PortCapabilities = PortCapabilities;
1263   PortCapabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
1264   PortCapabilities->MaximumTransferLength =
1265     PortDeviceExtension->PortConfig.MaximumTransferLength;
1266   PortCapabilities->MaximumPhysicalPages =
1267     PortCapabilities->MaximumTransferLength / PAGE_SIZE;
1268   PortCapabilities->SupportedAsynchronousEvents = 0; /* FIXME */
1269   PortCapabilities->AlignmentMask =
1270     PortDeviceExtension->PortConfig.AlignmentMask;
1271   PortCapabilities->TaggedQueuing =
1272     PortDeviceExtension->PortConfig.TaggedQueuing;
1273   PortCapabilities->AdapterScansDown =
1274     PortDeviceExtension->PortConfig.AdapterScansDown;
1275   PortCapabilities->AdapterUsesPio = TRUE; /* FIXME */
1276
1277   /* Initialize inquiry data */
1278   PortDeviceExtension->PortBusInfoSize = 0;
1279   PortDeviceExtension->PortBusInfo = NULL;
1280
1281   DPRINT("DeviceExtension %p\n", PortDeviceExtension);
1282   ScsiPortInquire(PortDeviceExtension);
1283
1284
1285   /* FIXME: Copy more configuration data? */
1286
1287
1288   /* Create the dos device link */
1289   swprintf(DosNameBuffer,
1290            L"\\??\\Scsi%lu:",
1291            PortNumber);
1292   RtlInitUnicodeString(&DosDeviceName,
1293                        DosNameBuffer);
1294
1295   IoCreateSymbolicLink(&DosDeviceName,
1296                        &DeviceName);
1297
1298   *RealDeviceExtension = PortDeviceExtension;
1299
1300   DPRINT("ScsiPortCreatePortDevice() done\n");
1301
1302   return(STATUS_SUCCESS);
1303 }
1304
1305
1306 static VOID
1307 ScsiPortInquire(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
1308 {
1309   PSCSI_ADAPTER_BUS_INFO AdapterInfo;
1310   PSCSI_INQUIRY_DATA UnitInfo, PrevUnit;
1311   SCSI_REQUEST_BLOCK Srb;
1312   ULONG Bus;
1313   ULONG Target;
1314   ULONG UnitCount;
1315   ULONG DataSize;
1316   BOOLEAN Result;
1317
1318   DPRINT("ScsiPortInquire() called\n");
1319
1320   DeviceExtension->Initializing = TRUE;
1321
1322   /* Copy inquiry data to the port device extension */
1323   AdapterInfo =(PSCSI_ADAPTER_BUS_INFO)ExAllocatePool(NonPagedPool, 4096);
1324   RtlZeroMemory(AdapterInfo, 4096);
1325   AdapterInfo->NumberOfBuses = DeviceExtension->PortConfig.NumberOfBuses;
1326
1327   UnitInfo = (PSCSI_INQUIRY_DATA)
1328         ((PUCHAR)AdapterInfo + sizeof(SCSI_ADAPTER_BUS_INFO) +
1329          (sizeof(SCSI_BUS_DATA) * (AdapterInfo->NumberOfBuses - 1)));
1330
1331   RtlZeroMemory(&Srb,
1332                 sizeof(SCSI_REQUEST_BLOCK));
1333   Srb.DataBuffer = ExAllocatePool(NonPagedPool, 256);
1334   Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
1335   Srb.DataTransferLength = 256;
1336   Srb.Cdb[0] = SCSIOP_INQUIRY;
1337
1338   for (Bus = 0; Bus < AdapterInfo->NumberOfBuses; Bus++)
1339     {
1340       Srb.PathId = Bus;
1341
1342       AdapterInfo->BusData[Bus].InitiatorBusId =
1343         DeviceExtension->PortConfig.InitiatorBusId[Bus];
1344       AdapterInfo->BusData[Bus].InquiryDataOffset =
1345         (ULONG)((PUCHAR)UnitInfo - (PUCHAR)AdapterInfo);
1346
1347       PrevUnit = NULL;
1348       UnitCount = 0;
1349
1350       for (Target = 0; Target < DeviceExtension->PortConfig.MaximumNumberOfTargets; Target++)
1351         {
1352           Srb.TargetId = Target;
1353           Srb.Lun = 0;
1354           Srb.SrbStatus = SRB_STATUS_SUCCESS;
1355
1356           Result = DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
1357                                               &Srb);
1358           DPRINT("Result: %s  Srb.SrbStatus %lx\n", (Result)?"True":"False", Srb.SrbStatus);
1359
1360           if (Result == TRUE && Srb.SrbStatus == SRB_STATUS_SUCCESS)
1361             {
1362               UnitInfo->PathId = Bus;
1363               UnitInfo->TargetId = Target;
1364               UnitInfo->Lun = 0;
1365               UnitInfo->InquiryDataLength = INQUIRYDATABUFFERSIZE;
1366               memcpy(&UnitInfo->InquiryData,
1367                      Srb.DataBuffer,
1368                      INQUIRYDATABUFFERSIZE);
1369               if (PrevUnit != NULL)
1370                 PrevUnit->NextInquiryDataOffset = (ULONG)((PUCHAR)UnitInfo-(PUCHAR)AdapterInfo);
1371               PrevUnit = UnitInfo;
1372               UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)UnitInfo + sizeof(SCSI_INQUIRY_DATA)+INQUIRYDATABUFFERSIZE-1);
1373               UnitCount++;
1374             }
1375         }
1376       DPRINT("UnitCount: %lu\n", UnitCount);
1377       AdapterInfo->BusData[Bus].NumberOfLogicalUnits = UnitCount;
1378       if (UnitCount == 0)
1379         AdapterInfo->BusData[Bus].InquiryDataOffset = 0;
1380     }
1381   DataSize = (ULONG)((PUCHAR)UnitInfo-(PUCHAR)AdapterInfo);
1382
1383   ExFreePool(Srb.DataBuffer);
1384
1385   DeviceExtension->Initializing = FALSE;
1386
1387   /* copy inquiry data to the port driver's device extension */
1388   DeviceExtension->PortBusInfoSize = DataSize;
1389   DeviceExtension->PortBusInfo = ExAllocatePool(NonPagedPool,
1390                                                 DataSize);
1391   RtlCopyMemory(DeviceExtension->PortBusInfo,
1392                 AdapterInfo,
1393                 DataSize);
1394
1395   ExFreePool(AdapterInfo);
1396
1397   DPRINT("ScsiPortInquire() done\n");
1398 }
1399
1400
1401 static BOOLEAN STDCALL
1402 ScsiPortIsr(IN PKINTERRUPT Interrupt,
1403             IN PVOID ServiceContext)
1404 {
1405   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1406   BOOLEAN Result;
1407
1408   DPRINT("ScsiPortIsr() called!\n");
1409
1410   DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext;
1411
1412   Result = DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension);
1413   if (Result == FALSE)
1414     {
1415       return(FALSE);
1416     }
1417
1418   if (DeviceExtension->IrpFlags)
1419     {
1420       IoRequestDpc(DeviceExtension->DeviceObject,
1421                    DeviceExtension->CurrentIrp,
1422                    DeviceExtension);
1423     }
1424
1425   return(TRUE);
1426 }
1427
1428
1429 //    ScsiPortDpcForIsr
1430 //  DESCRIPTION:
1431 //
1432 //  RUN LEVEL:
1433 //
1434 //  ARGUMENTS:
1435 //    IN PKDPC          Dpc
1436 //    IN PDEVICE_OBJECT DpcDeviceObject
1437 //    IN PIRP           DpcIrp
1438 //    IN PVOID          DpcContext
1439 //
1440 static VOID STDCALL
1441 ScsiPortDpcForIsr(IN PKDPC Dpc,
1442                   IN PDEVICE_OBJECT DpcDeviceObject,
1443                   IN PIRP DpcIrp,
1444                   IN PVOID DpcContext)
1445 {
1446   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1447   PIO_STACK_LOCATION IrpStack;
1448   PSCSI_REQUEST_BLOCK Srb;
1449   KIRQL oldIrql;
1450
1451   DPRINT("ScsiPortDpcForIsr(Dpc %p  DpcDeviceObject %p  DpcIrp %p  DpcContext %p)\n",
1452           Dpc, DpcDeviceObject, DpcIrp, DpcContext);
1453
1454   DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DpcContext;
1455
1456   KeAcquireSpinLock(&DeviceExtension->IrpLock, &oldIrql);
1457   if (DeviceExtension->IrpFlags)
1458   {
1459   IrpStack = IoGetCurrentIrpStackLocation(DeviceExtension->CurrentIrp);
1460   Srb = IrpStack->Parameters.Scsi.Srb;
1461
1462   if (DeviceExtension->OriginalSrb != NULL)
1463     {
1464       DPRINT("Got sense data!\n");
1465
1466       DPRINT("Valid: %x\n", DeviceExtension->InternalSenseData.Valid);
1467       DPRINT("ErrorCode: %x\n", DeviceExtension->InternalSenseData.ErrorCode);
1468       DPRINT("SenseKey: %x\n", DeviceExtension->InternalSenseData.SenseKey);
1469       DPRINT("SenseCode: %x\n", DeviceExtension->InternalSenseData.AdditionalSenseCode);
1470
1471       /* Copy sense data */
1472       if (DeviceExtension->OriginalSrb->SenseInfoBufferLength != 0)
1473         {
1474           RtlCopyMemory(DeviceExtension->OriginalSrb->SenseInfoBuffer,
1475                         &DeviceExtension->InternalSenseData,
1476                         sizeof(SENSE_DATA));
1477           DeviceExtension->OriginalSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
1478         }
1479
1480       /* Clear current sense data */
1481       RtlZeroMemory(&DeviceExtension->InternalSenseData, sizeof(SENSE_DATA));
1482
1483       IrpStack->Parameters.Scsi.Srb = DeviceExtension->OriginalSrb;
1484       DeviceExtension->OriginalSrb = NULL;
1485     }
1486   else if ((SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) &&
1487            (Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION))
1488     {
1489       DPRINT("SCSIOP_REQUEST_SENSE required!\n");
1490
1491       DeviceExtension->OriginalSrb = Srb;
1492       IrpStack->Parameters.Scsi.Srb = ScsiPortInitSenseRequestSrb(DeviceExtension,
1493                                                                   Srb);
1494       KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1495       if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
1496                                   ScsiPortStartPacket,
1497                                   DeviceExtension))
1498         {
1499           DPRINT("Synchronization failed!\n");
1500
1501           DpcIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
1502           DpcIrp->IoStatus.Information = 0;
1503           IoCompleteRequest(DpcIrp,
1504                             IO_NO_INCREMENT);
1505           IoStartNextPacket(DpcDeviceObject,
1506                             FALSE);
1507         }
1508
1509       return;
1510     }
1511
1512   DeviceExtension->CurrentIrp = NULL;
1513
1514
1515 //  DpcIrp->IoStatus.Information = 0;
1516 //  DpcIrp->IoStatus.Status = STATUS_SUCCESS;
1517
1518   if (DeviceExtension->IrpFlags & IRP_FLAG_COMPLETE)
1519     {
1520       DeviceExtension->IrpFlags &= ~IRP_FLAG_COMPLETE;
1521       IoCompleteRequest(DpcIrp, IO_NO_INCREMENT);
1522     }
1523
1524   if (DeviceExtension->IrpFlags & IRP_FLAG_NEXT)
1525     {
1526       DeviceExtension->IrpFlags &= ~IRP_FLAG_NEXT;
1527       KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1528       IoStartNextPacket(DpcDeviceObject, FALSE);
1529     }
1530     else
1531     {
1532       KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1533     }
1534   }
1535   else
1536   {
1537     KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1538   }
1539   DPRINT("ScsiPortDpcForIsr() done\n");
1540 }
1541
1542
1543 //    ScsiPortIoTimer
1544 //  DESCRIPTION:
1545 //    This function handles timeouts and other time delayed processing
1546 //
1547 //  RUN LEVEL:
1548 //
1549 //  ARGUMENTS:
1550 //    IN  PDEVICE_OBJECT  DeviceObject  Device object registered with timer
1551 //    IN  PVOID           Context       the Controller extension for the
1552 //                                      controller the device is on
1553 //
1554 static VOID STDCALL
1555 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
1556                 PVOID Context)
1557 {
1558   DPRINT1("ScsiPortIoTimer()\n");
1559 }
1560
1561
1562 static PSCSI_REQUEST_BLOCK
1563 ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1564                             PSCSI_REQUEST_BLOCK OriginalSrb)
1565 {
1566   PSCSI_REQUEST_BLOCK Srb;
1567   PCDB Cdb;
1568
1569   Srb = &DeviceExtension->InternalSrb;
1570
1571   RtlZeroMemory(Srb,
1572                 sizeof(SCSI_REQUEST_BLOCK));
1573
1574   Srb->PathId = OriginalSrb->PathId;
1575   Srb->TargetId = OriginalSrb->TargetId;
1576   Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1577   Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
1578   Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
1579
1580   Srb->TimeOutValue = 4;
1581
1582   Srb->CdbLength = 6;
1583   Srb->DataBuffer = &DeviceExtension->InternalSenseData;
1584   Srb->DataTransferLength = sizeof(SENSE_DATA);
1585
1586   Cdb = (PCDB)Srb->Cdb;
1587   Cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE;
1588   Cdb->CDB6INQUIRY.AllocationLength = sizeof(SENSE_DATA);
1589
1590   return(Srb);
1591 }
1592
1593
1594 static VOID
1595 ScsiPortFreeSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
1596 {
1597   DeviceExtension->OriginalSrb = NULL;
1598 }
1599
1600
1601 /**********************************************************************
1602  * NAME                                                 INTERNAL
1603  *      ScsiPortBuildDeviceMap
1604  *
1605  * DESCRIPTION
1606  *      Builds the registry device map of all device which are attached
1607  *      to the given SCSI HBA port. The device map is located at:
1608  *        \Registry\Machine\DeviceMap\Scsi
1609  *
1610  * RUN LEVEL
1611  *      PASSIVE_LEVEL
1612  *
1613  * ARGUMENTS
1614  *      DeviceExtension
1615  *              ...
1616  *
1617  *      RegistryPath
1618  *              Name of registry driver service key.
1619  *
1620  * RETURNS
1621  *      NTSTATUS
1622  */
1623
1624 static NTSTATUS
1625 ScsiPortBuildDeviceMap(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1626                        PUNICODE_STRING RegistryPath)
1627 {
1628   OBJECT_ATTRIBUTES ObjectAttributes;
1629   UNICODE_STRING KeyName;
1630   UNICODE_STRING ValueName;
1631   WCHAR NameBuffer[64];
1632   ULONG Disposition;
1633   HANDLE ScsiKey;
1634   HANDLE ScsiPortKey;
1635   HANDLE ScsiBusKey;
1636   HANDLE ScsiInitiatorKey;
1637   HANDLE ScsiTargetKey;
1638   HANDLE ScsiLunKey;
1639   ULONG BusNumber;
1640   UCHAR CurrentTarget;
1641   PSCSI_ADAPTER_BUS_INFO AdapterInfo;
1642   PSCSI_INQUIRY_DATA UnitInfo;
1643   PINQUIRYDATA InquiryData;
1644   PWCHAR DriverName;
1645   ULONG UlongData;
1646   PWCHAR TypeName;
1647   NTSTATUS Status;
1648
1649   DPRINT("ScsiPortBuildDeviceMap() called\n");
1650
1651   if (DeviceExtension == NULL || RegistryPath == NULL)
1652     {
1653       DPRINT1("Invalid parameter\n");
1654       return(STATUS_INVALID_PARAMETER);
1655     }
1656
1657   /* Open or create the 'Scsi' subkey */
1658   RtlInitUnicodeStringFromLiteral(&KeyName,
1659                                   L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
1660   InitializeObjectAttributes(&ObjectAttributes,
1661                              &KeyName,
1662                              OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
1663                              0,
1664                              NULL);
1665   Status = ZwCreateKey(&ScsiKey,
1666                        KEY_ALL_ACCESS,
1667                        &ObjectAttributes,
1668                        0,
1669                        NULL,
1670                        REG_OPTION_VOLATILE,
1671                        &Disposition);
1672   if (!NT_SUCCESS(Status))
1673     {
1674       DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
1675       return(Status);
1676     }
1677
1678   /* Create new 'Scsi Port X' subkey */
1679   DPRINT("Scsi Port %lu\n",
1680          DeviceExtension->PortNumber);
1681
1682   swprintf(NameBuffer,
1683            L"Scsi Port %lu",
1684            DeviceExtension->PortNumber);
1685   RtlInitUnicodeString(&KeyName,
1686                        NameBuffer);
1687   InitializeObjectAttributes(&ObjectAttributes,
1688                              &KeyName,
1689                              0,
1690                              ScsiKey,
1691                              NULL);
1692   Status = ZwCreateKey(&ScsiPortKey,
1693                        KEY_ALL_ACCESS,
1694                        &ObjectAttributes,
1695                        0,
1696                        NULL,
1697                        REG_OPTION_VOLATILE,
1698                        &Disposition);
1699   ZwClose(ScsiKey);
1700   if (!NT_SUCCESS(Status))
1701     {
1702       DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
1703       return(Status);
1704     }
1705
1706   /*
1707    * Create port-specific values
1708    */
1709
1710   /* Set 'DMA Enabled' (REG_DWORD) value */
1711   UlongData = (ULONG)!DeviceExtension->PortCapabilities->AdapterUsesPio;
1712   DPRINT("  DMA Enabled = %s\n", (UlongData) ? "TRUE" : "FALSE");
1713   RtlInitUnicodeString(&ValueName,
1714                        L"DMA Enabled");
1715   Status = ZwSetValueKey(ScsiPortKey,
1716                          &ValueName,
1717                          0,
1718                          REG_DWORD,
1719                          &UlongData,
1720                          sizeof(ULONG));
1721   if (!NT_SUCCESS(Status))
1722     {
1723       DPRINT("ZwSetValueKey('DMA Enabled') failed (Status %lx)\n", Status);
1724       ZwClose(ScsiPortKey);
1725       return(Status);
1726     }
1727
1728   /* Set 'Driver' (REG_SZ) value */
1729   DriverName = wcsrchr(RegistryPath->Buffer, L'\\') + 1;
1730   DPRINT("  Driver = '%S'\n", DriverName);
1731   RtlInitUnicodeString(&ValueName,
1732                        L"Driver");
1733   Status = ZwSetValueKey(ScsiPortKey,
1734                          &ValueName,
1735                          0,
1736                          REG_SZ,
1737                          DriverName,
1738                          wcslen(DriverName) * sizeof(WCHAR));
1739   if (!NT_SUCCESS(Status))
1740     {
1741       DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status);
1742       ZwClose(ScsiPortKey);
1743       return(Status);
1744     }
1745
1746   /* Set 'Interrupt' (REG_DWORD) value (NT4 only) */
1747   UlongData = (ULONG)DeviceExtension->PortConfig.BusInterruptLevel;
1748   DPRINT("  Interrupt = %lu\n", UlongData);
1749   RtlInitUnicodeString(&ValueName,
1750                        L"Interrupt");
1751   Status = ZwSetValueKey(ScsiPortKey,
1752                          &ValueName,
1753                          0,
1754                          REG_DWORD,
1755                          &UlongData,
1756                          sizeof(ULONG));
1757   if (!NT_SUCCESS(Status))
1758     {
1759       DPRINT("ZwSetValueKey('Interrupt') failed (Status %lx)\n", Status);
1760       ZwClose(ScsiPortKey);
1761       return(Status);
1762     }
1763
1764   /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
1765   UlongData = ScsiPortConvertPhysicalAddressToUlong(DeviceExtension->PortConfig.AccessRanges[0].RangeStart);
1766   DPRINT("  IOAddress = %lx\n", UlongData);
1767   RtlInitUnicodeString(&ValueName,
1768                        L"IOAddress");
1769   Status = ZwSetValueKey(ScsiPortKey,
1770                          &ValueName,
1771                          0,
1772                          REG_DWORD,
1773                          &UlongData,
1774                          sizeof(ULONG));
1775   if (!NT_SUCCESS(Status))
1776     {
1777       DPRINT("ZwSetValueKey('IOAddress') failed (Status %lx)\n", Status);
1778       ZwClose(ScsiPortKey);
1779       return(Status);
1780     }
1781
1782   /* Enumerate buses */
1783   for (BusNumber = 0; BusNumber < DeviceExtension->PortConfig.NumberOfBuses; BusNumber++)
1784     {
1785       /* Create 'Scsi Bus X' key */
1786       DPRINT("    Scsi Bus %lu\n", BusNumber);
1787       swprintf(NameBuffer,
1788                L"Scsi Bus %lu",
1789                BusNumber);
1790       RtlInitUnicodeString(&KeyName,
1791                            NameBuffer);
1792       InitializeObjectAttributes(&ObjectAttributes,
1793                                  &KeyName,
1794                                  0,
1795                                  ScsiPortKey,
1796                                  NULL);
1797       Status = ZwCreateKey(&ScsiBusKey,
1798                            KEY_ALL_ACCESS,
1799                            &ObjectAttributes,
1800                            0,
1801                            NULL,
1802                            REG_OPTION_VOLATILE,
1803                            &Disposition);
1804       if (!NT_SUCCESS(Status))
1805         {
1806           DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
1807           ZwClose(ScsiPortKey);
1808           return(Status);
1809         }
1810
1811       /* Create 'Initiator Id X' key */
1812       DPRINT("      Initiator Id %u\n",
1813               DeviceExtension->PortConfig.InitiatorBusId[BusNumber]);
1814       swprintf(NameBuffer,
1815                L"Initiator Id %u",
1816                DeviceExtension->PortConfig.InitiatorBusId[BusNumber]);
1817       RtlInitUnicodeString(&KeyName,
1818                            NameBuffer);
1819       InitializeObjectAttributes(&ObjectAttributes,
1820                                  &KeyName,
1821                                  0,
1822                                  ScsiBusKey,
1823                                  NULL);
1824       Status = ZwCreateKey(&ScsiInitiatorKey,
1825                            KEY_ALL_ACCESS,
1826                            &ObjectAttributes,
1827                            0,
1828                            NULL,
1829                            REG_OPTION_VOLATILE,
1830                            &Disposition);
1831       if (!NT_SUCCESS(Status))
1832         {
1833           DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
1834           ZwClose(ScsiBusKey);
1835           ZwClose(ScsiPortKey);
1836           return(Status);
1837         }
1838
1839       /* FIXME: Are there any initiator values (??) */
1840
1841       ZwClose(ScsiInitiatorKey);
1842
1843
1844       /* Enumerate targets */
1845       CurrentTarget = (UCHAR)-1;
1846       ScsiTargetKey = NULL;
1847       AdapterInfo = (PSCSI_ADAPTER_BUS_INFO)DeviceExtension->PortBusInfo;
1848       if (AdapterInfo->BusData[BusNumber].NumberOfLogicalUnits != 0)
1849         {
1850           UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo +
1851             AdapterInfo->BusData[BusNumber].InquiryDataOffset);
1852
1853           while (AdapterInfo->BusData[BusNumber].InquiryDataOffset)
1854             {
1855               if (UnitInfo->TargetId != CurrentTarget)
1856                 {
1857                   /* Close old target key */
1858                   if (ScsiTargetKey != NULL)
1859                     {
1860                       ZwClose(ScsiTargetKey);
1861                       ScsiTargetKey = NULL;
1862                     }
1863
1864                   /* Create 'Target Id X' key */
1865                   DPRINT("      Target Id %u\n",
1866                          UnitInfo->TargetId);
1867                   swprintf(NameBuffer,
1868                            L"Target Id %u",
1869                            UnitInfo->TargetId);
1870                   RtlInitUnicodeString(&KeyName,
1871                                        NameBuffer);
1872                   InitializeObjectAttributes(&ObjectAttributes,
1873                                              &KeyName,
1874                                              0,
1875                                              ScsiBusKey,
1876                                              NULL);
1877                   Status = ZwCreateKey(&ScsiTargetKey,
1878                                        KEY_ALL_ACCESS,
1879                                        &ObjectAttributes,
1880                                        0,
1881                                        NULL,
1882                                        REG_OPTION_VOLATILE,
1883                                        &Disposition);
1884                   if (!NT_SUCCESS(Status))
1885                     {
1886                       DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
1887                       ZwClose(ScsiBusKey);
1888                       ZwClose(ScsiPortKey);
1889                       return(Status);
1890                     }
1891
1892                   CurrentTarget = UnitInfo->TargetId;
1893                 }
1894
1895               /* Create 'Logical Unit Id X' key */
1896               DPRINT("        Logical Unit Id %u\n",
1897                      UnitInfo->Lun);
1898               swprintf(NameBuffer,
1899                        L"Logical Unit Id %u",
1900                        UnitInfo->Lun);
1901               RtlInitUnicodeString(&KeyName,
1902                                    NameBuffer);
1903               InitializeObjectAttributes(&ObjectAttributes,
1904                                          &KeyName,
1905                                          0,
1906                                          ScsiTargetKey,
1907                                          NULL);
1908               Status = ZwCreateKey(&ScsiLunKey,
1909                                    KEY_ALL_ACCESS,
1910                                    &ObjectAttributes,
1911                                    0,
1912                                    NULL,
1913                                    REG_OPTION_VOLATILE,
1914                                    &Disposition);
1915               if (!NT_SUCCESS(Status))
1916                 {
1917                   DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
1918                   ZwClose(ScsiTargetKey);
1919                   ZwClose(ScsiBusKey);
1920                   ZwClose(ScsiPortKey);
1921                   return(Status);
1922                 }
1923
1924               /* Set values for logical unit */
1925               InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
1926
1927               /* Set 'Identifier' (REG_SZ) value */
1928               swprintf(NameBuffer,
1929                        L"%.8S%.16S%.4S",
1930                        InquiryData->VendorId,
1931                        InquiryData->ProductId,
1932                        InquiryData->ProductRevisionLevel);
1933               DPRINT("          Identifier = '%S'\n",
1934                      NameBuffer);
1935               RtlInitUnicodeString(&ValueName,
1936                                    L"Identifier");
1937               Status = ZwSetValueKey(ScsiLunKey,
1938                                      &ValueName,
1939                                      0,
1940                                      REG_SZ,
1941                                      NameBuffer,
1942                                      wcslen(NameBuffer) * sizeof(WCHAR));
1943               if (!NT_SUCCESS(Status))
1944                 {
1945                   DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", Status);
1946                   ZwClose(ScsiLunKey);
1947                   ZwClose(ScsiTargetKey);
1948                   ZwClose(ScsiBusKey);
1949                   ZwClose(ScsiPortKey);
1950                   return(Status);
1951                 }
1952
1953               /* Set 'Type' (REG_SZ) value */
1954               switch (InquiryData->DeviceType)
1955                 {
1956                   case 0:
1957                     TypeName = L"DiskPeripheral";
1958                     break;
1959                   case 1:
1960                     TypeName = L"TapePeripheral";
1961                     break;
1962                   case 2:
1963                     TypeName = L"PrinterPeripheral";
1964                     break;
1965                   case 4:
1966                     TypeName = L"WormPeripheral";
1967                     break;
1968                   case 5:
1969                     TypeName = L"CdRomPeripheral";
1970                     break;
1971                   case 6:
1972                     TypeName = L"ScannerPeripheral";
1973                     break;
1974                   case 7:
1975                     TypeName = L"OpticalDiskPeripheral";
1976                     break;
1977                   case 8:
1978                     TypeName = L"MediumChangerPeripheral";
1979                     break;
1980                   case 9:
1981                     TypeName = L"CommunicationPeripheral";
1982                     break;
1983                   default:
1984                     TypeName = L"OtherPeripheral";
1985                     break;
1986                 }
1987               DPRINT("          Type = '%S'\n", TypeName);
1988               RtlInitUnicodeString(&ValueName,
1989                                    L"Type");
1990               Status = ZwSetValueKey(ScsiLunKey,
1991                                      &ValueName,
1992                                      0,
1993                                      REG_SZ,
1994                                      TypeName,
1995                                      wcslen(TypeName) * sizeof(WCHAR));
1996               if (!NT_SUCCESS(Status))
1997                 {
1998                   DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status);
1999                   ZwClose(ScsiLunKey);
2000                   ZwClose(ScsiTargetKey);
2001                   ZwClose(ScsiBusKey);
2002                   ZwClose(ScsiPortKey);
2003                   return(Status);
2004                 }
2005
2006               ZwClose(ScsiLunKey);
2007
2008               if (UnitInfo->NextInquiryDataOffset == 0)
2009                 break;
2010
2011               UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo +
2012                 UnitInfo->NextInquiryDataOffset);
2013             }
2014
2015           /* Close old target key */
2016           if (ScsiTargetKey != NULL)
2017             {
2018               ZwClose(ScsiTargetKey);
2019               ScsiTargetKey = NULL;
2020             }
2021         }
2022
2023         ZwClose(ScsiBusKey);
2024      }
2025
2026   ZwClose(ScsiPortKey);
2027
2028   DPRINT("ScsiPortBuildDeviceMap() done\n");
2029
2030   return(Status);
2031 }
2032
2033 /* EOF */