ReactOS  0.4.13-dev-479-gec9c8fd
scsiport.c
Go to the documentation of this file.
1 /*
2  * ReactOS kernel
3  * Copyright (C) 2001, 2002 ReactOS Team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 /*
20  * COPYRIGHT: See COPYING in the top level directory
21  * PROJECT: ReactOS Storage Stack
22  * FILE: drivers/storage/scsiport/scsiport.c
23  * PURPOSE: SCSI port driver
24  * PROGRAMMER: Eric Kohl
25  * Aleksey Bragin (aleksey reactos org)
26  */
27 
28 /* INCLUDES *****************************************************************/
29 
30 #include "precomp.h"
31 
32 #include <ntddk.h>
33 #include <stdio.h>
34 #include <scsi.h>
35 #include <ntddscsi.h>
36 #include <ntdddisk.h>
37 #include <mountdev.h>
38 
39 #define NDEBUG
40 #include <debug.h>
41 
42 #include "scsiport_int.h"
43 
45 
46 #undef ScsiPortMoveMemory
47 
48 /* GLOBALS *******************************************************************/
49 
50 static BOOLEAN
57  IN OUT PPCI_SLOT_NUMBER NextSlotNumber);
58 
59 static NTSTATUS NTAPI
61  IN PIRP Irp);
62 
64 static NTSTATUS NTAPI
66  IN PIRP Irp);
67 
68 static NTSTATUS NTAPI
70  IN PIRP Irp);
71 
72 static DRIVER_STARTIO ScsiPortStartIo;
73 static VOID NTAPI
75  IN PIRP Irp);
76 
77 static BOOLEAN NTAPI
79 
81 NTAPI
84 
87 
90  IN UCHAR PathId,
92  IN UCHAR Lun);
93 
96  PSCSI_PORT_LUN_EXTENSION LunExtension,
98 
99 static NTSTATUS
101  IN OUT PSCSI_LUN_INFO LunInfo);
102 
103 static VOID
105 
106 static NTSTATUS
108  IN PIRP Irp);
109 
112  IN UCHAR PathId,
113  IN UCHAR TargetId,
114  IN UCHAR Lun,
115  IN UCHAR QueueTag);
116 
117 static BOOLEAN NTAPI
118 ScsiPortIsr(IN PKINTERRUPT Interrupt,
120 
121 static VOID NTAPI
123  IN PDEVICE_OBJECT DpcDeviceObject,
124  IN PIRP DpcIrp,
125  IN PVOID DpcContext);
126 
127 static VOID NTAPI
129  PVOID Context);
130 
132 NTAPI
134  IN PIRP Irp,
136  IN PVOID Context);
137 
138 static NTSTATUS
141 
142 static NTSTATUS
143 SpiStatusSrbToNt(UCHAR SrbStatus);
144 
145 static VOID
148 
149 static IO_COMPLETION_ROUTINE SpiCompletionRoutine;
152  PIRP Irp,
153  PVOID Context);
154 
155 static VOID
156 NTAPI
159  OUT PBOOLEAN NeedToCallStartIo);
160 
161 VOID NTAPI
163  IN PSCSI_PORT_LUN_EXTENSION LunExtension);
164 
165 VOID NTAPI
170 
171 static NTSTATUS
173  PHW_INITIALIZATION_DATA HwInitData,
174  PCONFIGURATION_INFO InternalConfigInfo,
176  BOOLEAN FirstCall);
177 
180  IN PUNICODE_STRING PathName,
183  IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
184  IN CONFIGURATION_TYPE ControllerType,
185  IN ULONG ControllerNumber,
186  IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
187  IN CONFIGURATION_TYPE PeripheralType,
188  IN ULONG PeripheralNumber,
189  IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation);
190 
191 static VOID
193  IN HANDLE Key,
195  IN PCONFIGURATION_INFO InternalConfigInfo,
196  IN PUCHAR Buffer);
197 
198 static VOID
200  IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor,
202 
203 static PCM_RESOURCE_LIST
206 
207 static VOID
209 
210 static NTSTATUS
212  PIRP Irp);
213 
214 static NTSTATUS
215 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, ULONG NonCachedSize);
216 
220 
221 /* FUNCTIONS *****************************************************************/
222 
223 /**********************************************************************
224  * NAME EXPORTED
225  * DriverEntry
226  *
227  * DESCRIPTION
228  * This function initializes the driver.
229  *
230  * RUN LEVEL
231  * PASSIVE_LEVEL
232  *
233  * ARGUMENTS
234  * DriverObject
235  * System allocated Driver Object for this driver.
236  *
237  * RegistryPath
238  * Name of registry driver service key.
239  *
240  * RETURN VALUE
241  * Status.
242  */
243 
247 {
248  DPRINT("ScsiPort Driver %s\n", VERSION);
249  return(STATUS_SUCCESS);
250 }
251 
252 
253 /**********************************************************************
254  * NAME EXPORTED
255  * ScsiDebugPrint
256  *
257  * DESCRIPTION
258  * Prints debugging messages.
259  *
260  * RUN LEVEL
261  * PASSIVE_LEVEL
262  *
263  * ARGUMENTS
264  * DebugPrintLevel
265  * Debug level of the given message.
266  *
267  * DebugMessage
268  * Pointer to printf()-compatible format string.
269  *
270  * ...
271  Additional output data (see printf()).
272  *
273  * RETURN VALUE
274  * None.
275  *
276  * @implemented
277  */
278 
279 VOID
280 ScsiDebugPrint(IN ULONG DebugPrintLevel,
281  IN PCHAR DebugMessage,
282  ...)
283 {
284  char Buffer[256];
285  va_list ap;
286 
287  if (DebugPrintLevel > InternalDebugLevel)
288  return;
289 
290  va_start(ap, DebugMessage);
291  vsprintf(Buffer, DebugMessage, ap);
292  va_end(ap);
293 
294  DbgPrint(Buffer);
295 }
296 
297 /* An internal helper function for ScsiPortCompleteRequest */
298 VOID
299 NTAPI
300 SpiCompleteRequest(IN PVOID HwDeviceExtension,
302  IN UCHAR SrbStatus)
303 {
305 
306  /* Get current SRB */
307  Srb = SrbInfo->Srb;
308 
309  /* Return if there is no SRB or it is not active */
310  if (!Srb || !(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE)) return;
311 
312  /* Set status */
313  Srb->SrbStatus = SrbStatus;
314 
315  /* Set data transfered to 0 */
316  Srb->DataTransferLength = 0;
317 
318  /* Notify */
320  HwDeviceExtension,
321  Srb);
322 }
323 
324 /*
325  * @unimplemented
326  */
327 VOID NTAPI
328 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension,
329  IN UCHAR PathId,
330  IN UCHAR TargetId,
331  IN UCHAR Lun,
332  IN UCHAR SrbStatus)
333 {
334  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
335  PSCSI_PORT_LUN_EXTENSION LunExtension;
336  PSCSI_REQUEST_BLOCK_INFO SrbInfo;
337  PLIST_ENTRY ListEntry;
339  ULONG Target;
340 
341  DPRINT("ScsiPortCompleteRequest() called\n");
342 
343  DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
345  MiniPortDeviceExtension);
346 
347  /* Go through all buses */
348  for (BusNumber = 0; BusNumber < 8; BusNumber++)
349  {
350  /* Go through all targets */
351  for (Target = 0; Target < DeviceExtension->MaxTargedIds; Target++)
352  {
353  /* Get logical unit list head */
354  LunExtension = DeviceExtension->LunExtensionList[Target % 8];
355 
356  /* Go through all logical units */
357  while (LunExtension)
358  {
359  /* Now match what caller asked with what we are at now */
360  if ((PathId == SP_UNTAGGED || PathId == LunExtension->PathId) &&
361  (TargetId == SP_UNTAGGED || TargetId == LunExtension->TargetId) &&
362  (Lun == SP_UNTAGGED || Lun == LunExtension->Lun))
363  {
364  /* Yes, that's what caller asked for. Complete abort requests */
365  if (LunExtension->CompletedAbortRequests)
366  {
367  /* TODO: Save SrbStatus in this request */
368  DPRINT1("Completing abort request without setting SrbStatus!\n");
369 
370  /* Issue a notification request */
372  HwDeviceExtension,
373  LunExtension->CompletedAbortRequests);
374  }
375 
376  /* Complete the request using our helper */
377  SpiCompleteRequest(HwDeviceExtension,
378  &LunExtension->SrbInfo,
379  SrbStatus);
380 
381  /* Go through the queue and complete everything there too */
382  ListEntry = LunExtension->SrbInfo.Requests.Flink;
383  while (ListEntry != &LunExtension->SrbInfo.Requests)
384  {
385  /* Get the actual SRB info entry */
386  SrbInfo = CONTAINING_RECORD(ListEntry,
388  Requests);
389 
390  /* Complete it */
391  SpiCompleteRequest(HwDeviceExtension,
392  SrbInfo,
393  SrbStatus);
394 
395  /* Advance to the next request in queue */
396  ListEntry = SrbInfo->Requests.Flink;
397  }
398  }
399 
400  /* Advance to the next one */
401  LunExtension = LunExtension->Next;
402  }
403  }
404  }
405 }
406 
407 /*
408  * @unimplemented
409  */
410 VOID NTAPI
411 ScsiPortFlushDma(IN PVOID HwDeviceExtension)
412 {
413  DPRINT("ScsiPortFlushDma()\n");
415 }
416 
417 
418 /*
419  * @implemented
420  */
421 VOID NTAPI
422 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension,
423  IN PVOID MappedAddress)
424 {
425  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
426  PMAPPED_ADDRESS NextMa, LastMa;
427 
428  //DPRINT("ScsiPortFreeDeviceBase() called\n");
429 
430  DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
432  MiniPortDeviceExtension);
433 
434  /* Initialize our pointers */
435  NextMa = DeviceExtension->MappedAddressList;
436  LastMa = NextMa;
437 
438  while (NextMa)
439  {
440  if (NextMa->MappedAddress == MappedAddress)
441  {
442  /* Unmap it first */
443  MmUnmapIoSpace(MappedAddress, NextMa->NumberOfBytes);
444 
445  /* Remove it from the list */
446  if (NextMa == DeviceExtension->MappedAddressList)
447  {
448  /* Remove the first entry */
449  DeviceExtension->MappedAddressList = NextMa->NextMappedAddress;
450  }
451  else
452  {
453  LastMa->NextMappedAddress = NextMa->NextMappedAddress;
454  }
455 
456  /* Free the resources and quit */
457  ExFreePool(NextMa);
458 
459  return;
460  }
461  else
462  {
463  LastMa = NextMa;
464  NextMa = NextMa->NextMappedAddress;
465  }
466  }
467 }
468 
469 
470 /*
471  * @implemented
472  */
473 ULONG NTAPI
474 ScsiPortGetBusData(IN PVOID DeviceExtension,
475  IN ULONG BusDataType,
476  IN ULONG SystemIoBusNumber,
478  IN PVOID Buffer,
479  IN ULONG Length)
480 {
481  DPRINT("ScsiPortGetBusData()\n");
482 
483  if (Length)
484  {
485  /* If Length is non-zero, just forward the call to
486  HalGetBusData() function */
487  return HalGetBusData(BusDataType,
488  SystemIoBusNumber,
489  SlotNumber,
490  Buffer,
491  Length);
492  }
493 
494  /* We have a more complex case here */
496  return 0;
497 }
498 
499 /*
500  * @implemented
501  */
502 ULONG NTAPI
504  IN ULONG BusDataType,
505  IN ULONG SystemIoBusNumber,
507  IN PVOID Buffer,
508  IN ULONG Offset,
509  IN ULONG Length)
510 {
511  DPRINT("ScsiPortSetBusDataByOffset()\n");
512  return HalSetBusDataByOffset(BusDataType,
513  SystemIoBusNumber,
514  SlotNumber,
515  Buffer,
516  Offset,
517  Length);
518 }
519 
520 /*
521  * @implemented
522  */
523 PVOID NTAPI
524 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension,
526  IN ULONG SystemIoBusNumber,
527  IN SCSI_PHYSICAL_ADDRESS IoAddress,
529  IN BOOLEAN InIoSpace)
530 {
531  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
533  PMAPPED_ADDRESS DeviceBase;
535  PVOID MappedAddress;
536 
537  //DPRINT ("ScsiPortGetDeviceBase() called\n");
538 
539  DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
541  MiniPortDeviceExtension);
542 
543  AddressSpace = (ULONG)InIoSpace;
545  SystemIoBusNumber,
546  IoAddress,
547  &AddressSpace,
549  {
550  return NULL;
551  }
552 
553  /* i/o space */
554  if (AddressSpace != 0)
556 
557  MappedAddress = MmMapIoSpace(TranslatedAddress,
559  FALSE);
560 
561  DeviceBase = ExAllocatePoolWithTag(NonPagedPool,
562  sizeof(MAPPED_ADDRESS), TAG_SCSIPORT);
563 
564  if (DeviceBase == NULL)
565  return MappedAddress;
566 
567  DeviceBase->MappedAddress = MappedAddress;
568  DeviceBase->NumberOfBytes = NumberOfBytes;
569  DeviceBase->IoAddress = IoAddress;
570  DeviceBase->BusNumber = SystemIoBusNumber;
571 
572  /* Link it to the Device Extension list */
573  DeviceBase->NextMappedAddress = DeviceExtension->MappedAddressList;
574  DeviceExtension->MappedAddressList = DeviceBase;
575 
576  return MappedAddress;
577 }
578 
579 /*
580  * @unimplemented
581  */
582 PVOID NTAPI
583 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension,
584  IN UCHAR PathId,
585  IN UCHAR TargetId,
586  IN UCHAR Lun)
587 {
588  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
589  PSCSI_PORT_LUN_EXTENSION LunExtension;
590 
591  DPRINT("ScsiPortGetLogicalUnit() called\n");
592 
593  DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
595  MiniPortDeviceExtension);
596 
597  /* Check the extension size */
598  if (!DeviceExtension->LunExtensionSize)
599  {
600  /* They didn't want one */
601  return NULL;
602  }
603 
604  LunExtension = SpiGetLunExtension(DeviceExtension,
605  PathId,
606  TargetId,
607  Lun);
608  /* Check that the logical unit exists */
609  if (!LunExtension)
610  {
611  /* Nope, return NULL */
612  return NULL;
613  }
614 
615  /* Return the logical unit miniport extension */
616  return (LunExtension + 1);
617 }
618 
619 
620 /*
621  * @implemented
622  */
627  OUT ULONG *Length)
628 {
629  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
631  SIZE_T BufferLength = 0;
633  PSCSI_SG_ADDRESS SGList;
634  PSCSI_REQUEST_BLOCK_INFO SrbInfo;
635 
636  DPRINT("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
637  HwDeviceExtension, Srb, VirtualAddress, Length);
638 
639  DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
641  MiniPortDeviceExtension);
642 
643  if (Srb == NULL || Srb->SenseInfoBuffer == VirtualAddress)
644  {
645  /* Simply look it up in the allocated common buffer */
646  Offset = (PUCHAR)VirtualAddress - (PUCHAR)DeviceExtension->SrbExtensionBuffer;
647 
648  BufferLength = DeviceExtension->CommonBufferLength - Offset;
649  PhysicalAddress.QuadPart = DeviceExtension->PhysicalAddress.QuadPart + Offset;
650  }
651  else if (DeviceExtension->MapRegisters)
652  {
653  /* Scatter-gather list must be used */
654  SrbInfo = SpiGetSrbData(DeviceExtension,
655  Srb->PathId,
656  Srb->TargetId,
657  Srb->Lun,
658  Srb->QueueTag);
659 
660  SGList = SrbInfo->ScatterGather;
661 
662  /* Find needed item in the SG list */
663  Offset = (PCHAR)VirtualAddress - (PCHAR)Srb->DataBuffer;
664  while (Offset >= SGList->Length)
665  {
666  Offset -= SGList->Length;
667  SGList++;
668  }
669 
670  /* We're done, store length and physical address */
671  BufferLength = SGList->Length - Offset;
673  }
674  else
675  {
676  /* Nothing */
678  }
679 
681  return PhysicalAddress;
682 }
683 
684 
685 /*
686  * @unimplemented
687  */
689 ScsiPortGetSrb(IN PVOID DeviceExtension,
690  IN UCHAR PathId,
691  IN UCHAR TargetId,
692  IN UCHAR Lun,
693  IN LONG QueueTag)
694 {
695  DPRINT1("ScsiPortGetSrb() unimplemented\n");
697  return NULL;
698 }
699 
700 
701 /*
702  * @implemented
703  */
704 PVOID NTAPI
708 {
709  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
711  ULONG MapRegistersCount;
713 
714  DPRINT("ScsiPortGetUncachedExtension(%p %p %lu)\n",
715  HwDeviceExtension, ConfigInfo, NumberOfBytes);
716 
717  DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
719  MiniPortDeviceExtension);
720 
721  /* Check for allocated common DMA buffer */
722  if (DeviceExtension->SrbExtensionBuffer != NULL)
723  {
724  DPRINT1("The HBA has already got a common DMA buffer!\n");
725  return NULL;
726  }
727 
728  /* Check for DMA adapter object */
729  if (DeviceExtension->AdapterObject == NULL)
730  {
731  /* Initialize DMA adapter description */
733 
735  DeviceDescription.Master = ConfigInfo->Master;
736  DeviceDescription.ScatterGather = ConfigInfo->ScatterGather;
737  DeviceDescription.DemandMode = ConfigInfo->DemandMode;
738  DeviceDescription.Dma32BitAddresses = ConfigInfo->Dma32BitAddresses;
739  DeviceDescription.BusNumber = ConfigInfo->SystemIoBusNumber;
740  DeviceDescription.DmaChannel = ConfigInfo->DmaChannel;
741  DeviceDescription.InterfaceType = ConfigInfo->AdapterInterfaceType;
742  DeviceDescription.DmaWidth = ConfigInfo->DmaWidth;
743  DeviceDescription.DmaSpeed = ConfigInfo->DmaSpeed;
744  DeviceDescription.MaximumLength = ConfigInfo->MaximumTransferLength;
745  DeviceDescription.DmaPort = ConfigInfo->DmaPort;
746 
747  /* Get a DMA adapter object */
748  DeviceExtension->AdapterObject =
749  HalGetAdapter(&DeviceDescription, &MapRegistersCount);
750 
751  /* Fail in case of error */
752  if (DeviceExtension->AdapterObject == NULL)
753  {
754  DPRINT1("HalGetAdapter() failed\n");
755  return NULL;
756  }
757 
758  /* Set number of physical breaks */
759  if (ConfigInfo->NumberOfPhysicalBreaks != 0 &&
760  MapRegistersCount > ConfigInfo->NumberOfPhysicalBreaks)
761  {
762  DeviceExtension->PortCapabilities.MaximumPhysicalPages =
763  ConfigInfo->NumberOfPhysicalBreaks;
764  }
765  else
766  {
767  DeviceExtension->PortCapabilities.MaximumPhysicalPages = MapRegistersCount;
768  }
769  }
770 
771  /* Update auto request sense feature */
772  DeviceExtension->SupportsAutoSense = ConfigInfo->AutoRequestSense;
773 
774  /* Update Srb extension size */
775  if (DeviceExtension->SrbExtensionSize != ConfigInfo->SrbExtensionSize)
776  DeviceExtension->SrbExtensionSize = ConfigInfo->SrbExtensionSize;
777 
778  /* Update Srb extension alloc flag */
779  if (ConfigInfo->AutoRequestSense || DeviceExtension->SrbExtensionSize)
780  DeviceExtension->NeedSrbExtensionAlloc = TRUE;
781 
782  /* Allocate a common DMA buffer */
783  Status = SpiAllocateCommonBuffer(DeviceExtension, NumberOfBytes);
784 
785  if (!NT_SUCCESS(Status))
786  {
787  DPRINT1("SpiAllocateCommonBuffer() failed with Status = 0x%08X!\n", Status);
788  return NULL;
789  }
790 
791  return DeviceExtension->NonCachedExtension;
792 }
793 
794 static NTSTATUS
796 {
797  PVOID *SrbExtension, CommonBuffer;
798  ULONG CommonBufferLength, BufSize;
799 
800  /* If size is 0, set it to 16 */
801  if (!DeviceExtension->SrbExtensionSize)
802  DeviceExtension->SrbExtensionSize = 16;
803 
804  /* Calculate size */
805  BufSize = DeviceExtension->SrbExtensionSize;
806 
807  /* Add autosense data size if needed */
808  if (DeviceExtension->SupportsAutoSense)
809  BufSize += sizeof(SENSE_DATA);
810 
811 
812  /* Round it */
813  BufSize = (BufSize + sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1);
814 
815  /* Sum up into the total common buffer length, and round it to page size */
816  CommonBufferLength =
817  ROUND_TO_PAGES(NonCachedSize + BufSize * DeviceExtension->RequestsNumber);
818 
819  /* Allocate it */
820  if (!DeviceExtension->AdapterObject)
821  {
822  /* From nonpaged pool if there is no DMA */
823  CommonBuffer = ExAllocatePoolWithTag(NonPagedPool, CommonBufferLength, TAG_SCSIPORT);
824  }
825  else
826  {
827  /* Perform a full request since we have a DMA adapter*/
828  CommonBuffer = HalAllocateCommonBuffer(DeviceExtension->AdapterObject,
829  CommonBufferLength,
830  &DeviceExtension->PhysicalAddress,
831  FALSE );
832  }
833 
834  /* Fail in case of error */
835  if (!CommonBuffer)
837 
838  /* Zero it */
839  RtlZeroMemory(CommonBuffer, CommonBufferLength);
840 
841  /* Store its size in Device Extension */
842  DeviceExtension->CommonBufferLength = CommonBufferLength;
843 
844  /* SrbExtension buffer is located at the beginning of the buffer */
845  DeviceExtension->SrbExtensionBuffer = CommonBuffer;
846 
847  /* Non-cached extension buffer is located at the end of
848  the common buffer */
849  if (NonCachedSize)
850  {
851  CommonBufferLength -= NonCachedSize;
852  DeviceExtension->NonCachedExtension = (PUCHAR)CommonBuffer + CommonBufferLength;
853  }
854  else
855  {
856  DeviceExtension->NonCachedExtension = NULL;
857  }
858 
859  if (DeviceExtension->NeedSrbExtensionAlloc)
860  {
861  /* Look up how many SRB data structures we need */
862  DeviceExtension->SrbDataCount = CommonBufferLength / BufSize;
863 
864  /* Initialize the free SRB extensions list */
865  SrbExtension = (PVOID *)CommonBuffer;
866  DeviceExtension->FreeSrbExtensions = SrbExtension;
867 
868  /* Fill the remaining pointers (if we have more than 1 SRB) */
869  while (CommonBufferLength >= 2 * BufSize)
870  {
871  *SrbExtension = (PVOID*)((PCHAR)SrbExtension + BufSize);
872  SrbExtension = *SrbExtension;
873 
874  CommonBufferLength -= BufSize;
875  }
876  }
877 
878  return STATUS_SUCCESS;
879 }
880 
881 
882 
883 /*
884  * @implemented
885  */
886 PVOID NTAPI
889 {
890  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
891  ULONG Offset;
892 
893  DPRINT("ScsiPortGetVirtualAddress(%p %I64x)\n",
894  HwDeviceExtension, PhysicalAddress.QuadPart);
895 
896  DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
898  MiniPortDeviceExtension);
899 
900  if (DeviceExtension->PhysicalAddress.QuadPart > PhysicalAddress.QuadPart)
901  return NULL;
902 
903  Offset = (ULONG)(PhysicalAddress.QuadPart - DeviceExtension->PhysicalAddress.QuadPart);
904 
905  if (Offset >= DeviceExtension->CommonBufferLength)
906  return NULL;
907 
908  return (PVOID)((ULONG_PTR)DeviceExtension->SrbExtensionBuffer + Offset);
909 }
910 
911 static VOID
913 {
917 
918  /* Open the service key */
920  RegistryPath,
922  NULL,
923  NULL);
924 
925  Status = ZwOpenKey(&ConfigInfo->ServiceKey,
926  KEY_READ,
928 
929  if (!NT_SUCCESS(Status))
930  {
931  DPRINT("Unable to open driver's registry key %wZ, status 0x%08x\n", RegistryPath, Status);
932  ConfigInfo->ServiceKey = NULL;
933  }
934 
935  /* If we could open driver's service key, then proceed to the Parameters key */
936  if (ConfigInfo->ServiceKey != NULL)
937  {
938  RtlInitUnicodeString(&KeyName, L"Parameters");
940  &KeyName,
942  ConfigInfo->ServiceKey,
944 
945  /* Try to open it */
946  Status = ZwOpenKey(&ConfigInfo->DeviceKey,
947  KEY_READ,
949 
950  if (NT_SUCCESS(Status))
951  {
952  /* Yes, Parameters key exist, and it must be used instead of
953  the Service key */
954  ZwClose(ConfigInfo->ServiceKey);
955  ConfigInfo->ServiceKey = ConfigInfo->DeviceKey;
956  ConfigInfo->DeviceKey = NULL;
957  }
958  }
959 
960  if (ConfigInfo->ServiceKey != NULL)
961  {
962  /* Open the Device key */
963  RtlInitUnicodeString(&KeyName, L"Device");
965  &KeyName,
967  ConfigInfo->ServiceKey,
968  NULL);
969 
970  /* We don't check for failure here - not needed */
971  ZwOpenKey(&ConfigInfo->DeviceKey,
972  KEY_READ,
974  }
975 }
976 
977 
978 /**********************************************************************
979  * NAME EXPORTED
980  * ScsiPortInitialize
981  *
982  * DESCRIPTION
983  * Initializes SCSI port driver specific data.
984  *
985  * RUN LEVEL
986  * PASSIVE_LEVEL
987  *
988  * ARGUMENTS
989  * Argument1
990  * Pointer to the miniport driver's driver object.
991  *
992  * Argument2
993  * Pointer to the miniport driver's registry path.
994  *
995  * HwInitializationData
996  * Pointer to port driver specific configuration data.
997  *
998  * HwContext
999  Miniport driver specific context.
1000  *
1001  * RETURN VALUE
1002  * Status.
1003  *
1004  * @implemented
1005  */
1006 
1007 ULONG NTAPI
1009  IN PVOID Argument2,
1011  IN PVOID HwContext)
1012 {
1015  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = NULL;
1016  PCONFIGURATION_INFORMATION SystemConfig;
1018  PORT_CONFIGURATION_INFORMATION InitialPortConfig;
1019  CONFIGURATION_INFO ConfigInfo;
1020  ULONG DeviceExtensionSize;
1021  ULONG PortConfigSize;
1022  BOOLEAN Again;
1023  BOOLEAN DeviceFound = FALSE;
1024  BOOLEAN FirstConfigCall = TRUE;
1025  ULONG Result;
1026  NTSTATUS Status;
1027  ULONG MaxBus;
1029 
1030  PDEVICE_OBJECT PortDeviceObject;
1031  WCHAR NameBuffer[80];
1033  WCHAR DosNameBuffer[80];
1035  PIO_SCSI_CAPABILITIES PortCapabilities;
1036 
1037  KIRQL OldIrql;
1039  BOOLEAN Conflict;
1040  SIZE_T BusConfigSize;
1041 
1042 
1043  DPRINT ("ScsiPortInitialize() called!\n");
1044 
1045  /* Check params for validity */
1046  if ((HwInitializationData->HwInitialize == NULL) ||
1047  (HwInitializationData->HwStartIo == NULL) ||
1048  (HwInitializationData->HwInterrupt == NULL) ||
1049  (HwInitializationData->HwFindAdapter == NULL) ||
1050  (HwInitializationData->HwResetBus == NULL))
1051  {
1052  return STATUS_INVALID_PARAMETER;
1053  }
1054 
1055  /* Set handlers */
1061 
1062  /* Obtain configuration information */
1063  SystemConfig = IoGetConfigurationInformation();
1064 
1065  /* Zero the internal configuration info structure */
1066  RtlZeroMemory(&ConfigInfo, sizeof(CONFIGURATION_INFO));
1067 
1068  /* Zero starting slot number */
1069  SlotNumber.u.AsULONG = 0;
1070 
1071  /* Allocate space for access ranges */
1072  if (HwInitializationData->NumberOfAccessRanges)
1073  {
1074  ConfigInfo.AccessRanges =
1076  HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE), TAG_SCSIPORT);
1077 
1078  /* Fail if failed */
1079  if (ConfigInfo.AccessRanges == NULL)
1081  }
1082 
1083  /* Open registry keys */
1084  SpiInitOpenKeys(&ConfigInfo, (PUNICODE_STRING)Argument2);
1085 
1086  /* Last adapter number = not known */
1088 
1089  /* Calculate sizes of DeviceExtension and PortConfig */
1090  DeviceExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) +
1091  HwInitializationData->DeviceExtensionSize;
1092 
1093  MaxBus = (HwInitializationData->AdapterInterfaceType == PCIBus) ? 8 : 1;
1094  DPRINT("MaxBus: %lu\n", MaxBus);
1095 
1096  while (TRUE)
1097  {
1098  /* Create a unicode device name */
1099  swprintf(NameBuffer,
1100  L"\\Device\\ScsiPort%lu",
1101  SystemConfig->ScsiPortCount);
1102  RtlInitUnicodeString(&DeviceName, NameBuffer);
1103 
1104  DPRINT("Creating device: %wZ\n", &DeviceName);
1105 
1106  /* Create the port device */
1108  DeviceExtensionSize,
1109  &DeviceName,
1111  0,
1112  FALSE,
1113  &PortDeviceObject);
1114 
1115  if (!NT_SUCCESS(Status))
1116  {
1117  DPRINT1("IoCreateDevice call failed! (Status 0x%lX)\n", Status);
1118  PortDeviceObject = NULL;
1119  break;
1120  }
1121 
1122  DPRINT ("Created device: %wZ (%p)\n", &DeviceName, PortDeviceObject);
1123 
1124  /* Set the buffering strategy here... */
1125  PortDeviceObject->Flags |= DO_DIRECT_IO;
1126  PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT; /* FIXME: Is this really needed? */
1127 
1128  /* Fill Device Extension */
1129  DeviceExtension = PortDeviceObject->DeviceExtension;
1130  RtlZeroMemory(DeviceExtension, DeviceExtensionSize);
1131  DeviceExtension->Length = DeviceExtensionSize;
1132  DeviceExtension->DeviceObject = PortDeviceObject;
1133  DeviceExtension->PortNumber = SystemConfig->ScsiPortCount;
1134 
1135  /* Driver's routines... */
1136  DeviceExtension->HwInitialize = HwInitializationData->HwInitialize;
1137  DeviceExtension->HwStartIo = HwInitializationData->HwStartIo;
1138  DeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
1139  DeviceExtension->HwResetBus = HwInitializationData->HwResetBus;
1140  DeviceExtension->HwDmaStarted = HwInitializationData->HwDmaStarted;
1141 
1142  /* Extensions sizes */
1143  DeviceExtension->MiniPortExtensionSize = HwInitializationData->DeviceExtensionSize;
1144  DeviceExtension->LunExtensionSize = HwInitializationData->SpecificLuExtensionSize;
1145  DeviceExtension->SrbExtensionSize = HwInitializationData->SrbExtensionSize;
1146 
1147  /* Round Srb extension size to the quadword */
1148  DeviceExtension->SrbExtensionSize =
1149  ~(sizeof(LONGLONG) - 1) & (DeviceExtension->SrbExtensionSize +
1150  sizeof(LONGLONG) - 1);
1151 
1152  /* Fill some numbers (bus count, lun count, etc) */
1153  DeviceExtension->MaxLunCount = SCSI_MAXIMUM_LOGICAL_UNITS;
1154  DeviceExtension->RequestsNumber = 16;
1155 
1156  /* Initialize the spin lock in the controller extension */
1157  KeInitializeSpinLock(&DeviceExtension->IrqLock);
1158  KeInitializeSpinLock(&DeviceExtension->SpinLock);
1159 
1160  /* Initialize the DPC object */
1161  IoInitializeDpcRequest(PortDeviceObject,
1163 
1164  /* Initialize the device timer */
1165  DeviceExtension->TimerCount = -1;
1166  IoInitializeTimer(PortDeviceObject,
1168  DeviceExtension);
1169 
1170  /* Initialize miniport timer */
1171  KeInitializeTimer(&DeviceExtension->MiniportTimer);
1172  KeInitializeDpc(&DeviceExtension->MiniportTimerDpc,
1174  PortDeviceObject);
1175 
1176 CreatePortConfig:
1177 
1178  Status = SpiCreatePortConfig(DeviceExtension,
1180  &ConfigInfo,
1181  &InitialPortConfig,
1182  FirstConfigCall);
1183 
1184  if (!NT_SUCCESS(Status))
1185  {
1186  DPRINT("SpiCreatePortConfig() failed with Status 0x%08X\n", Status);
1187  break;
1188  }
1189 
1190  /* Allocate and initialize port configuration info */
1191  PortConfigSize = (sizeof(PORT_CONFIGURATION_INFORMATION) +
1192  HwInitializationData->NumberOfAccessRanges *
1193  sizeof(ACCESS_RANGE) + 7) & ~7;
1194  DeviceExtension->PortConfig = ExAllocatePoolWithTag(NonPagedPool, PortConfigSize, TAG_SCSIPORT);
1195 
1196  /* Fail if failed */
1197  if (DeviceExtension->PortConfig == NULL)
1198  {
1200  break;
1201  }
1202 
1203  PortConfig = DeviceExtension->PortConfig;
1204 
1205  /* Copy information here */
1206  RtlCopyMemory(PortConfig,
1207  &InitialPortConfig,
1209 
1210 
1211  /* Copy extension sizes into the PortConfig */
1212  PortConfig->SpecificLuExtensionSize = DeviceExtension->LunExtensionSize;
1213  PortConfig->SrbExtensionSize = DeviceExtension->SrbExtensionSize;
1214 
1215  /* Initialize Access ranges */
1216  if (HwInitializationData->NumberOfAccessRanges != 0)
1217  {
1218  PortConfig->AccessRanges = (PVOID)(PortConfig+1);
1219 
1220  /* Align to LONGLONG */
1221  PortConfig->AccessRanges = (PVOID)((ULONG_PTR)(PortConfig->AccessRanges) + 7);
1222  PortConfig->AccessRanges = (PVOID)((ULONG_PTR)(PortConfig->AccessRanges) & ~7);
1223 
1224  /* Copy the data */
1225  RtlCopyMemory(PortConfig->AccessRanges,
1226  ConfigInfo.AccessRanges,
1227  HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE));
1228  }
1229 
1230  /* Search for matching PCI device */
1231  if ((HwInitializationData->AdapterInterfaceType == PCIBus) &&
1232  (HwInitializationData->VendorIdLength > 0) &&
1233  (HwInitializationData->VendorId != NULL) &&
1234  (HwInitializationData->DeviceIdLength > 0) &&
1235  (HwInitializationData->DeviceId != NULL))
1236  {
1237  PortConfig->BusInterruptLevel = 0;
1238 
1239  /* Get PCI device data */
1240  DPRINT("VendorId '%.*s' DeviceId '%.*s'\n",
1241  HwInitializationData->VendorIdLength,
1242  HwInitializationData->VendorId,
1243  HwInitializationData->DeviceIdLength,
1244  HwInitializationData->DeviceId);
1245 
1247  PortDeviceObject,
1249  PortConfig,
1250  RegistryPath,
1251  ConfigInfo.BusNumber,
1252  &SlotNumber))
1253  {
1254  /* Continue to the next bus, nothing here */
1255  ConfigInfo.BusNumber++;
1256  DeviceExtension->PortConfig = NULL;
1257  ExFreePool(PortConfig);
1258  Again = FALSE;
1259  goto CreatePortConfig;
1260  }
1261 
1262  if (!PortConfig->BusInterruptLevel)
1263  {
1264  /* Bypass this slot, because no interrupt was assigned */
1265  DeviceExtension->PortConfig = NULL;
1266  ExFreePool(PortConfig);
1267  goto CreatePortConfig;
1268  }
1269  }
1270  else
1271  {
1272  DPRINT("Non-pci bus\n");
1273  }
1274 
1275  /* Note: HwFindAdapter is called once for each bus */
1276  Again = FALSE;
1277  DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber);
1278  Result = (HwInitializationData->HwFindAdapter)(&DeviceExtension->MiniPortDeviceExtension,
1279  HwContext,
1280  0, /* BusInformation */
1281  ConfigInfo.Parameter, /* ArgumentString */
1282  PortConfig,
1283  &Again);
1284 
1285  DPRINT("HwFindAdapter() Result: %lu Again: %s\n",
1286  Result, (Again) ? "True" : "False");
1287 
1288  /* Free MapRegisterBase, it's not needed anymore */
1289  if (DeviceExtension->MapRegisterBase != NULL)
1290  {
1291  ExFreePool(DeviceExtension->MapRegisterBase);
1292  DeviceExtension->MapRegisterBase = NULL;
1293  }
1294 
1295  /* If result is nothing good... */
1296  if (Result != SP_RETURN_FOUND)
1297  {
1298  DPRINT("HwFindAdapter() Result: %lu\n", Result);
1299 
1300  if (Result == SP_RETURN_NOT_FOUND)
1301  {
1302  /* We can continue on the next bus */
1303  ConfigInfo.BusNumber++;
1304  Again = FALSE;
1305 
1306  DeviceExtension->PortConfig = NULL;
1307  ExFreePool(PortConfig);
1308  goto CreatePortConfig;
1309  }
1310 
1311  /* Otherwise, break */
1313  break;
1314  }
1315 
1316  DPRINT("ScsiPortInitialize(): Found HBA! (%x), adapter Id %d\n",
1317  PortConfig->BusInterruptVector, PortConfig->InitiatorBusId[0]);
1318 
1319  /* If the SRB extension size was updated */
1320  if (!DeviceExtension->NonCachedExtension &&
1321  (PortConfig->SrbExtensionSize != DeviceExtension->SrbExtensionSize))
1322  {
1323  /* Set it (rounding to LONGLONG again) */
1324  DeviceExtension->SrbExtensionSize =
1325  (PortConfig->SrbExtensionSize +
1326  sizeof(LONGLONG)) & ~(sizeof(LONGLONG) - 1);
1327  }
1328 
1329  /* The same with LUN extension size */
1330  if (PortConfig->SpecificLuExtensionSize != DeviceExtension->LunExtensionSize)
1331  DeviceExtension->LunExtensionSize = PortConfig->SpecificLuExtensionSize;
1332 
1333 
1334  if (!((HwInitializationData->AdapterInterfaceType == PCIBus) &&
1335  (HwInitializationData->VendorIdLength > 0) &&
1336  (HwInitializationData->VendorId != NULL) &&
1337  (HwInitializationData->DeviceIdLength > 0) &&
1338  (HwInitializationData->DeviceId != NULL)))
1339  {
1340  /* Construct a resource list */
1341  ResourceList = SpiConfigToResource(DeviceExtension,
1342  PortConfig);
1343 
1344  if (ResourceList)
1345  {
1347  RtlInitUnicodeString(&UnicodeString, L"ScsiAdapter");
1348  DPRINT("Reporting resources\n");
1350  DriverObject,
1351  NULL,
1352  0,
1353  PortDeviceObject,
1354  ResourceList,
1356  List[0].PartialResourceList.PartialDescriptors) +
1357  ResourceList->List[0].PartialResourceList.Count
1359  FALSE,
1360  &Conflict);
1362 
1363  /* In case of a failure or a conflict, break */
1364  if (Conflict || (!NT_SUCCESS(Status)))
1365  {
1366  if (Conflict)
1368  break;
1369  }
1370  }
1371  }
1372 
1373  /* Reset the Conflict var */
1374  Conflict = FALSE;
1375 
1376  /* Copy all stuff which we ever need from PortConfig to the DeviceExtension */
1378  DeviceExtension->MaxTargedIds = SCSI_MAXIMUM_TARGETS_PER_BUS;
1379  else
1380  DeviceExtension->MaxTargedIds = PortConfig->MaximumNumberOfTargets;
1381 
1382  DeviceExtension->BusNum = PortConfig->NumberOfBuses;
1383  DeviceExtension->CachesData = PortConfig->CachesData;
1384  DeviceExtension->ReceiveEvent = PortConfig->ReceiveEvent;
1385  DeviceExtension->SupportsTaggedQueuing = PortConfig->TaggedQueuing;
1386  DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu;
1387 
1388  /* If something was disabled via registry - apply it */
1389  if (ConfigInfo.DisableMultipleLun)
1390  DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu = FALSE;
1391 
1392  if (ConfigInfo.DisableTaggedQueueing)
1393  DeviceExtension->SupportsTaggedQueuing = PortConfig->MultipleRequestPerLu = FALSE;
1394 
1395  /* Check if we need to alloc SRB data */
1396  if (DeviceExtension->SupportsTaggedQueuing ||
1397  DeviceExtension->MultipleReqsPerLun)
1398  {
1399  DeviceExtension->NeedSrbDataAlloc = TRUE;
1400  }
1401  else
1402  {
1403  DeviceExtension->NeedSrbDataAlloc = FALSE;
1404  }
1405 
1406  /* Get a pointer to the port capabilities */
1407  PortCapabilities = &DeviceExtension->PortCapabilities;
1408 
1409  /* Copy one field there */
1410  DeviceExtension->MapBuffers = PortConfig->MapBuffers;
1411  PortCapabilities->AdapterUsesPio = PortConfig->MapBuffers;
1412 
1413  if (DeviceExtension->AdapterObject == NULL &&
1414  (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE || PortConfig->Master))
1415  {
1416  DPRINT1("DMA is not supported yet\n");
1417  ASSERT(FALSE);
1418  }
1419 
1420  if (DeviceExtension->SrbExtensionBuffer == NULL &&
1421  (DeviceExtension->SrbExtensionSize != 0 ||
1422  PortConfig->AutoRequestSense))
1423  {
1424  DeviceExtension->SupportsAutoSense = PortConfig->AutoRequestSense;
1425  DeviceExtension->NeedSrbExtensionAlloc = TRUE;
1426 
1427  /* Allocate common buffer */
1428  Status = SpiAllocateCommonBuffer(DeviceExtension, 0);
1429 
1430  /* Check for failure */
1431  if (!NT_SUCCESS(Status))
1432  break;
1433  }
1434 
1435  /* Allocate SrbData, if needed */
1436  if (DeviceExtension->NeedSrbDataAlloc)
1437  {
1438  ULONG Count;
1439  PSCSI_REQUEST_BLOCK_INFO SrbData;
1440 
1441  if (DeviceExtension->SrbDataCount != 0)
1442  Count = DeviceExtension->SrbDataCount;
1443  else
1444  Count = DeviceExtension->RequestsNumber * 2;
1445 
1446  /* Allocate the data */
1448  if (SrbData == NULL)
1450 
1451  RtlZeroMemory(SrbData, Count * sizeof(SCSI_REQUEST_BLOCK_INFO));
1452 
1453  DeviceExtension->SrbInfo = SrbData;
1454  DeviceExtension->FreeSrbInfo = SrbData;
1455  DeviceExtension->SrbDataCount = Count;
1456 
1457  /* Link it to the list */
1458  while (Count > 0)
1459  {
1460  SrbData->Requests.Flink = (PLIST_ENTRY)(SrbData + 1);
1461  SrbData++;
1462  Count--;
1463  }
1464 
1465  /* Mark the last entry of the list */
1466  SrbData--;
1467  SrbData->Requests.Flink = NULL;
1468  }
1469 
1470  /* Initialize port capabilities */
1471  PortCapabilities = &DeviceExtension->PortCapabilities;
1472  PortCapabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
1473  PortCapabilities->MaximumTransferLength = PortConfig->MaximumTransferLength;
1474 
1475  if (PortConfig->ReceiveEvent)
1477 
1478  PortCapabilities->TaggedQueuing = DeviceExtension->SupportsTaggedQueuing;
1479  PortCapabilities->AdapterScansDown = PortConfig->AdapterScansDown;
1480 
1481  if (PortConfig->AlignmentMask > PortDeviceObject->AlignmentRequirement)
1482  PortDeviceObject->AlignmentRequirement = PortConfig->AlignmentMask;
1483 
1484  PortCapabilities->AlignmentMask = PortDeviceObject->AlignmentRequirement;
1485 
1486  if (PortCapabilities->MaximumPhysicalPages == 0)
1487  {
1488  PortCapabilities->MaximumPhysicalPages =
1489  BYTES_TO_PAGES(PortCapabilities->MaximumTransferLength);
1490 
1491  /* Apply miniport's limits */
1492  if (PortConfig->NumberOfPhysicalBreaks < PortCapabilities->MaximumPhysicalPages)
1493  {
1494  PortCapabilities->MaximumPhysicalPages = PortConfig->NumberOfPhysicalBreaks;
1495  }
1496  }
1497 
1498  /* Deal with interrupts */
1499  if (DeviceExtension->HwInterrupt == NULL ||
1500  (PortConfig->BusInterruptLevel == 0 && PortConfig->BusInterruptVector == 0))
1501  {
1502  /* No interrupts */
1503  DeviceExtension->InterruptCount = 0;
1504 
1505  DPRINT1("Interrupt Count: 0\n");
1506 
1507  UNIMPLEMENTED;
1508 
1509  /* This code path will ALWAYS crash so stop it now */
1510  while(TRUE);
1511  }
1512  else
1513  {
1514  BOOLEAN InterruptShareable;
1516  ULONG InterruptVector[2], i, MappedIrq[2];
1517  KIRQL Dirql[2], MaxDirql;
1518  KAFFINITY Affinity[2];
1519 
1520  DeviceExtension->InterruptLevel[0] = PortConfig->BusInterruptLevel;
1521  DeviceExtension->InterruptLevel[1] = PortConfig->BusInterruptLevel2;
1522 
1523  InterruptVector[0] = PortConfig->BusInterruptVector;
1524  InterruptVector[1] = PortConfig->BusInterruptVector2;
1525 
1526  InterruptMode[0] = PortConfig->InterruptMode;
1527  InterruptMode[1] = PortConfig->InterruptMode2;
1528 
1529  DeviceExtension->InterruptCount = (PortConfig->BusInterruptLevel2 != 0 || PortConfig->BusInterruptVector2 != 0) ? 2 : 1;
1530 
1531  for (i = 0; i < DeviceExtension->InterruptCount; i++)
1532  {
1533  /* Register an interrupt handler for this device */
1534  MappedIrq[i] = HalGetInterruptVector(PortConfig->AdapterInterfaceType,
1535  PortConfig->SystemIoBusNumber,
1536  DeviceExtension->InterruptLevel[i],
1537  InterruptVector[i],
1538  &Dirql[i],
1539  &Affinity[i]);
1540  }
1541 
1542  if (DeviceExtension->InterruptCount == 1 || Dirql[0] > Dirql[1])
1543  MaxDirql = Dirql[0];
1544  else
1545  MaxDirql = Dirql[1];
1546 
1547  for (i = 0; i < DeviceExtension->InterruptCount; i++)
1548  {
1549  /* Determine IRQ sharability as usual */
1550  if (PortConfig->AdapterInterfaceType == MicroChannel ||
1552  {
1553  InterruptShareable = TRUE;
1554  }
1555  else
1556  {
1557  InterruptShareable = FALSE;
1558  }
1559 
1560  Status = IoConnectInterrupt(&DeviceExtension->Interrupt[i],
1562  DeviceExtension,
1563  &DeviceExtension->IrqLock,
1564  MappedIrq[i],
1565  Dirql[i],
1566  MaxDirql,
1567  InterruptMode[i],
1568  InterruptShareable,
1569  Affinity[i],
1570  FALSE);
1571 
1572  if (!(NT_SUCCESS(Status)))
1573  {
1574  DPRINT1("Could not connect interrupt %d\n",
1575  InterruptVector[i]);
1576  DeviceExtension->Interrupt[i] = NULL;
1577  break;
1578  }
1579  }
1580 
1581  if (!NT_SUCCESS(Status))
1582  break;
1583  }
1584 
1585  /* Save IoAddress (from access ranges) */
1586  if (HwInitializationData->NumberOfAccessRanges != 0)
1587  {
1588  DeviceExtension->IoAddress =
1589  ((*(PortConfig->AccessRanges))[0]).RangeStart.LowPart;
1590 
1591  DPRINT("Io Address %x\n", DeviceExtension->IoAddress);
1592  }
1593 
1594  /* Set flag that it's allowed to disconnect during this command */
1595  DeviceExtension->Flags |= SCSI_PORT_DISCONNECT_ALLOWED;
1596 
1597  /* Initialize counter of active requests (-1 means there are none) */
1598  DeviceExtension->ActiveRequestCounter = -1;
1599 
1600  /* Analyze what we have about DMA */
1601  if (DeviceExtension->AdapterObject != NULL &&
1602  PortConfig->Master &&
1603  PortConfig->NeedPhysicalAddresses)
1604  {
1605  DeviceExtension->MapRegisters = TRUE;
1606  }
1607  else
1608  {
1609  DeviceExtension->MapRegisters = FALSE;
1610  }
1611 
1612  /* Call HwInitialize at DISPATCH_LEVEL */
1614 
1615  if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0],
1616  DeviceExtension->HwInitialize,
1617  DeviceExtension->MiniPortDeviceExtension))
1618  {
1619  DPRINT1("HwInitialize() failed!\n");
1622  break;
1623  }
1624 
1625  /* Check if a notification is needed */
1626  if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
1627  {
1628  /* Call DPC right away, because we're already at DISPATCH_LEVEL */
1630  DeviceExtension->DeviceObject,
1631  NULL,
1632  NULL);
1633  }
1634 
1635  /* Lower irql back to what it was */
1637 
1638  /* Start our timer */
1639  IoStartTimer(PortDeviceObject);
1640 
1641  /* Initialize bus scanning information */
1643  BusScanInfo[DeviceExtension->PortConfig->NumberOfBuses]);
1644  DeviceExtension->BusesConfig = ExAllocatePoolWithTag(PagedPool,
1645  BusConfigSize,
1646  TAG_SCSIPORT);
1647  if (!DeviceExtension->BusesConfig)
1648  {
1649  DPRINT1("Out of resources!\n");
1651  break;
1652  }
1653 
1654  /* Zero it */
1655  RtlZeroMemory(DeviceExtension->BusesConfig, BusConfigSize);
1656 
1657  /* Store number of buses there */
1658  DeviceExtension->BusesConfig->NumberOfBuses = (UCHAR)DeviceExtension->BusNum;
1659 
1660  /* Scan the adapter for devices */
1661  SpiScanAdapter(DeviceExtension);
1662 
1663  /* Build the registry device map */
1664  SpiBuildDeviceMap(DeviceExtension,
1666 
1667  /* Create the dos device link */
1668  swprintf(DosNameBuffer,
1669  L"\\??\\Scsi%lu:",
1670  SystemConfig->ScsiPortCount);
1671  RtlInitUnicodeString(&DosDeviceName, DosNameBuffer);
1673 
1674  /* Increase the port count */
1675  SystemConfig->ScsiPortCount++;
1676  FirstConfigCall = FALSE;
1677 
1678  /* Increase adapter number and bus number respectively */
1679  ConfigInfo.AdapterNumber++;
1680 
1681  if (!Again)
1682  ConfigInfo.BusNumber++;
1683 
1684  DPRINT("Bus: %lu MaxBus: %lu\n", ConfigInfo.BusNumber, MaxBus);
1685 
1686  DeviceFound = TRUE;
1687  }
1688 
1689  /* Clean up the mess */
1690  SpiCleanupAfterInit(DeviceExtension);
1691 
1692  /* Close registry keys */
1693  if (ConfigInfo.ServiceKey != NULL)
1694  ZwClose(ConfigInfo.ServiceKey);
1695 
1696  if (ConfigInfo.DeviceKey != NULL)
1697  ZwClose(ConfigInfo.DeviceKey);
1698 
1699  if (ConfigInfo.BusKey != NULL)
1700  ZwClose(ConfigInfo.BusKey);
1701 
1702  if (ConfigInfo.AccessRanges != NULL)
1703  ExFreePool(ConfigInfo.AccessRanges);
1704 
1705  if (ConfigInfo.Parameter != NULL)
1706  ExFreePool(ConfigInfo.Parameter);
1707 
1708  DPRINT("ScsiPortInitialize() done, Status = 0x%08X, DeviceFound = %d!\n",
1709  Status, DeviceFound);
1710 
1711  return (DeviceFound == FALSE) ? Status : STATUS_SUCCESS;
1712 }
1713 
1714 static VOID
1716 {
1717  PSCSI_LUN_INFO LunInfo;
1718  PVOID Ptr;
1719  ULONG Bus, Lun;
1720 
1721  /* Check if we have something to clean up */
1722  if (DeviceExtension == NULL)
1723  return;
1724 
1725  /* Stop the timer */
1726  IoStopTimer(DeviceExtension->DeviceObject);
1727 
1728  /* Disconnect the interrupts */
1729  while (DeviceExtension->InterruptCount)
1730  {
1731  if (DeviceExtension->Interrupt[--DeviceExtension->InterruptCount])
1732  IoDisconnectInterrupt(DeviceExtension->Interrupt[DeviceExtension->InterruptCount]);
1733  }
1734 
1735  /* Delete ConfigInfo */
1736  if (DeviceExtension->BusesConfig)
1737  {
1738  for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
1739  {
1740  if (!DeviceExtension->BusesConfig->BusScanInfo[Bus])
1741  continue;
1742 
1743  LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
1744 
1745  while (LunInfo)
1746  {
1747  /* Free current, but save pointer to the next one */
1748  Ptr = LunInfo->Next;
1749  ExFreePool(LunInfo);
1750  LunInfo = Ptr;
1751  }
1752 
1753  ExFreePool(DeviceExtension->BusesConfig->BusScanInfo[Bus]);
1754  }
1755 
1756  ExFreePool(DeviceExtension->BusesConfig);
1757  }
1758 
1759  /* Free PortConfig */
1760  if (DeviceExtension->PortConfig)
1761  ExFreePool(DeviceExtension->PortConfig);
1762 
1763  /* Free LUNs*/
1764  for(Lun = 0; Lun < LUS_NUMBER; Lun++)
1765  {
1766  while (DeviceExtension->LunExtensionList[Lun])
1767  {
1768  Ptr = DeviceExtension->LunExtensionList[Lun];
1769  DeviceExtension->LunExtensionList[Lun] = DeviceExtension->LunExtensionList[Lun]->Next;
1770 
1771  ExFreePool(Ptr);
1772  }
1773  }
1774 
1775  /* Free common buffer (if it exists) */
1776  if (DeviceExtension->SrbExtensionBuffer != NULL &&
1777  DeviceExtension->CommonBufferLength != 0)
1778  {
1779  if (!DeviceExtension->AdapterObject)
1780  {
1781  ExFreePool(DeviceExtension->SrbExtensionBuffer);
1782  }
1783  else
1784  {
1785  HalFreeCommonBuffer(DeviceExtension->AdapterObject,
1786  DeviceExtension->CommonBufferLength,
1787  DeviceExtension->PhysicalAddress,
1788  DeviceExtension->SrbExtensionBuffer,
1789  FALSE);
1790  }
1791  }
1792 
1793  /* Free SRB info */
1794  if (DeviceExtension->SrbInfo != NULL)
1795  ExFreePool(DeviceExtension->SrbInfo);
1796 
1797  /* Unmap mapped addresses */
1798  while (DeviceExtension->MappedAddressList != NULL)
1799  {
1800  MmUnmapIoSpace(DeviceExtension->MappedAddressList->MappedAddress,
1801  DeviceExtension->MappedAddressList->NumberOfBytes);
1802 
1803  Ptr = DeviceExtension->MappedAddressList;
1804  DeviceExtension->MappedAddressList = DeviceExtension->MappedAddressList->NextMappedAddress;
1805 
1806  ExFreePool(Ptr);
1807  }
1808 
1809  /* Finally delete the device object */
1810  DPRINT("Deleting device %p\n", DeviceExtension->DeviceObject);
1811  IoDeleteDevice(DeviceExtension->DeviceObject);
1812 }
1813 
1814 /*
1815  * @unimplemented
1816  */
1817 VOID NTAPI
1818 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension,
1820  IN PVOID LogicalAddress,
1821  IN ULONG Length)
1822 {
1823  DPRINT1("ScsiPortIoMapTransfer()\n");
1824  UNIMPLEMENTED;
1825 }
1826 
1827 /*
1828  * @unimplemented
1829  */
1830 VOID NTAPI
1831 ScsiPortLogError(IN PVOID HwDeviceExtension,
1833  IN UCHAR PathId,
1834  IN UCHAR TargetId,
1835  IN UCHAR Lun,
1836  IN ULONG ErrorCode,
1837  IN ULONG UniqueId)
1838 {
1839  //PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1840 
1841  DPRINT1("ScsiPortLogError() called\n");
1842  DPRINT1("PathId: 0x%02x TargetId: 0x%02x Lun: 0x%02x ErrorCode: 0x%08lx UniqueId: 0x%08lx\n",
1843  PathId, TargetId, Lun, ErrorCode, UniqueId);
1844 
1845  //DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, SCSI_PORT_DEVICE_EXTENSION, MiniPortDeviceExtension);
1846 
1847 
1848  DPRINT("ScsiPortLogError() done\n");
1849 }
1850 
1851 /*
1852  * @implemented
1853  */
1854 VOID NTAPI
1856  IN PVOID Source,
1857  IN ULONG Length)
1858 {
1860  Source,
1861  Length);
1862 }
1863 
1864 
1865 /*
1866  * @implemented
1867  */
1868 VOID
1870  IN PVOID HwDeviceExtension,
1871  ...)
1872 {
1873  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1874  va_list ap;
1875 
1876  DPRINT("ScsiPortNotification() called\n");
1877 
1878  DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
1880  MiniPortDeviceExtension);
1881 
1882  DPRINT("DeviceExtension %p\n", DeviceExtension);
1883 
1884  va_start(ap, HwDeviceExtension);
1885 
1886  switch (NotificationType)
1887  {
1888  case RequestComplete:
1889  {
1891  PSCSI_REQUEST_BLOCK_INFO SrbData;
1892 
1894 
1895  DPRINT("Notify: RequestComplete (Srb %p)\n", Srb);
1896 
1897  /* Make sure Srb is alright */
1898  ASSERT(Srb->SrbStatus != SRB_STATUS_PENDING);
1899  ASSERT(Srb->Function != SRB_FUNCTION_EXECUTE_SCSI || Srb->SrbStatus != SRB_STATUS_SUCCESS || Srb->ScsiStatus == SCSISTAT_GOOD);
1900 
1901  if (!(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE))
1902  {
1903  /* It's been already completed */
1904  va_end(ap);
1905  return;
1906  }
1907 
1908  /* It's not active anymore */
1909  Srb->SrbFlags &= ~SRB_FLAGS_IS_ACTIVE;
1910 
1911  if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
1912  {
1913  /* TODO: Treat it specially */
1914  ASSERT(FALSE);
1915  }
1916  else
1917  {
1918  /* Get the SRB data */
1919  SrbData = SpiGetSrbData(DeviceExtension,
1920  Srb->PathId,
1921  Srb->TargetId,
1922  Srb->Lun,
1923  Srb->QueueTag);
1924 
1925  /* Make sure there are no CompletedRequests and there is a Srb */
1926  ASSERT(SrbData->CompletedRequests == NULL && SrbData->Srb != NULL);
1927 
1928  /* If it's a read/write request, make sure it has data inside it */
1929  if ((Srb->SrbStatus == SRB_STATUS_SUCCESS) &&
1930  ((Srb->Cdb[0] == SCSIOP_READ) || (Srb->Cdb[0] == SCSIOP_WRITE)))
1931  {
1932  ASSERT(Srb->DataTransferLength);
1933  }
1934 
1935  SrbData->CompletedRequests = DeviceExtension->InterruptData.CompletedRequests;
1936  DeviceExtension->InterruptData.CompletedRequests = SrbData;
1937  }
1938  }
1939  break;
1940 
1941  case NextRequest:
1942  DPRINT("Notify: NextRequest\n");
1943  DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY;
1944  break;
1945 
1946  case NextLuRequest:
1947  {
1948  UCHAR PathId;
1949  UCHAR TargetId;
1950  UCHAR Lun;
1951  PSCSI_PORT_LUN_EXTENSION LunExtension;
1952 
1953  PathId = (UCHAR) va_arg (ap, int);
1954  TargetId = (UCHAR) va_arg (ap, int);
1955  Lun = (UCHAR) va_arg (ap, int);
1956 
1957  DPRINT("Notify: NextLuRequest(PathId %u TargetId %u Lun %u)\n",
1958  PathId, TargetId, Lun);
1959 
1960  /* Mark it in the flags field */
1961  DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY;
1962 
1963  /* Get the LUN extension */
1964  LunExtension = SpiGetLunExtension(DeviceExtension,
1965  PathId,
1966  TargetId,
1967  Lun);
1968 
1969  /* If returned LunExtension is NULL, break out */
1970  if (!LunExtension) break;
1971 
1972  /* This request should not be processed if */
1973  if ((LunExtension->ReadyLun) ||
1974  (LunExtension->SrbInfo.Srb))
1975  {
1976  /* Nothing to do here */
1977  break;
1978  }
1979 
1980  /* Add this LUN to the list */
1981  LunExtension->ReadyLun = DeviceExtension->InterruptData.ReadyLun;
1982  DeviceExtension->InterruptData.ReadyLun = LunExtension;
1983  }
1984  break;
1985 
1986  case ResetDetected:
1987  DPRINT("Notify: ResetDetected\n");
1988  /* Add RESET flags */
1989  DeviceExtension->InterruptData.Flags |=
1991  break;
1992 
1993  case CallDisableInterrupts:
1994  DPRINT1("UNIMPLEMENTED SCSI Notification called: CallDisableInterrupts!\n");
1995  break;
1996 
1997  case CallEnableInterrupts:
1998  DPRINT1("UNIMPLEMENTED SCSI Notification called: CallEnableInterrupts!\n");
1999  break;
2000 
2001  case RequestTimerCall:
2002  DPRINT("Notify: RequestTimerCall\n");
2003  DeviceExtension->InterruptData.Flags |= SCSI_PORT_TIMER_NEEDED;
2004  DeviceExtension->InterruptData.HwScsiTimer = (PHW_TIMER)va_arg(ap, PHW_TIMER);
2005  DeviceExtension->InterruptData.MiniportTimerValue = (ULONG)va_arg(ap, ULONG);
2006  break;
2007 
2008  case BusChangeDetected:
2009  DPRINT1("UNIMPLEMENTED SCSI Notification called: BusChangeDetected!\n");
2010  break;
2011 
2012  default:
2013  DPRINT1 ("Unsupported notification from WMI: %lu\n", NotificationType);
2014  break;
2015  }
2016 
2017  va_end(ap);
2018 
2019  /* Request a DPC after we're done with the interrupt */
2020  DeviceExtension->InterruptData.Flags |= SCSI_PORT_NOTIFICATION_NEEDED;
2021 }
2022 
2023 /*
2024  * @implemented
2025  */
2026 BOOLEAN NTAPI
2027 ScsiPortValidateRange(IN PVOID HwDeviceExtension,
2029  IN ULONG SystemIoBusNumber,
2030  IN SCSI_PHYSICAL_ADDRESS IoAddress,
2032  IN BOOLEAN InIoSpace)
2033 {
2034  DPRINT("ScsiPortValidateRange()\n");
2035  return(TRUE);
2036 }
2037 
2038 
2039 /* INTERNAL FUNCTIONS ********************************************************/
2040 
2041 static VOID
2043  IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor,
2045 {
2046  PACCESS_RANGE AccessRange;
2047  PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialData;
2048  ULONG RangeNumber;
2049  ULONG Index;
2050  ULONG Interrupt = 0;
2051  ULONG Dma = 0;
2052 
2053  RangeNumber = 0;
2054 
2055  /* Loop through all entries */
2056  for (Index = 0; Index < ResourceDescriptor->PartialResourceList.Count; Index++)
2057  {
2058  PartialData = &ResourceDescriptor->PartialResourceList.PartialDescriptors[Index];
2059 
2060  switch (PartialData->Type)
2061  {
2062  case CmResourceTypePort:
2063  /* Copy access ranges */
2064  if (RangeNumber < HwInitializationData->NumberOfAccessRanges)
2065  {
2066  AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]);
2067 
2068  AccessRange->RangeStart = PartialData->u.Port.Start;
2069  AccessRange->RangeLength = PartialData->u.Port.Length;
2070 
2071  AccessRange->RangeInMemory = FALSE;
2072  RangeNumber++;
2073  }
2074  break;
2075 
2076  case CmResourceTypeMemory:
2077  /* Copy access ranges */
2078  if (RangeNumber < HwInitializationData->NumberOfAccessRanges)
2079  {
2080  AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]);
2081 
2082  AccessRange->RangeStart = PartialData->u.Memory.Start;
2083  AccessRange->RangeLength = PartialData->u.Memory.Length;
2084 
2085  AccessRange->RangeInMemory = TRUE;
2086  RangeNumber++;
2087  }
2088  break;
2089 
2091 
2092  if (Interrupt == 0)
2093  {
2094  /* Copy interrupt data */
2095  PortConfig->BusInterruptLevel = PartialData->u.Interrupt.Level;
2096  PortConfig->BusInterruptVector = PartialData->u.Interrupt.Vector;
2097 
2098  /* Set interrupt mode accordingly to the resource */
2099  if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
2100  {
2101  PortConfig->InterruptMode = Latched;
2102  }
2103  else if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
2104  {
2105  PortConfig->InterruptMode = LevelSensitive;
2106  }
2107  }
2108  else if (Interrupt == 1)
2109  {
2110  /* Copy interrupt data */
2111  PortConfig->BusInterruptLevel2 = PartialData->u.Interrupt.Level;
2112  PortConfig->BusInterruptVector2 = PartialData->u.Interrupt.Vector;
2113 
2114  /* Set interrupt mode accordingly to the resource */
2115  if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
2116  {
2117  PortConfig->InterruptMode2 = Latched;
2118  }
2119  else if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
2120  {
2121  PortConfig->InterruptMode2 = LevelSensitive;
2122  }
2123  }
2124 
2125  Interrupt++;
2126  break;
2127 
2128  case CmResourceTypeDma:
2129 
2130  if (Dma == 0)
2131  {
2132  PortConfig->DmaChannel = PartialData->u.Dma.Channel;
2133  PortConfig->DmaPort = PartialData->u.Dma.Port;
2134 
2135  if (PartialData->Flags & CM_RESOURCE_DMA_8)
2136  PortConfig->DmaWidth = Width8Bits;
2137  else if ((PartialData->Flags & CM_RESOURCE_DMA_16) ||
2138  (PartialData->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
2139  PortConfig->DmaWidth = Width16Bits;
2140  else if (PartialData->Flags & CM_RESOURCE_DMA_32)
2141  PortConfig->DmaWidth = Width32Bits;
2142  }
2143  else if (Dma == 1)
2144  {
2145  PortConfig->DmaChannel2 = PartialData->u.Dma.Channel;
2146  PortConfig->DmaPort2 = PartialData->u.Dma.Port;
2147 
2148  if (PartialData->Flags & CM_RESOURCE_DMA_8)
2149  PortConfig->DmaWidth2 = Width8Bits;
2150  else if ((PartialData->Flags & CM_RESOURCE_DMA_16) ||
2151  (PartialData->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
2152  PortConfig->DmaWidth2 = Width16Bits;
2153  else if (PartialData->Flags & CM_RESOURCE_DMA_32)
2154  PortConfig->DmaWidth2 = Width32Bits;
2155  }
2156  break;
2157  }
2158  }
2159 }
2160 
2161 static PCM_RESOURCE_LIST
2164 {
2165  PCONFIGURATION_INFORMATION ConfigInfo;
2167  PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor;
2168  PACCESS_RANGE AccessRange;
2169  ULONG ListLength = 0, i, FullSize;
2170  ULONG Interrupt, Dma;
2171 
2172  /* Get current Atdisk usage from the system */
2173  ConfigInfo = IoGetConfigurationInformation();
2174 
2175  if (PortConfig->AtdiskPrimaryClaimed)
2176  ConfigInfo->AtDiskPrimaryAddressClaimed = TRUE;
2177 
2178  if (PortConfig->AtdiskSecondaryClaimed)
2179  ConfigInfo->AtDiskSecondaryAddressClaimed = TRUE;
2180 
2181  /* Do we use DMA? */
2182  if (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE ||
2183  PortConfig->DmaPort != SP_UNINITIALIZED_VALUE)
2184  {
2185  Dma = 1;
2186 
2187  if (PortConfig->DmaChannel2 != SP_UNINITIALIZED_VALUE ||
2188  PortConfig->DmaPort2 != SP_UNINITIALIZED_VALUE)
2189  Dma++;
2190  }
2191  else
2192  {
2193  Dma = 0;
2194  }
2195  ListLength += Dma;
2196 
2197  /* How many interrupts to we have? */
2198  Interrupt = DeviceExtension->InterruptCount;
2199  ListLength += Interrupt;
2200 
2201  /* How many access ranges do we use? */
2202  AccessRange = &((*(PortConfig->AccessRanges))[0]);
2203  for (i = 0; i < PortConfig->NumberOfAccessRanges; i++)
2204  {
2205  if (AccessRange->RangeLength != 0)
2206  ListLength++;
2207 
2208  AccessRange++;
2209  }
2210 
2211  /* Allocate the resource list, since we know its size now */
2212  FullSize = sizeof(CM_RESOURCE_LIST) + (ListLength - 1) *
2214 
2216 
2217  if (!ResourceList)
2218  return NULL;
2219 
2220  /* Zero it */
2221  RtlZeroMemory(ResourceList, FullSize);
2222 
2223  /* Initialize it */
2224  ResourceList->Count = 1;
2225  ResourceList->List[0].InterfaceType = PortConfig->AdapterInterfaceType;
2226  ResourceList->List[0].BusNumber = PortConfig->SystemIoBusNumber;
2227  ResourceList->List[0].PartialResourceList.Count = ListLength;
2228  ResourceDescriptor = ResourceList->List[0].PartialResourceList.PartialDescriptors;
2229 
2230  /* Copy access ranges array over */
2231  for (i = 0; i < PortConfig->NumberOfAccessRanges; i++)
2232  {
2233  AccessRange = &((*(PortConfig->AccessRanges))[i]);
2234 
2235  /* If the range is empty - skip it */
2236  if (AccessRange->RangeLength == 0)
2237  continue;
2238 
2239  if (AccessRange->RangeInMemory)
2240  {
2241  ResourceDescriptor->Type = CmResourceTypeMemory;
2242  ResourceDescriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
2243  }
2244  else
2245  {
2246  ResourceDescriptor->Type = CmResourceTypePort;
2247  ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
2248  }
2249 
2250  ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
2251 
2252  ResourceDescriptor->u.Memory.Start = AccessRange->RangeStart;
2253  ResourceDescriptor->u.Memory.Length = AccessRange->RangeLength;
2254 
2255  ResourceDescriptor++;
2256  }
2257 
2258  /* If we use interrupt(s), copy them */
2259  while (Interrupt)
2260  {
2261  ResourceDescriptor->Type = CmResourceTypeInterrupt;
2262 
2263  if (PortConfig->AdapterInterfaceType == MicroChannel ||
2264  ((Interrupt == 2) ? PortConfig->InterruptMode2 : PortConfig->InterruptMode) == LevelSensitive)
2265  {
2266  ResourceDescriptor->ShareDisposition = CmResourceShareShared;
2267  ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
2268  }
2269  else
2270  {
2271  ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
2272  ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
2273  }
2274 
2275  ResourceDescriptor->u.Interrupt.Level = (Interrupt == 2) ? PortConfig->BusInterruptLevel2 : PortConfig->BusInterruptLevel;
2276  ResourceDescriptor->u.Interrupt.Vector = (Interrupt == 2) ? PortConfig->BusInterruptVector2 : PortConfig->BusInterruptVector;
2277  ResourceDescriptor->u.Interrupt.Affinity = 0;
2278 
2279  ResourceDescriptor++;
2280  Interrupt--;
2281  }
2282 
2283  /* Copy DMA data */
2284  while (Dma)
2285  {
2286  ResourceDescriptor->Type = CmResourceTypeDma;
2287  ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
2288  ResourceDescriptor->u.Dma.Channel = (Dma == 2) ? PortConfig->DmaChannel2 : PortConfig->DmaChannel;
2289  ResourceDescriptor->u.Dma.Port = (Dma == 2) ? PortConfig->DmaPort2 : PortConfig->DmaPort;
2290  ResourceDescriptor->Flags = 0;
2291 
2292  if (((Dma == 2) ? PortConfig->DmaWidth2 : PortConfig->DmaWidth) == Width8Bits)
2293  ResourceDescriptor->Flags |= CM_RESOURCE_DMA_8;
2294  else if (((Dma == 2) ? PortConfig->DmaWidth2 : PortConfig->DmaWidth) == Width16Bits)
2295  ResourceDescriptor->Flags |= CM_RESOURCE_DMA_16;
2296  else
2297  ResourceDescriptor->Flags |= CM_RESOURCE_DMA_32;
2298 
2299  if (((Dma == 2) ? PortConfig->DmaChannel2 : PortConfig->DmaChannel) == SP_UNINITIALIZED_VALUE)
2300  ResourceDescriptor->u.Dma.Channel = 0;
2301 
2302  if (((Dma == 2) ? PortConfig->DmaPort2 : PortConfig->DmaPort) == SP_UNINITIALIZED_VALUE)
2303  ResourceDescriptor->u.Dma.Port = 0;
2304 
2305  ResourceDescriptor++;
2306  Dma--;
2307  }
2308 
2309  return ResourceList;
2310 }
2311 
2312 
2313 static BOOLEAN
2319  IN ULONG BusNumber,
2320  IN OUT PPCI_SLOT_NUMBER NextSlotNumber)
2321 {
2322  PCI_COMMON_CONFIG PciConfig;
2324  ULONG DataSize;
2326  ULONG FunctionNumber;
2327  CHAR VendorIdString[8];
2328  CHAR DeviceIdString[8];
2329  UNICODE_STRING UnicodeStr;
2331  NTSTATUS Status;
2332 
2333  DPRINT ("SpiGetPciConfiguration() called\n");
2334 
2335  SlotNumber.u.AsULONG = 0;
2336 
2337  /* Loop through all devices */
2338  for (DeviceNumber = NextSlotNumber->u.bits.DeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
2339  {
2340  SlotNumber.u.bits.DeviceNumber = DeviceNumber;
2341 
2342  /* Loop through all functions */
2343  for (FunctionNumber = NextSlotNumber->u.bits.FunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
2344  {
2345  SlotNumber.u.bits.FunctionNumber = FunctionNumber;
2346 
2347  /* Get PCI config bytes */
2349  BusNumber,
2350  SlotNumber.u.AsULONG,
2351  &PciConfig,
2352  sizeof(ULONG));
2353 
2354  /* If result of HalGetBusData is 0, then the bus is wrong */
2355  if (DataSize == 0)
2356  return FALSE;
2357 
2358  /* Check if result is PCI_INVALID_VENDORID or too small */
2359  if ((DataSize < sizeof(ULONG)) ||
2360  (PciConfig.VendorID == PCI_INVALID_VENDORID))
2361  {
2362  /* Continue to try the next function */
2363  continue;
2364  }
2365 
2366  sprintf (VendorIdString, "%04hx", PciConfig.VendorID);
2367  sprintf (DeviceIdString, "%04hx", PciConfig.DeviceID);
2368 
2369  if (_strnicmp(VendorIdString, HwInitializationData->VendorId, HwInitializationData->VendorIdLength) ||
2370  _strnicmp(DeviceIdString, HwInitializationData->DeviceId, HwInitializationData->DeviceIdLength))
2371  {
2372  /* It is not our device */
2373  continue;
2374  }
2375 
2376  DPRINT("Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n",
2377  PciConfig.VendorID,
2378  PciConfig.DeviceID,
2379  BusNumber,
2380  SlotNumber.u.bits.DeviceNumber,
2381  SlotNumber.u.bits.FunctionNumber);
2382 
2383 
2384  RtlInitUnicodeString(&UnicodeStr, L"ScsiAdapter");
2386  &UnicodeStr,
2387  DriverObject,
2388  DeviceObject,
2389  PCIBus,
2390  BusNumber,
2391  SlotNumber.u.AsULONG,
2392  &ResourceList);
2393 
2394  if (!NT_SUCCESS(Status))
2395  break;
2396 
2397  /* Create configuration information */
2399  ResourceList->List,
2400  PortConfig);
2401 
2402  /* Free the resource list */
2404 
2405  /* Set dev & fn numbers */
2406  NextSlotNumber->u.bits.DeviceNumber = DeviceNumber;
2407  NextSlotNumber->u.bits.FunctionNumber = FunctionNumber + 1;
2408 
2409  /* Save the slot number */
2410  PortConfig->SlotNumber = SlotNumber.u.AsULONG;
2411 
2412  return TRUE;
2413  }
2414  NextSlotNumber->u.bits.FunctionNumber = 0;
2415  }
2416 
2417  NextSlotNumber->u.bits.DeviceNumber = 0;
2418  DPRINT ("No device found\n");
2419 
2420  return FALSE;
2421 }
2422 
2423 
2424 
2425 /**********************************************************************
2426  * NAME INTERNAL
2427  * ScsiPortCreateClose
2428  *
2429  * DESCRIPTION
2430  * Answer requests for Create/Close calls: a null operation.
2431  *
2432  * RUN LEVEL
2433  * PASSIVE_LEVEL
2434  *
2435  * ARGUMENTS
2436  * DeviceObject
2437  * Pointer to a device object.
2438  *
2439  * Irp
2440  * Pointer to an IRP.
2441  *
2442  * RETURN VALUE
2443  * Status.
2444  */
2445 
2446 static NTSTATUS NTAPI
2448  IN PIRP Irp)
2449 {
2450  DPRINT("ScsiPortCreateClose()\n");
2451 
2452  Irp->IoStatus.Status = STATUS_SUCCESS;
2454 
2455  return STATUS_SUCCESS;
2456 }
2457 
2458 static NTSTATUS
2460  PIRP Irp)
2461 {
2462  PSCSI_LUN_INFO LunInfo;
2463  PIO_STACK_LOCATION IrpStack;
2466  KIRQL Irql;
2467 
2468  /* Get pointer to the SRB */
2469  IrpStack = IoGetCurrentIrpStackLocation(Irp);
2470  Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
2471 
2472  /* Check if PathId matches number of buses */
2473  if (DeviceExtension->BusesConfig == NULL ||
2474  DeviceExtension->BusesConfig->NumberOfBuses <= Srb->PathId)
2475  {
2476  Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
2478  }
2479 
2480  /* Get pointer to LunInfo */
2481  LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Srb->PathId]->LunInfo;
2482 
2483  /* Find matching LunInfo */
2484  while (LunInfo)
2485  {
2486  if (LunInfo->PathId == Srb->PathId &&
2487  LunInfo->TargetId == Srb->TargetId &&
2488  LunInfo->Lun == Srb->Lun)
2489  {
2490  break;
2491  }
2492 
2493  LunInfo = LunInfo->Next;
2494  }
2495 
2496  /* If we couldn't find it - exit */
2497  if (LunInfo == NULL)
2499 
2500 
2501  /* Get spinlock */
2502  KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
2503 
2504  /* Release, if asked */
2505  if (Srb->Function == SRB_FUNCTION_RELEASE_DEVICE)
2506  {
2507  LunInfo->DeviceClaimed = FALSE;
2508  KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2509  Srb->SrbStatus = SRB_STATUS_SUCCESS;
2510 
2511  return STATUS_SUCCESS;
2512  }
2513 
2514  /* Attach, if not already claimed */
2515  if (LunInfo->DeviceClaimed)
2516  {
2517  KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2518  Srb->SrbStatus = SRB_STATUS_BUSY;
2519 
2520  return STATUS_DEVICE_BUSY;
2521  }
2522 
2523  /* Save the device object */
2524  DeviceObject = LunInfo->DeviceObject;
2525 
2526  if (Srb->Function == SRB_FUNCTION_CLAIM_DEVICE)
2527  LunInfo->DeviceClaimed = TRUE;
2528 
2529  if (Srb->Function == SRB_FUNCTION_ATTACH_DEVICE)
2530  LunInfo->DeviceObject = Srb->DataBuffer;
2531 
2532  Srb->DataBuffer = DeviceObject;
2533 
2534  KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2535  Srb->SrbStatus = SRB_STATUS_SUCCESS;
2536 
2537  return STATUS_SUCCESS;
2538 }
2539 
2540 
2541 /**********************************************************************
2542  * NAME INTERNAL
2543  * ScsiPortDispatchScsi
2544  *
2545  * DESCRIPTION
2546  * Answer requests for SCSI calls
2547  *
2548  * RUN LEVEL
2549  * PASSIVE_LEVEL
2550  *
2551  * ARGUMENTS
2552  * Standard dispatch arguments
2553  *
2554  * RETURNS
2555  * NTSTATUS
2556  */
2557 
2558 static NTSTATUS NTAPI
2560  IN PIRP Irp)
2561 {
2562  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2563  PSCSI_PORT_LUN_EXTENSION LunExtension;
2564  PIO_STACK_LOCATION Stack;
2566  KIRQL Irql;
2568  PIRP NextIrp, IrpList;
2570 
2571  DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n",
2572  DeviceObject, Irp);
2573 
2574  DeviceExtension = DeviceObject->DeviceExtension;
2576 
2577  Srb = Stack->Parameters.Scsi.Srb;
2578  if (Srb == NULL)
2579  {
2580  DPRINT1("ScsiPortDispatchScsi() called with Srb = NULL!\n");
2582 
2583  Irp->IoStatus.Status = Status;
2584  Irp->IoStatus.Information = 0;
2585 
2587 
2588  return(Status);
2589  }
2590 
2591  DPRINT("Srb: %p\n", Srb);
2592  DPRINT("Srb->Function: %lu\n", Srb->Function);
2593  DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
2594 
2595  LunExtension = SpiGetLunExtension(DeviceExtension,
2596  Srb->PathId,
2597  Srb->TargetId,
2598  Srb->Lun);
2599  if (LunExtension == NULL)
2600  {
2601  DPRINT("ScsiPortDispatchScsi() called with an invalid LUN\n");
2603 
2604  Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
2605  Irp->IoStatus.Status = Status;
2606  Irp->IoStatus.Information = 0;
2607 
2609 
2610  return(Status);
2611  }
2612 
2613  switch (Srb->Function)
2614  {
2615  case SRB_FUNCTION_SHUTDOWN:
2616  case SRB_FUNCTION_FLUSH:
2617  DPRINT (" SRB_FUNCTION_SHUTDOWN or FLUSH\n");
2618  if (DeviceExtension->CachesData == FALSE)
2619  {
2620  /* All success here */
2621  Srb->SrbStatus = SRB_STATUS_SUCCESS;
2622  Irp->IoStatus.Status = STATUS_SUCCESS;
2624  return STATUS_SUCCESS;
2625  }
2626  /* Fall through to a usual execute operation */
2627 
2630  DPRINT(" SRB_FUNCTION_EXECUTE_SCSI or SRB_FUNCTION_IO_CONTROL\n");
2631  /* Mark IRP as pending in all cases */
2633 
2634  if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
2635  {
2636  /* Start IO directly */
2638  }
2639  else
2640  {
2641  KIRQL oldIrql;
2642 
2643  /* We need to be at DISPATCH_LEVEL */
2644  KeRaiseIrql (DISPATCH_LEVEL, &oldIrql);
2645 
2646  /* Insert IRP into the queue */
2647  if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue,
2648  &Irp->Tail.Overlay.DeviceQueueEntry,
2649  Srb->QueueSortKey))
2650  {
2651  /* It means the queue is empty, and we just start this request */
2653  }
2654 
2655  /* Back to the old IRQL */
2656  KeLowerIrql (oldIrql);
2657  }
2658  return STATUS_PENDING;
2659 
2662  DPRINT (" SRB_FUNCTION_CLAIM_DEVICE or ATTACH\n");
2663 
2664  /* Reference device object and keep the device object */
2665  Status = SpiHandleAttachRelease(DeviceExtension, Irp);
2666  break;
2667 
2669  DPRINT (" SRB_FUNCTION_RELEASE_DEVICE\n");
2670 
2671  /* Dereference device object and clear the device object */
2672  Status = SpiHandleAttachRelease(DeviceExtension, Irp);
2673  break;
2674 
2676  DPRINT(" SRB_FUNCTION_RELEASE_QUEUE\n");
2677 
2678  /* Guard with the spinlock */
2679  KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
2680 
2681  if (!(LunExtension->Flags & LUNEX_FROZEN_QUEUE))
2682  {
2683  DPRINT("Queue is not frozen really\n");
2684 
2685  KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2686  Srb->SrbStatus = SRB_STATUS_SUCCESS;
2688  break;
2689 
2690  }
2691 
2692  /* Unfreeze the queue */
2693  LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
2694 
2695  if (LunExtension->SrbInfo.Srb == NULL)
2696  {
2697  /* Get next logical unit request */
2698  SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
2699 
2700  /* SpiGetNextRequestFromLun() releases the spinlock */
2701  KeLowerIrql(Irql);
2702  }
2703  else
2704  {
2705  DPRINT("The queue has active request\n");
2706  KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2707  }
2708 
2709 
2710  Srb->SrbStatus = SRB_STATUS_SUCCESS;
2712  break;
2713 
2715  DPRINT(" SRB_FUNCTION_FLUSH_QUEUE\n");
2716 
2717  /* Guard with the spinlock */
2718  KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
2719 
2720  if (!(LunExtension->Flags & LUNEX_FROZEN_QUEUE))
2721  {
2722  DPRINT("Queue is not frozen really\n");
2723 
2724  KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2726  break;
2727  }
2728 
2729  /* Make sure there is no active request */
2730  ASSERT(LunExtension->SrbInfo.Srb == NULL);
2731 
2732  /* Compile a list from the device queue */
2733  IrpList = NULL;
2734  while ((Entry = KeRemoveDeviceQueue(&LunExtension->DeviceQueue)) != NULL)
2735  {
2736  NextIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
2737 
2738  /* Get the Srb */
2739  Stack = IoGetCurrentIrpStackLocation(NextIrp);
2740  Srb = Stack->Parameters.Scsi.Srb;
2741 
2742  /* Set statuse */
2743  Srb->SrbStatus = SRB_STATUS_REQUEST_FLUSHED;
2744  NextIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
2745 
2746  /* Add then to the list */
2747  NextIrp->Tail.Overlay.ListEntry.Flink = (PLIST_ENTRY)IrpList;
2748  IrpList = NextIrp;
2749  }
2750 
2751  /* Unfreeze the queue */
2752  LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
2753 
2754  /* Release the spinlock */
2755  KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2756 
2757  /* Complete those requests */
2758  while (IrpList)
2759  {
2760  NextIrp = IrpList;
2761  IrpList = (PIRP)NextIrp->Tail.Overlay.ListEntry.Flink;
2762 
2763  IoCompleteRequest(NextIrp, 0);
2764  }
2765 
2767  break;
2768 
2769  default:
2770  DPRINT1("SRB function not implemented (Function %lu)\n", Srb->Function);
2772  break;
2773  }
2774 
2775  Irp->IoStatus.Status = Status;
2776 
2778 
2779  return(Status);
2780 }
2781 
2782 
2783 /**********************************************************************
2784  * NAME INTERNAL
2785  * ScsiPortDeviceControl
2786  *
2787  * DESCRIPTION
2788  * Answer requests for device control calls
2789  *
2790  * RUN LEVEL
2791  * PASSIVE_LEVEL
2792  *
2793  * ARGUMENTS
2794  * Standard dispatch arguments
2795  *
2796  * RETURNS
2797  * NTSTATUS
2798  */
2799 
2800 static NTSTATUS NTAPI
2802  IN PIRP Irp)
2803 {
2804  PIO_STACK_LOCATION Stack;
2805  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2806  PDUMP_POINTERS DumpPointers;
2807  NTSTATUS Status;
2808 
2809  DPRINT("ScsiPortDeviceControl()\n");
2810 
2811  Irp->IoStatus.Information = 0;
2812 
2814  DeviceExtension = DeviceObject->DeviceExtension;
2815 
2816  switch (Stack->Parameters.DeviceIoControl.IoControlCode)
2817  {
2819  DPRINT(" IOCTL_SCSI_GET_DUMP_POINTERS\n");
2820 
2821  if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DUMP_POINTERS))
2822  {
2824  Irp->IoStatus.Information = sizeof(DUMP_POINTERS);
2825  break;
2826  }
2827 
2828  DumpPointers = Irp->AssociatedIrp.SystemBuffer;
2829  DumpPointers->DeviceObject = DeviceObject;
2830  /* More data.. ? */
2831 
2833  Irp->IoStatus.Information = sizeof(DUMP_POINTERS);
2834  break;
2835 
2837  DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
2838  if (Stack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(PVOID))
2839  {
2840  *((PVOID *)Irp->AssociatedIrp.SystemBuffer) = &DeviceExtension->PortCapabilities;
2841 
2842  Irp->IoStatus.Information = sizeof(PVOID);
2844  break;
2845  }
2846 
2847  if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(IO_SCSI_CAPABILITIES))
2848  {
2850  break;
2851  }
2852 
2853  RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
2854  &DeviceExtension->PortCapabilities,
2855  sizeof(IO_SCSI_CAPABILITIES));
2856 
2857  Irp->IoStatus.Information = sizeof(IO_SCSI_CAPABILITIES);
2859  break;
2860 
2862  DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
2863 
2864  /* Copy inquiry data to the port device extension */
2865  Status = SpiGetInquiryData(DeviceExtension, Irp);
2866  break;
2867 
2868  case IOCTL_SCSI_MINIPORT:
2869  DPRINT1("IOCTL_SCSI_MINIPORT unimplemented!\n");
2871  break;
2872 
2874  DPRINT1("IOCTL_SCSI_PASS_THROUGH unimplemented!\n");
2876  break;
2877 
2878  default:
2879  if (DEVICE_TYPE_FROM_CTL_CODE(Stack->Parameters.DeviceIoControl.IoControlCode) == MOUNTDEVCONTROLTYPE)
2880  {
2881  switch (Stack->Parameters.DeviceIoControl.IoControlCode)
2882  {
2884  DPRINT1("Got unexpected IOCTL_MOUNTDEV_QUERY_DEVICE_NAME\n");
2885  break;
2887  DPRINT1("Got unexpected IOCTL_MOUNTDEV_QUERY_UNIQUE_ID\n");
2888  break;
2889  default:
2890  DPRINT1(" got ioctl intended for the mount manager: 0x%lX\n", Stack->Parameters.DeviceIoControl.IoControlCode);
2891  break;
2892  }
2893  } else {
2894  DPRINT1(" unknown ioctl code: 0x%lX\n", Stack->Parameters.DeviceIoControl.IoControlCode);
2895  }
2897  break;
2898  }
2899 
2900  /* Complete the request with the given status */
2901  Irp->IoStatus.Status = Status;
2903 
2904  return Status;
2905 }
2906 
2907 
2908 static VOID NTAPI
2910  IN PIRP Irp)
2911 {
2912  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2913  PSCSI_PORT_LUN_EXTENSION LunExtension;
2914  PIO_STACK_LOCATION IrpStack;
2916  PSCSI_REQUEST_BLOCK_INFO SrbInfo;
2917  LONG CounterResult;
2918  NTSTATUS Status;
2919 
2920  DPRINT("ScsiPortStartIo() called!\n");
2921 
2922  DeviceExtension = DeviceObject->DeviceExtension;
2923  IrpStack = IoGetCurrentIrpStackLocation(Irp);
2924 
2925  DPRINT("DeviceExtension %p\n", DeviceExtension);
2926 
2927  Srb = IrpStack->Parameters.Scsi.Srb;
2928 
2929  /* Apply "default" flags */
2930  Srb->SrbFlags |= DeviceExtension->SrbFlags;
2931 
2932  /* Get LUN extension */
2933  LunExtension = SpiGetLunExtension(DeviceExtension,
2934  Srb->PathId,
2935  Srb->TargetId,
2936  Srb->Lun);
2937 
2938  if (DeviceExtension->NeedSrbDataAlloc ||
2939  DeviceExtension->NeedSrbExtensionAlloc)
2940  {
2941  /* Allocate them */
2942  SrbInfo = SpiAllocateSrbStructures(DeviceExtension,
2943  LunExtension,
2944  Srb);
2945 
2946  /* Couldn't alloc one or both data structures, return */
2947  if (SrbInfo == NULL)
2948  {
2949  /* We have to call IoStartNextPacket, because this request
2950  was not started */
2951  if (LunExtension->Flags & LUNEX_REQUEST_PENDING)
2953 
2954  return;
2955  }
2956  }
2957  else
2958  {
2959  /* No allocations are needed */
2960  SrbInfo = &LunExtension->SrbInfo;
2961  Srb->SrbExtension = NULL;
2962  Srb->QueueTag = SP_UNTAGGED;
2963  }
2964 
2965  /* Increase sequence number of SRB */
2966  if (!SrbInfo->SequenceNumber)
2967  {
2968  /* Increase global sequence number */
2969  DeviceExtension->SequenceNumber++;
2970 
2971  /* Assign it */
2972  SrbInfo->SequenceNumber = DeviceExtension->SequenceNumber;
2973  }
2974 
2975  /* Check some special SRBs */
2976  if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
2977  {
2978  /* Some special handling */
2979  DPRINT1("Abort command! Unimplemented now\n");
2980  }
2981  else
2982  {
2983  SrbInfo->Srb = Srb;
2984  }
2985 
2986  if (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION)
2987  {
2988  // Store the MDL virtual address in SrbInfo structure
2989  SrbInfo->DataOffset = MmGetMdlVirtualAddress(Irp->MdlAddress);
2990 
2991  if (DeviceExtension->MapBuffers)
2992  {
2993  /* Calculate offset within DataBuffer */
2994  SrbInfo->DataOffset = MmGetSystemAddressForMdl(Irp->MdlAddress);
2995  Srb->DataBuffer = SrbInfo->DataOffset +
2996  (ULONG)((PUCHAR)Srb->DataBuffer -
2997  (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress));
2998  }
2999 
3000  if (DeviceExtension->AdapterObject)
3001  {
3002  /* Flush buffers */
3003  KeFlushIoBuffers(Irp->MdlAddress,
3004  Srb->SrbFlags & SRB_FLAGS_DATA_IN ? TRUE : FALSE,
3005  TRUE);
3006  }
3007 
3008  if (DeviceExtension->MapRegisters)
3009  {
3010  /* Calculate number of needed map registers */
3012  Srb->DataBuffer,
3013  Srb->DataTransferLength);
3014 
3015  /* Allocate adapter channel */
3016  Status = IoAllocateAdapterChannel(DeviceExtension->AdapterObject,
3017  DeviceExtension->DeviceObject,
3018  SrbInfo->NumberOfMapRegisters,
3020  SrbInfo);
3021 
3022  if (!NT_SUCCESS(Status))
3023  {
3024  DPRINT1("IoAllocateAdapterChannel() failed!\n");
3025 
3026  Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
3028  DeviceExtension + 1,
3029  Srb);
3030 
3032  DeviceExtension + 1);
3033 
3034  /* Request DPC for that work */
3035  IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
3036  }
3037 
3038  /* Control goes to SpiAdapterControl */
3039  return;
3040  }
3041  }
3042 
3043  /* Increase active request counter */
3044  CounterResult = InterlockedIncrement(&DeviceExtension->ActiveRequestCounter);
3045 
3046  if (CounterResult == 0 &&
3047  DeviceExtension->AdapterObject != NULL &&
3048  !DeviceExtension->MapRegisters)
3049  {
3051  DeviceExtension->AdapterObject,
3052  DeviceObject,
3053  DeviceExtension->PortCapabilities.MaximumPhysicalPages,
3055  LunExtension
3056  );
3057 
3058  return;
3059  }
3060 
3061  KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
3062 
3063  if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0],
3065  DeviceObject))
3066  {
3067  DPRINT("Synchronization failed!\n");
3068 
3069  Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
3070  Irp->IoStatus.Information = 0;
3071  KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3072 
3074  }
3075  else
3076  {
3077  /* Release the spinlock only */
3078  KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3079  }
3080 
3081 
3082  DPRINT("ScsiPortStartIo() done\n");
3083 }
3084 
3085 
3086 static BOOLEAN NTAPI
3088 {
3089  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
3090  PIO_STACK_LOCATION IrpStack;
3093  PSCSI_PORT_LUN_EXTENSION LunExtension;
3094  PSCSI_REQUEST_BLOCK_INFO SrbInfo;
3095  BOOLEAN Result;
3096  BOOLEAN StartTimer;
3097 
3098  DPRINT("ScsiPortStartPacket() called\n");
3099 
3101 
3102  IrpStack = IoGetCurrentIrpStackLocation(DeviceObject->CurrentIrp);
3103  Srb = IrpStack->Parameters.Scsi.Srb;
3104 
3105  /* Get LUN extension */
3106  LunExtension = SpiGetLunExtension(DeviceExtension,
3107  Srb->PathId,
3108  Srb->TargetId,
3109  Srb->Lun);
3110 
3111  /* Check if we are in a reset state */
3112  if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET)
3113  {
3114  /* Mark the we've got requests while being in the reset state */
3115  DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET_REQUEST;
3116  return TRUE;
3117  }
3118 
3119  /* Set the time out value */
3120  DeviceExtension->TimerCount = Srb->TimeOutValue;
3121 
3122  /* We are busy */
3123  DeviceExtension->Flags |= SCSI_PORT_DEVICE_BUSY;
3124 
3125  if (LunExtension->RequestTimeout != -1)
3126  {
3127  /* Timer already active */
3128  StartTimer = FALSE;
3129  }
3130  else
3131  {
3132  /* It hasn't been initialized yet */
3133  LunExtension->RequestTimeout = Srb->TimeOutValue;
3134  StartTimer = TRUE;
3135  }
3136 
3137  if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
3138  {
3139  /* Handle bypass-requests */
3140 
3141  /* Is this an abort request? */
3142  if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
3143  {
3144  /* Get pointer to SRB info structure */
3145  SrbInfo = SpiGetSrbData(DeviceExtension,
3146  Srb->PathId,
3147  Srb->TargetId,
3148  Srb->Lun,
3149  Srb->QueueTag);
3150 
3151  /* Check if the request is still "active" */
3152  if (SrbInfo == NULL ||
3153  SrbInfo->Srb == NULL ||
3154  !(SrbInfo->Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE))
3155  {
3156  /* It's not, mark it as active then */
3157  Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
3158 
3159  if (StartTimer)
3160  LunExtension->RequestTimeout = -1;
3161 
3162  DPRINT("Request has been already completed, but abort request came\n");
3163  Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
3164 
3165  /* Notify about request complete */
3167  DeviceExtension->MiniPortDeviceExtension,
3168  Srb);
3169 
3170  /* and about readiness for the next request */
3172  DeviceExtension->MiniPortDeviceExtension);
3173 
3174  /* They might ask for some work, so queue the DPC for them */
3175  IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
3176 
3177  /* We're done in this branch */
3178  return TRUE;
3179  }
3180  }
3181  else
3182  {
3183  /* Add number of queued requests */
3184  LunExtension->QueueCount++;
3185  }
3186 
3187  /* Bypass requests don't need request sense */
3188  LunExtension->Flags &= ~LUNEX_NEED_REQUEST_SENSE;
3189 
3190  /* Is disconnect disabled for this request? */
3191  if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
3192  {
3193  /* Set the corresponding flag */
3194  DeviceExtension->Flags &= ~SCSI_PORT_DISCONNECT_ALLOWED;
3195  }
3196 
3197  /* Transfer timeout value from Srb to Lun */
3198  LunExtension->RequestTimeout = Srb->TimeOutValue;
3199  }
3200  else
3201  {
3202  if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
3203  {
3204  /* It's a disconnect, so no more requests can go */
3205  DeviceExtension->Flags &= ~SCSI_PORT_DISCONNECT_ALLOWED;
3206  }
3207 
3208  LunExtension->Flags |= SCSI_PORT_LU_ACTIVE;
3209 
3210  /* Increment queue count */
3211  LunExtension->QueueCount++;
3212 
3213  /* If it's tagged - special thing */
3214  if (Srb->QueueTag != SP_UNTAGGED)
3215  {
3216  SrbInfo = &DeviceExtension->SrbInfo[Srb->QueueTag - 1];
3217 
3218  /* Chek for consistency */
3219  ASSERT(SrbInfo->Requests.Blink == NULL);
3220 
3221  /* Insert it into the list of requests */
3222  InsertTailList(&LunExtension->SrbInfo.Requests, &SrbInfo->Requests);
3223  }
3224  }
3225 
3226  /* Mark this Srb active */
3227  Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
3228 
3229  /* Call HwStartIo routine */
3230  Result = DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
3231  Srb);
3232 
3233  /* If notification is needed, then request a DPC */
3234  if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
3235  IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
3236 
3237  return Result;
3238 }
3239 
3241 NTAPI
3243  PIRP Irp,
3245  PVOID Context)
3246 {
3248  PSCSI_SG_ADDRESS ScatterGatherList;
3249  KIRQL CurrentIrql;
3250  PIO_STACK_LOCATION IrpStack;
3251  ULONG TotalLength = 0;
3252  PSCSI_REQUEST_BLOCK_INFO SrbInfo;
3253  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
3254  PUCHAR DataVA;
3255  BOOLEAN WriteToDevice;
3256 
3257  /* Get pointers to SrbInfo and DeviceExtension */
3258  SrbInfo = (PSCSI_REQUEST_BLOCK_INFO)Context;
3259  DeviceExtension = DeviceObject->DeviceExtension;
3260 
3261  /* Get pointer to SRB */
3262  IrpStack = IoGetCurrentIrpStackLocation(Irp);
3263  Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
3264 
3265  /* Depending on the map registers number, we allocate
3266  either from NonPagedPool, or from our static list */
3267  if (SrbInfo->NumberOfMapRegisters > MAX_SG_LIST)
3268  {
3271 
3272  if (SrbInfo->ScatterGather == NULL)
3273  ASSERT(FALSE);
3274 
3275  Srb->SrbFlags |= SRB_FLAGS_SGLIST_FROM_POOL;
3276  }
3277  else
3278  {
3279  SrbInfo->ScatterGather = SrbInfo->ScatterGatherList;
3280  }
3281 
3282  /* Use chosen SG list source */
3283  ScatterGatherList = SrbInfo->ScatterGather;
3284 
3285  /* Save map registers base */
3287 
3288  /* Determine WriteToDevice flag */
3289  WriteToDevice = Srb->SrbFlags & SRB_FLAGS_DATA_OUT ? TRUE : FALSE;
3290 
3291  /* Get virtual address of the data buffer */
3292  DataVA = (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress) +
3293  ((PCHAR)Srb->DataBuffer - SrbInfo->DataOffset);
3294 
3295  /* Build the actual SG list */
3296  while (TotalLength < Srb->DataTransferLength)
3297  {
3298  if (!ScatterGatherList)
3299  break;
3300 
3301  ScatterGatherList->Length = Srb->DataTransferLength - TotalLength;
3302  ScatterGatherList->PhysicalAddress = IoMapTransfer(DeviceExtension->AdapterObject,
3303  Irp->MdlAddress,
3305  DataVA + TotalLength,
3306  &ScatterGatherList->Length,
3307  WriteToDevice);
3308 
3309  TotalLength += ScatterGatherList->Length;
3310  ScatterGatherList++;
3311  }
3312 
3313  /* Schedule an active request */
3314  InterlockedIncrement(&DeviceExtension->ActiveRequestCounter );
3315  KeAcquireSpinLock(&DeviceExtension->SpinLock, &CurrentIrql);
3316  KeSynchronizeExecution(DeviceExtension->Interrupt[0],
3318  DeviceObject);
3319  KeReleaseSpinLock(&DeviceExtension->SpinLock, CurrentIrql);
3320 
3322 }
3323 
3326 {
3327  PSCSI_PORT_LUN_EXTENSION LunExtension;
3328  ULONG LunExtensionSize;
3329 
3330  DPRINT("SpiAllocateLunExtension(%p)\n", DeviceExtension);
3331 
3332  /* Round LunExtensionSize first to the sizeof LONGLONG */
3333  LunExtensionSize = (DeviceExtension->LunExtensionSize +
3334  sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1);
3335 
3336  LunExtensionSize += sizeof(SCSI_PORT_LUN_EXTENSION);
3337  DPRINT("LunExtensionSize %lu\n", LunExtensionSize);
3338 
3339  LunExtension = ExAllocatePoolWithTag(NonPagedPool, LunExtensionSize, TAG_SCSIPORT);
3340  if (LunExtension == NULL)
3341  {
3342  DPRINT1("Out of resources!\n");
3343  return NULL;
3344  }
3345 
3346  /* Zero everything */
3347  RtlZeroMemory(LunExtension, LunExtensionSize);
3348 
3349  /* Initialize a list of requests */
3350  InitializeListHead(&LunExtension->SrbInfo.Requests);
3351 
3352  /* Initialize timeout counter */
3353  LunExtension->RequestTimeout = -1;
3354 
3355  /* Set maximum queue size */
3356  LunExtension->MaxQueueCount = 256;
3357 
3358  /* Initialize request queue */
3359  KeInitializeDeviceQueue(&LunExtension->DeviceQueue);
3360 
3361  return LunExtension;
3362 }
3363 
3366  IN UCHAR PathId,
3367  IN UCHAR TargetId,
3368  IN UCHAR Lun)
3369 {
3370  PSCSI_PORT_LUN_EXTENSION LunExtension;
3371 
3372  DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
3373  DeviceExtension, PathId, TargetId, Lun);
3374 
3375  /* Get appropriate list */
3376  LunExtension = DeviceExtension->LunExtensionList[(TargetId + Lun) % LUS_NUMBER];
3377 
3378  /* Iterate it until we find what we need */
3379  while (LunExtension)
3380  {
3381  if (LunExtension->TargetId == TargetId &&
3382  LunExtension->Lun == Lun &&
3383  LunExtension->PathId == PathId)
3384  {
3385  /* All matches, return */
3386  return LunExtension;
3387  }
3388 
3389  /* Advance to the next item */
3390  LunExtension = LunExtension->Next;
3391  }
3392 
3393  /* We did not find anything */
3394  DPRINT("Nothing found\n");
3395  return NULL;
3396 }
3397 
3400  PSCSI_PORT_LUN_EXTENSION LunExtension,
3402 {
3403  PCHAR SrbExtension;
3404  PSCSI_REQUEST_BLOCK_INFO SrbInfo;
3405 
3406  /* Spinlock must be held while this function executes */
3407  KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
3408 
3409  /* Allocate SRB data structure */
3410  if (DeviceExtension->NeedSrbDataAlloc)
3411  {
3412  /* Treat the abort request in a special way */
3413  if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
3414  {
3415  SrbInfo = SpiGetSrbData(DeviceExtension,
3416  Srb->PathId,
3417  Srb->TargetId,
3418  Srb->Lun,
3419  Srb->QueueTag);
3420  }
3421  else if (Srb->SrbFlags &
3423  !(Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
3424  )
3425  {
3426  /* Do not process tagged commands if need request sense is set */
3427  if (LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE)
3428  {
3429  ASSERT(!(LunExtension->Flags & LUNEX_REQUEST_PENDING));
3430 
3431  LunExtension->PendingRequest = Srb->OriginalRequest;
3432  LunExtension->Flags |= LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE;
3433 
3434  /* Release the spinlock and return */
3435  KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3436  return NULL;
3437  }
3438 
3439  ASSERT(LunExtension->SrbInfo.Srb == NULL);
3440  SrbInfo = DeviceExtension->FreeSrbInfo;
3441 
3442  if (SrbInfo == NULL)
3443  {
3444  /* No SRB structures left in the list. We have to leave
3445  and wait while we are called again */
3446 
3447  DeviceExtension->Flags |= SCSI_PORT_REQUEST_PENDING;
3448  KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3449  return NULL;
3450  }
3451 
3452  DeviceExtension->FreeSrbInfo = (PSCSI_REQUEST_BLOCK_INFO)SrbInfo->Requests.Flink;
3453 
3454  /* QueueTag must never be 0, so +1 to it */
3455  Srb->QueueTag = (UCHAR)(SrbInfo - DeviceExtension->SrbInfo) + 1;
3456  }
3457  else
3458  {
3459  /* Usual untagged command */
3460  if (
3461  (!IsListEmpty(&LunExtension->SrbInfo.Requests) ||
3462  LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE) &&
3463  !(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
3464  )
3465  {
3466  /* Mark it as pending and leave */
3467  ASSERT(!(LunExtension->Flags & LUNEX_REQUEST_PENDING));
3468  LunExtension->Flags |= LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE;
3469  LunExtension->PendingRequest = Srb->OriginalRequest;
3470 
3471  KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3472  return(NULL);
3473  }
3474 
3475  Srb->QueueTag = SP_UNTAGGED;
3476  SrbInfo = &LunExtension->SrbInfo;
3477  }
3478  }
3479  else
3480  {
3481  Srb->QueueTag = SP_UNTAGGED;
3482  SrbInfo = &LunExtension->SrbInfo;
3483  }
3484 
3485  /* Allocate SRB extension structure */
3486  if (DeviceExtension->NeedSrbExtensionAlloc)
3487  {
3488  /* Check the list of free extensions */
3489  SrbExtension = DeviceExtension->FreeSrbExtensions;
3490 
3491  /* If no free extensions... */
3492  if (SrbExtension == NULL)
3493  {
3494  /* Free SRB data */
3495  if (Srb->Function != SRB_FUNCTION_ABORT_COMMAND &&
3496  Srb->QueueTag != SP_UNTAGGED)
3497  {
3498  SrbInfo->Requests.Blink = NULL;
3499  SrbInfo->Requests.Flink = (PLIST_ENTRY)DeviceExtension->FreeSrbInfo;
3500  DeviceExtension->FreeSrbInfo = SrbInfo;
3501  }
3502 
3503  /* Return, in order to be called again later */
3504  DeviceExtension->Flags |= SCSI_PORT_REQUEST_PENDING;
3505  KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3506  return NULL;
3507  }
3508 
3509  /* Remove that free SRB extension from the list (since
3510  we're going to use it) */
3511  DeviceExtension->FreeSrbExtensions = *((PVOID *)SrbExtension);
3512 
3513  /* Spinlock can be released now */
3514  KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3515 
3516  Srb->SrbExtension = SrbExtension;
3517 
3518  if (Srb->SenseInfoBuffer != NULL &&
3519  DeviceExtension->SupportsAutoSense)
3520  {
3521  /* Store pointer to the SenseInfo buffer */
3522  SrbInfo->SaveSenseRequest = Srb->SenseInfoBuffer;
3523 
3524  /* Does data fit the buffer? */
3525  if (Srb->SenseInfoBufferLength > sizeof(SENSE_DATA))
3526  {
3527  /* No, disabling autosense at all */
3528  Srb->SrbFlags |= SRB_FLAGS_DISABLE_AUTOSENSE;
3529  }
3530  else
3531  {
3532  /* Yes, update the buffer pointer */
3533  Srb->SenseInfoBuffer = SrbExtension + DeviceExtension->SrbExtensionSize;
3534  }
3535  }
3536  }
3537  else
3538  {
3539  /* Cleanup... */
3540  Srb->SrbExtension = NULL;
3541  KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3542  }
3543 
3544  return SrbInfo;
3545 }
3546 
3547 
3548 static NTSTATUS
3550  IN OUT PSCSI_LUN_INFO LunInfo)
3551 {
3553  PIO_STACK_LOCATION IrpStack;
3554  KEVENT Event;
3555  KIRQL Irql;
3556  PIRP Irp;
3557  NTSTATUS Status;
3558  PINQUIRYDATA InquiryBuffer;
3559  PSENSE_DATA SenseBuffer;
3560  BOOLEAN KeepTrying = TRUE;
3561  ULONG RetryCount = 0;
3563  PCDB Cdb;
3564  PSCSI_PORT_LUN_EXTENSION LunExtension;
3565  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
3566 
3567  DPRINT("SpiSendInquiry() called\n");
3568 
3570 
3572  if (InquiryBuffer == NULL)
3574 
3576  if (SenseBuffer == NULL)
3577  {
3578  ExFreePoolWithTag(InquiryBuffer, TAG_SCSIPORT);
3580  }
3581 
3582  while (KeepTrying)
3583  {
3584  /* Initialize event for waiting */
3587  FALSE);
3588 
3589  /* Create an IRP */
3591  DeviceObject,
3592  NULL,
3593  0,
3594  InquiryBuffer,
3596  TRUE,
3597  &Event,
3598  &IoStatusBlock);
3599  if (Irp == NULL)
3600  {
3601  DPRINT("IoBuildDeviceIoControlRequest() failed\n");
3602 
3603  /* Quit the loop */
3605  KeepTrying = FALSE;
3606  continue;
3607  }
3608 
3609  /* Prepare SRB */
3611 
3612  Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
3613  Srb.OriginalRequest = Irp;
3614  Srb.PathId = LunInfo->PathId;
3615  Srb.TargetId = LunInfo->TargetId;
3616  Srb.Lun = LunInfo->Lun;
3617  Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
3619  Srb.TimeOutValue = 4;
3620  Srb.CdbLength = 6;
3621 
3622  Srb.SenseInfoBuffer = SenseBuffer;
3623  Srb.SenseInfoBufferLength = SENSE_BUFFER_SIZE;
3624 
3625  Srb.DataBuffer = InquiryBuffer;
3626  Srb.DataTransferLength = INQUIRYDATABUFFERSIZE;
3627 
3628  /* Attach Srb to the Irp */
3629  IrpStack = IoGetNextIrpStackLocation (Irp);
3630  IrpStack->Parameters.Scsi.Srb = &Srb;
3631 
3632  /* Fill in CDB */
3633  Cdb = (PCDB)Srb.Cdb;
3634  Cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
3635  Cdb->CDB6INQUIRY.LogicalUnitNumber = LunInfo->Lun;
3636  Cdb->CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE;
3637 
3638  /* Call the driver */
3640 
3641  /* Wait for it to complete */
3642  if (Status == STATUS_PENDING)
3643  {
3644  DPRINT("SpiSendInquiry(): Waiting for the driver to process request...\n");
3646  Executive,
3647  KernelMode,
3648  FALSE,
3649  NULL);
3651  }
3652 
3653  DPRINT("SpiSendInquiry(): Request processed by driver, status = 0x%08X\n", Status);
3654 
3655  if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_SUCCESS)
3656  {
3657  /* All fine, copy data over */
3658  RtlCopyMemory(LunInfo->InquiryData,
3659  InquiryBuffer,
3661 
3662  /* Quit the loop */
3664  KeepTrying = FALSE;
3665  continue;
3666  }
3667 
3668  DPRINT("Inquiry SRB failed with SrbStatus 0x%08X\n", Srb.SrbStatus);
3669 
3670  /* Check if the queue is frozen */
3671  if (Srb.SrbStatus & SRB_STATUS_QUEUE_FROZEN)
3672  {
3673  /* Something weird happened, deal with it (unfreeze the queue) */
3674  KeepTrying = FALSE;
3675 
3676  DPRINT("SpiSendInquiry(): the queue is frozen at TargetId %d\n", Srb.TargetId);
3677 
3678  LunExtension = SpiGetLunExtension(DeviceExtension,
3679  LunInfo->PathId,
3680  LunInfo->TargetId,
3681  LunInfo->Lun);
3682 
3683  /* Clear frozen flag */
3684  LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
3685 
3686  /* Acquire the spinlock */
3687  KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
3688 
3689  /* Process the request */
3691 
3692  /* SpiGetNextRequestFromLun() releases the spinlock,
3693  so we just lower irql back to what it was before */
3694  KeLowerIrql(Irql);
3695  }
3696 
3697  /* Check if data overrun happened */
3698  if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN)
3699  {
3700  DPRINT("Data overrun at TargetId %d\n", LunInfo->TargetId);
3701 
3702  /* Nothing dramatic, just copy data, but limiting the size */
3703  RtlCopyMemory(LunInfo->InquiryData,
3704  InquiryBuffer,
3705  (Srb.DataTransferLength > INQUIRYDATABUFFERSIZE) ?
3706  INQUIRYDATABUFFERSIZE : Srb.DataTransferLength);
3707 
3708  /* Quit the loop */
3710  KeepTrying = FALSE;
3711  }
3712  else if ((Srb.SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
3713  SenseBuffer->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST)
3714  {
3715  /* LUN is not valid, but some device responds there.
3716  Mark it as invalid anyway */
3717 
3718  /* Quit the loop */
3720  KeepTrying = FALSE;
3721  }
3722  else
3723  {
3724  /* Retry a couple of times if no timeout happened */
3725  if ((RetryCount < 2) &&
3726  (SRB_STATUS(Srb.SrbStatus) != SRB_STATUS_NO_DEVICE) &&
3728  {
3729  RetryCount++;
3730  KeepTrying = TRUE;
3731  }
3732  else
3733  {
3734  /* That's all, quit the loop */
3735  KeepTrying = FALSE;
3736 
3737  /* Set status according to SRB status */
3738  if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_BAD_FUNCTION ||
3740  {
3742  }
3743  else
3744  {
3746  }
3747  }
3748  }
3749  }
3750 
3751  /* Free buffers */
3752  ExFreePoolWithTag(InquiryBuffer, TAG_SCSIPORT);
3753  ExFreePoolWithTag(SenseBuffer, TAG_SCSIPORT);
3754 
3755  DPRINT("SpiSendInquiry() done with Status 0x%08X\n", Status);
3756 
3757  return Status;
3758 }
3759 
3760 
3761 /* Scans all SCSI buses */
3762 static VOID
3764 {
3765  PSCSI_PORT_LUN_EXTENSION LunExtension;
3766  ULONG Bus;
3767  ULONG Target;
3768  ULONG Lun;
3769  PSCSI_BUS_SCAN_INFO BusScanInfo;
3770  PSCSI_LUN_INFO LastLunInfo, LunInfo, LunInfoExists;
3771  BOOLEAN DeviceExists;
3772  ULONG Hint;
3773  NTSTATUS Status;
3774  ULONG DevicesFound;
3775 
3776  DPRINT("SpiScanAdapter() called\n");
3777 
3778  /* Scan all buses */
3779  for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
3780  {
3781  DPRINT(" Scanning bus %d\n", Bus);
3782  DevicesFound = 0;
3783 
3784  /* Get pointer to the scan information */
3785  BusScanInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus];
3786 
3787  if (BusScanInfo)
3788  {
3789  /* Find the last LUN info in the list */
3790  LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
3791  LastLunInfo = LunInfo;
3792 
3793  while (LunInfo != NULL)
3794  {
3795  LastLunInfo = LunInfo;
3796  LunInfo = LunInfo->Next;
3797  }
3798  }
3799  else
3800  {
3801  /* We need to allocate this buffer */
3803  if (!BusScanInfo)
3804  {
3805  DPRINT1("Out of resources!\n");
3806  return;
3807  }
3808 
3809  /* Store the pointer in the BusScanInfo array */
3810  DeviceExtension->BusesConfig->BusScanInfo[Bus] = BusScanInfo;
3811 
3812  /* Fill this struct (length and bus ids for now) */
3813  BusScanInfo->Length = sizeof(SCSI_BUS_SCAN_INFO);
3814  BusScanInfo->LogicalUnitsCount = 0;
3815  BusScanInfo->BusIdentifier = DeviceExtension->PortConfig->InitiatorBusId[Bus];
3816  BusScanInfo->LunInfo = NULL;
3817 
3818  /* Set pointer to the last LUN info to NULL */
3819  LastLunInfo = NULL;
3820  }
3821 
3822  /* Create LUN information structure */
3824  if (!LunInfo)
3825  {
3826  DPRINT1("Out of resources!\n");
3827  return;
3828  }
3829 
3830  RtlZeroMemory(LunInfo, sizeof(SCSI_LUN_INFO));
3831 
3832  /* Create LunExtension */
3833  LunExtension = SpiAllocateLunExtension(DeviceExtension);
3834 
3835  /* And send INQUIRY to every target */
3836  for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
3837  {
3838  /* TODO: Support scan bottom-up */
3839 
3840  /* Skip if it's the same address */
3841  if (Target == BusScanInfo->BusIdentifier)
3842  continue;
3843 
3844  /* Try to find an existing device here */
3845  DeviceExists = FALSE;
3846  LunInfoExists = BusScanInfo->LunInfo;
3847 
3848  /* Find matching address on this bus */
3849  while (LunInfoExists)
3850  {
3851  if (LunInfoExists->TargetId == Target)
3852  {
3853  DeviceExists = TRUE;
3854  break;
3855  }
3856 
3857  /* Advance to the next one */
3858  LunInfoExists = LunInfoExists->Next;
3859  }
3860 
3861  /* No need to bother rescanning, since we already did that before */
3862  if (DeviceExists)
3863  continue;
3864 
3865  /* Scan all logical units */
3866  for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
3867  {
3868  if ((!LunExtension) || (!LunInfo))
3869  break;
3870 
3871  /* Add extension to the list */
3872  Hint = (Target + Lun) % LUS_NUMBER;
3873  LunExtension->Next = DeviceExtension->LunExtensionList[Hint];
3874  DeviceExtension->LunExtensionList[Hint] = LunExtension;
3875 
3876  /* Fill Path, Target, Lun fields */
3877  LunExtension->PathId = LunInfo->PathId = (UCHAR)Bus;
3878  LunExtension->TargetId = LunInfo->TargetId = (UCHAR)Target;
3879  LunExtension->Lun = LunInfo->Lun = (UCHAR)Lun;
3880 
3881  /* Set flag to prevent race conditions */
3882  LunExtension->Flags |= SCSI_PORT_SCAN_IN_PROGRESS;
3883 
3884  /* Zero LU extension contents */
3885  if (DeviceExtension->LunExtensionSize)
3886  {
3887  RtlZeroMemory(LunExtension + 1,
3888  DeviceExtension->LunExtensionSize);
3889  }
3890 
3891  /* Finally send the inquiry command */
3892  Status = SpiSendInquiry(DeviceExtension->DeviceObject, LunInfo);
3893 
3894  if (NT_SUCCESS(Status))
3895  {
3896  /* Let's see if we really found a device */
3897  PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData;
3898 
3899  /* Check if this device is unsupported */
3901  {
3902  DeviceExtension->LunExtensionList[Hint] =
3903  DeviceExtension->LunExtensionList[Hint]->Next;
3904 
3905  continue;
3906  }
3907 
3908  /* Clear the "in scan" flag */
3909  LunExtension->Flags &= ~SCSI_PORT_SCAN_IN_PROGRESS;
3910 
3911  DPRINT("SpiScanAdapter(): Found device of type %d at bus %d tid %d lun %d\n",
3912  InquiryData->DeviceType, Bus, Target, Lun);
3913 
3914  /*
3915  * Cache the inquiry data into the LUN extension (or alternatively
3916  * we could save a pointer to LunInfo within the LunExtension?)
3917  */
3918  RtlCopyMemory(&LunExtension->InquiryData,
3919  InquiryData,
3921 
3922  /* Add this info to the linked list */
3923  LunInfo->Next = NULL;
3924  if (LastLunInfo)
3925  LastLunInfo->Next = LunInfo;
3926  else
3927  BusScanInfo->LunInfo = LunInfo;
3928 
3929  /* Store the last LUN info */
3930  LastLunInfo = LunInfo;
3931 
3932  /* Store DeviceObject */
3933  LunInfo->DeviceObject = DeviceExtension->DeviceObject;
3934 
3935  /* Allocate another buffer */
3937  if (!LunInfo)
3938  {
3939  DPRINT1("Out of resources!\n");
3940  break;
3941  }
3942 
3943  RtlZeroMemory(LunInfo, sizeof(SCSI_LUN_INFO));
3944 
3945  /* Create a new LU extension */
3946  LunExtension = SpiAllocateLunExtension(DeviceExtension);
3947 
3948  DevicesFound++;
3949  }
3950  else
3951  {
3952  /* Remove this LUN from the list */
3953  DeviceExtension->LunExtensionList[Hint] =
3954  DeviceExtension->LunExtensionList[Hint]->Next;
3955 
3956  /* Decide whether we are continuing or not */
3958  continue;
3959  else
3960  break;
3961  }
3962  }
3963  }
3964 
3965  /* Free allocated buffers */
3966  if (LunExtension)
3967  ExFreePoolWithTag(LunExtension, TAG_SCSIPORT);
3968 
3969  if (LunInfo)
3970  ExFreePoolWithTag(LunInfo, TAG_SCSIPORT);
3971 
3972  /* Sum what we found */
3973  BusScanInfo->LogicalUnitsCount += (UCHAR)DevicesFound;
3974  DPRINT(" Found %d devices on bus %d\n", DevicesFound, Bus);
3975  }
3976 
3977  DPRINT("SpiScanAdapter() done\n");
3978 }
3979 
3980 
3981 static NTSTATUS
3983  IN PIRP Irp)
3984 {
3985  ULONG InquiryDataSize;
3986  PSCSI_LUN_INFO LunInfo;
3987  ULONG BusCount, LunCount, Length;
3988  PIO_STACK_LOCATION IrpStack;
3989  PSCSI_ADAPTER_BUS_INFO AdapterBusInfo;
3990  PSCSI_INQUIRY_DATA InquiryData;
3991  PSCSI_BUS_DATA BusData;
3992  ULONG Bus;
3993  PUCHAR Buffer;
3994 
3995  DPRINT("SpiGetInquiryData() called\n");
3996 
3997  /* Get pointer to the buffer */
3998  IrpStack = IoGetCurrentIrpStackLocation(Irp);
3999  Buffer = Irp->AssociatedIrp.SystemBuffer;
4000 
4001  /* Initialize bus and LUN counters */
4002  BusCount = DeviceExtension->BusesConfig->NumberOfBuses;
4003  LunCount = 0;
4004 
4005  /* Calculate total number of LUNs */
4006  for (Bus = 0; Bus < BusCount; Bus++)
4007  LunCount += DeviceExtension->BusesConfig->BusScanInfo[Bus]->LogicalUnitsCount;
4008 
4009  /* Calculate size of inquiry data, rounding up to sizeof(ULONG) */
4010  InquiryDataSize =
4011  ((sizeof(SCSI_INQUIRY_DATA) - 1 + INQUIRYDATABUFFERSIZE +
4012  sizeof(ULONG) - 1) & ~(sizeof(ULONG) - 1));
4013 
4014  /* Calculate data size */
4015  Length = sizeof(SCSI_ADAPTER_BUS_INFO) + (BusCount - 1) * sizeof(SCSI_BUS_DATA);
4016 
4017  Length += InquiryDataSize * LunCount;
4018 
4019  /* Check, if all data is going to fit into provided buffer */
4020  if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < Length)
4021  {
4022  Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
4023  return STATUS_BUFFER_TOO_SMALL;
4024  }
4025 
4026  /* Store data size in the IRP */
4027  Irp->IoStatus.Information = Length;
4028 
4029  DPRINT("Data size: %lu\n", Length);
4030 
4031  AdapterBusInfo = (PSCSI_ADAPTER_BUS_INFO)Buffer;
4032 
4033  AdapterBusInfo->NumberOfBuses = (UCHAR)BusCount;
4034 
4035  /* Point InquiryData to the corresponding place inside Buffer */
4036  InquiryData = (PSCSI_INQUIRY_DATA)(Buffer + sizeof(SCSI_ADAPTER_BUS_INFO) +
4037  (BusCount - 1) * sizeof(SCSI_BUS_DATA));
4038 
4039  /* Loop each bus */
4040  for (Bus = 0; Bus < BusCount; Bus++)
4041  {
4042  BusData = &AdapterBusInfo->BusData[Bus];
4043 
4044  /* Calculate and save an offset of the inquiry data */
4045  BusData->InquiryDataOffset = (ULONG)((PUCHAR)InquiryData - Buffer);
4046 
4047  /* Get a pointer to the LUN information structure */
4048  LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
4049 
4050  /* Store Initiator Bus Id */
4051  BusData->InitiatorBusId =
4052  DeviceExtension->BusesConfig->BusScanInfo[Bus]->BusIdentifier;
4053 
4054  /* Store LUN count */
4055  BusData->NumberOfLogicalUnits =
4056  DeviceExtension->BusesConfig->BusScanInfo[Bus]->LogicalUnitsCount;
4057 
4058  /* Loop all LUNs */
4059  while (LunInfo != NULL)
4060  {
4061  DPRINT("(Bus %lu Target %lu Lun %lu)\n",
4062  Bus, LunInfo->TargetId, LunInfo->Lun);
4063 
4064  /* Fill InquiryData with values */
4065  InquiryData->PathId = LunInfo->PathId;
4066  InquiryData->TargetId = LunInfo->TargetId;
4067  InquiryData->Lun = LunInfo->Lun;
4069  InquiryData->DeviceClaimed = LunInfo->DeviceClaimed;
4070  InquiryData->NextInquiryDataOffset =
4071  (ULONG)((PUCHAR)InquiryData + InquiryDataSize - Buffer);
4072 
4073  /* Copy data in it */
4074  RtlCopyMemory(InquiryData->InquiryData,
4075  LunInfo->InquiryData,
4077 
4078  /* Move to the next LUN */
4079  LunInfo = LunInfo->Next;
4080  InquiryData = (PSCSI_INQUIRY_DATA) ((PCHAR)InquiryData + InquiryDataSize);
4081  }
4082 
4083  /* Either mark the end, or set offset to 0 */
4084  if (BusData->NumberOfLogicalUnits != 0)
4085  ((PSCSI_INQUIRY_DATA) ((PCHAR)InquiryData - InquiryDataSize))->NextInquiryDataOffset = 0;
4086  else
4087  BusData->InquiryDataOffset = 0;
4088  }
4089 
4090  /* Finish with success */
4091  Irp->IoStatus.Status = STATUS_SUCCESS;
4092  return STATUS_SUCCESS;
4093 }
4094 
4097  IN UCHAR PathId,
4098  IN UCHAR TargetId,
4099  IN UCHAR Lun,
4100  IN UCHAR QueueTag)
4101 {
4102  PSCSI_PORT_LUN_EXTENSION LunExtension;
4103 
4104  if (QueueTag == SP_UNTAGGED)
4105  {
4106  /* Untagged request, get LU and return pointer to SrbInfo */
4107  LunExtension = SpiGetLunExtension(DeviceExtension,
4108  PathId,
4109  TargetId,
4110  Lun);
4111 
4112  /* Return NULL in case of error */
4113  if (!LunExtension)
4114  return(NULL);
4115 
4116  /* Return the pointer to SrbInfo */
4117  return &LunExtension->SrbInfo;
4118  }
4119  else
4120  {
4121  /* Make sure the tag is valid, if it is - return the data */
4122  if (QueueTag > DeviceExtension->SrbDataCount || QueueTag < 1)
4123  return NULL;
4124  else
4125  return &DeviceExtension->SrbInfo[QueueTag -1];
4126  }
4127 }
4128 
4129 static VOID
4131  IN PSCSI_REQUEST_BLOCK InitialSrb)
4132 {
4134  PCDB Cdb;
4135  PIRP Irp;
4136  PIO_STACK_LOCATION IrpStack;
4137  LARGE_INTEGER LargeInt;
4138  PVOID *Ptr;
4139 
4140  DPRINT("SpiSendRequestSense() entered, InitialSrb %p\n", InitialSrb);
4141 
4142  /* Allocate Srb */
4145 
4146  /* Allocate IRP */
4147  LargeInt.QuadPart = (LONGLONG) 1;
4149  DeviceExtension->DeviceObject,
4150  InitialSrb->SenseInfoBuffer,
4151  InitialSrb->SenseInfoBufferLength,
4152  &LargeInt,
4153  NULL);
4154 
4157  Srb,
4158  TRUE,
4159  TRUE,
4160  TRUE);
4161 
4162  if (!Srb)
4163  {
4164  DPRINT("SpiSendRequestSense() failed, Srb %p\n", Srb);
4165  return;
4166  }
4167 
4168  IrpStack = IoGetNextIrpStackLocation(Irp);
4169  IrpStack->MajorFunction = IRP_MJ_SCSI;
4170 
4171  /* Put Srb address into Irp... */
4172  IrpStack->Parameters.Others.Argument1 = (PVOID)Srb;
4173 
4174  /* ...and vice versa */
4175  Srb->OriginalRequest = Irp;
4176 
4177  /* Save Srb */
4178  Ptr = (PVOID *)(Srb+1);
4179  *Ptr = InitialSrb;
4180 
4181  /* Build CDB for REQUEST SENSE */
4182  Srb->CdbLength = 6;
4183  Cdb = (PCDB)Srb->Cdb;
4184 
4185  Cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE;
4186  Cdb->CDB6INQUIRY.LogicalUnitNumber = 0;
4187  Cdb->CDB6INQUIRY.Reserved1 = 0;
4188  Cdb->CDB6INQUIRY.PageCode = 0;
4189  Cdb->CDB6INQUIRY.IReserved = 0;
4190  Cdb->CDB6INQUIRY.AllocationLength = (UCHAR)InitialSrb->SenseInfoBufferLength;
4191  Cdb->CDB6INQUIRY.Control = 0;
4192 
4193  /* Set address */
4194  Srb->TargetId = InitialSrb->TargetId;
4195  Srb->Lun = InitialSrb->Lun;
4196  Srb->PathId = InitialSrb->PathId;
4197 
4198  Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
4199  Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
4200 
4201  /* Timeout will be 2 seconds */
4202  Srb->TimeOutValue = 2;
4203 
4204  /* No auto request sense */
4205  Srb->SenseInfoBufferLength = 0;
4206  Srb->SenseInfoBuffer = NULL;
4207 
4208  /* Set necessary flags */
4211 
4212  /* Transfer disable synch transfer flag */
4213  if (InitialSrb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER)
4215 
4216  Srb->DataBuffer = InitialSrb->SenseInfoBuffer;
4217 
4218  /* Fill the transfer length */
4219  Srb->DataTransferLength = InitialSrb->SenseInfoBufferLength;
4220 
4221  /* Clear statuses */
4222  Srb->ScsiStatus = Srb->SrbStatus = 0;
4223  Srb->NextSrb = 0;
4224 
4225  /* Call the driver */
4226  (VOID)IoCallDriver(DeviceExtension->DeviceObject, Irp);
4227 
4228  DPRINT("SpiSendRequestSense() done\n");
4229 }
4230 
4231 
4232 static
4233 VOID
4234 NTAPI
4236  IN PSCSI_REQUEST_BLOCK_INFO SrbInfo,
4237  OUT PBOOLEAN NeedToCallStartIo)
4238 {
4240  PSCSI_PORT_LUN_EXTENSION LunExtension;
4241  LONG Result;
4242  PIRP Irp;
4243  //ULONG SequenceNumber;
4244 
4245  Srb = SrbInfo->Srb;
4246  Irp = Srb->OriginalRequest;
4247 
4248  /* Get Lun extension */
4249  LunExtension = SpiGetLunExtension(DeviceExtension,
4250  Srb->PathId,
4251  Srb->TargetId,
4252  Srb->Lun);
4253 
4254  if (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION &&
4255  DeviceExtension->MapBuffers &&
4256  Irp->MdlAddress)
4257  {
4258  /* MDL is shared if transfer is broken into smaller parts */
4259  Srb->DataBuffer = (PCCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress) +
4260  ((PCCHAR)Srb->DataBuffer - SrbInfo->DataOffset);
4261 
4262  /* In case of data going in, flush the buffers */
4263  if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
4264  {
4265  KeFlushIoBuffers(Irp->MdlAddress,
4266  TRUE,
4267  FALSE);
4268  }
4269  }
4270 
4271  /* Flush adapter if needed */
4272  if (SrbInfo->BaseOfMapRegister)
4273  {
4274  /* TODO: Implement */
4275  ASSERT(FALSE);
4276  }
4277 
4278  /* Clear the request */
4279  SrbInfo->Srb = NULL;
4280 
4281  /* If disconnect is disabled... */
4282  if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
4283  {
4284  /* Acquire the spinlock since we mess with flags */
4285  KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
4286 
4287  /* Set corresponding flag */
4288  DeviceExtension->Flags |= SCSI_PORT_DISCONNECT_ALLOWED;
4289 
4290  /* Clear the timer if needed */
4291  if (!(DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET))
4292  DeviceExtension->TimerCount = -1;
4293 
4294  /* Spinlock is not needed anymore */
4295  KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4296 
4297  if (!(DeviceExtension->Flags & SCSI_PORT_REQUEST_PENDING) &&
4298  !(DeviceExtension->Flags & SCSI_PORT_DEVICE_BUSY) &&
4299  !(*NeedToCallStartIo))
4300  {
4301  /* We're not busy, but we have a request pending */
4302  IoStartNextPacket(DeviceExtension->DeviceObject, FALSE);
4303  }
4304  }
4305 
4306  /* Scatter/gather */
4307  if (Srb->SrbFlags & SRB_FLAGS_SGLIST_FROM_POOL)
4308  {
4309  /* TODO: Implement */
4310  ASSERT(FALSE);
4311  }
4312 
4313  /* Acquire spinlock (we're freeing SrbExtension) */
4314  KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
4315 
4316  /* Free it (if needed) */
4317  if (Srb->SrbExtension)
4318  {
4319  if (Srb->SenseInfoBuffer != NULL && DeviceExtension->SupportsAutoSense)
4320  {
4321  ASSERT(Srb->SenseInfoBuffer == NULL || SrbInfo->SaveSenseRequest != NULL);
4322 
4323  if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)
4324  {
4325  /* Copy sense data to the buffer */
4326  RtlCopyMemory(SrbInfo->SaveSenseRequest,
4327  Srb->SenseInfoBuffer,
4328  Srb->SenseInfoBufferLength);
4329  }
4330 
4331  /* And restore the pointer */
4332  Srb->SenseInfoBuffer = SrbInfo->SaveSenseRequest;
4333  }
4334 
4335  /* Put it into the free srb extensions list */
4336  *((PVOID *)Srb->SrbExtension) = DeviceExtension->FreeSrbExtensions;
4337  DeviceExtension->FreeSrbExtensions = Srb->SrbExtension;
4338  }
4339 
4340  /* Save transfer length in the IRP */
4341  Irp->IoStatus.Information = Srb->DataTransferLength;
4342 
4343  //SequenceNumber = SrbInfo->SequenceNumber;
4344  SrbInfo->SequenceNumber = 0;
4345 
4346  /* Decrement the queue count */
4347  LunExtension->QueueCount--;
4348 
4349  /* Free Srb, if needed*/
4350  if (Srb->QueueTag != SP_UNTAGGED)
4351  {
4352  /* Put it into the free list */
4353  SrbInfo->Requests.Blink = NULL;
4354  SrbInfo->Requests.Flink = (PLIST_ENTRY)DeviceExtension->FreeSrbInfo;
4355  DeviceExtension->FreeSrbInfo = SrbInfo;
4356  }
4357 
4358  /* SrbInfo is not used anymore */
4359  SrbInfo = NULL;
4360 
4361  if (DeviceExtension->Flags & SCSI_PORT_REQUEST_PENDING)
4362  {
4363  /* Clear the flag */
4364  DeviceExtension->Flags &= ~SCSI_PORT_REQUEST_PENDING;
4365 
4366  /* Note the caller about StartIo */
4367  *NeedToCallStartIo = TRUE;
4368  }
4369 
4370  if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
4371  {
4372  /* Start the packet */
4373  Irp->IoStatus.Status = STATUS_SUCCESS;
4374 
4375  if (!(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE) &&
4376  LunExtension->RequestTimeout == -1)
4377  {
4378  /* Start the next packet */
4379  SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
4380  }
4381  else
4382  {
4383  /* Release the spinlock */
4384  KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4385  }
4386 
4387  DPRINT("IoCompleting request IRP 0x%p\n", Irp);
4388 
4390 
4391  /* Decrement number of active requests, and analyze the result */
4392  Result = InterlockedDecrement(&DeviceExtension->ActiveRequestCounter);
4393 
4394  if (Result < 0 &&
4395  !DeviceExtension->MapRegisters &&
4396  DeviceExtension->AdapterObject != NULL)
4397  {
4398  /* Nullify map registers */
4399  DeviceExtension->MapRegisterBase = NULL;
4400  IoFreeAdapterChannel(DeviceExtension->AdapterObject);
4401  }
4402 
4403  /* Exit, we're done */
4404  return;
4405  }
4406 
4407  /* Decrement number of active requests, and analyze the result */
4408  Result = InterlockedDecrement(&DeviceExtension->ActiveRequestCounter);
4409 
4410  if (Result < 0 &&
4411  !DeviceExtension->MapRegisters &&
4412  DeviceExtension->AdapterObject != NULL)
4413  {
4414  /* Result is negative, so this is a slave, free map registers */
4415  DeviceExtension->MapRegisterBase = NULL;
4416  IoFreeAdapterChannel(DeviceExtension->AdapterObject);
4417  }
4418 
4419  /* Convert status */
4420  Irp->IoStatus.Status = SpiStatusSrbToNt(Srb->SrbStatus);
4421 
4422  /* It's not a bypass, it's busy or the queue is full? */
4423  if ((Srb->ScsiStatus == SCSISTAT_BUSY ||
4424  Srb->SrbStatus == SRB_STATUS_BUSY ||
4425  Srb->ScsiStatus == SCSISTAT_QUEUE_FULL) &&
4426  !(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE))
4427  {
4428 
4429  DPRINT("Busy SRB status %x\n", Srb->SrbStatus);
4430 
4431  /* Requeue, if needed */
4432  if (LunExtension->Flags & (LUNEX_FROZEN_QUEUE | LUNEX_BUSY))
4433  {
4434  DPRINT("it's being requeued\n");
4435 
4436  Srb->SrbStatus = SRB_STATUS_PENDING;
4437  Srb->ScsiStatus = 0;
4438 
4439  if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue,
4440  &Irp->Tail.Overlay.DeviceQueueEntry,
4441  Srb->QueueSortKey))
4442  {
4443  /* It's a big f.ck up if we got here */
4444  Srb->SrbStatus = SRB_STATUS_ERROR;
4445  Srb->ScsiStatus = SCSISTAT_BUSY;
4446 
4447  ASSERT(FALSE);
4448  goto Error;
4449  }
4450 
4451  /* Release the spinlock */
4452  KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4453 
4454  }
4455  else if (LunExtension->AttemptCount++ < 20)
4456  {
4457  /* LUN is still busy */
4458  Srb->ScsiStatus = 0;
4459  Srb->SrbStatus = SRB_STATUS_PENDING;
4460 
4461  LunExtension->BusyRequest = Irp;
4462  LunExtension->Flags |= LUNEX_BUSY;
4463 
4464  /* Release the spinlock */
4465  KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4466  }
4467  else
4468  {
4469 Error:
4470  /* Freeze the queue*/
4471  Srb->SrbStatus |= SRB_STATUS_QUEUE_FROZEN;
4472  LunExtension->Flags |= LUNEX_FROZEN_QUEUE;
4473 
4474  /* "Unfull" the queue */
4475  LunExtension->Flags &= ~LUNEX_FULL_QUEUE;
4476 
4477  /* Release the spinlock */
4478  KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4479 
4480  /* Return status that the device is not ready */
4481  Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
4483  }
4484 
4485  return;
4486  }
4487 
4488  /* Start the next request, if LUN is idle, and this is sense request */
4489  if (((Srb->ScsiStatus != SCSISTAT_CHECK_CONDITION) ||
4490  (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) ||
4491  !Srb->SenseInfoBuffer || !Srb->SenseInfoBufferLength)
4492  && (Srb->SrbFlags & SRB_FLAGS_NO_QUEUE_FREEZE))
4493  {
4494  if (LunExtension->RequestTimeout == -1)
4495  SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
4496  else
4497  KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4498  }
4499  else
4500  {
4501  /* Freeze the queue */
4502  Srb->SrbStatus |= SRB_STATUS_QUEUE_FROZEN;
4503  LunExtension->Flags |= LUNEX_FROZEN_QUEUE;
4504 
4505  /* Do we need a request sense? */
4506  if (Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION &&
4507  !(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
4508  Srb->SenseInfoBuffer && Srb->SenseInfoBufferLength)
4509  {
4510  /* If LUN is busy, we have to requeue it in order to allow request sense */
4511  if (LunExtension->Flags & LUNEX_BUSY)
4512  {
4513  DPRINT("Requeuing busy request to allow request sense\n");
4514 
4515  if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue,
4516  &LunExtension->BusyRequest->Tail.Overlay.DeviceQueueEntry,
4517  Srb->QueueSortKey))
4518  {
4519  /* We should never get here */
4520  ASSERT(FALSE);
4521 
4522  KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4524  return;
4525 
4526  }
4527 
4528  /* Clear busy flags */
4529  LunExtension->Flags &= ~(LUNEX_FULL_QUEUE | LUNEX_BUSY);
4530  }
4531 
4532  /* Release the spinlock */
4533  KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4534 
4535  /* Send RequestSense */
4536  SpiSendRequestSense(DeviceExtension, Srb);
4537 
4538  /* Exit */
4539  return;
4540  }
4541 
4542  /* Release the spinlock */
4543  KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4544  }
4545 
4546  /* Complete the request */
4548 }
4549 
4550 NTSTATUS
4551 NTAPI
4553  PIRP Irp,
4554  PVOID Context)
4555 {
4557  PSCSI_REQUEST_BLOCK InitialSrb;
4558  PIRP InitialIrp;
4559 
4560  DPRINT("SpiCompletionRoutine() entered, IRP %p \n", Irp);
4561 
4562  if ((Srb->Function == SRB_FUNCTION_RESET_BUS) ||
4563  (Srb->Function == SRB_FUNCTION_ABORT_COMMAND))
4564  {
4565  /* Deallocate SRB and IRP and exit */
4566  ExFreePool(Srb);
4567  IoFreeIrp(Irp);
4568 
4570  }
4571 
4572  /* Get a pointer to the SRB and IRP which were initially sent */
4573  InitialSrb = *((PVOID *)(Srb+1));
4574  InitialIrp = InitialSrb->OriginalRequest;
4575 
4576  if ((SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS) ||
4577  (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN))
4578  {
4579  /* Sense data is OK */
4580  InitialSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
4581 
4582  /* Set length to be the same */
4583  InitialSrb->SenseInfoBufferLength = (UCHAR)Srb->DataTransferLength;
4584  }
4585 
4586  /* Make sure initial SRB's queue is frozen */
4587  ASSERT(InitialSrb->SrbStatus & SRB_STATUS_QUEUE_FROZEN);
4588 
4589  /* Complete this request */
4590  IoCompleteRequest(InitialIrp, IO_DISK_INCREMENT);
4591 
4592  /* Deallocate everything (internal) */
4593  ExFreePool(Srb);
4594 
4595  if (Irp->MdlAddress != NULL)
4596  {
4597  MmUnlockPages(Irp->MdlAddress);
4598  IoFreeMdl(Irp->MdlAddress);
4599  Irp->MdlAddress = NULL;
4600  }
4601 
4602  IoFreeIrp(Irp);
4604 }
4605 
4606 static BOOLEAN NTAPI
4609 {
4610  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
4611 
4612  DPRINT("ScsiPortIsr() called!\n");
4613 
4614  DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext;
4615 
4616  /* If interrupts are disabled - we don't expect any */
4617  if (DeviceExtension->InterruptData.Flags & SCSI_PORT_DISABLE_INTERRUPTS)
4618  return FALSE;
4619 
4620  /* Call miniport's HwInterrupt routine */
4621  if (DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension) == FALSE)
4622  {
4623  /* This interrupt doesn't belong to us */
4624  return FALSE;
4625  }
4626 
4627  /* If flag of notification is set - queue a DPC */
4628  if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
4629  {
4630  IoRequestDpc(DeviceExtension->DeviceObject,
4631  DeviceExtension->CurrentIrp,
4632  DeviceExtension);
4633  }
4634 
4635  return TRUE;
4636 }
4637 
4638 BOOLEAN
4639 NTAPI
4641 {
4642  PSCSI_PORT_SAVE_INTERRUPT InterruptContext = Context;
4643  PSCSI_PORT_LUN_EXTENSION LunExtension;
4645  PSCSI_REQUEST_BLOCK_INFO SrbInfo, NextSrbInfo;
4646  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
4647  BOOLEAN IsTimed;
4648 
4649  /* Get pointer to the device extension */
4650  DeviceExtension = InterruptContext->DeviceExtension;
4651 
4652  /* If we don't have anything pending - return */
4653  if (!(DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED))
4654  return FALSE;
4655 
4656  /* Actually save the interrupt data */
4657  *InterruptContext->InterruptData = DeviceExtension->InterruptData;
4658 
4659  /* Clear the data stored in the device extension */
4660  DeviceExtension->InterruptData.Flags &=
4662  DeviceExtension->InterruptData.CompletedAbort = NULL;
4663  DeviceExtension->InterruptData.ReadyLun = NULL;
4664  DeviceExtension->InterruptData.CompletedRequests = NULL;
4665 
4666  /* Loop through the list of completed requests */
4667  SrbInfo = InterruptContext->InterruptData->CompletedRequests;
4668 
4669  while (SrbInfo)
4670  {
4671  /* Make sure we have SRV */
4672  ASSERT(SrbInfo->Srb);
4673 
4674  /* Get SRB and LunExtension */
4675  Srb = SrbInfo->Srb;
4676 
4677  LunExtension = SpiGetLunExtension(DeviceExtension,
4678  Srb->PathId,
4679  Srb->TargetId,
4680  Srb->Lun);
4681 
4682  /* We have to check special cases if request is unsuccessful*/
4683  if (Srb->SrbStatus != SRB_STATUS_SUCCESS)
4684  {
4685  /* Check if we need request sense by a few conditions */
4686  if (Srb->SenseInfoBuffer && Srb->SenseInfoBufferLength &&
4687  Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION &&
4688  !(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID))
4689  {
4690  if (LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE)
4691  {
4692  /* It means: we tried to send REQUEST SENSE, but failed */
4693 
4694  Srb->ScsiStatus = 0;
4695  Srb->SrbStatus = SRB_STATUS_REQUEST_SENSE_FAILED;
4696  }
4697  else
4698  {
4699  /* Set the corresponding flag, so that REQUEST SENSE
4700  will be sent */
4701  LunExtension->Flags |= LUNEX_NEED_REQUEST_SENSE;
4702  }
4703 
4704  }
4705 
4706  /* Check for a full queue */
4707  if (Srb->ScsiStatus == SCSISTAT_QUEUE_FULL)
4708  {
4709  /* TODO: Implement when it's encountered */
4710  ASSERT(FALSE);
4711  }
4712  }
4713 
4714  /* Let's decide if we need to watch timeout or not */
4715  if (Srb->QueueTag == SP_UNTAGGED)
4716  {
4717  IsTimed = TRUE;
4718  }
4719  else
4720  {
4721  if (LunExtension->SrbInfo.Requests.Flink == &SrbInfo->Requests)
4722  IsTimed = TRUE;
4723  else
4724  IsTimed = FALSE;
4725 
4726  /* Remove it from the queue */
4727  RemoveEntryList(&SrbInfo->Requests);
4728  }
4729 
4730  if (IsTimed)
4731  {
4732  /* We have to maintain timeout counter */
4733  if (IsListEmpty(&LunExtension->SrbInfo.Requests))
4734  {
4735  LunExtension->RequestTimeout = -1;
4736  }
4737  else
4738  {
4739  NextSrbInfo = CONTAINING_RECORD(LunExtension->SrbInfo.Requests.Flink,
4741  Requests);
4742 
4743  Srb = NextSrbInfo->Srb;
4744 
4745  /* Update timeout counter */
4746  LunExtension->RequestTimeout = Srb->TimeOutValue;
4747  }
4748  }
4749 
4750  SrbInfo = SrbInfo->CompletedRequests;
4751  }
4752 
4753  return TRUE;
4754 }
4755 
4756 VOID
4757 NTAPI
4759  IN PSCSI_PORT_LUN_EXTENSION LunExtension)
4760 {
4761  PIO_STACK_LOCATION IrpStack;
4762  PIRP NextIrp;
4765 
4766 
4767  /* If LUN is not active or queue is more than maximum allowed */
4768  if (LunExtension->QueueCount >= LunExtension->MaxQueueCount ||
4769  !(LunExtension->Flags & SCSI_PORT_LU_ACTIVE))
4770  {
4771  /* Release the spinlock and exit */
4772  KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4773  return;
4774  }
4775 
4776  /* Check if we can get a next request */
4777  if (LunExtension->Flags &
4780  {
4781  /* Pending requests can only be started if the queue is empty */
4782  if (IsListEmpty(&LunExtension->SrbInfo.Requests) &&
4783  !(LunExtension->Flags &
4785  {
4786  /* Make sure we have SRB */
4787  ASSERT(LunExtension->SrbInfo.Srb == NULL);
4788 
4789  /* Clear active and pending flags */
4790  LunExtension->Flags &= ~(LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE);
4791 
4792  /* Get next Irp, and clear pending requests list */
4793  NextIrp = LunExtension->PendingRequest;
4794  LunExtension->PendingRequest = NULL;
4795 
4796  /* Set attempt counter to zero */
4797  LunExtension->AttemptCount = 0;
4798 
4799  /* Release the spinlock */
4800  KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4801 
4802  /* Start the next pending request */
4803  IoStartPacket(DeviceExtension->DeviceObject, NextIrp, (PULONG)NULL, NULL);
4804 
4805  return;
4806  }
4807  else
4808  {
4809  /* Release the spinlock, without clearing any flags and exit */
4810  KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4811 
4812  return;
4813  }
4814  }
4815 
4816  /* Reset active flag */
4817  LunExtension->Flags &= ~SCSI_PORT_LU_ACTIVE;
4818 
4819  /* Set attempt counter to zero */
4820  LunExtension->AttemptCount = 0;
4821 
4822  /* Remove packet from the device queue */
4823  Entry = KeRemoveByKeyDeviceQueue(&LunExtension->DeviceQueue, LunExtension->SortKey);
4824 
4825  if (Entry != NULL)
4826  {
4827  /* Get pointer to the next irp */
4828  NextIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
4829 
4830  /* Get point to the SRB */
4831  IrpStack = IoGetCurrentIrpStackLocation(NextIrp);
4832  Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
4833 
4834  /* Set new key*/
4835  LunExtension->SortKey = Srb->QueueSortKey;
4836  LunExtension->SortKey++;
4837 
4838  /* Release the spinlock */
4839  KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4840 
4841  /* Start the next pending request */
4842  IoStartPacket(DeviceExtension->DeviceObject, NextIrp, (PULONG)NULL, NULL);
4843  }
4844  else
4845  {
4846  /* Release the spinlock */
4847  KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4848  }
4849 }
4850 
4851 
4852 
4853 // ScsiPortDpcForIsr
4854 // DESCRIPTION:
4855 //
4856 // RUN LEVEL:
4857 //
4858 // ARGUMENTS:
4859 // IN PKDPC Dpc
4860 // IN PDEVICE_OBJECT DpcDeviceObject
4861 // IN PIRP DpcIrp
4862 // IN PVOID DpcContext
4863 //
4864 static VOID NTAPI
4866  IN PDEVICE_OBJECT DpcDeviceObject,
4867  IN PIRP DpcIrp,
4868  IN PVOID DpcContext)
4869 {
4870  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DpcDeviceObject->DeviceExtension;
4871  SCSI_PORT_INTERRUPT_DATA InterruptData;
4873  PSCSI_PORT_LUN_EXTENSION LunExtension;
4874  BOOLEAN NeedToStartIo;
4875  PSCSI_REQUEST_BLOCK_INFO SrbInfo;
4876  LARGE_INTEGER TimerValue;
4877 
4878  DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
4879  Dpc, DpcDeviceObject, DpcIrp, DpcContext);
4880 
4881  /* We need to acquire spinlock */
4882  KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
4883 
4884  RtlZeroMemory(&InterruptData, sizeof(SCSI_PORT_INTERRUPT_DATA));
4885 
4886 TryAgain:
4887 
4888  /* Interrupt structure must be snapshotted, and only then analyzed */
4889  Context.InterruptData = &InterruptData;
4890  Context.DeviceExtension = DeviceExtension;
4891 
4892  if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0],
4894  &Context))
4895  {
4896  /* Nothing - just return (don't forget to release the spinlock */
4897  KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4898  DPRINT("ScsiPortDpcForIsr() done\n");
4899  return;
4900  }
4901 
4902  /* If flush of adapters is needed - do it */
4903  if (InterruptData.Flags & SCSI_PORT_FLUSH_ADAPTERS)
4904  {
4905  /* TODO: Implement */
4906  ASSERT(FALSE);
4907  }
4908 
4909  /* Check for IoMapTransfer */
4910  if (InterruptData.Flags & SCSI_PORT_MAP_TRANSFER)
4911  {
4912  /* TODO: Implement */
4913  ASSERT(FALSE);
4914  }
4915 
4916  /* Check if timer is needed */
4917  if (InterruptData.Flags & SCSI_PORT_TIMER_NEEDED)
4918  {
4919  /* Save the timer routine */
4920  DeviceExtension->HwScsiTimer = InterruptData.HwScsiTimer;
4921 
4922  if (InterruptData.MiniportTimerValue == 0)
4923  {
4924  /* Cancel the timer */
4925  KeCancelTimer(&DeviceExtension->MiniportTimer);
4926  }
4927  else
4928  {
4929  /* Convert timer value */
4930  TimerValue.QuadPart = Int32x32To64(InterruptData.MiniportTimerValue, -10);
4931 
4932  /* Set the timer */
4933  KeSetTimer(&DeviceExtension->MiniportTimer,
4934  TimerValue,
4935  &DeviceExtension->MiniportTimerDpc);
4936  }
4937  }
4938 
4939  /* If it's ready for the next request */
4940  if (InterruptData.Flags & SCSI_PORT_NEXT_REQUEST_READY)
4941  {
4942  /* Check for a duplicate request (NextRequest+NextLuRequest) */
4943  if ((DeviceExtension->Flags &
4946  {
4947  /* Clear busy flag set by ScsiPortStartPacket() */
4948  DeviceExtension->Flags &= ~SCSI_PORT_DEVICE_BUSY;
4949 
4950  if (!(InterruptData.Flags & SCSI_PORT_RESET))
4951  {
4952  /* Ready for next, and no reset is happening */
4953  DeviceExtension->TimerCount = -1;
4954  }
4955  }
4956  else
4957  {
4958  /* Not busy, but not ready for the next request */
4959  DeviceExtension->Flags &= ~SCSI_PORT_DEVICE_BUSY;
4960  InterruptData.Flags &= ~SCSI_PORT_NEXT_REQUEST_READY;
4961  }
4962  }
4963 
4964  /* Any resets? */
4965  if (InterruptData.Flags & SCSI_PORT_RESET_REPORTED)
4966  {
4967  /* Hold for a bit */
4968  DeviceExtension->TimerCount = 4;
4969  }
4970 
4971  /* Any ready LUN? */
4972  if (InterruptData.ReadyLun != NULL)
4973  {
4974 
4975  /* Process all LUNs from the list*/
4976  while (TRUE)
4977  {
4978  /* Remove it from the list first (as processed) */
4979  LunExtension = InterruptData.ReadyLun;
4980  InterruptData.ReadyLun = LunExtension->ReadyLun;
4981  LunExtension->ReadyLun = NULL;
4982 
4983  /* Get next request for this LUN */
4984  SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
4985 
4986  /* Still ready requests exist?
4987  If yes - get spinlock, if no - stop here */
4988  if (InterruptData.ReadyLun != NULL)
4989  KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
4990  else
4991  break;
4992  }
4993  }
4994  else
4995  {
4996  /* Release the spinlock */
4997  KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4998  }
4999 
5000  /* If we ready for next packet, start it */
5001  if (InterruptData.Flags & SCSI_PORT_NEXT_REQUEST_READY)
5002  IoStartNextPacket(DeviceExtension->DeviceObject, FALSE);
5003 
5004  NeedToStartIo = FALSE;
5005 
5006  /* Loop the completed request list */
5007  while (InterruptData.CompletedRequests)
5008  {
5009  /* Remove the request */
5010  SrbInfo = InterruptData.CompletedRequests;
5011  InterruptData.CompletedRequests = SrbInfo->CompletedRequests;
5012  SrbInfo->CompletedRequests = NULL;
5013 
5014  /* Process it */
5015  SpiProcessCompletedRequest(DeviceExtension,
5016  SrbInfo,
5017  &NeedToStartIo);
5018  }
5019 
5020  /* Loop abort request list */
5021  while (InterruptData.CompletedAbort)
5022  {
5023  LunExtension = InterruptData.CompletedAbort;
5024 
5025  /* Remove the request */
5026  InterruptData.CompletedAbort = LunExtension->CompletedAbortRequests;
5027 
5028  /* Get spinlock since we're going to change flags */
5029  KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
5030 
5031  /* TODO: Put SrbExtension to the list of free extensions */
5032  ASSERT(FALSE);
5033  }
5034 
5035  /* If we need - call StartIo routine */
5036  if (NeedToStartIo)
5037  {
5038  /* Make sure CurrentIrp is not null! */
5039  ASSERT(DpcDeviceObject->CurrentIrp != NULL);
5040  ScsiPortStartIo(DpcDeviceObject, DpcDeviceObject->CurrentIrp);
5041  }
5042 
5043  /* Everything has been done, check */
5044  if (InterruptData.Flags & SCSI_PORT_ENABLE_INT_REQUEST)
5045  {
5046  /* Synchronize using spinlock */
5047  KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
5048 
5049  /* Request an interrupt */
5050  DeviceExtension->HwInterrupt(DeviceExtension->MiniPortDeviceExtension);
5051 
5052  ASSERT(DeviceExtension->Flags & SCSI_PORT_DISABLE_INT_REQUESET);
5053 
5054  /* Should interrupts be enabled again? */
5055  if (DeviceExtension->Flags & SCSI_PORT_DISABLE_INT_REQUESET)
5056  {
5057  /* Clear this flag */
5058  DeviceExtension->Flags &= ~SCSI_PORT_DISABLE_INT_REQUESET;
5059 
5060  /* Call a special routine to do this */
5061  ASSERT(FALSE);
5062 #if 0
5063  KeSynchronizeExecution(DeviceExtension->Interrupt,
5064  SpiEnableInterrupts,
5065  DeviceExtension);
5066 #endif
5067  }
5068 
5069  /* If we need a notification again - loop */
5070  if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
5071  goto TryAgain;
5072 
5073  /* Release the spinlock */
5074  KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
5075  }
5076 
5077  DPRINT("ScsiPortDpcForIsr() done\n");
5078 }
5079 
5080 BOOLEAN
5081 NTAPI
5083 {
5086  ULONG Bus;
5087 
5088  DPRINT("SpiProcessTimeout() entered\n");
5089 
5090  DeviceExtension->TimerCount = -1;
5091 
5092  if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET)
5093  {
5094  DeviceExtension->InterruptData.Flags &= ~SCSI_PORT_RESET;
5095 
5096  if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET_REQUEST)
5097  {
5098  DeviceExtension->InterruptData.Flags &= ~SCSI_PORT_RESET_REQUEST;
5100  }
5101 
5102  return FALSE;
5103  }
5104  else
5105  {
5106  DPRINT("Resetting the bus\n");
5107 
5108  for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
5109  {
5110  DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension, Bus);
5111 
5112  /* Reset flags and set reset timeout to 4 seconds */
5113  DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET;
5114  DeviceExtension->TimerCount = 4;
5115  }
5116 
5117  /* If miniport requested - request a dpc for it */
5118  if (DeviceExtension->InterruptData.Flags &