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