1 /*
2 * PROJECT: ReactOS Storage Stack / SCSIPORT storage port library
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Main and exported functions
5 * COPYRIGHT: Eric Kohl (eric.kohl@reactos.org)
6 * Aleksey Bragin (aleksey@reactos.org)
7 * 2020 Victor Perevertkin (victor.perevertkin@reactos.org)
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include "scsiport.h"
13
14 #define NDEBUG
15 #include <debug.h>
16
17 ULONG InternalDebugLevel = 0x00;
18
19 #undef ScsiPortMoveMemory
20
21 /* GLOBALS *******************************************************************/
22
23 static BOOLEAN
24 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject,
25 IN PDEVICE_OBJECT DeviceObject,
26 IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
27 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,
28 IN PUNICODE_STRING RegistryPath,
29 IN ULONG BusNumber,
30 IN OUT PPCI_SLOT_NUMBER NextSlotNumber);
31
32 static NTSTATUS NTAPI
33 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
34 IN PIRP Irp);
35
36 static VOID NTAPI
37 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
38 PVOID Context);
39
40 VOID NTAPI
41 SpiMiniportTimerDpc(IN struct _KDPC *Dpc,
42 IN PVOID DeviceObject,
43 IN PVOID SystemArgument1,
44 IN PVOID SystemArgument2);
45
46 static NTSTATUS
47 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
48 PHW_INITIALIZATION_DATA HwInitData,
49 PCONFIGURATION_INFO InternalConfigInfo,
50 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
51 BOOLEAN FirstCall);
52
53 NTSTATUS NTAPI
54 SpQueryDeviceCallout(IN PVOID Context,
55 IN PUNICODE_STRING PathName,
56 IN INTERFACE_TYPE BusType,
57 IN ULONG BusNumber,
58 IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
59 IN CONFIGURATION_TYPE ControllerType,
60 IN ULONG ControllerNumber,
61 IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
62 IN CONFIGURATION_TYPE PeripheralType,
63 IN ULONG PeripheralNumber,
64 IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation);
65
66 static VOID
67 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
68 IN HANDLE Key,
69 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
70 IN PCONFIGURATION_INFO InternalConfigInfo,
71 IN PUCHAR Buffer);
72
73 static VOID
74 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData,
75 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor,
76 IN PPORT_CONFIGURATION_INFORMATION PortConfig);
77
78 static PCM_RESOURCE_LIST
79 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
80 PPORT_CONFIGURATION_INFORMATION PortConfig);
81
82 static NTSTATUS
83 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, ULONG NonCachedSize);
84
85 NTHALAPI ULONG NTAPI HalGetBusData(BUS_DATA_TYPE, ULONG, ULONG, PVOID, ULONG);
86 NTHALAPI ULONG NTAPI HalGetInterruptVector(INTERFACE_TYPE, ULONG, ULONG, ULONG, PKIRQL, PKAFFINITY);
87 NTHALAPI NTSTATUS NTAPI HalAssignSlotResources(PUNICODE_STRING, PUNICODE_STRING, PDRIVER_OBJECT, PDEVICE_OBJECT, INTERFACE_TYPE, ULONG, ULONG, PCM_RESOURCE_LIST *);
88
89 /* FUNCTIONS *****************************************************************/
90
91 /**********************************************************************
92 * NAME EXPORTED
93 * DriverEntry
94 *
95 * DESCRIPTION
96 * This function initializes the driver.
97 *
98 * RUN LEVEL
99 * PASSIVE_LEVEL
100 *
101 * ARGUMENTS
102 * DriverObject
103 * System allocated Driver Object for this driver.
104 *
105 * RegistryPath
106 * Name of registry driver service key.
107 *
108 * RETURN VALUE
109 * Status.
110 */
111
112 NTSTATUS NTAPI
DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)113 DriverEntry(IN PDRIVER_OBJECT DriverObject,
114 IN PUNICODE_STRING RegistryPath)
115 {
116 return STATUS_SUCCESS;
117 }
118
119 VOID
120 NTAPI
ScsiPortUnload(_In_ PDRIVER_OBJECT DriverObject)121 ScsiPortUnload(
122 _In_ PDRIVER_OBJECT DriverObject)
123 {
124 // no-op
125 }
126
127 NTSTATUS
128 NTAPI
ScsiPortDispatchPnp(PDEVICE_OBJECT DeviceObject,PIRP Irp)129 ScsiPortDispatchPnp(
130 PDEVICE_OBJECT DeviceObject,
131 PIRP Irp)
132 {
133 if (((PSCSI_PORT_COMMON_EXTENSION)DeviceObject->DeviceExtension)->IsFDO)
134 {
135 return FdoDispatchPnp(DeviceObject, Irp);
136 }
137 else
138 {
139 return PdoDispatchPnp(DeviceObject, Irp);
140 }
141 }
142
143 NTSTATUS
144 NTAPI
ScsiPortAddDevice(_In_ PDRIVER_OBJECT DriverObject,_In_ PDEVICE_OBJECT PhysicalDeviceObject)145 ScsiPortAddDevice(
146 _In_ PDRIVER_OBJECT DriverObject,
147 _In_ PDEVICE_OBJECT PhysicalDeviceObject)
148 {
149
150 DPRINT("AddDevice no-op DriverObj: %p, PDO: %p\n", DriverObject, PhysicalDeviceObject);
151
152 return STATUS_SUCCESS;
153 }
154
155
156 /**********************************************************************
157 * NAME EXPORTED
158 * ScsiDebugPrint
159 *
160 * DESCRIPTION
161 * Prints debugging messages.
162 *
163 * RUN LEVEL
164 * PASSIVE_LEVEL
165 *
166 * ARGUMENTS
167 * DebugPrintLevel
168 * Debug level of the given message.
169 *
170 * DebugMessage
171 * Pointer to printf()-compatible format string.
172 *
173 * ...
174 Additional output data (see printf()).
175 *
176 * RETURN VALUE
177 * None.
178 *
179 * @implemented
180 */
181
182 VOID
ScsiDebugPrint(IN ULONG DebugPrintLevel,IN PCHAR DebugMessage,...)183 ScsiDebugPrint(IN ULONG DebugPrintLevel,
184 IN PCHAR DebugMessage,
185 ...)
186 {
187 char Buffer[256];
188 va_list ap;
189
190 if (DebugPrintLevel > InternalDebugLevel)
191 return;
192
193 va_start(ap, DebugMessage);
194 vsprintf(Buffer, DebugMessage, ap);
195 va_end(ap);
196
197 DbgPrint(Buffer);
198 }
199
200 /* An internal helper function for ScsiPortCompleteRequest */
201 VOID
202 NTAPI
SpiCompleteRequest(IN PVOID HwDeviceExtension,IN PSCSI_REQUEST_BLOCK_INFO SrbInfo,IN UCHAR SrbStatus)203 SpiCompleteRequest(IN PVOID HwDeviceExtension,
204 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo,
205 IN UCHAR SrbStatus)
206 {
207 PSCSI_REQUEST_BLOCK Srb;
208
209 /* Get current SRB */
210 Srb = SrbInfo->Srb;
211
212 /* Return if there is no SRB or it is not active */
213 if (!Srb || !(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE)) return;
214
215 /* Set status */
216 Srb->SrbStatus = SrbStatus;
217
218 /* Set data transfered to 0 */
219 Srb->DataTransferLength = 0;
220
221 /* Notify */
222 ScsiPortNotification(RequestComplete,
223 HwDeviceExtension,
224 Srb);
225 }
226
227 /*
228 * @unimplemented
229 */
230 VOID NTAPI
ScsiPortCompleteRequest(IN PVOID HwDeviceExtension,IN UCHAR PathId,IN UCHAR TargetId,IN UCHAR Lun,IN UCHAR SrbStatus)231 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension,
232 IN UCHAR PathId,
233 IN UCHAR TargetId,
234 IN UCHAR Lun,
235 IN UCHAR SrbStatus)
236 {
237 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
238 PSCSI_PORT_LUN_EXTENSION LunExtension;
239 PSCSI_REQUEST_BLOCK_INFO SrbInfo;
240 PLIST_ENTRY ListEntry;
241
242 DPRINT("ScsiPortCompleteRequest() called\n");
243
244 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
245 SCSI_PORT_DEVICE_EXTENSION,
246 MiniPortDeviceExtension);
247
248 /* Go through all buses */
249 for (UINT8 pathId = 0; pathId < DeviceExtension->NumberOfBuses; pathId++)
250 {
251 PSCSI_BUS_INFO bus = &DeviceExtension->Buses[pathId];
252
253 /* Go through all logical units */
254 for (PLIST_ENTRY lunEntry = bus->LunsListHead.Flink;
255 lunEntry != &bus->LunsListHead;
256 lunEntry = lunEntry->Flink)
257 {
258 LunExtension = CONTAINING_RECORD(lunEntry, SCSI_PORT_LUN_EXTENSION, LunEntry);
259
260 /* Now match what caller asked with what we are at now */
261 if ((PathId == SP_UNTAGGED || PathId == LunExtension->PathId) &&
262 (TargetId == SP_UNTAGGED || TargetId == LunExtension->TargetId) &&
263 (Lun == SP_UNTAGGED || Lun == LunExtension->Lun))
264 {
265 /* Yes, that's what caller asked for. Complete abort requests */
266 if (LunExtension->CompletedAbortRequests)
267 {
268 /* TODO: Save SrbStatus in this request */
269 DPRINT1("Completing abort request without setting SrbStatus!\n");
270
271 /* Issue a notification request */
272 ScsiPortNotification(RequestComplete,
273 HwDeviceExtension,
274 LunExtension->CompletedAbortRequests);
275 }
276
277 /* Complete the request using our helper */
278 SpiCompleteRequest(HwDeviceExtension,
279 &LunExtension->SrbInfo,
280 SrbStatus);
281
282 /* Go through the queue and complete everything there too */
283 ListEntry = LunExtension->SrbInfo.Requests.Flink;
284 while (ListEntry != &LunExtension->SrbInfo.Requests)
285 {
286 /* Get the actual SRB info entry */
287 SrbInfo = CONTAINING_RECORD(ListEntry,
288 SCSI_REQUEST_BLOCK_INFO,
289 Requests);
290
291 /* Complete it */
292 SpiCompleteRequest(HwDeviceExtension,
293 SrbInfo,
294 SrbStatus);
295
296 /* Advance to the next request in queue */
297 ListEntry = SrbInfo->Requests.Flink;
298 }
299 }
300 }
301 }
302 }
303
304 /*
305 * @unimplemented
306 */
307 VOID NTAPI
ScsiPortFlushDma(IN PVOID HwDeviceExtension)308 ScsiPortFlushDma(IN PVOID HwDeviceExtension)
309 {
310 DPRINT("ScsiPortFlushDma()\n");
311 UNIMPLEMENTED;
312 }
313
314
315 /*
316 * @implemented
317 */
318 VOID NTAPI
ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension,IN PVOID MappedAddress)319 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension,
320 IN PVOID MappedAddress)
321 {
322 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
323 PMAPPED_ADDRESS NextMa, LastMa;
324
325 //DPRINT("ScsiPortFreeDeviceBase() called\n");
326
327 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
328 SCSI_PORT_DEVICE_EXTENSION,
329 MiniPortDeviceExtension);
330
331 /* Initialize our pointers */
332 NextMa = DeviceExtension->MappedAddressList;
333 LastMa = NextMa;
334
335 while (NextMa)
336 {
337 if (NextMa->MappedAddress == MappedAddress)
338 {
339 /* Unmap it first */
340 MmUnmapIoSpace(MappedAddress, NextMa->NumberOfBytes);
341
342 /* Remove it from the list */
343 if (NextMa == DeviceExtension->MappedAddressList)
344 {
345 /* Remove the first entry */
346 DeviceExtension->MappedAddressList = NextMa->NextMappedAddress;
347 }
348 else
349 {
350 LastMa->NextMappedAddress = NextMa->NextMappedAddress;
351 }
352
353 /* Free the resources and quit */
354 ExFreePool(NextMa);
355
356 return;
357 }
358 else
359 {
360 LastMa = NextMa;
361 NextMa = NextMa->NextMappedAddress;
362 }
363 }
364 }
365
366
367 /*
368 * @implemented
369 */
370 ULONG NTAPI
ScsiPortGetBusData(IN PVOID DeviceExtension,IN ULONG BusDataType,IN ULONG SystemIoBusNumber,IN ULONG SlotNumber,IN PVOID Buffer,IN ULONG Length)371 ScsiPortGetBusData(IN PVOID DeviceExtension,
372 IN ULONG BusDataType,
373 IN ULONG SystemIoBusNumber,
374 IN ULONG SlotNumber,
375 IN PVOID Buffer,
376 IN ULONG Length)
377 {
378 DPRINT("ScsiPortGetBusData()\n");
379
380 if (Length)
381 {
382 /* If Length is non-zero, just forward the call to
383 HalGetBusData() function */
384 return HalGetBusData(BusDataType,
385 SystemIoBusNumber,
386 SlotNumber,
387 Buffer,
388 Length);
389 }
390
391 /* We have a more complex case here */
392 UNIMPLEMENTED;
393 return 0;
394 }
395
396 /*
397 * @implemented
398 */
399 ULONG NTAPI
ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension,IN ULONG BusDataType,IN ULONG SystemIoBusNumber,IN ULONG SlotNumber,IN PVOID Buffer,IN ULONG Offset,IN ULONG Length)400 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension,
401 IN ULONG BusDataType,
402 IN ULONG SystemIoBusNumber,
403 IN ULONG SlotNumber,
404 IN PVOID Buffer,
405 IN ULONG Offset,
406 IN ULONG Length)
407 {
408 DPRINT("ScsiPortSetBusDataByOffset()\n");
409 return HalSetBusDataByOffset(BusDataType,
410 SystemIoBusNumber,
411 SlotNumber,
412 Buffer,
413 Offset,
414 Length);
415 }
416
417 /*
418 * @implemented
419 */
420 PVOID NTAPI
ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension,IN INTERFACE_TYPE BusType,IN ULONG SystemIoBusNumber,IN SCSI_PHYSICAL_ADDRESS IoAddress,IN ULONG NumberOfBytes,IN BOOLEAN InIoSpace)421 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension,
422 IN INTERFACE_TYPE BusType,
423 IN ULONG SystemIoBusNumber,
424 IN SCSI_PHYSICAL_ADDRESS IoAddress,
425 IN ULONG NumberOfBytes,
426 IN BOOLEAN InIoSpace)
427 {
428 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
429 PHYSICAL_ADDRESS TranslatedAddress;
430 PMAPPED_ADDRESS DeviceBase;
431 ULONG AddressSpace;
432 PVOID MappedAddress;
433
434 //DPRINT ("ScsiPortGetDeviceBase() called\n");
435
436 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
437 SCSI_PORT_DEVICE_EXTENSION,
438 MiniPortDeviceExtension);
439
440 AddressSpace = (ULONG)InIoSpace;
441 if (HalTranslateBusAddress(BusType,
442 SystemIoBusNumber,
443 IoAddress,
444 &AddressSpace,
445 &TranslatedAddress) == FALSE)
446 {
447 return NULL;
448 }
449
450 /* i/o space */
451 if (AddressSpace != 0)
452 return((PVOID)(ULONG_PTR)TranslatedAddress.QuadPart);
453
454 MappedAddress = MmMapIoSpace(TranslatedAddress,
455 NumberOfBytes,
456 FALSE);
457
458 DeviceBase = ExAllocatePoolWithTag(NonPagedPool,
459 sizeof(MAPPED_ADDRESS), TAG_SCSIPORT);
460
461 if (DeviceBase == NULL)
462 return MappedAddress;
463
464 DeviceBase->MappedAddress = MappedAddress;
465 DeviceBase->NumberOfBytes = NumberOfBytes;
466 DeviceBase->IoAddress = IoAddress;
467 DeviceBase->BusNumber = SystemIoBusNumber;
468
469 /* Link it to the Device Extension list */
470 DeviceBase->NextMappedAddress = DeviceExtension->MappedAddressList;
471 DeviceExtension->MappedAddressList = DeviceBase;
472
473 return MappedAddress;
474 }
475
476 /*
477 * @unimplemented
478 */
479 PVOID NTAPI
ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension,IN UCHAR PathId,IN UCHAR TargetId,IN UCHAR Lun)480 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension,
481 IN UCHAR PathId,
482 IN UCHAR TargetId,
483 IN UCHAR Lun)
484 {
485 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
486 PSCSI_PORT_LUN_EXTENSION LunExtension;
487
488 DPRINT("ScsiPortGetLogicalUnit() called\n");
489
490 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
491 SCSI_PORT_DEVICE_EXTENSION,
492 MiniPortDeviceExtension);
493
494 /* Check the extension size */
495 if (!DeviceExtension->LunExtensionSize)
496 {
497 /* They didn't want one */
498 return NULL;
499 }
500
501 LunExtension = GetLunByPath(DeviceExtension, PathId, TargetId, Lun);
502
503 /* Check that the logical unit exists */
504 if (!LunExtension)
505 {
506 /* Nope, return NULL */
507 return NULL;
508 }
509
510 /* Return the logical unit miniport extension */
511 return (LunExtension + 1);
512 }
513
514
515 /*
516 * @implemented
517 */
518 SCSI_PHYSICAL_ADDRESS NTAPI
ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension,IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,IN PVOID VirtualAddress,OUT ULONG * Length)519 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension,
520 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
521 IN PVOID VirtualAddress,
522 OUT ULONG *Length)
523 {
524 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
525 SCSI_PHYSICAL_ADDRESS PhysicalAddress;
526 SIZE_T BufferLength = 0;
527 ULONG_PTR Offset;
528 PSCSI_SG_ADDRESS SGList;
529 PSCSI_REQUEST_BLOCK_INFO SrbInfo;
530
531 DPRINT("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
532 HwDeviceExtension, Srb, VirtualAddress, Length);
533
534 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
535 SCSI_PORT_DEVICE_EXTENSION,
536 MiniPortDeviceExtension);
537
538 if (Srb == NULL || Srb->SenseInfoBuffer == VirtualAddress)
539 {
540 /* Simply look it up in the allocated common buffer */
541 Offset = (PUCHAR)VirtualAddress - (PUCHAR)DeviceExtension->SrbExtensionBuffer;
542
543 BufferLength = DeviceExtension->CommonBufferLength - Offset;
544 PhysicalAddress.QuadPart = DeviceExtension->PhysicalAddress.QuadPart + Offset;
545 }
546 else if (DeviceExtension->MapRegisters)
547 {
548 PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Srb->OriginalRequest);
549 PSCSI_PORT_LUN_EXTENSION LunExtension = IoStack->DeviceObject->DeviceExtension;
550 ASSERT(LunExtension && !LunExtension->Common.IsFDO);
551
552 /* Scatter-gather list must be used */
553 SrbInfo = SpiGetSrbData(DeviceExtension, LunExtension, Srb->QueueTag);
554
555 SGList = SrbInfo->ScatterGather;
556
557 /* Find needed item in the SG list */
558 Offset = (PCHAR)VirtualAddress - (PCHAR)Srb->DataBuffer;
559 while (Offset >= SGList->Length)
560 {
561 Offset -= SGList->Length;
562 SGList++;
563 }
564
565 /* We're done, store length and physical address */
566 BufferLength = SGList->Length - Offset;
567 PhysicalAddress.QuadPart = SGList->PhysicalAddress.QuadPart + Offset;
568 }
569 else
570 {
571 /* Nothing */
572 PhysicalAddress.QuadPart = (LONGLONG)SP_UNINITIALIZED_VALUE;
573 }
574
575 *Length = (ULONG)BufferLength;
576 return PhysicalAddress;
577 }
578
579
580 /*
581 * @unimplemented
582 */
583 PSCSI_REQUEST_BLOCK NTAPI
ScsiPortGetSrb(IN PVOID DeviceExtension,IN UCHAR PathId,IN UCHAR TargetId,IN UCHAR Lun,IN LONG QueueTag)584 ScsiPortGetSrb(IN PVOID DeviceExtension,
585 IN UCHAR PathId,
586 IN UCHAR TargetId,
587 IN UCHAR Lun,
588 IN LONG QueueTag)
589 {
590 DPRINT1("ScsiPortGetSrb() unimplemented\n");
591 UNIMPLEMENTED;
592 return NULL;
593 }
594
595
596 /*
597 * @implemented
598 */
599 PVOID NTAPI
ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension,IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,IN ULONG NumberOfBytes)600 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension,
601 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
602 IN ULONG NumberOfBytes)
603 {
604 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
605 DEVICE_DESCRIPTION DeviceDescription;
606 ULONG MapRegistersCount;
607 NTSTATUS Status;
608
609 DPRINT("ScsiPortGetUncachedExtension(%p %p %lu)\n",
610 HwDeviceExtension, ConfigInfo, NumberOfBytes);
611
612 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
613 SCSI_PORT_DEVICE_EXTENSION,
614 MiniPortDeviceExtension);
615
616 /* Check for allocated common DMA buffer */
617 if (DeviceExtension->SrbExtensionBuffer != NULL)
618 {
619 DPRINT1("The HBA has already got a common DMA buffer!\n");
620 return NULL;
621 }
622
623 /* Check for DMA adapter object */
624 if (DeviceExtension->AdapterObject == NULL)
625 {
626 /* Initialize DMA adapter description */
627 RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
628
629 DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
630 DeviceDescription.Master = ConfigInfo->Master;
631 DeviceDescription.ScatterGather = ConfigInfo->ScatterGather;
632 DeviceDescription.DemandMode = ConfigInfo->DemandMode;
633 DeviceDescription.Dma32BitAddresses = ConfigInfo->Dma32BitAddresses;
634 DeviceDescription.BusNumber = ConfigInfo->SystemIoBusNumber;
635 DeviceDescription.DmaChannel = ConfigInfo->DmaChannel;
636 DeviceDescription.InterfaceType = ConfigInfo->AdapterInterfaceType;
637 DeviceDescription.DmaWidth = ConfigInfo->DmaWidth;
638 DeviceDescription.DmaSpeed = ConfigInfo->DmaSpeed;
639 DeviceDescription.MaximumLength = ConfigInfo->MaximumTransferLength;
640 DeviceDescription.DmaPort = ConfigInfo->DmaPort;
641
642 /* Get a DMA adapter object */
643 DeviceExtension->AdapterObject =
644 HalGetAdapter(&DeviceDescription, &MapRegistersCount);
645
646 /* Fail in case of error */
647 if (DeviceExtension->AdapterObject == NULL)
648 {
649 DPRINT1("HalGetAdapter() failed\n");
650 return NULL;
651 }
652
653 /* Set number of physical breaks */
654 if (ConfigInfo->NumberOfPhysicalBreaks != 0 &&
655 MapRegistersCount > ConfigInfo->NumberOfPhysicalBreaks)
656 {
657 DeviceExtension->PortCapabilities.MaximumPhysicalPages =
658 ConfigInfo->NumberOfPhysicalBreaks;
659 }
660 else
661 {
662 DeviceExtension->PortCapabilities.MaximumPhysicalPages = MapRegistersCount;
663 }
664 }
665
666 /* Update auto request sense feature */
667 DeviceExtension->SupportsAutoSense = ConfigInfo->AutoRequestSense;
668
669 /* Update Srb extension size */
670 if (DeviceExtension->SrbExtensionSize != ConfigInfo->SrbExtensionSize)
671 DeviceExtension->SrbExtensionSize = ConfigInfo->SrbExtensionSize;
672
673 /* Update Srb extension alloc flag */
674 if (ConfigInfo->AutoRequestSense || DeviceExtension->SrbExtensionSize)
675 DeviceExtension->NeedSrbExtensionAlloc = TRUE;
676
677 /* Allocate a common DMA buffer */
678 Status = SpiAllocateCommonBuffer(DeviceExtension, NumberOfBytes);
679
680 if (!NT_SUCCESS(Status))
681 {
682 DPRINT1("SpiAllocateCommonBuffer() failed with Status = 0x%08X!\n", Status);
683 return NULL;
684 }
685
686 return DeviceExtension->NonCachedExtension;
687 }
688
689 static NTSTATUS
SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,ULONG NonCachedSize)690 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, ULONG NonCachedSize)
691 {
692 PVOID *SrbExtension, CommonBuffer;
693 ULONG CommonBufferLength, BufSize;
694
695 /* If size is 0, set it to 16 */
696 if (!DeviceExtension->SrbExtensionSize)
697 DeviceExtension->SrbExtensionSize = 16;
698
699 /* Calculate size */
700 BufSize = DeviceExtension->SrbExtensionSize;
701
702 /* Add autosense data size if needed */
703 if (DeviceExtension->SupportsAutoSense)
704 BufSize += sizeof(SENSE_DATA);
705
706
707 /* Round it */
708 BufSize = (BufSize + sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1);
709
710 /* Sum up into the total common buffer length, and round it to page size */
711 CommonBufferLength =
712 ROUND_TO_PAGES(NonCachedSize + BufSize * DeviceExtension->RequestsNumber);
713
714 /* Allocate it */
715 if (!DeviceExtension->AdapterObject)
716 {
717 /* From nonpaged pool if there is no DMA */
718 CommonBuffer = ExAllocatePoolWithTag(NonPagedPool, CommonBufferLength, TAG_SCSIPORT);
719 }
720 else
721 {
722 /* Perform a full request since we have a DMA adapter*/
723 CommonBuffer = HalAllocateCommonBuffer(DeviceExtension->AdapterObject,
724 CommonBufferLength,
725 &DeviceExtension->PhysicalAddress,
726 FALSE );
727 }
728
729 /* Fail in case of error */
730 if (!CommonBuffer)
731 return STATUS_INSUFFICIENT_RESOURCES;
732
733 /* Zero it */
734 RtlZeroMemory(CommonBuffer, CommonBufferLength);
735
736 /* Store its size in Device Extension */
737 DeviceExtension->CommonBufferLength = CommonBufferLength;
738
739 /* SrbExtension buffer is located at the beginning of the buffer */
740 DeviceExtension->SrbExtensionBuffer = CommonBuffer;
741
742 /* Non-cached extension buffer is located at the end of
743 the common buffer */
744 if (NonCachedSize)
745 {
746 CommonBufferLength -= NonCachedSize;
747 DeviceExtension->NonCachedExtension = (PUCHAR)CommonBuffer + CommonBufferLength;
748 }
749 else
750 {
751 DeviceExtension->NonCachedExtension = NULL;
752 }
753
754 if (DeviceExtension->NeedSrbExtensionAlloc)
755 {
756 /* Look up how many SRB data structures we need */
757 DeviceExtension->SrbDataCount = CommonBufferLength / BufSize;
758
759 /* Initialize the free SRB extensions list */
760 SrbExtension = (PVOID *)CommonBuffer;
761 DeviceExtension->FreeSrbExtensions = SrbExtension;
762
763 /* Fill the remaining pointers (if we have more than 1 SRB) */
764 while (CommonBufferLength >= 2 * BufSize)
765 {
766 *SrbExtension = (PVOID*)((PCHAR)SrbExtension + BufSize);
767 SrbExtension = *SrbExtension;
768
769 CommonBufferLength -= BufSize;
770 }
771 }
772
773 return STATUS_SUCCESS;
774 }
775
776
777
778 /*
779 * @implemented
780 */
781 PVOID NTAPI
ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension,IN SCSI_PHYSICAL_ADDRESS PhysicalAddress)782 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension,
783 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress)
784 {
785 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
786 ULONG Offset;
787
788 DPRINT("ScsiPortGetVirtualAddress(%p %I64x)\n",
789 HwDeviceExtension, PhysicalAddress.QuadPart);
790
791 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
792 SCSI_PORT_DEVICE_EXTENSION,
793 MiniPortDeviceExtension);
794
795 if (DeviceExtension->PhysicalAddress.QuadPart > PhysicalAddress.QuadPart)
796 return NULL;
797
798 Offset = (ULONG)(PhysicalAddress.QuadPart - DeviceExtension->PhysicalAddress.QuadPart);
799
800 if (Offset >= DeviceExtension->CommonBufferLength)
801 return NULL;
802
803 return (PVOID)((ULONG_PTR)DeviceExtension->SrbExtensionBuffer + Offset);
804 }
805
806 /**********************************************************************
807 * NAME EXPORTED
808 * ScsiPortInitialize
809 *
810 * DESCRIPTION
811 * Initializes SCSI port driver specific data.
812 *
813 * RUN LEVEL
814 * PASSIVE_LEVEL
815 *
816 * ARGUMENTS
817 * Argument1
818 * Pointer to the miniport driver's driver object.
819 *
820 * Argument2
821 * Pointer to the miniport driver's registry path.
822 *
823 * HwInitializationData
824 * Pointer to port driver specific configuration data.
825 *
826 * HwContext
827 Miniport driver specific context.
828 *
829 * RETURN VALUE
830 * Status.
831 *
832 * @implemented
833 */
834
835 ULONG NTAPI
ScsiPortInitialize(IN PVOID Argument1,IN PVOID Argument2,IN struct _HW_INITIALIZATION_DATA * HwInitializationData,IN PVOID HwContext)836 ScsiPortInitialize(
837 IN PVOID Argument1,
838 IN PVOID Argument2,
839 IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
840 IN PVOID HwContext)
841 {
842 PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Argument1;
843 PUNICODE_STRING RegistryPath = (PUNICODE_STRING)Argument2;
844 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = NULL;
845 PCONFIGURATION_INFORMATION SystemConfig;
846 PPORT_CONFIGURATION_INFORMATION PortConfig;
847 CONFIGURATION_INFO ConfigInfo;
848 ULONG DeviceExtensionSize;
849 ULONG PortConfigSize;
850 BOOLEAN Again;
851 BOOLEAN DeviceFound = FALSE;
852 BOOLEAN FirstConfigCall = TRUE;
853 ULONG Result;
854 NTSTATUS Status;
855 PCI_SLOT_NUMBER SlotNumber;
856
857 PDEVICE_OBJECT PortDeviceObject;
858 UNICODE_STRING DeviceName;
859 PIO_SCSI_CAPABILITIES PortCapabilities;
860
861 PCM_RESOURCE_LIST ResourceList;
862
863 DPRINT("ScsiPortInitialize() called!\n");
864
865 /* Check params for validity */
866 if ((HwInitializationData->HwInitialize == NULL) ||
867 (HwInitializationData->HwStartIo == NULL) ||
868 (HwInitializationData->HwInterrupt == NULL) ||
869 (HwInitializationData->HwFindAdapter == NULL) ||
870 (HwInitializationData->HwResetBus == NULL))
871 {
872 return STATUS_REVISION_MISMATCH;
873 }
874
875 PSCSI_PORT_DRIVER_EXTENSION driverExtension;
876
877 // ScsiPortInitialize may be called multiple times by the same driver
878 driverExtension = IoGetDriverObjectExtension(DriverObject, HwInitializationData->HwInitialize);
879
880 if (!driverExtension)
881 {
882 Status = IoAllocateDriverObjectExtension(DriverObject,
883 HwInitializationData->HwInitialize,
884 sizeof(SCSI_PORT_DRIVER_EXTENSION),
885 (PVOID *)&driverExtension);
886
887 if (!NT_SUCCESS(Status))
888 {
889 DPRINT1("Failed to allocate the driver extension! Status 0x%x\n", Status);
890 return Status;
891 }
892 }
893
894 // set up the driver extension
895 driverExtension->RegistryPath.Buffer =
896 ExAllocatePoolWithTag(PagedPool, RegistryPath->MaximumLength, TAG_SCSIPORT);
897 driverExtension->RegistryPath.MaximumLength = RegistryPath->MaximumLength;
898 RtlCopyUnicodeString(&driverExtension->RegistryPath, RegistryPath);
899
900 driverExtension->DriverObject = DriverObject;
901
902 /* Set handlers */
903 DriverObject->DriverUnload = ScsiPortUnload;
904 DriverObject->DriverStartIo = ScsiPortStartIo;
905 DriverObject->DriverExtension->AddDevice = ScsiPortAddDevice;
906 DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiPortCreateClose;
907 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiPortCreateClose;
908 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiPortDeviceControl;
909 DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiPortDispatchScsi;
910 DriverObject->MajorFunction[IRP_MJ_PNP] = ScsiPortDispatchPnp;
911 DriverObject->MajorFunction[IRP_MJ_POWER] = ScsiPortDispatchPower;
912
913 /* Obtain configuration information */
914 SystemConfig = IoGetConfigurationInformation();
915
916 /* Zero the internal configuration info structure */
917 RtlZeroMemory(&ConfigInfo, sizeof(CONFIGURATION_INFO));
918
919 /* Zero starting slot number */
920 SlotNumber.u.AsULONG = 0;
921
922 /* Allocate space for access ranges */
923 if (HwInitializationData->NumberOfAccessRanges)
924 {
925 ConfigInfo.AccessRanges =
926 ExAllocatePoolWithTag(PagedPool,
927 HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE), TAG_SCSIPORT);
928
929 /* Fail if failed */
930 if (ConfigInfo.AccessRanges == NULL)
931 return STATUS_INSUFFICIENT_RESOURCES;
932 }
933
934 /* Open registry keys and fill the driverExtension */
935 SpiInitOpenKeys(&ConfigInfo, driverExtension);
936
937 // FIXME: PnP miniports are not supported
938 ASSERT(driverExtension->IsLegacyDriver);
939
940 /* Last adapter number = not known */
941 ConfigInfo.LastAdapterNumber = SP_UNINITIALIZED_VALUE;
942
943 /* Calculate sizes of DeviceExtension and PortConfig */
944 DeviceExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) +
945 HwInitializationData->DeviceExtensionSize;
946
947 DPRINT("AdapterInterfaceType: %lu\n",
948 HwInitializationData->AdapterInterfaceType);
949
950 while (TRUE)
951 {
952 WCHAR NameBuffer[27];
953 /* Create a unicode device name */
954 swprintf(NameBuffer,
955 L"\\Device\\ScsiPort%lu",
956 SystemConfig->ScsiPortCount);
957 if (!RtlCreateUnicodeString(&DeviceName, NameBuffer))
958 {
959 DPRINT1("Failed to allocate memory for device name!\n");
960 Status = STATUS_INSUFFICIENT_RESOURCES;
961 PortDeviceObject = NULL;
962 break;
963 }
964
965 DPRINT("Creating device: %wZ\n", &DeviceName);
966
967 /* Create the port device */
968 Status = IoCreateDevice(DriverObject,
969 DeviceExtensionSize,
970 &DeviceName,
971 FILE_DEVICE_CONTROLLER,
972 FILE_DEVICE_SECURE_OPEN,
973 FALSE,
974 &PortDeviceObject);
975
976 if (!NT_SUCCESS(Status))
977 {
978 DPRINT1("IoCreateDevice call failed! (Status 0x%lX)\n", Status);
979 PortDeviceObject = NULL;
980 break;
981 }
982
983 /* Set the buffering strategy here... */
984 PortDeviceObject->Flags |= DO_DIRECT_IO;
985 PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT; /* FIXME: Is this really needed? */
986
987 /* Fill Device Extension */
988 DeviceExtension = PortDeviceObject->DeviceExtension;
989 RtlZeroMemory(DeviceExtension, DeviceExtensionSize);
990 DeviceExtension->Common.DeviceObject = PortDeviceObject;
991 DeviceExtension->Common.IsFDO = TRUE;
992 DeviceExtension->Length = DeviceExtensionSize;
993 DeviceExtension->PortNumber = SystemConfig->ScsiPortCount;
994 DeviceExtension->DeviceName = DeviceName;
995
996 /* Driver's routines... */
997 DeviceExtension->HwInitialize = HwInitializationData->HwInitialize;
998 DeviceExtension->HwStartIo = HwInitializationData->HwStartIo;
999 DeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
1000 DeviceExtension->HwResetBus = HwInitializationData->HwResetBus;
1001 DeviceExtension->HwDmaStarted = HwInitializationData->HwDmaStarted;
1002
1003 /* Extensions sizes */
1004 DeviceExtension->MiniPortExtensionSize = HwInitializationData->DeviceExtensionSize;
1005 DeviceExtension->LunExtensionSize =
1006 ALIGN_UP(HwInitializationData->SpecificLuExtensionSize, INT64);
1007 DeviceExtension->SrbExtensionSize =
1008 ALIGN_UP(HwInitializationData->SrbExtensionSize, INT64);
1009
1010 /* Fill some numbers (bus count, lun count, etc) */
1011 DeviceExtension->MaxLunCount = SCSI_MAXIMUM_LOGICAL_UNITS;
1012 DeviceExtension->RequestsNumber = 16;
1013
1014 /* Initialize the spin lock in the controller extension */
1015 KeInitializeSpinLock(&DeviceExtension->IrqLock);
1016 KeInitializeSpinLock(&DeviceExtension->SpinLock);
1017
1018 /* Initialize the DPC object */
1019 IoInitializeDpcRequest(PortDeviceObject,
1020 ScsiPortDpcForIsr);
1021
1022 /* Initialize the device timer */
1023 DeviceExtension->TimerCount = -1;
1024 IoInitializeTimer(PortDeviceObject,
1025 ScsiPortIoTimer,
1026 DeviceExtension);
1027
1028 /* Initialize miniport timer */
1029 KeInitializeTimer(&DeviceExtension->MiniportTimer);
1030 KeInitializeDpc(&DeviceExtension->MiniportTimerDpc,
1031 SpiMiniportTimerDpc,
1032 PortDeviceObject);
1033
1034 CreatePortConfig:
1035
1036 /* Allocate and initialize port configuration info */
1037 PortConfigSize = sizeof(PORT_CONFIGURATION_INFORMATION) +
1038 HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE);
1039 PortConfigSize = ALIGN_UP(PortConfigSize, INT64);
1040 DeviceExtension->PortConfig = ExAllocatePoolWithTag(NonPagedPool, PortConfigSize, TAG_SCSIPORT);
1041
1042 /* Fail if failed */
1043 if (DeviceExtension->PortConfig == NULL)
1044 {
1045 Status = STATUS_INSUFFICIENT_RESOURCES;
1046 break;
1047 }
1048
1049 Status = SpiCreatePortConfig(DeviceExtension,
1050 HwInitializationData,
1051 &ConfigInfo,
1052 DeviceExtension->PortConfig,
1053 FirstConfigCall);
1054
1055 if (!NT_SUCCESS(Status))
1056 {
1057 DPRINT("SpiCreatePortConfig() failed with Status 0x%08X\n", Status);
1058 break;
1059 }
1060
1061 PortConfig = DeviceExtension->PortConfig;
1062
1063 /* Copy extension sizes into the PortConfig */
1064 PortConfig->SpecificLuExtensionSize = DeviceExtension->LunExtensionSize;
1065 PortConfig->SrbExtensionSize = DeviceExtension->SrbExtensionSize;
1066
1067 /* Initialize Access ranges */
1068 if (HwInitializationData->NumberOfAccessRanges != 0)
1069 {
1070 PortConfig->AccessRanges = ALIGN_UP_POINTER(PortConfig + 1, INT64);
1071
1072 /* Copy the data */
1073 RtlCopyMemory(PortConfig->AccessRanges,
1074 ConfigInfo.AccessRanges,
1075 HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE));
1076 }
1077
1078 /* Search for matching PCI device */
1079 if ((HwInitializationData->AdapterInterfaceType == PCIBus) &&
1080 (HwInitializationData->VendorIdLength > 0) &&
1081 (HwInitializationData->VendorId != NULL) &&
1082 (HwInitializationData->DeviceIdLength > 0) &&
1083 (HwInitializationData->DeviceId != NULL))
1084 {
1085 PortConfig->BusInterruptLevel = 0;
1086
1087 /* Get PCI device data */
1088 DPRINT(
1089 "VendorId '%.*s' DeviceId '%.*s'\n", HwInitializationData->VendorIdLength,
1090 HwInitializationData->VendorId, HwInitializationData->DeviceIdLength,
1091 HwInitializationData->DeviceId);
1092
1093 if (!SpiGetPciConfigData(
1094 DriverObject, PortDeviceObject, HwInitializationData, PortConfig, RegistryPath,
1095 ConfigInfo.BusNumber, &SlotNumber))
1096 {
1097 /* Continue to the next bus, nothing here */
1098 ConfigInfo.BusNumber++;
1099 DeviceExtension->PortConfig = NULL;
1100 ExFreePool(PortConfig);
1101 Again = FALSE;
1102 goto CreatePortConfig;
1103 }
1104
1105 if (!PortConfig->BusInterruptLevel)
1106 {
1107 /* Bypass this slot, because no interrupt was assigned */
1108 DeviceExtension->PortConfig = NULL;
1109 ExFreePool(PortConfig);
1110 goto CreatePortConfig;
1111 }
1112 }
1113 else
1114 {
1115 DPRINT("Non-pci bus\n");
1116 }
1117
1118 /* Note: HwFindAdapter is called once for each bus */
1119 Again = FALSE;
1120 DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber);
1121 Result = (HwInitializationData->HwFindAdapter)(
1122 &DeviceExtension->MiniPortDeviceExtension, HwContext, 0, /* BusInformation */
1123 ConfigInfo.Parameter, /* ArgumentString */
1124 PortConfig, &Again);
1125
1126 DPRINT("HwFindAdapter() Result: %lu Again: %s\n", Result, (Again) ? "True" : "False");
1127
1128 /* Free MapRegisterBase, it's not needed anymore */
1129 if (DeviceExtension->MapRegisterBase != NULL)
1130 {
1131 ExFreePool(DeviceExtension->MapRegisterBase);
1132 DeviceExtension->MapRegisterBase = NULL;
1133 }
1134
1135 /* If result is nothing good... */
1136 if (Result != SP_RETURN_FOUND)
1137 {
1138 DPRINT("HwFindAdapter() Result: %lu\n", Result);
1139
1140 if (Result == SP_RETURN_NOT_FOUND)
1141 {
1142 /* We can continue on the next bus */
1143 ConfigInfo.BusNumber++;
1144 Again = FALSE;
1145
1146 DeviceExtension->PortConfig = NULL;
1147 ExFreePool(PortConfig);
1148 goto CreatePortConfig;
1149 }
1150
1151 /* Otherwise, break */
1152 Status = STATUS_INTERNAL_ERROR;
1153 break;
1154 }
1155
1156 DPRINT(
1157 "ScsiPortInitialize(): Found HBA! (%x), adapter Id %d\n",
1158 PortConfig->BusInterruptVector, PortConfig->InitiatorBusId[0]);
1159
1160 /* If the SRB extension size was updated */
1161 if (!DeviceExtension->NonCachedExtension &&
1162 (PortConfig->SrbExtensionSize != DeviceExtension->SrbExtensionSize))
1163 {
1164 /* Set it (rounding to LONGLONG again) */
1165 DeviceExtension->SrbExtensionSize = ALIGN_UP(PortConfig->SrbExtensionSize, INT64);
1166 }
1167
1168 /* The same with LUN extension size */
1169 if (PortConfig->SpecificLuExtensionSize != DeviceExtension->LunExtensionSize)
1170 DeviceExtension->LunExtensionSize = PortConfig->SpecificLuExtensionSize;
1171
1172 /* Construct a resource list */
1173 ResourceList = SpiConfigToResource(DeviceExtension, PortConfig);
1174
1175 PDEVICE_OBJECT LowerPDO = NULL;
1176
1177 Status = IoReportDetectedDevice(DriverObject,
1178 HwInitializationData->AdapterInterfaceType,
1179 ConfigInfo.BusNumber,
1180 PortConfig->SlotNumber,
1181 ResourceList,
1182 NULL,
1183 TRUE,
1184 &LowerPDO);
1185
1186 if (!NT_SUCCESS(Status))
1187 {
1188 DPRINT1("IoReportDetectedDevice failed. Status: 0x%x\n", Status);
1189 __debugbreak();
1190 break;
1191 }
1192
1193 DeviceExtension->Common.LowerDevice = IoAttachDeviceToDeviceStack(PortDeviceObject, LowerPDO);
1194
1195 ASSERT(DeviceExtension->Common.LowerDevice);
1196
1197 PortDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1198
1199 if (ResourceList)
1200 {
1201 ExFreePoolWithTag(ResourceList, TAG_SCSIPORT);
1202 }
1203
1204 /* Copy all stuff which we ever need from PortConfig to the DeviceExtension */
1205 if (PortConfig->MaximumNumberOfTargets > SCSI_MAXIMUM_TARGETS_PER_BUS)
1206 DeviceExtension->MaxTargedIds = SCSI_MAXIMUM_TARGETS_PER_BUS;
1207 else
1208 DeviceExtension->MaxTargedIds = PortConfig->MaximumNumberOfTargets;
1209
1210 DeviceExtension->NumberOfBuses = PortConfig->NumberOfBuses;
1211 DeviceExtension->CachesData = PortConfig->CachesData;
1212 DeviceExtension->ReceiveEvent = PortConfig->ReceiveEvent;
1213 DeviceExtension->SupportsTaggedQueuing = PortConfig->TaggedQueuing;
1214 DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu;
1215
1216 /* Initialize bus scanning information */
1217 size_t BusConfigSize = DeviceExtension->NumberOfBuses * sizeof(*DeviceExtension->Buses);
1218 DeviceExtension->Buses = ExAllocatePoolZero(NonPagedPool, BusConfigSize, TAG_SCSIPORT);
1219 if (!DeviceExtension->Buses)
1220 {
1221 DPRINT1("Out of resources!\n");
1222 Status = STATUS_INSUFFICIENT_RESOURCES;
1223 break;
1224 }
1225
1226 // initialize bus data
1227 for (UINT8 pathId = 0; pathId < DeviceExtension->NumberOfBuses; pathId++)
1228 {
1229 DeviceExtension->Buses[pathId].BusIdentifier =
1230 DeviceExtension->PortConfig->InitiatorBusId[pathId];
1231 InitializeListHead(&DeviceExtension->Buses[pathId].LunsListHead);
1232 }
1233
1234 /* If something was disabled via registry - apply it */
1235 if (ConfigInfo.DisableMultipleLun)
1236 DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu = FALSE;
1237
1238 if (ConfigInfo.DisableTaggedQueueing)
1239 DeviceExtension->SupportsTaggedQueuing = PortConfig->MultipleRequestPerLu = FALSE;
1240
1241 /* Check if we need to alloc SRB data */
1242 if (DeviceExtension->SupportsTaggedQueuing || DeviceExtension->MultipleReqsPerLun)
1243 {
1244 DeviceExtension->NeedSrbDataAlloc = TRUE;
1245 }
1246 else
1247 {
1248 DeviceExtension->NeedSrbDataAlloc = FALSE;
1249 }
1250
1251 /* Get a pointer to the port capabilities */
1252 PortCapabilities = &DeviceExtension->PortCapabilities;
1253
1254 /* Copy one field there */
1255 DeviceExtension->MapBuffers = PortConfig->MapBuffers;
1256 PortCapabilities->AdapterUsesPio = PortConfig->MapBuffers;
1257
1258 if (DeviceExtension->AdapterObject == NULL &&
1259 (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE || PortConfig->Master))
1260 {
1261 DPRINT1("DMA is not supported yet\n");
1262 ASSERT(FALSE);
1263 }
1264
1265 if (DeviceExtension->SrbExtensionBuffer == NULL &&
1266 (DeviceExtension->SrbExtensionSize != 0 || PortConfig->AutoRequestSense))
1267 {
1268 DeviceExtension->SupportsAutoSense = PortConfig->AutoRequestSense;
1269 DeviceExtension->NeedSrbExtensionAlloc = TRUE;
1270
1271 /* Allocate common buffer */
1272 Status = SpiAllocateCommonBuffer(DeviceExtension, 0);
1273
1274 /* Check for failure */
1275 if (!NT_SUCCESS(Status))
1276 break;
1277 }
1278
1279 /* Allocate SrbData, if needed */
1280 if (DeviceExtension->NeedSrbDataAlloc)
1281 {
1282 ULONG Count;
1283 PSCSI_REQUEST_BLOCK_INFO SrbData;
1284
1285 if (DeviceExtension->SrbDataCount != 0)
1286 Count = DeviceExtension->SrbDataCount;
1287 else
1288 Count = DeviceExtension->RequestsNumber * 2;
1289
1290 /* Allocate the data */
1291 SrbData = ExAllocatePoolWithTag(
1292 NonPagedPool, Count * sizeof(SCSI_REQUEST_BLOCK_INFO), TAG_SCSIPORT);
1293 if (SrbData == NULL)
1294 return STATUS_INSUFFICIENT_RESOURCES;
1295
1296 RtlZeroMemory(SrbData, Count * sizeof(SCSI_REQUEST_BLOCK_INFO));
1297
1298 DeviceExtension->SrbInfo = SrbData;
1299 DeviceExtension->FreeSrbInfo = SrbData;
1300 DeviceExtension->SrbDataCount = Count;
1301
1302 /* Link it to the list */
1303 while (Count > 0)
1304 {
1305 SrbData->Requests.Flink = (PLIST_ENTRY)(SrbData + 1);
1306 SrbData++;
1307 Count--;
1308 }
1309
1310 /* Mark the last entry of the list */
1311 SrbData--;
1312 SrbData->Requests.Flink = NULL;
1313 }
1314
1315 /* Initialize port capabilities */
1316 PortCapabilities = &DeviceExtension->PortCapabilities;
1317 PortCapabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
1318 PortCapabilities->MaximumTransferLength = PortConfig->MaximumTransferLength;
1319
1320 if (PortConfig->ReceiveEvent)
1321 PortCapabilities->SupportedAsynchronousEvents |= SRBEV_SCSI_ASYNC_NOTIFICATION;
1322
1323 PortCapabilities->TaggedQueuing = DeviceExtension->SupportsTaggedQueuing;
1324 PortCapabilities->AdapterScansDown = PortConfig->AdapterScansDown;
1325
1326 if (PortConfig->AlignmentMask > PortDeviceObject->AlignmentRequirement)
1327 PortDeviceObject->AlignmentRequirement = PortConfig->AlignmentMask;
1328
1329 PortCapabilities->AlignmentMask = PortDeviceObject->AlignmentRequirement;
1330
1331 if (PortCapabilities->MaximumPhysicalPages == 0)
1332 {
1333 PortCapabilities->MaximumPhysicalPages =
1334 BYTES_TO_PAGES(PortCapabilities->MaximumTransferLength);
1335
1336 /* Apply miniport's limits */
1337 if (PortConfig->NumberOfPhysicalBreaks < PortCapabilities->MaximumPhysicalPages)
1338 {
1339 PortCapabilities->MaximumPhysicalPages = PortConfig->NumberOfPhysicalBreaks;
1340 }
1341 }
1342
1343 FdoCallHWInitialize(DeviceExtension);
1344
1345 Status = FdoStartAdapter(DeviceExtension);
1346
1347 if (!NT_SUCCESS(Status))
1348 {
1349 DPRINT1("Failed to start the legacy adapter. Status 0x%x\n", Status);
1350 break;
1351 }
1352
1353 FdoScanAdapter(DeviceExtension);
1354
1355 FirstConfigCall = FALSE;
1356
1357 /* Increase adapter number and bus number respectively */
1358 ConfigInfo.AdapterNumber++;
1359
1360 if (!Again)
1361 ConfigInfo.BusNumber++;
1362
1363 DPRINT(" Bus: %lu\n", ConfigInfo.BusNumber);
1364
1365 DeviceFound = TRUE;
1366 }
1367
1368 /* Clean up the mess */
1369 if (!NT_SUCCESS(Status) && PortDeviceObject)
1370 {
1371 FdoRemoveAdapter(DeviceExtension);
1372 }
1373
1374 /* Close registry keys */
1375 if (ConfigInfo.ServiceKey != NULL)
1376 ZwClose(ConfigInfo.ServiceKey);
1377
1378 if (ConfigInfo.DeviceKey != NULL)
1379 ZwClose(ConfigInfo.DeviceKey);
1380
1381 if (ConfigInfo.BusKey != NULL)
1382 ZwClose(ConfigInfo.BusKey);
1383
1384 if (ConfigInfo.AccessRanges != NULL)
1385 ExFreePool(ConfigInfo.AccessRanges);
1386
1387 if (ConfigInfo.Parameter != NULL)
1388 ExFreePool(ConfigInfo.Parameter);
1389
1390 DPRINT("ScsiPortInitialize() done, Status = 0x%08X, DeviceFound = %d!\n",
1391 Status, DeviceFound);
1392
1393 return (DeviceFound == FALSE) ? Status : STATUS_SUCCESS;
1394 }
1395
1396 /*
1397 * @unimplemented
1398 */
1399 VOID NTAPI
ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension,IN PSCSI_REQUEST_BLOCK Srb,IN PVOID LogicalAddress,IN ULONG Length)1400 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension,
1401 IN PSCSI_REQUEST_BLOCK Srb,
1402 IN PVOID LogicalAddress,
1403 IN ULONG Length)
1404 {
1405 DPRINT1("ScsiPortIoMapTransfer()\n");
1406 UNIMPLEMENTED;
1407 }
1408
1409 /*
1410 * @unimplemented
1411 */
1412 VOID NTAPI
ScsiPortLogError(IN PVOID HwDeviceExtension,IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,IN UCHAR PathId,IN UCHAR TargetId,IN UCHAR Lun,IN ULONG ErrorCode,IN ULONG UniqueId)1413 ScsiPortLogError(IN PVOID HwDeviceExtension,
1414 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
1415 IN UCHAR PathId,
1416 IN UCHAR TargetId,
1417 IN UCHAR Lun,
1418 IN ULONG ErrorCode,
1419 IN ULONG UniqueId)
1420 {
1421 //PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1422
1423 DPRINT1("ScsiPortLogError() called\n");
1424 DPRINT1("PathId: 0x%02x TargetId: 0x%02x Lun: 0x%02x ErrorCode: 0x%08lx UniqueId: 0x%08lx\n",
1425 PathId, TargetId, Lun, ErrorCode, UniqueId);
1426
1427 //DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, SCSI_PORT_DEVICE_EXTENSION, MiniPortDeviceExtension);
1428
1429
1430 DPRINT("ScsiPortLogError() done\n");
1431 }
1432
1433 /*
1434 * @implemented
1435 */
1436 VOID NTAPI
ScsiPortMoveMemory(OUT PVOID Destination,IN PVOID Source,IN ULONG Length)1437 ScsiPortMoveMemory(OUT PVOID Destination,
1438 IN PVOID Source,
1439 IN ULONG Length)
1440 {
1441 RtlMoveMemory(Destination,
1442 Source,
1443 Length);
1444 }
1445
1446
1447 /*
1448 * @implemented
1449 */
1450 VOID
ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType,IN PVOID HwDeviceExtension,...)1451 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType, IN PVOID HwDeviceExtension, ...)
1452 {
1453 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1454 va_list ap;
1455
1456 DPRINT("ScsiPortNotification() called\n");
1457
1458 DeviceExtension =
1459 CONTAINING_RECORD(HwDeviceExtension, SCSI_PORT_DEVICE_EXTENSION, MiniPortDeviceExtension);
1460
1461 DPRINT("DeviceExtension %p\n", DeviceExtension);
1462
1463 va_start(ap, HwDeviceExtension);
1464
1465 switch (NotificationType)
1466 {
1467 case RequestComplete:
1468 {
1469 PSCSI_REQUEST_BLOCK Srb;
1470 PSCSI_REQUEST_BLOCK_INFO SrbData;
1471
1472 Srb = (PSCSI_REQUEST_BLOCK)va_arg(ap, PSCSI_REQUEST_BLOCK);
1473
1474 DPRINT("Notify: RequestComplete (Srb %p)\n", Srb);
1475
1476 /* Make sure Srb is alright */
1477 ASSERT(Srb->SrbStatus != SRB_STATUS_PENDING);
1478 ASSERT(
1479 Srb->Function != SRB_FUNCTION_EXECUTE_SCSI ||
1480 Srb->SrbStatus != SRB_STATUS_SUCCESS || Srb->ScsiStatus == SCSISTAT_GOOD);
1481
1482 if (!(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE))
1483 {
1484 /* It's been already completed */
1485 va_end(ap);
1486 return;
1487 }
1488
1489 /* It's not active anymore */
1490 Srb->SrbFlags &= ~SRB_FLAGS_IS_ACTIVE;
1491
1492 if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
1493 {
1494 /* TODO: Treat it specially */
1495 ASSERT(FALSE);
1496 }
1497 else
1498 {
1499 PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Srb->OriginalRequest);
1500 PSCSI_PORT_LUN_EXTENSION LunExtension = IoStack->DeviceObject->DeviceExtension;
1501 ASSERT(LunExtension && !LunExtension->Common.IsFDO);
1502
1503 /* Get the SRB data */
1504 SrbData = SpiGetSrbData(DeviceExtension, LunExtension, Srb->QueueTag);
1505
1506 /* Make sure there are no CompletedRequests and there is a Srb */
1507 ASSERT(SrbData->CompletedRequests == NULL && SrbData->Srb != NULL);
1508
1509 /* If it's a read/write request, make sure it has data inside it */
1510 if ((Srb->SrbStatus == SRB_STATUS_SUCCESS) &&
1511 ((Srb->Cdb[0] == SCSIOP_READ) || (Srb->Cdb[0] == SCSIOP_WRITE)))
1512 {
1513 ASSERT(Srb->DataTransferLength);
1514 }
1515
1516 SrbData->CompletedRequests = DeviceExtension->InterruptData.CompletedRequests;
1517 DeviceExtension->InterruptData.CompletedRequests = SrbData;
1518 }
1519 }
1520 break;
1521
1522 case NextRequest:
1523 DPRINT("Notify: NextRequest\n");
1524 DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY;
1525 break;
1526
1527 case NextLuRequest:
1528 {
1529 UCHAR PathId;
1530 UCHAR TargetId;
1531 UCHAR Lun;
1532 PSCSI_PORT_LUN_EXTENSION LunExtension;
1533
1534 PathId = (UCHAR)va_arg(ap, int);
1535 TargetId = (UCHAR)va_arg(ap, int);
1536 Lun = (UCHAR)va_arg(ap, int);
1537
1538 DPRINT(
1539 "Notify: NextLuRequest(PathId %u TargetId %u Lun %u)\n", PathId, TargetId, Lun);
1540
1541 /* Mark it in the flags field */
1542 DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY;
1543
1544 /* Get the LUN extension */
1545 LunExtension = GetLunByPath(DeviceExtension, PathId, TargetId, Lun);
1546
1547 /* If returned LunExtension is NULL, break out */
1548 if (!LunExtension)
1549 break;
1550
1551 /* This request should not be processed if */
1552 if ((LunExtension->ReadyLun) || (LunExtension->SrbInfo.Srb))
1553 {
1554 /* Nothing to do here */
1555 break;
1556 }
1557
1558 /* Add this LUN to the list */
1559 LunExtension->ReadyLun = DeviceExtension->InterruptData.ReadyLun;
1560 DeviceExtension->InterruptData.ReadyLun = LunExtension;
1561 }
1562 break;
1563
1564 case ResetDetected:
1565 DPRINT("Notify: ResetDetected\n");
1566 /* Add RESET flags */
1567 DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET | SCSI_PORT_RESET_REPORTED;
1568 break;
1569
1570 case CallDisableInterrupts:
1571 DPRINT1("UNIMPLEMENTED SCSI Notification called: CallDisableInterrupts!\n");
1572 break;
1573
1574 case CallEnableInterrupts:
1575 DPRINT1("UNIMPLEMENTED SCSI Notification called: CallEnableInterrupts!\n");
1576 break;
1577
1578 case RequestTimerCall:
1579 DPRINT("Notify: RequestTimerCall\n");
1580 DeviceExtension->InterruptData.Flags |= SCSI_PORT_TIMER_NEEDED;
1581 DeviceExtension->InterruptData.HwScsiTimer = (PHW_TIMER)va_arg(ap, PHW_TIMER);
1582 DeviceExtension->InterruptData.MiniportTimerValue = (ULONG)va_arg(ap, ULONG);
1583 break;
1584
1585 case BusChangeDetected:
1586 DPRINT1("UNIMPLEMENTED SCSI Notification called: BusChangeDetected!\n");
1587 break;
1588
1589 default:
1590 DPRINT1("Unsupported notification from WMI: %lu\n", NotificationType);
1591 break;
1592 }
1593
1594 va_end(ap);
1595
1596 /* Request a DPC after we're done with the interrupt */
1597 DeviceExtension->InterruptData.Flags |= SCSI_PORT_NOTIFICATION_NEEDED;
1598 }
1599
1600 /*
1601 * @implemented
1602 */
1603 BOOLEAN NTAPI
ScsiPortValidateRange(IN PVOID HwDeviceExtension,IN INTERFACE_TYPE BusType,IN ULONG SystemIoBusNumber,IN SCSI_PHYSICAL_ADDRESS IoAddress,IN ULONG NumberOfBytes,IN BOOLEAN InIoSpace)1604 ScsiPortValidateRange(IN PVOID HwDeviceExtension,
1605 IN INTERFACE_TYPE BusType,
1606 IN ULONG SystemIoBusNumber,
1607 IN SCSI_PHYSICAL_ADDRESS IoAddress,
1608 IN ULONG NumberOfBytes,
1609 IN BOOLEAN InIoSpace)
1610 {
1611 DPRINT("ScsiPortValidateRange()\n");
1612 return(TRUE);
1613 }
1614
1615
1616 /* INTERNAL FUNCTIONS ********************************************************/
1617
1618 static VOID
SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData,IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor,IN PPORT_CONFIGURATION_INFORMATION PortConfig)1619 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData,
1620 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor,
1621 IN PPORT_CONFIGURATION_INFORMATION PortConfig)
1622 {
1623 PACCESS_RANGE AccessRange;
1624 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialData;
1625 ULONG RangeNumber;
1626 ULONG Index;
1627 ULONG Interrupt = 0;
1628 ULONG Dma = 0;
1629
1630 RangeNumber = 0;
1631
1632 /* Loop through all entries */
1633 for (Index = 0; Index < ResourceDescriptor->PartialResourceList.Count; Index++)
1634 {
1635 PartialData = &ResourceDescriptor->PartialResourceList.PartialDescriptors[Index];
1636
1637 switch (PartialData->Type)
1638 {
1639 case CmResourceTypePort:
1640 /* Copy access ranges */
1641 if (RangeNumber < HwInitializationData->NumberOfAccessRanges)
1642 {
1643 AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]);
1644
1645 AccessRange->RangeStart = PartialData->u.Port.Start;
1646 AccessRange->RangeLength = PartialData->u.Port.Length;
1647
1648 AccessRange->RangeInMemory = FALSE;
1649 RangeNumber++;
1650 }
1651 break;
1652
1653 case CmResourceTypeMemory:
1654 /* Copy access ranges */
1655 if (RangeNumber < HwInitializationData->NumberOfAccessRanges)
1656 {
1657 AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]);
1658
1659 AccessRange->RangeStart = PartialData->u.Memory.Start;
1660 AccessRange->RangeLength = PartialData->u.Memory.Length;
1661
1662 AccessRange->RangeInMemory = TRUE;
1663 RangeNumber++;
1664 }
1665 break;
1666
1667 case CmResourceTypeInterrupt:
1668
1669 if (Interrupt == 0)
1670 {
1671 /* Copy interrupt data */
1672 PortConfig->BusInterruptLevel = PartialData->u.Interrupt.Level;
1673 PortConfig->BusInterruptVector = PartialData->u.Interrupt.Vector;
1674
1675 /* Set interrupt mode accordingly to the resource */
1676 if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
1677 {
1678 PortConfig->InterruptMode = Latched;
1679 }
1680 else if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
1681 {
1682 PortConfig->InterruptMode = LevelSensitive;
1683 }
1684 }
1685 else if (Interrupt == 1)
1686 {
1687 /* Copy interrupt data */
1688 PortConfig->BusInterruptLevel2 = PartialData->u.Interrupt.Level;
1689 PortConfig->BusInterruptVector2 = PartialData->u.Interrupt.Vector;
1690
1691 /* Set interrupt mode accordingly to the resource */
1692 if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
1693 {
1694 PortConfig->InterruptMode2 = Latched;
1695 }
1696 else if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
1697 {
1698 PortConfig->InterruptMode2 = LevelSensitive;
1699 }
1700 }
1701
1702 Interrupt++;
1703 break;
1704
1705 case CmResourceTypeDma:
1706
1707 if (Dma == 0)
1708 {
1709 PortConfig->DmaChannel = PartialData->u.Dma.Channel;
1710 PortConfig->DmaPort = PartialData->u.Dma.Port;
1711
1712 if (PartialData->Flags & CM_RESOURCE_DMA_8)
1713 PortConfig->DmaWidth = Width8Bits;
1714 else if ((PartialData->Flags & CM_RESOURCE_DMA_16) ||
1715 (PartialData->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
1716 PortConfig->DmaWidth = Width16Bits;
1717 else if (PartialData->Flags & CM_RESOURCE_DMA_32)
1718 PortConfig->DmaWidth = Width32Bits;
1719 }
1720 else if (Dma == 1)
1721 {
1722 PortConfig->DmaChannel2 = PartialData->u.Dma.Channel;
1723 PortConfig->DmaPort2 = PartialData->u.Dma.Port;
1724
1725 if (PartialData->Flags & CM_RESOURCE_DMA_8)
1726 PortConfig->DmaWidth2 = Width8Bits;
1727 else if ((PartialData->Flags & CM_RESOURCE_DMA_16) ||
1728 (PartialData->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
1729 PortConfig->DmaWidth2 = Width16Bits;
1730 else if (PartialData->Flags & CM_RESOURCE_DMA_32)
1731 PortConfig->DmaWidth2 = Width32Bits;
1732 }
1733 break;
1734 }
1735 }
1736 }
1737
1738 static PCM_RESOURCE_LIST
SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,PPORT_CONFIGURATION_INFORMATION PortConfig)1739 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1740 PPORT_CONFIGURATION_INFORMATION PortConfig)
1741 {
1742 PCONFIGURATION_INFORMATION ConfigInfo;
1743 PCM_RESOURCE_LIST ResourceList;
1744 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor;
1745 PACCESS_RANGE AccessRange;
1746 ULONG ListLength = 0, i, FullSize;
1747 ULONG Interrupt, Dma;
1748
1749 /* Get current Atdisk usage from the system */
1750 ConfigInfo = IoGetConfigurationInformation();
1751
1752 if (PortConfig->AtdiskPrimaryClaimed)
1753 ConfigInfo->AtDiskPrimaryAddressClaimed = TRUE;
1754
1755 if (PortConfig->AtdiskSecondaryClaimed)
1756 ConfigInfo->AtDiskSecondaryAddressClaimed = TRUE;
1757
1758 /* Do we use DMA? */
1759 if (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE ||
1760 PortConfig->DmaPort != SP_UNINITIALIZED_VALUE)
1761 {
1762 Dma = 1;
1763
1764 if (PortConfig->DmaChannel2 != SP_UNINITIALIZED_VALUE ||
1765 PortConfig->DmaPort2 != SP_UNINITIALIZED_VALUE)
1766 Dma++;
1767 }
1768 else
1769 {
1770 Dma = 0;
1771 }
1772 ListLength += Dma;
1773
1774 /* How many interrupts to we have? */
1775 Interrupt = DeviceExtension->InterruptCount;
1776 ListLength += Interrupt;
1777
1778 /* How many access ranges do we use? */
1779 AccessRange = &((*(PortConfig->AccessRanges))[0]);
1780 for (i = 0; i < PortConfig->NumberOfAccessRanges; i++)
1781 {
1782 if (AccessRange->RangeLength != 0)
1783 ListLength++;
1784
1785 AccessRange++;
1786 }
1787
1788 /* Allocate the resource list, since we know its size now */
1789 FullSize = sizeof(CM_RESOURCE_LIST) + (ListLength - 1) *
1790 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1791
1792 ResourceList = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(PagedPool, FullSize, TAG_SCSIPORT);
1793
1794 if (!ResourceList)
1795 return NULL;
1796
1797 /* Zero it */
1798 RtlZeroMemory(ResourceList, FullSize);
1799
1800 /* Initialize it */
1801 ResourceList->Count = 1;
1802 ResourceList->List[0].InterfaceType = PortConfig->AdapterInterfaceType;
1803 ResourceList->List[0].BusNumber = PortConfig->SystemIoBusNumber;
1804 ResourceList->List[0].PartialResourceList.Count = ListLength;
1805 ResourceDescriptor = ResourceList->List[0].PartialResourceList.PartialDescriptors;
1806
1807 /* Copy access ranges array over */
1808 for (i = 0; i < PortConfig->NumberOfAccessRanges; i++)
1809 {
1810 AccessRange = &((*(PortConfig->AccessRanges))[i]);
1811
1812 /* If the range is empty - skip it */
1813 if (AccessRange->RangeLength == 0)
1814 continue;
1815
1816 if (AccessRange->RangeInMemory)
1817 {
1818 ResourceDescriptor->Type = CmResourceTypeMemory;
1819 ResourceDescriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
1820 }
1821 else
1822 {
1823 ResourceDescriptor->Type = CmResourceTypePort;
1824 ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
1825 }
1826
1827 ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1828
1829 ResourceDescriptor->u.Memory.Start = AccessRange->RangeStart;
1830 ResourceDescriptor->u.Memory.Length = AccessRange->RangeLength;
1831
1832 ResourceDescriptor++;
1833 }
1834
1835 /* If we use interrupt(s), copy them */
1836 while (Interrupt)
1837 {
1838 ResourceDescriptor->Type = CmResourceTypeInterrupt;
1839
1840 if (PortConfig->AdapterInterfaceType == MicroChannel ||
1841 ((Interrupt == 2) ? PortConfig->InterruptMode2 : PortConfig->InterruptMode) == LevelSensitive)
1842 {
1843 ResourceDescriptor->ShareDisposition = CmResourceShareShared;
1844 ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
1845 }
1846 else
1847 {
1848 ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1849 ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
1850 }
1851
1852 ResourceDescriptor->u.Interrupt.Level = (Interrupt == 2) ? PortConfig->BusInterruptLevel2 : PortConfig->BusInterruptLevel;
1853 ResourceDescriptor->u.Interrupt.Vector = (Interrupt == 2) ? PortConfig->BusInterruptVector2 : PortConfig->BusInterruptVector;
1854 ResourceDescriptor->u.Interrupt.Affinity = 0;
1855
1856 ResourceDescriptor++;
1857 Interrupt--;
1858 }
1859
1860 /* Copy DMA data */
1861 while (Dma)
1862 {
1863 ResourceDescriptor->Type = CmResourceTypeDma;
1864 ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
1865 ResourceDescriptor->u.Dma.Channel = (Dma == 2) ? PortConfig->DmaChannel2 : PortConfig->DmaChannel;
1866 ResourceDescriptor->u.Dma.Port = (Dma == 2) ? PortConfig->DmaPort2 : PortConfig->DmaPort;
1867 ResourceDescriptor->Flags = 0;
1868
1869 if (((Dma == 2) ? PortConfig->DmaWidth2 : PortConfig->DmaWidth) == Width8Bits)
1870 ResourceDescriptor->Flags |= CM_RESOURCE_DMA_8;
1871 else if (((Dma == 2) ? PortConfig->DmaWidth2 : PortConfig->DmaWidth) == Width16Bits)
1872 ResourceDescriptor->Flags |= CM_RESOURCE_DMA_16;
1873 else
1874 ResourceDescriptor->Flags |= CM_RESOURCE_DMA_32;
1875
1876 if (((Dma == 2) ? PortConfig->DmaChannel2 : PortConfig->DmaChannel) == SP_UNINITIALIZED_VALUE)
1877 ResourceDescriptor->u.Dma.Channel = 0;
1878
1879 if (((Dma == 2) ? PortConfig->DmaPort2 : PortConfig->DmaPort) == SP_UNINITIALIZED_VALUE)
1880 ResourceDescriptor->u.Dma.Port = 0;
1881
1882 ResourceDescriptor++;
1883 Dma--;
1884 }
1885
1886 return ResourceList;
1887 }
1888
1889
1890 static BOOLEAN
SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT DeviceObject,IN struct _HW_INITIALIZATION_DATA * HwInitializationData,IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,IN PUNICODE_STRING RegistryPath,IN ULONG BusNumber,IN OUT PPCI_SLOT_NUMBER NextSlotNumber)1891 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject,
1892 IN PDEVICE_OBJECT DeviceObject,
1893 IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
1894 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,
1895 IN PUNICODE_STRING RegistryPath,
1896 IN ULONG BusNumber,
1897 IN OUT PPCI_SLOT_NUMBER NextSlotNumber)
1898 {
1899 PCI_COMMON_CONFIG PciConfig;
1900 PCI_SLOT_NUMBER SlotNumber;
1901 ULONG DataSize;
1902 ULONG DeviceNumber;
1903 ULONG FunctionNumber;
1904 CHAR VendorIdString[8];
1905 CHAR DeviceIdString[8];
1906 UNICODE_STRING UnicodeStr;
1907 PCM_RESOURCE_LIST ResourceList = NULL;
1908 NTSTATUS Status;
1909
1910 DPRINT ("SpiGetPciConfiguration() called\n");
1911
1912 SlotNumber.u.AsULONG = 0;
1913
1914 /* Loop through all devices */
1915 for (DeviceNumber = NextSlotNumber->u.bits.DeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
1916 {
1917 SlotNumber.u.bits.DeviceNumber = DeviceNumber;
1918
1919 /* Loop through all functions */
1920 for (FunctionNumber = NextSlotNumber->u.bits.FunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
1921 {
1922 SlotNumber.u.bits.FunctionNumber = FunctionNumber;
1923
1924 /* Get PCI config bytes */
1925 DataSize = HalGetBusData(PCIConfiguration,
1926 BusNumber,
1927 SlotNumber.u.AsULONG,
1928 &PciConfig,
1929 sizeof(ULONG));
1930
1931 /* If result of HalGetBusData is 0, then the bus is wrong */
1932 if (DataSize == 0)
1933 return FALSE;
1934
1935 /* Check if result is PCI_INVALID_VENDORID or too small */
1936 if ((DataSize < sizeof(ULONG)) ||
1937 (PciConfig.VendorID == PCI_INVALID_VENDORID))
1938 {
1939 /* Continue to try the next function */
1940 continue;
1941 }
1942
1943 sprintf (VendorIdString, "%04hx", PciConfig.VendorID);
1944 sprintf (DeviceIdString, "%04hx", PciConfig.DeviceID);
1945
1946 if (_strnicmp(VendorIdString, HwInitializationData->VendorId, HwInitializationData->VendorIdLength) ||
1947 _strnicmp(DeviceIdString, HwInitializationData->DeviceId, HwInitializationData->DeviceIdLength))
1948 {
1949 /* It is not our device */
1950 continue;
1951 }
1952
1953 DPRINT("Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n",
1954 PciConfig.VendorID,
1955 PciConfig.DeviceID,
1956 BusNumber,
1957 SlotNumber.u.bits.DeviceNumber,
1958 SlotNumber.u.bits.FunctionNumber);
1959
1960
1961 RtlInitUnicodeString(&UnicodeStr, L"ScsiAdapter");
1962 Status = HalAssignSlotResources(RegistryPath,
1963 &UnicodeStr,
1964 DriverObject,
1965 DeviceObject,
1966 PCIBus,
1967 BusNumber,
1968 SlotNumber.u.AsULONG,
1969 &ResourceList);
1970
1971 if (!NT_SUCCESS(Status))
1972 break;
1973
1974 /* Create configuration information */
1975 SpiResourceToConfig(HwInitializationData,
1976 ResourceList->List,
1977 PortConfig);
1978
1979 /* Free the resource list */
1980 ExFreePool(ResourceList);
1981
1982 /* Set dev & fn numbers */
1983 NextSlotNumber->u.bits.DeviceNumber = DeviceNumber;
1984 NextSlotNumber->u.bits.FunctionNumber = FunctionNumber + 1;
1985
1986 /* Save the slot number */
1987 PortConfig->SlotNumber = SlotNumber.u.AsULONG;
1988
1989 return TRUE;
1990 }
1991 NextSlotNumber->u.bits.FunctionNumber = 0;
1992 }
1993
1994 NextSlotNumber->u.bits.DeviceNumber = 0;
1995 DPRINT ("No device found\n");
1996
1997 return FALSE;
1998 }
1999
2000
2001
2002 /**********************************************************************
2003 * NAME INTERNAL
2004 * ScsiPortCreateClose
2005 *
2006 * DESCRIPTION
2007 * Answer requests for Create/Close calls: a null operation.
2008 *
2009 * RUN LEVEL
2010 * PASSIVE_LEVEL
2011 *
2012 * ARGUMENTS
2013 * DeviceObject
2014 * Pointer to a device object.
2015 *
2016 * Irp
2017 * Pointer to an IRP.
2018 *
2019 * RETURN VALUE
2020 * Status.
2021 */
2022
2023 static NTSTATUS NTAPI
ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)2024 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
2025 IN PIRP Irp)
2026 {
2027 DPRINT("ScsiPortCreateClose()\n");
2028
2029 Irp->IoStatus.Status = STATUS_SUCCESS;
2030 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2031
2032 return STATUS_SUCCESS;
2033 }
2034
2035 IO_ALLOCATION_ACTION
2036 NTAPI
SpiAdapterControl(PDEVICE_OBJECT DeviceObject,PIRP Irp,PVOID MapRegisterBase,PVOID Context)2037 SpiAdapterControl(PDEVICE_OBJECT DeviceObject,
2038 PIRP Irp,
2039 PVOID MapRegisterBase,
2040 PVOID Context)
2041 {
2042 PSCSI_REQUEST_BLOCK Srb;
2043 PSCSI_SG_ADDRESS ScatterGatherList;
2044 KIRQL CurrentIrql;
2045 PIO_STACK_LOCATION IrpStack;
2046 ULONG TotalLength = 0;
2047 PSCSI_REQUEST_BLOCK_INFO SrbInfo;
2048 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2049 PUCHAR DataVA;
2050 BOOLEAN WriteToDevice;
2051
2052 /* Get pointers to SrbInfo and DeviceExtension */
2053 SrbInfo = (PSCSI_REQUEST_BLOCK_INFO)Context;
2054 DeviceExtension = DeviceObject->DeviceExtension;
2055
2056 /* Get pointer to SRB */
2057 IrpStack = IoGetCurrentIrpStackLocation(Irp);
2058 Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
2059
2060 /* Depending on the map registers number, we allocate
2061 either from NonPagedPool, or from our static list */
2062 if (SrbInfo->NumberOfMapRegisters > MAX_SG_LIST)
2063 {
2064 SrbInfo->ScatterGather = ExAllocatePoolWithTag(
2065 NonPagedPool, SrbInfo->NumberOfMapRegisters * sizeof(SCSI_SG_ADDRESS), TAG_SCSIPORT);
2066
2067 if (SrbInfo->ScatterGather == NULL)
2068 ASSERT(FALSE);
2069
2070 Srb->SrbFlags |= SRB_FLAGS_SGLIST_FROM_POOL;
2071 }
2072 else
2073 {
2074 SrbInfo->ScatterGather = SrbInfo->ScatterGatherList;
2075 }
2076
2077 /* Use chosen SG list source */
2078 ScatterGatherList = SrbInfo->ScatterGather;
2079
2080 /* Save map registers base */
2081 SrbInfo->BaseOfMapRegister = MapRegisterBase;
2082
2083 /* Determine WriteToDevice flag */
2084 WriteToDevice = Srb->SrbFlags & SRB_FLAGS_DATA_OUT ? TRUE : FALSE;
2085
2086 /* Get virtual address of the data buffer */
2087 DataVA = (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress) +
2088 ((PCHAR)Srb->DataBuffer - SrbInfo->DataOffset);
2089
2090 /* Build the actual SG list */
2091 while (TotalLength < Srb->DataTransferLength)
2092 {
2093 if (!ScatterGatherList)
2094 break;
2095
2096 ScatterGatherList->Length = Srb->DataTransferLength - TotalLength;
2097 ScatterGatherList->PhysicalAddress = IoMapTransfer(DeviceExtension->AdapterObject,
2098 Irp->MdlAddress,
2099 MapRegisterBase,
2100 DataVA + TotalLength,
2101 &ScatterGatherList->Length,
2102 WriteToDevice);
2103
2104 TotalLength += ScatterGatherList->Length;
2105 ScatterGatherList++;
2106 }
2107
2108 /* Schedule an active request */
2109 InterlockedIncrement(&DeviceExtension->ActiveRequestCounter );
2110 KeAcquireSpinLock(&DeviceExtension->SpinLock, &CurrentIrql);
2111 KeSynchronizeExecution(DeviceExtension->Interrupt[0],
2112 ScsiPortStartPacket,
2113 DeviceObject);
2114 KeReleaseSpinLock(&DeviceExtension->SpinLock, CurrentIrql);
2115
2116 return DeallocateObjectKeepRegisters;
2117 }
2118
2119 BOOLEAN
2120 NTAPI
ScsiPortIsr(_In_ PKINTERRUPT Interrupt,_In_ PVOID ServiceContext)2121 ScsiPortIsr(
2122 _In_ PKINTERRUPT Interrupt,
2123 _In_ PVOID ServiceContext)
2124 {
2125 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2126
2127 DPRINT("ScsiPortIsr() called!\n");
2128
2129 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext;
2130
2131 /* If interrupts are disabled - we don't expect any */
2132 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_DISABLE_INTERRUPTS)
2133 return FALSE;
2134
2135 /* Call miniport's HwInterrupt routine */
2136 if (DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension) == FALSE)
2137 {
2138 /* This interrupt doesn't belong to us */
2139 return FALSE;
2140 }
2141
2142 /* If flag of notification is set - queue a DPC */
2143 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
2144 {
2145 IoRequestDpc(DeviceExtension->Common.DeviceObject,
2146 DeviceExtension->CurrentIrp,
2147 DeviceExtension);
2148 }
2149
2150 return TRUE;
2151 }
2152
2153 BOOLEAN
2154 NTAPI
SpiProcessTimeout(PVOID ServiceContext)2155 SpiProcessTimeout(PVOID ServiceContext)
2156 {
2157 PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)ServiceContext;
2158 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
2159 ULONG Bus;
2160
2161 DPRINT("SpiProcessTimeout() entered\n");
2162
2163 DeviceExtension->TimerCount = -1;
2164
2165 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET)
2166 {
2167 DeviceExtension->InterruptData.Flags &= ~SCSI_PORT_RESET;
2168
2169 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET_REQUEST)
2170 {
2171 DeviceExtension->InterruptData.Flags &= ~SCSI_PORT_RESET_REQUEST;
2172 ScsiPortStartPacket(ServiceContext);
2173 }
2174
2175 return FALSE;
2176 }
2177 else
2178 {
2179 DPRINT("Resetting the bus\n");
2180
2181 for (Bus = 0; Bus < DeviceExtension->NumberOfBuses; Bus++)
2182 {
2183 DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension, Bus);
2184
2185 /* Reset flags and set reset timeout to 4 seconds */
2186 DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET;
2187 DeviceExtension->TimerCount = 4;
2188 }
2189
2190 /* If miniport requested - request a dpc for it */
2191 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
2192 IoRequestDpc(DeviceExtension->Common.DeviceObject, NULL, NULL);
2193 }
2194
2195 return TRUE;
2196 }
2197
2198
2199 BOOLEAN
2200 NTAPI
SpiResetBus(PVOID ServiceContext)2201 SpiResetBus(PVOID ServiceContext)
2202 {
2203 PRESETBUS_PARAMS ResetParams = (PRESETBUS_PARAMS)ServiceContext;
2204 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2205
2206 /* Perform the bus reset */
2207 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ResetParams->DeviceExtension;
2208 DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension,
2209 ResetParams->PathId);
2210
2211 /* Set flags and start the timer */
2212 DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET;
2213 DeviceExtension->TimerCount = 4;
2214
2215 /* If miniport requested - give him a DPC */
2216 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
2217 IoRequestDpc(DeviceExtension->Common.DeviceObject, NULL, NULL);
2218
2219 return TRUE;
2220 }
2221
2222 // ScsiPortIoTimer
2223 // DESCRIPTION:
2224 // This function handles timeouts and other time delayed processing
2225 //
2226 // RUN LEVEL:
2227 //
2228 // ARGUMENTS:
2229 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
2230 // IN PVOID Context the Controller extension for the
2231 // controller the device is on
2232 //
2233 static VOID NTAPI
ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,PVOID Context)2234 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
2235 PVOID Context)
2236 {
2237 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2238 PSCSI_PORT_LUN_EXTENSION LunExtension;
2239 PIRP Irp;
2240
2241 DPRINT("ScsiPortIoTimer()\n");
2242
2243 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
2244
2245 /* Protect with the spinlock */
2246 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
2247
2248 /* Check timeouts */
2249 if (DeviceExtension->TimerCount > 0)
2250 {
2251 /* Decrease the timeout counter */
2252 DeviceExtension->TimerCount--;
2253
2254 if (DeviceExtension->TimerCount == 0)
2255 {
2256 /* Timeout, process it */
2257 if (KeSynchronizeExecution(DeviceExtension->Interrupt[0],
2258 SpiProcessTimeout,
2259 DeviceExtension->Common.DeviceObject))
2260 {
2261 DPRINT("Error happened during processing timeout, but nothing critical\n");
2262 }
2263 }
2264
2265 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
2266
2267 /* We should exit now, since timeout is processed */
2268 return;
2269 }
2270
2271 /* Per-Lun scanning of timeouts is needed... */
2272 for (UINT8 pathId = 0; pathId < DeviceExtension->NumberOfBuses; pathId++)
2273 {
2274 PSCSI_BUS_INFO bus = &DeviceExtension->Buses[pathId];
2275
2276 for (PLIST_ENTRY lunEntry = bus->LunsListHead.Flink;
2277 lunEntry != &bus->LunsListHead;
2278 lunEntry = lunEntry->Flink)
2279 {
2280 LunExtension = CONTAINING_RECORD(lunEntry, SCSI_PORT_LUN_EXTENSION, LunEntry);
2281
2282 if (LunExtension->Flags & LUNEX_BUSY)
2283 {
2284 if (!(LunExtension->Flags &
2285 (LUNEX_NEED_REQUEST_SENSE | LUNEX_FROZEN_QUEUE)))
2286 {
2287 DPRINT("Retrying busy request\n");
2288
2289 /* Clear flags, and retry busy request */
2290 LunExtension->Flags &= ~(LUNEX_BUSY | LUNEX_FULL_QUEUE);
2291 Irp = LunExtension->BusyRequest;
2292
2293 /* Clearing busy request */
2294 LunExtension->BusyRequest = NULL;
2295
2296 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
2297
2298 IoStartPacket(DeviceObject, Irp, (PULONG)NULL, NULL);
2299
2300 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
2301 }
2302 }
2303 else if (LunExtension->RequestTimeout == 0)
2304 {
2305 RESETBUS_PARAMS ResetParams;
2306
2307 LunExtension->RequestTimeout = -1;
2308
2309 DPRINT("Request timed out, resetting bus\n");
2310
2311 /* Pass params to the bus reset routine */
2312 ResetParams.PathId = LunExtension->PathId;
2313 ResetParams.DeviceExtension = DeviceExtension;
2314
2315 if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0],
2316 SpiResetBus,
2317 &ResetParams))
2318 {
2319 DPRINT1("Reset failed\n");
2320 }
2321 }
2322 else if (LunExtension->RequestTimeout > 0)
2323 {
2324 /* Decrement the timeout counter */
2325 LunExtension->RequestTimeout--;
2326 }
2327 }
2328 }
2329
2330 /* Release the spinlock */
2331 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
2332 }
2333
2334 VOID
2335 NTAPI
SpiMiniportTimerDpc(IN struct _KDPC * Dpc,IN PVOID DeviceObject,IN PVOID SystemArgument1,IN PVOID SystemArgument2)2336 SpiMiniportTimerDpc(IN struct _KDPC *Dpc,
2337 IN PVOID DeviceObject,
2338 IN PVOID SystemArgument1,
2339 IN PVOID SystemArgument2)
2340 {
2341 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2342
2343 DPRINT("Miniport timer DPC\n");
2344
2345 DeviceExtension = ((PDEVICE_OBJECT)DeviceObject)->DeviceExtension;
2346
2347 /* Acquire the spinlock */
2348 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
2349
2350 /* Call the timer routine */
2351 if (DeviceExtension->HwScsiTimer != NULL)
2352 {
2353 DeviceExtension->HwScsiTimer(&DeviceExtension->MiniPortDeviceExtension);
2354 }
2355
2356 /* Release the spinlock */
2357 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
2358
2359 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
2360 {
2361 ScsiPortDpcForIsr(NULL,
2362 DeviceExtension->Common.DeviceObject,
2363 NULL,
2364 NULL);
2365 }
2366 }
2367
2368 static NTSTATUS
SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,PHW_INITIALIZATION_DATA HwInitData,PCONFIGURATION_INFO InternalConfigInfo,PPORT_CONFIGURATION_INFORMATION ConfigInfo,BOOLEAN ZeroStruct)2369 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
2370 PHW_INITIALIZATION_DATA HwInitData,
2371 PCONFIGURATION_INFO InternalConfigInfo,
2372 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
2373 BOOLEAN ZeroStruct)
2374 {
2375 UNICODE_STRING UnicodeString;
2376 OBJECT_ATTRIBUTES ObjectAttributes;
2377 PCONFIGURATION_INFORMATION DdkConfigInformation;
2378 HANDLE RootKey, Key;
2379 BOOLEAN Found;
2380 WCHAR DeviceBuffer[16];
2381 WCHAR StrBuffer[512];
2382 ULONG Bus;
2383 NTSTATUS Status;
2384
2385 /* Zero out the struct if told so */
2386 if (ZeroStruct)
2387 {
2388 /* First zero the portconfig */
2389 RtlZeroMemory(ConfigInfo, sizeof(PORT_CONFIGURATION_INFORMATION));
2390
2391 /* Then access ranges */
2392 RtlZeroMemory(InternalConfigInfo->AccessRanges,
2393 HwInitData->NumberOfAccessRanges * sizeof(ACCESS_RANGE));
2394
2395 /* Initialize the struct */
2396 ConfigInfo->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
2397 ConfigInfo->AdapterInterfaceType = HwInitData->AdapterInterfaceType;
2398 ConfigInfo->InterruptMode = Latched;
2399 ConfigInfo->DmaChannel = SP_UNINITIALIZED_VALUE;
2400 ConfigInfo->DmaPort = SP_UNINITIALIZED_VALUE;
2401 ConfigInfo->DmaChannel2 = SP_UNINITIALIZED_VALUE;
2402 ConfigInfo->DmaPort2 = SP_UNINITIALIZED_VALUE;
2403 ConfigInfo->MaximumTransferLength = SP_UNINITIALIZED_VALUE;
2404 ConfigInfo->NumberOfAccessRanges = HwInitData->NumberOfAccessRanges;
2405 ConfigInfo->MaximumNumberOfTargets = SCSI_MAXIMUM_TARGETS; // NOTE: Using legacy value.
2406
2407 /* Store parameters */
2408 ConfigInfo->NeedPhysicalAddresses = HwInitData->NeedPhysicalAddresses;
2409 ConfigInfo->MapBuffers = HwInitData->MapBuffers;
2410 ConfigInfo->AutoRequestSense = HwInitData->AutoRequestSense;
2411 ConfigInfo->ReceiveEvent = HwInitData->ReceiveEvent;
2412 ConfigInfo->TaggedQueuing = HwInitData->TaggedQueuing;
2413 ConfigInfo->MultipleRequestPerLu = HwInitData->MultipleRequestPerLu;
2414
2415 /* Get the disk usage */
2416 DdkConfigInformation = IoGetConfigurationInformation();
2417 ConfigInfo->AtdiskPrimaryClaimed = DdkConfigInformation->AtDiskPrimaryAddressClaimed;
2418 ConfigInfo->AtdiskSecondaryClaimed = DdkConfigInformation->AtDiskSecondaryAddressClaimed;
2419
2420 /* Initiator bus id is not set */
2421 for (Bus = 0; Bus < RTL_NUMBER_OF(ConfigInfo->InitiatorBusId); Bus++)
2422 {
2423 ConfigInfo->InitiatorBusId[Bus] = (CCHAR)SP_UNINITIALIZED_VALUE;
2424 }
2425 }
2426
2427 ConfigInfo->NumberOfPhysicalBreaks = 17;
2428
2429 /* Clear this information */
2430 InternalConfigInfo->DisableTaggedQueueing = FALSE;
2431 InternalConfigInfo->DisableMultipleLun = FALSE;
2432
2433 /* Store Bus Number */
2434 ConfigInfo->SystemIoBusNumber = InternalConfigInfo->BusNumber;
2435
2436 TryNextAd:
2437
2438 if (ConfigInfo->AdapterInterfaceType == Internal)
2439 {
2440 /* Open registry key for HW database */
2441 InitializeObjectAttributes(&ObjectAttributes,
2442 DeviceExtension->Common.DeviceObject->DriverObject->HardwareDatabase,
2443 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2444 NULL,
2445 NULL);
2446
2447 Status = ZwOpenKey(&RootKey,
2448 KEY_READ,
2449 &ObjectAttributes);
2450
2451 if (NT_SUCCESS(Status))
2452 {
2453 /* Create name for it */
2454 swprintf(StrBuffer, L"ScsiAdapter\\%lu",
2455 InternalConfigInfo->AdapterNumber);
2456
2457 RtlInitUnicodeString(&UnicodeString, StrBuffer);
2458
2459 /* Open device key */
2460 InitializeObjectAttributes(&ObjectAttributes,
2461 &UnicodeString,
2462 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2463 RootKey,
2464 NULL);
2465
2466 Status = ZwOpenKey(&Key,
2467 KEY_READ,
2468 &ObjectAttributes);
2469
2470 ZwClose(RootKey);
2471
2472 if (NT_SUCCESS(Status))
2473 {
2474 if (InternalConfigInfo->LastAdapterNumber != InternalConfigInfo->AdapterNumber)
2475 {
2476 DPRINT("Hardware info found at %S\n", StrBuffer);
2477
2478 /* Parse it */
2479 SpiParseDeviceInfo(DeviceExtension,
2480 Key,
2481 ConfigInfo,
2482 InternalConfigInfo,
2483 (PUCHAR)StrBuffer);
2484
2485 InternalConfigInfo->BusNumber = 0;
2486 }
2487 else
2488 {
2489 /* Try the next adapter */
2490 InternalConfigInfo->AdapterNumber++;
2491 goto TryNextAd;
2492 }
2493 }
2494 else
2495 {
2496 /* Info was not found, exit */
2497 DPRINT("ZwOpenKey() failed with Status=0x%08X\n", Status);
2498 return STATUS_DEVICE_DOES_NOT_EXIST;
2499 }
2500 }
2501 else
2502 {
2503 DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status);
2504 }
2505 }
2506
2507 /* Look at device params */
2508 Key = NULL;
2509 if (InternalConfigInfo->Parameter)
2510 {
2511 ExFreePool(InternalConfigInfo->Parameter);
2512 InternalConfigInfo->Parameter = NULL;
2513 }
2514
2515 if (InternalConfigInfo->ServiceKey != NULL)
2516 {
2517 swprintf(DeviceBuffer, L"Device%lu", InternalConfigInfo->AdapterNumber);
2518 RtlInitUnicodeString(&UnicodeString, DeviceBuffer);
2519
2520 /* Open the service key */
2521 InitializeObjectAttributes(&ObjectAttributes,
2522 &UnicodeString,
2523 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2524 InternalConfigInfo->ServiceKey,
2525 NULL);
2526
2527 Status = ZwOpenKey(&Key,
2528 KEY_READ,
2529 &ObjectAttributes);
2530 }
2531
2532 /* Parse device key */
2533 if (InternalConfigInfo->DeviceKey != NULL)
2534 {
2535 SpiParseDeviceInfo(DeviceExtension,
2536 InternalConfigInfo->DeviceKey,
2537 ConfigInfo,
2538 InternalConfigInfo,
2539 (PUCHAR)StrBuffer);
2540 }
2541
2542 /* Then parse hw info */
2543 if (Key != NULL)
2544 {
2545 if (InternalConfigInfo->LastAdapterNumber != InternalConfigInfo->AdapterNumber)
2546 {
2547 SpiParseDeviceInfo(DeviceExtension,
2548 Key,
2549 ConfigInfo,
2550 InternalConfigInfo,
2551 (PUCHAR)StrBuffer);
2552
2553 /* Close the key */
2554 ZwClose(Key);
2555 }
2556 else
2557 {
2558 /* Adapter not found, go try the next one */
2559 InternalConfigInfo->AdapterNumber++;
2560
2561 /* Close the key */
2562 ZwClose(Key);
2563
2564 goto TryNextAd;
2565 }
2566 }
2567
2568 /* Update the last adapter number */
2569 InternalConfigInfo->LastAdapterNumber = InternalConfigInfo->AdapterNumber;
2570
2571 /* Do we have this kind of bus at all? */
2572 Found = FALSE;
2573 Status = IoQueryDeviceDescription(&HwInitData->AdapterInterfaceType,
2574 &InternalConfigInfo->BusNumber,
2575 NULL,
2576 NULL,
2577 NULL,
2578 NULL,
2579 SpQueryDeviceCallout,
2580 &Found);
2581
2582 /* This bus was not found */
2583 if (!Found)
2584 {
2585 INTERFACE_TYPE InterfaceType = Eisa;
2586
2587 /* Check for EISA */
2588 if (HwInitData->AdapterInterfaceType == Isa)
2589 {
2590 Status = IoQueryDeviceDescription(&InterfaceType,
2591 &InternalConfigInfo->BusNumber,
2592 NULL,
2593 NULL,
2594 NULL,
2595 NULL,
2596 SpQueryDeviceCallout,
2597 &Found);
2598
2599 /* Return respectively */
2600 if (Found)
2601 return STATUS_SUCCESS;
2602 else
2603 return STATUS_DEVICE_DOES_NOT_EXIST;
2604 }
2605 else
2606 {
2607 return STATUS_DEVICE_DOES_NOT_EXIST;
2608 }
2609 }
2610 else
2611 {
2612 return STATUS_SUCCESS;
2613 }
2614 }
2615
2616 static VOID
SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,IN HANDLE Key,IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,IN PCONFIGURATION_INFO InternalConfigInfo,IN PUCHAR Buffer)2617 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
2618 IN HANDLE Key,
2619 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
2620 IN PCONFIGURATION_INFO InternalConfigInfo,
2621 IN PUCHAR Buffer)
2622 {
2623 PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
2624 PCM_FULL_RESOURCE_DESCRIPTOR FullResource;
2625 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
2626 PCM_SCSI_DEVICE_DATA ScsiDeviceData;
2627 ULONG Length, Count, Dma = 0, Interrupt = 0;
2628 ULONG Index = 0, RangeCount = 0;
2629 UNICODE_STRING UnicodeString;
2630 ANSI_STRING AnsiString;
2631 NTSTATUS Status = STATUS_SUCCESS;
2632
2633
2634 KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION) Buffer;
2635
2636 /* Loop through all values in the device node */
2637 while(TRUE)
2638 {
2639 Status = ZwEnumerateValueKey(Key,
2640 Index,
2641 KeyValueFullInformation,
2642 Buffer,
2643 512,
2644 &Length);
2645
2646 if (!NT_SUCCESS(Status))
2647 return;
2648
2649 Index++;
2650
2651 /* Length for DWORD is ok? */
2652 if (KeyValueInformation->Type == REG_DWORD &&
2653 KeyValueInformation->DataLength != sizeof(ULONG))
2654 {
2655 continue;
2656 }
2657
2658 /* Get MaximumLogicalUnit */
2659 if (_wcsnicmp(KeyValueInformation->Name, L"MaximumLogicalUnit",
2660 KeyValueInformation->NameLength/2) == 0)
2661 {
2662
2663 if (KeyValueInformation->Type != REG_DWORD)
2664 {
2665 DPRINT("Bad data type for MaximumLogicalUnit\n");
2666 continue;
2667 }
2668
2669 DeviceExtension->MaxLunCount = *((PUCHAR)
2670 (Buffer + KeyValueInformation->DataOffset));
2671
2672 /* Check / reset if needed */
2673 if (DeviceExtension->MaxLunCount > SCSI_MAXIMUM_LOGICAL_UNITS)
2674 DeviceExtension->MaxLunCount = SCSI_MAXIMUM_LOGICAL_UNITS;
2675
2676 DPRINT("MaximumLogicalUnit = %d\n", DeviceExtension->MaxLunCount);
2677 }
2678
2679 /* Get InitiatorTargetId */
2680 if (_wcsnicmp(KeyValueInformation->Name, L"InitiatorTargetId",
2681 KeyValueInformation->NameLength / 2) == 0)
2682 {
2683
2684 if (KeyValueInformation->Type != REG_DWORD)
2685 {
2686 DPRINT("Bad data type for InitiatorTargetId\n");
2687 continue;
2688 }
2689
2690 ConfigInfo->InitiatorBusId[0] = *((PUCHAR)
2691 (Buffer + KeyValueInformation->DataOffset));
2692
2693 /* Check / reset if needed */
2694 if (ConfigInfo->InitiatorBusId[0] > ConfigInfo->MaximumNumberOfTargets - 1)
2695 ConfigInfo->InitiatorBusId[0] = (CCHAR)SP_UNINITIALIZED_VALUE;
2696
2697 DPRINT("InitiatorTargetId = %d\n", ConfigInfo->InitiatorBusId[0]);
2698 }
2699
2700 /* Get ScsiDebug */
2701 if (_wcsnicmp(KeyValueInformation->Name, L"ScsiDebug",
2702 KeyValueInformation->NameLength/2) == 0)
2703 {
2704 DPRINT("ScsiDebug key not supported\n");
2705 }
2706
2707 /* Check for a breakpoint */
2708 if (_wcsnicmp(KeyValueInformation->Name, L"BreakPointOnEntry",
2709 KeyValueInformation->NameLength/2) == 0)
2710 {
2711 DPRINT1("Breakpoint on entry requested!\n");
2712 DbgBreakPoint();
2713 }
2714
2715 /* Get DisableSynchronousTransfers */
2716 if (_wcsnicmp(KeyValueInformation->Name, L"DisableSynchronousTransfers",
2717 KeyValueInformation->NameLength/2) == 0)
2718 {
2719 DeviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
2720 DPRINT("Synch transfers disabled\n");
2721 }
2722
2723 /* Get DisableDisconnects */
2724 if (_wcsnicmp(KeyValueInformation->Name, L"DisableDisconnects",
2725 KeyValueInformation->NameLength/2) == 0)
2726 {
2727 DeviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT;
2728 DPRINT("Disconnects disabled\n");
2729 }
2730
2731 /* Get DisableTaggedQueuing */
2732 if (_wcsnicmp(KeyValueInformation->Name, L"DisableTaggedQueuing",
2733 KeyValueInformation->NameLength/2) == 0)
2734 {
2735 InternalConfigInfo->DisableTaggedQueueing = TRUE;
2736 DPRINT("Tagged queueing disabled\n");
2737 }
2738
2739 /* Get DisableMultipleRequests */
2740 if (_wcsnicmp(KeyValueInformation->Name, L"DisableMultipleRequests",
2741 KeyValueInformation->NameLength/2) == 0)
2742 {
2743 InternalConfigInfo->DisableMultipleLun = TRUE;
2744 DPRINT("Multiple requests disabled\n");
2745 }
2746
2747 /* Get DriverParameters */
2748 if (_wcsnicmp(KeyValueInformation->Name, L"DriverParameters",
2749 KeyValueInformation->NameLength/2) == 0)
2750 {
2751 /* Skip if nothing */
2752 if (KeyValueInformation->DataLength == 0)
2753 continue;
2754
2755 /* If there was something previously allocated - free it */
2756 if (InternalConfigInfo->Parameter != NULL)
2757 ExFreePool(InternalConfigInfo->Parameter);
2758
2759 /* Allocate it */
2760 InternalConfigInfo->Parameter = ExAllocatePoolWithTag(NonPagedPool,
2761 KeyValueInformation->DataLength, TAG_SCSIPORT);
2762
2763 if (InternalConfigInfo->Parameter != NULL)
2764 {
2765 if (KeyValueInformation->Type != REG_SZ)
2766 {
2767 /* Just copy */
2768 RtlCopyMemory(
2769 InternalConfigInfo->Parameter,
2770 (PCCHAR)KeyValueInformation + KeyValueInformation->DataOffset,
2771 KeyValueInformation->DataLength);
2772 }
2773 else
2774 {
2775 /* If it's a unicode string, convert it to ansi */
2776 UnicodeString.Length = (USHORT)KeyValueInformation->DataLength;
2777 UnicodeString.MaximumLength = (USHORT)KeyValueInformation->DataLength;
2778 UnicodeString.Buffer =
2779 (PWSTR)((PCCHAR)KeyValueInformation + KeyValueInformation->DataOffset);
2780
2781 AnsiString.Length = 0;
2782 AnsiString.MaximumLength = (USHORT)KeyValueInformation->DataLength;
2783 AnsiString.Buffer = (PCHAR)InternalConfigInfo->Parameter;
2784
2785 Status = RtlUnicodeStringToAnsiString(&AnsiString,
2786 &UnicodeString,
2787 FALSE);
2788
2789 /* In case of error, free the allocated space */
2790 if (!NT_SUCCESS(Status))
2791 {
2792 ExFreePool(InternalConfigInfo->Parameter);
2793 InternalConfigInfo->Parameter = NULL;
2794 }
2795
2796 }
2797 }
2798
2799 DPRINT("Found driver parameter\n");
2800 }
2801
2802 /* Get MaximumSGList */
2803 if (_wcsnicmp(KeyValueInformation->Name, L"MaximumSGList",
2804 KeyValueInformation->NameLength/2) == 0)
2805 {
2806 if (KeyValueInformation->Type != REG_DWORD)
2807 {
2808 DPRINT("Bad data type for MaximumSGList\n");
2809 continue;
2810 }
2811
2812 ConfigInfo->NumberOfPhysicalBreaks = *((PUCHAR)(Buffer + KeyValueInformation->DataOffset));
2813
2814 /* Check / fix */
2815 if (ConfigInfo->NumberOfPhysicalBreaks > SCSI_MAXIMUM_PHYSICAL_BREAKS)
2816 {
2817 ConfigInfo->NumberOfPhysicalBreaks = SCSI_MAXIMUM_PHYSICAL_BREAKS;
2818 }
2819 else if (ConfigInfo->NumberOfPhysicalBreaks < SCSI_MINIMUM_PHYSICAL_BREAKS)
2820 {
2821 ConfigInfo->NumberOfPhysicalBreaks = SCSI_MINIMUM_PHYSICAL_BREAKS;
2822 }
2823
2824 DPRINT("MaximumSGList = %d\n", ConfigInfo->NumberOfPhysicalBreaks);
2825 }
2826
2827 /* Get NumberOfRequests */
2828 if (_wcsnicmp(KeyValueInformation->Name, L"NumberOfRequests",
2829 KeyValueInformation->NameLength/2) == 0)
2830 {
2831 if (KeyValueInformation->Type != REG_DWORD)
2832 {
2833 DPRINT("NumberOfRequests has wrong data type\n");
2834 continue;
2835 }
2836
2837 DeviceExtension->RequestsNumber = *((PUCHAR)(Buffer + KeyValueInformation->DataOffset));
2838
2839 /* Check / fix */
2840 if (DeviceExtension->RequestsNumber < 16)
2841 {
2842 DeviceExtension->RequestsNumber = 16;
2843 }
2844 else if (DeviceExtension->RequestsNumber > 512)
2845 {
2846 DeviceExtension->RequestsNumber = 512;
2847 }
2848
2849 DPRINT("Number Of Requests = %d\n", DeviceExtension->RequestsNumber);
2850 }
2851
2852 /* Get resource list */
2853 if (_wcsnicmp(KeyValueInformation->Name, L"ResourceList",
2854 KeyValueInformation->NameLength/2) == 0 ||
2855 _wcsnicmp(KeyValueInformation->Name, L"Configuration Data",
2856 KeyValueInformation->NameLength/2) == 0 )
2857 {
2858 if (KeyValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR ||
2859 KeyValueInformation->DataLength < sizeof(REG_FULL_RESOURCE_DESCRIPTOR))
2860 {
2861 DPRINT("Bad data type for ResourceList\n");
2862 continue;
2863 }
2864 else
2865 {
2866 DPRINT("Found ResourceList\n");
2867 }
2868
2869 FullResource = (PCM_FULL_RESOURCE_DESCRIPTOR)(Buffer + KeyValueInformation->DataOffset);
2870
2871 /* Copy some info from it */
2872 InternalConfigInfo->BusNumber = FullResource->BusNumber;
2873 ConfigInfo->SystemIoBusNumber = FullResource->BusNumber;
2874
2875 /* Loop through it */
2876 for (Count = 0; Count < FullResource->PartialResourceList.Count; Count++)
2877 {
2878 /* Get partial descriptor */
2879 PartialDescriptor =
2880 &FullResource->PartialResourceList.PartialDescriptors[Count];
2881
2882 /* Check datalength */
2883 if ((ULONG)((PCHAR)(PartialDescriptor + 1) -
2884 (PCHAR)FullResource) > KeyValueInformation->DataLength)
2885 {
2886 DPRINT("Resource data is of incorrect size\n");
2887 break;
2888 }
2889
2890 switch (PartialDescriptor->Type)
2891 {
2892 case CmResourceTypePort:
2893 if (RangeCount >= ConfigInfo->NumberOfAccessRanges)
2894 {
2895 DPRINT("Too many access ranges\n");
2896 continue;
2897 }
2898
2899 InternalConfigInfo->AccessRanges[RangeCount].RangeInMemory = FALSE;
2900 InternalConfigInfo->AccessRanges[RangeCount].RangeStart = PartialDescriptor->u.Port.Start;
2901 InternalConfigInfo->AccessRanges[RangeCount].RangeLength = PartialDescriptor->u.Port.Length;
2902 RangeCount++;
2903
2904 break;
2905
2906 case CmResourceTypeMemory:
2907 if (RangeCount >= ConfigInfo->NumberOfAccessRanges)
2908 {
2909 DPRINT("Too many access ranges\n");
2910 continue;
2911 }
2912
2913 InternalConfigInfo->AccessRanges[RangeCount].RangeInMemory = TRUE;
2914 InternalConfigInfo->AccessRanges[RangeCount].RangeStart = PartialDescriptor->u.Memory.Start;
2915 InternalConfigInfo->AccessRanges[RangeCount].RangeLength = PartialDescriptor->u.Memory.Length;
2916 RangeCount++;
2917
2918 break;
2919
2920 case CmResourceTypeInterrupt:
2921
2922 if (Interrupt == 0)
2923 {
2924 ConfigInfo->BusInterruptLevel =
2925 PartialDescriptor->u.Interrupt.Level;
2926
2927 ConfigInfo->BusInterruptVector =
2928 PartialDescriptor->u.Interrupt.Vector;
2929
2930 ConfigInfo->InterruptMode = (PartialDescriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive;
2931 }
2932 else if (Interrupt == 1)
2933 {
2934 ConfigInfo->BusInterruptLevel2 =
2935 PartialDescriptor->u.Interrupt.Level;
2936
2937 ConfigInfo->BusInterruptVector2 =
2938 PartialDescriptor->u.Interrupt.Vector;
2939
2940 ConfigInfo->InterruptMode2 = (PartialDescriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive;
2941 }
2942
2943 Interrupt++;
2944 break;
2945
2946 case CmResourceTypeDma:
2947
2948 if (Dma == 0)
2949 {
2950 ConfigInfo->DmaChannel = PartialDescriptor->u.Dma.Channel;
2951 ConfigInfo->DmaPort = PartialDescriptor->u.Dma.Port;
2952
2953 if (PartialDescriptor->Flags & CM_RESOURCE_DMA_8)
2954 ConfigInfo->DmaWidth = Width8Bits;
2955 else if ((PartialDescriptor->Flags & CM_RESOURCE_DMA_16) ||
2956 (PartialDescriptor->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
2957 ConfigInfo->DmaWidth = Width16Bits;
2958 else if (PartialDescriptor->Flags & CM_RESOURCE_DMA_32)
2959 ConfigInfo->DmaWidth = Width32Bits;
2960 }
2961 else if (Dma == 1)
2962 {
2963 ConfigInfo->DmaChannel2 = PartialDescriptor->u.Dma.Channel;
2964 ConfigInfo->DmaPort2 = PartialDescriptor->u.Dma.Port;
2965
2966 if (PartialDescriptor->Flags & CM_RESOURCE_DMA_8)
2967 ConfigInfo->DmaWidth2 = Width8Bits;
2968 else if ((PartialDescriptor->Flags & CM_RESOURCE_DMA_16) ||
2969 (PartialDescriptor->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
2970 ConfigInfo->DmaWidth2 = Width16Bits;
2971 else if (PartialDescriptor->Flags & CM_RESOURCE_DMA_32)
2972 ConfigInfo->DmaWidth2 = Width32Bits;
2973 }
2974
2975 Dma++;
2976 break;
2977
2978 case CmResourceTypeDeviceSpecific:
2979 if (PartialDescriptor->u.DeviceSpecificData.DataSize <
2980 sizeof(CM_SCSI_DEVICE_DATA) ||
2981 (PCHAR) (PartialDescriptor + 1) - (PCHAR)FullResource +
2982 PartialDescriptor->u.DeviceSpecificData.DataSize >
2983 KeyValueInformation->DataLength)
2984 {
2985 DPRINT("Resource data length is incorrect");
2986 break;
2987 }
2988
2989 /* Set only one field from it */
2990 ScsiDeviceData = (PCM_SCSI_DEVICE_DATA) (PartialDescriptor+1);
2991 ConfigInfo->InitiatorBusId[0] = ScsiDeviceData->HostIdentifier;
2992 break;
2993 }
2994 }
2995 }
2996 }
2997 }
2998
2999 NTSTATUS
3000 NTAPI
SpQueryDeviceCallout(IN PVOID Context,IN PUNICODE_STRING PathName,IN INTERFACE_TYPE BusType,IN ULONG BusNumber,IN PKEY_VALUE_FULL_INFORMATION * BusInformation,IN CONFIGURATION_TYPE ControllerType,IN ULONG ControllerNumber,IN PKEY_VALUE_FULL_INFORMATION * ControllerInformation,IN CONFIGURATION_TYPE PeripheralType,IN ULONG PeripheralNumber,IN PKEY_VALUE_FULL_INFORMATION * PeripheralInformation)3001 SpQueryDeviceCallout(IN PVOID Context,
3002 IN PUNICODE_STRING PathName,
3003 IN INTERFACE_TYPE BusType,
3004 IN ULONG BusNumber,
3005 IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
3006 IN CONFIGURATION_TYPE ControllerType,
3007 IN ULONG ControllerNumber,
3008 IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
3009 IN CONFIGURATION_TYPE PeripheralType,
3010 IN ULONG PeripheralNumber,
3011 IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation)
3012 {
3013 PBOOLEAN Found = (PBOOLEAN)Context;
3014 /* We just set our Found variable to TRUE */
3015
3016 *Found = TRUE;
3017 return STATUS_SUCCESS;
3018 }
3019
3020 IO_ALLOCATION_ACTION
3021 NTAPI
ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID MapRegisterBase,IN PVOID Context)3022 ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject,
3023 IN PIRP Irp,
3024 IN PVOID MapRegisterBase,
3025 IN PVOID Context)
3026 {
3027 KIRQL Irql;
3028 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
3029
3030 /* Guard access with the spinlock */
3031 KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
3032
3033 /* Save MapRegisterBase we've got here */
3034 DeviceExtension->MapRegisterBase = MapRegisterBase;
3035
3036 /* Start pending request */
3037 KeSynchronizeExecution(DeviceExtension->Interrupt[0],
3038 ScsiPortStartPacket, DeviceObject);
3039
3040 /* Release spinlock we took */
3041 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
3042
3043 return KeepObject;
3044 }
3045
3046 #undef ScsiPortConvertPhysicalAddressToUlong
3047 /*
3048 * @implemented
3049 */
3050 ULONG NTAPI
ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address)3051 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address)
3052 {
3053 DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
3054 return(Address.u.LowPart);
3055 }
3056