[SCSIPORT]: Fixes + documentation:
[reactos.git] / reactos / drivers / storage / scsiport / scsiport.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2001, 2002 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS Storage Stack
22 * FILE: drivers/storage/scsiport/scsiport.c
23 * PURPOSE: SCSI port driver
24 * PROGRAMMER: Eric Kohl
25 * Aleksey Bragin (aleksey reactos org)
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #include "precomp.h"
31
32 #include <ntddk.h>
33 #include <stdio.h>
34 #include <scsi.h>
35 #include <ntddscsi.h>
36 #include <ntdddisk.h>
37 #include <mountdev.h>
38
39 #define NDEBUG
40 #include <debug.h>
41
42 #include "scsiport_int.h"
43
44 ULONG InternalDebugLevel = 0x00;
45
46 #undef ScsiPortMoveMemory
47
48 /* GLOBALS *******************************************************************/
49
50 static BOOLEAN
51 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject,
52 IN PDEVICE_OBJECT DeviceObject,
53 IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
54 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,
55 IN PUNICODE_STRING RegistryPath,
56 IN ULONG BusNumber,
57 IN OUT PPCI_SLOT_NUMBER NextSlotNumber);
58
59 static NTSTATUS NTAPI
60 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
61 IN PIRP Irp);
62
63 static DRIVER_DISPATCH ScsiPortDispatchScsi;
64 static NTSTATUS NTAPI
65 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
66 IN PIRP Irp);
67
68 static NTSTATUS NTAPI
69 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
70 IN PIRP Irp);
71
72 static DRIVER_STARTIO ScsiPortStartIo;
73 static VOID NTAPI
74 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
75 IN PIRP Irp);
76
77 static BOOLEAN NTAPI
78 ScsiPortStartPacket(IN OUT PVOID Context);
79
80 IO_ALLOCATION_ACTION
81 NTAPI
82 SpiAdapterControl(PDEVICE_OBJECT DeviceObject, PIRP Irp,
83 PVOID MapRegisterBase, PVOID Context);
84
85 static PSCSI_PORT_LUN_EXTENSION
86 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
87
88 static PSCSI_PORT_LUN_EXTENSION
89 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
90 IN UCHAR PathId,
91 IN UCHAR TargetId,
92 IN UCHAR Lun);
93
94 static PSCSI_REQUEST_BLOCK_INFO
95 SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
96 PSCSI_PORT_LUN_EXTENSION LunExtension,
97 PSCSI_REQUEST_BLOCK Srb);
98
99 static NTSTATUS
100 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject,
101 IN PSCSI_LUN_INFO LunInfo);
102
103 static VOID
104 SpiScanAdapter (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
105
106 static NTSTATUS
107 SpiGetInquiryData (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
108 IN PIRP Irp);
109
110 static PSCSI_REQUEST_BLOCK_INFO
111 SpiGetSrbData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
112 IN UCHAR PathId,
113 IN UCHAR TargetId,
114 IN UCHAR Lun,
115 IN UCHAR QueueTag);
116
117 static BOOLEAN NTAPI
118 ScsiPortIsr(IN PKINTERRUPT Interrupt,
119 IN PVOID ServiceContext);
120
121 static VOID NTAPI
122 ScsiPortDpcForIsr(IN PKDPC Dpc,
123 IN PDEVICE_OBJECT DpcDeviceObject,
124 IN PIRP DpcIrp,
125 IN PVOID DpcContext);
126
127 static VOID NTAPI
128 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
129 PVOID Context);
130
131 IO_ALLOCATION_ACTION
132 NTAPI
133 ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject,
134 IN PIRP Irp,
135 IN PVOID MapRegisterBase,
136 IN PVOID Context);
137
138 static NTSTATUS
139 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
140 PUNICODE_STRING RegistryPath);
141
142 static NTSTATUS
143 SpiStatusSrbToNt(UCHAR SrbStatus);
144
145 static VOID
146 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
147 IN PSCSI_REQUEST_BLOCK Srb);
148
149 static IO_COMPLETION_ROUTINE SpiCompletionRoutine;
150 NTSTATUS NTAPI
151 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject,
152 PIRP Irp,
153 PVOID Context);
154
155 static VOID
156 NTAPI
157 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
158 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo,
159 OUT PBOOLEAN NeedToCallStartIo);
160
161 VOID NTAPI
162 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
163 IN PSCSI_PORT_LUN_EXTENSION LunExtension);
164
165 VOID NTAPI
166 SpiMiniportTimerDpc(IN struct _KDPC *Dpc,
167 IN PVOID DeviceObject,
168 IN PVOID SystemArgument1,
169 IN PVOID SystemArgument2);
170
171 static NTSTATUS
172 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
173 PHW_INITIALIZATION_DATA HwInitData,
174 PCONFIGURATION_INFO InternalConfigInfo,
175 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
176 BOOLEAN FirstCall);
177
178 NTSTATUS NTAPI
179 SpQueryDeviceCallout(IN PVOID Context,
180 IN PUNICODE_STRING PathName,
181 IN INTERFACE_TYPE BusType,
182 IN ULONG BusNumber,
183 IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
184 IN CONFIGURATION_TYPE ControllerType,
185 IN ULONG ControllerNumber,
186 IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
187 IN CONFIGURATION_TYPE PeripheralType,
188 IN ULONG PeripheralNumber,
189 IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation);
190
191 static VOID
192 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
193 IN HANDLE Key,
194 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
195 IN PCONFIGURATION_INFO InternalConfigInfo,
196 IN PUCHAR Buffer);
197
198 static VOID
199 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData,
200 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor,
201 IN PPORT_CONFIGURATION_INFORMATION PortConfig);
202
203 static PCM_RESOURCE_LIST
204 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
205 PPORT_CONFIGURATION_INFORMATION PortConfig);
206
207 static VOID
208 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
209
210 static NTSTATUS
211 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
212 PIRP Irp);
213
214 static NTSTATUS
215 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, ULONG NonCachedSize);
216
217 NTHALAPI ULONG NTAPI HalGetBusData(BUS_DATA_TYPE, ULONG, ULONG, PVOID, ULONG);
218 NTHALAPI ULONG NTAPI HalGetInterruptVector(INTERFACE_TYPE, ULONG, ULONG, ULONG, PKIRQL, PKAFFINITY);
219 NTHALAPI NTSTATUS NTAPI HalAssignSlotResources(PUNICODE_STRING, PUNICODE_STRING, PDRIVER_OBJECT, PDEVICE_OBJECT, INTERFACE_TYPE, ULONG, ULONG, PCM_RESOURCE_LIST *);
220
221 /* FUNCTIONS *****************************************************************/
222
223 /**********************************************************************
224 * NAME EXPORTED
225 * DriverEntry
226 *
227 * DESCRIPTION
228 * This function initializes the driver.
229 *
230 * RUN LEVEL
231 * PASSIVE_LEVEL
232 *
233 * ARGUMENTS
234 * DriverObject
235 * System allocated Driver Object for this driver.
236 *
237 * RegistryPath
238 * Name of registry driver service key.
239 *
240 * RETURN VALUE
241 * Status.
242 */
243
244 NTSTATUS NTAPI
245 DriverEntry(IN PDRIVER_OBJECT DriverObject,
246 IN PUNICODE_STRING RegistryPath)
247 {
248 DPRINT("ScsiPort Driver %s\n", VERSION);
249 return(STATUS_SUCCESS);
250 }
251
252
253 /**********************************************************************
254 * NAME EXPORTED
255 * ScsiDebugPrint
256 *
257 * DESCRIPTION
258 * Prints debugging messages.
259 *
260 * RUN LEVEL
261 * PASSIVE_LEVEL
262 *
263 * ARGUMENTS
264 * DebugPrintLevel
265 * Debug level of the given message.
266 *
267 * DebugMessage
268 * Pointer to printf()-compatible format string.
269 *
270 * ...
271 Additional output data (see printf()).
272 *
273 * RETURN VALUE
274 * None.
275 *
276 * @implemented
277 */
278
279 VOID
280 ScsiDebugPrint(IN ULONG DebugPrintLevel,
281 IN PCHAR DebugMessage,
282 ...)
283 {
284 char Buffer[256];
285 va_list ap;
286
287 if (DebugPrintLevel > InternalDebugLevel)
288 return;
289
290 va_start(ap, DebugMessage);
291 vsprintf(Buffer, DebugMessage, ap);
292 va_end(ap);
293
294 DbgPrint(Buffer);
295 }
296
297 /* An internal helper function for ScsiPortCompleteRequest */
298 VOID
299 NTAPI
300 SpiCompleteRequest(IN PVOID HwDeviceExtension,
301 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo,
302 IN UCHAR SrbStatus)
303 {
304 PSCSI_REQUEST_BLOCK Srb;
305
306 /* Get current SRB */
307 Srb = SrbInfo->Srb;
308
309 /* Return if there is no SRB or it is not active */
310 if (!Srb || !(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE)) return;
311
312 /* Set status */
313 Srb->SrbStatus = SrbStatus;
314
315 /* Set data transfered to 0 */
316 Srb->DataTransferLength = 0;
317
318 /* Notify */
319 ScsiPortNotification(RequestComplete,
320 HwDeviceExtension,
321 Srb);
322 }
323
324 /*
325 * @unimplemented
326 */
327 VOID NTAPI
328 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension,
329 IN UCHAR PathId,
330 IN UCHAR TargetId,
331 IN UCHAR Lun,
332 IN UCHAR SrbStatus)
333 {
334 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
335 PSCSI_PORT_LUN_EXTENSION LunExtension;
336 PSCSI_REQUEST_BLOCK_INFO SrbInfo;
337 PLIST_ENTRY ListEntry;
338 ULONG BusNumber;
339 ULONG Target;
340
341 DPRINT("ScsiPortCompleteRequest() called\n");
342
343 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
344 SCSI_PORT_DEVICE_EXTENSION,
345 MiniPortDeviceExtension);
346
347 /* Go through all buses */
348 for (BusNumber = 0; BusNumber < 8; BusNumber++)
349 {
350 /* Go through all targets */
351 for (Target = 0; Target < DeviceExtension->MaxTargedIds; Target++)
352 {
353 /* Get logical unit list head */
354 LunExtension = DeviceExtension->LunExtensionList[Target % 8];
355
356 /* Go through all logical units */
357 while (LunExtension)
358 {
359 /* Now match what caller asked with what we are at now */
360 if ((PathId == SP_UNTAGGED || PathId == LunExtension->PathId) &&
361 (TargetId == SP_UNTAGGED || TargetId == LunExtension->TargetId) &&
362 (Lun == SP_UNTAGGED || Lun == LunExtension->Lun))
363 {
364 /* Yes, that's what caller asked for. Complete abort requests */
365 if (LunExtension->CompletedAbortRequests)
366 {
367 /* TODO: Save SrbStatus in this request */
368 DPRINT1("Completing abort request without setting SrbStatus!\n");
369
370 /* Issue a notification request */
371 ScsiPortNotification(RequestComplete,
372 HwDeviceExtension,
373 LunExtension->CompletedAbortRequests);
374 }
375
376 /* Complete the request using our helper */
377 SpiCompleteRequest(HwDeviceExtension,
378 &LunExtension->SrbInfo,
379 SrbStatus);
380
381 /* Go through the queue and complete everything there too */
382 ListEntry = LunExtension->SrbInfo.Requests.Flink;
383 while (ListEntry != &LunExtension->SrbInfo.Requests)
384 {
385 /* Get the actual SRB info entry */
386 SrbInfo = CONTAINING_RECORD(ListEntry,
387 SCSI_REQUEST_BLOCK_INFO,
388 Requests);
389
390 /* Complete it */
391 SpiCompleteRequest(HwDeviceExtension,
392 SrbInfo,
393 SrbStatus);
394
395 /* Advance to the next request in queue */
396 ListEntry = SrbInfo->Requests.Flink;
397 }
398 }
399
400 /* Advance to the next one */
401 LunExtension = LunExtension->Next;
402 }
403 }
404 }
405 }
406
407 /*
408 * @unimplemented
409 */
410 VOID NTAPI
411 ScsiPortFlushDma(IN PVOID HwDeviceExtension)
412 {
413 DPRINT("ScsiPortFlushDma()\n");
414 UNIMPLEMENTED;
415 }
416
417
418 /*
419 * @implemented
420 */
421 VOID NTAPI
422 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension,
423 IN PVOID MappedAddress)
424 {
425 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
426 PMAPPED_ADDRESS NextMa, LastMa;
427
428 //DPRINT("ScsiPortFreeDeviceBase() called\n");
429
430 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
431 SCSI_PORT_DEVICE_EXTENSION,
432 MiniPortDeviceExtension);
433
434 /* Initialize our pointers */
435 NextMa = DeviceExtension->MappedAddressList;
436 LastMa = NextMa;
437
438 while (NextMa)
439 {
440 if (NextMa->MappedAddress == MappedAddress)
441 {
442 /* Unmap it first */
443 MmUnmapIoSpace(MappedAddress, NextMa->NumberOfBytes);
444
445 /* Remove it from the list */
446 if (NextMa == DeviceExtension->MappedAddressList)
447 {
448 /* Remove the first entry */
449 DeviceExtension->MappedAddressList = NextMa->NextMappedAddress;
450 }
451 else
452 {
453 LastMa->NextMappedAddress = NextMa->NextMappedAddress;
454 }
455
456 /* Free the resources and quit */
457 ExFreePool(NextMa);
458
459 return;
460 }
461 else
462 {
463 LastMa = NextMa;
464 NextMa = NextMa->NextMappedAddress;
465 }
466 }
467 }
468
469
470 /*
471 * @implemented
472 */
473 ULONG NTAPI
474 ScsiPortGetBusData(IN PVOID DeviceExtension,
475 IN ULONG BusDataType,
476 IN ULONG SystemIoBusNumber,
477 IN ULONG SlotNumber,
478 IN PVOID Buffer,
479 IN ULONG Length)
480 {
481 DPRINT("ScsiPortGetBusData()\n");
482
483 if (Length)
484 {
485 /* If Length is non-zero, just forward the call to
486 HalGetBusData() function */
487 return HalGetBusData(BusDataType,
488 SystemIoBusNumber,
489 SlotNumber,
490 Buffer,
491 Length);
492 }
493
494 /* We have a more complex case here */
495 UNIMPLEMENTED;
496 return 0;
497 }
498
499 /*
500 * @implemented
501 */
502 ULONG NTAPI
503 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension,
504 IN ULONG BusDataType,
505 IN ULONG SystemIoBusNumber,
506 IN ULONG SlotNumber,
507 IN PVOID Buffer,
508 IN ULONG Offset,
509 IN ULONG Length)
510 {
511 DPRINT("ScsiPortSetBusDataByOffset()\n");
512 return HalSetBusDataByOffset(BusDataType,
513 SystemIoBusNumber,
514 SlotNumber,
515 Buffer,
516 Offset,
517 Length);
518 }
519
520 /*
521 * @implemented
522 */
523 PVOID NTAPI
524 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension,
525 IN INTERFACE_TYPE BusType,
526 IN ULONG SystemIoBusNumber,
527 IN SCSI_PHYSICAL_ADDRESS IoAddress,
528 IN ULONG NumberOfBytes,
529 IN BOOLEAN InIoSpace)
530 {
531 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
532 PHYSICAL_ADDRESS TranslatedAddress;
533 PMAPPED_ADDRESS DeviceBase;
534 ULONG AddressSpace;
535 PVOID MappedAddress;
536
537 //DPRINT ("ScsiPortGetDeviceBase() called\n");
538
539 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
540 SCSI_PORT_DEVICE_EXTENSION,
541 MiniPortDeviceExtension);
542
543 AddressSpace = (ULONG)InIoSpace;
544 if (HalTranslateBusAddress(BusType,
545 SystemIoBusNumber,
546 IoAddress,
547 &AddressSpace,
548 &TranslatedAddress) == FALSE)
549 {
550 return NULL;
551 }
552
553 /* i/o space */
554 if (AddressSpace != 0)
555 return((PVOID)(ULONG_PTR)TranslatedAddress.QuadPart);
556
557 MappedAddress = MmMapIoSpace(TranslatedAddress,
558 NumberOfBytes,
559 FALSE);
560
561 DeviceBase = ExAllocatePoolWithTag(NonPagedPool,
562 sizeof(MAPPED_ADDRESS), TAG_SCSIPORT);
563
564 if (DeviceBase == NULL)
565 return MappedAddress;
566
567 DeviceBase->MappedAddress = MappedAddress;
568 DeviceBase->NumberOfBytes = NumberOfBytes;
569 DeviceBase->IoAddress = IoAddress;
570 DeviceBase->BusNumber = SystemIoBusNumber;
571
572 /* Link it to the Device Extension list */
573 DeviceBase->NextMappedAddress = DeviceExtension->MappedAddressList;
574 DeviceExtension->MappedAddressList = DeviceBase;
575
576 return MappedAddress;
577 }
578
579 /*
580 * @unimplemented
581 */
582 PVOID NTAPI
583 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension,
584 IN UCHAR PathId,
585 IN UCHAR TargetId,
586 IN UCHAR Lun)
587 {
588 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
589 PSCSI_PORT_LUN_EXTENSION LunExtension;
590
591 DPRINT("ScsiPortGetLogicalUnit() called\n");
592
593 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
594 SCSI_PORT_DEVICE_EXTENSION,
595 MiniPortDeviceExtension);
596
597 /* Check the extension size */
598 if (!DeviceExtension->LunExtensionSize)
599 {
600 /* They didn't want one */
601 return NULL;
602 }
603
604 LunExtension = SpiGetLunExtension(DeviceExtension,
605 PathId,
606 TargetId,
607 Lun);
608 /* Check that the logical unit exists */
609 if (!LunExtension)
610 {
611 /* Nope, return NULL */
612 return NULL;
613 }
614
615 /* Return the logical unit miniport extension */
616 return (LunExtension + 1);
617 }
618
619
620 /*
621 * @implemented
622 */
623 SCSI_PHYSICAL_ADDRESS NTAPI
624 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension,
625 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
626 IN PVOID VirtualAddress,
627 OUT ULONG *Length)
628 {
629 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
630 SCSI_PHYSICAL_ADDRESS PhysicalAddress;
631 SIZE_T BufferLength = 0;
632 ULONG_PTR Offset;
633 PSCSI_SG_ADDRESS SGList;
634 PSCSI_REQUEST_BLOCK_INFO SrbInfo;
635
636 DPRINT("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
637 HwDeviceExtension, Srb, VirtualAddress, Length);
638
639 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
640 SCSI_PORT_DEVICE_EXTENSION,
641 MiniPortDeviceExtension);
642
643 if (Srb == NULL || Srb->SenseInfoBuffer == VirtualAddress)
644 {
645 /* Simply look it up in the allocated common buffer */
646 Offset = (PUCHAR)VirtualAddress - (PUCHAR)DeviceExtension->SrbExtensionBuffer;
647
648 BufferLength = DeviceExtension->CommonBufferLength - Offset;
649 PhysicalAddress.QuadPart = DeviceExtension->PhysicalAddress.QuadPart + Offset;
650 }
651 else if (DeviceExtension->MapRegisters)
652 {
653 /* Scatter-gather list must be used */
654 SrbInfo = SpiGetSrbData(DeviceExtension,
655 Srb->PathId,
656 Srb->TargetId,
657 Srb->Lun,
658 Srb->QueueTag);
659
660 SGList = SrbInfo->ScatterGather;
661
662 /* Find needed item in the SG list */
663 Offset = (PCHAR)VirtualAddress - (PCHAR)Srb->DataBuffer;
664 while (Offset >= SGList->Length)
665 {
666 Offset -= SGList->Length;
667 SGList++;
668 }
669
670 /* We're done, store length and physical address */
671 BufferLength = SGList->Length - Offset;
672 PhysicalAddress.QuadPart = SGList->PhysicalAddress.QuadPart + Offset;
673 }
674 else
675 {
676 /* Nothing */
677 PhysicalAddress.QuadPart = (LONGLONG)(SP_UNINITIALIZED_VALUE);
678 }
679
680 *Length = (ULONG)BufferLength;
681 return PhysicalAddress;
682 }
683
684
685 /*
686 * @unimplemented
687 */
688 PSCSI_REQUEST_BLOCK NTAPI
689 ScsiPortGetSrb(IN PVOID DeviceExtension,
690 IN UCHAR PathId,
691 IN UCHAR TargetId,
692 IN UCHAR Lun,
693 IN LONG QueueTag)
694 {
695 DPRINT1("ScsiPortGetSrb() unimplemented\n");
696 UNIMPLEMENTED;
697 return NULL;
698 }
699
700
701 /*
702 * @implemented
703 */
704 PVOID NTAPI
705 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension,
706 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
707 IN ULONG NumberOfBytes)
708 {
709 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
710 DEVICE_DESCRIPTION DeviceDescription;
711 ULONG MapRegistersCount;
712 NTSTATUS Status;
713
714 DPRINT("ScsiPortGetUncachedExtension(%p %p %lu)\n",
715 HwDeviceExtension, ConfigInfo, NumberOfBytes);
716
717 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
718 SCSI_PORT_DEVICE_EXTENSION,
719 MiniPortDeviceExtension);
720
721 /* Check for allocated common DMA buffer */
722 if (DeviceExtension->SrbExtensionBuffer != NULL)
723 {
724 DPRINT1("The HBA has already got a common DMA buffer!\n");
725 return NULL;
726 }
727
728 /* Check for DMA adapter object */
729 if (DeviceExtension->AdapterObject == NULL)
730 {
731 /* Initialize DMA adapter description */
732 RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
733
734 DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
735 DeviceDescription.Master = ConfigInfo->Master;
736 DeviceDescription.ScatterGather = ConfigInfo->ScatterGather;
737 DeviceDescription.DemandMode = ConfigInfo->DemandMode;
738 DeviceDescription.Dma32BitAddresses = ConfigInfo->Dma32BitAddresses;
739 DeviceDescription.BusNumber = ConfigInfo->SystemIoBusNumber;
740 DeviceDescription.DmaChannel = ConfigInfo->DmaChannel;
741 DeviceDescription.InterfaceType = ConfigInfo->AdapterInterfaceType;
742 DeviceDescription.DmaWidth = ConfigInfo->DmaWidth;
743 DeviceDescription.DmaSpeed = ConfigInfo->DmaSpeed;
744 DeviceDescription.MaximumLength = ConfigInfo->MaximumTransferLength;
745 DeviceDescription.DmaPort = ConfigInfo->DmaPort;
746
747 /* Get a DMA adapter object */
748 DeviceExtension->AdapterObject =
749 HalGetAdapter(&DeviceDescription, &MapRegistersCount);
750
751 /* Fail in case of error */
752 if (DeviceExtension->AdapterObject == NULL)
753 {
754 DPRINT1("HalGetAdapter() failed\n");
755 return NULL;
756 }
757
758 /* Set number of physical breaks */
759 if (ConfigInfo->NumberOfPhysicalBreaks != 0 &&
760 MapRegistersCount > ConfigInfo->NumberOfPhysicalBreaks)
761 {
762 DeviceExtension->PortCapabilities.MaximumPhysicalPages =
763 ConfigInfo->NumberOfPhysicalBreaks;
764 }
765 else
766 {
767 DeviceExtension->PortCapabilities.MaximumPhysicalPages = MapRegistersCount;
768 }
769 }
770
771 /* Update auto request sense feature */
772 DeviceExtension->SupportsAutoSense = ConfigInfo->AutoRequestSense;
773
774 /* Update Srb extension size */
775 if (DeviceExtension->SrbExtensionSize != ConfigInfo->SrbExtensionSize)
776 DeviceExtension->SrbExtensionSize = ConfigInfo->SrbExtensionSize;
777
778 /* Update Srb extension alloc flag */
779 if (ConfigInfo->AutoRequestSense || DeviceExtension->SrbExtensionSize)
780 DeviceExtension->NeedSrbExtensionAlloc = TRUE;
781
782 /* Allocate a common DMA buffer */
783 Status = SpiAllocateCommonBuffer(DeviceExtension, NumberOfBytes);
784
785 if (!NT_SUCCESS(Status))
786 {
787 DPRINT1("SpiAllocateCommonBuffer() failed with Status = 0x%08X!\n", Status);
788 return NULL;
789 }
790
791 return DeviceExtension->NonCachedExtension;
792 }
793
794 static NTSTATUS
795 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, ULONG NonCachedSize)
796 {
797 PVOID *SrbExtension, CommonBuffer;
798 ULONG CommonBufferLength, BufSize;
799
800 /* If size is 0, set it to 16 */
801 if (!DeviceExtension->SrbExtensionSize)
802 DeviceExtension->SrbExtensionSize = 16;
803
804 /* Calculate size */
805 BufSize = DeviceExtension->SrbExtensionSize;
806
807 /* Add autosense data size if needed */
808 if (DeviceExtension->SupportsAutoSense)
809 BufSize += sizeof(SENSE_DATA);
810
811
812 /* Round it */
813 BufSize = (BufSize + sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1);
814
815 /* Sum up into the total common buffer length, and round it to page size */
816 CommonBufferLength =
817 ROUND_TO_PAGES(NonCachedSize + BufSize * DeviceExtension->RequestsNumber);
818
819 /* Allocate it */
820 if (!DeviceExtension->AdapterObject)
821 {
822 /* From nonpaged pool if there is no DMA */
823 CommonBuffer = ExAllocatePoolWithTag(NonPagedPool, CommonBufferLength, TAG_SCSIPORT);
824 }
825 else
826 {
827 /* Perform a full request since we have a DMA adapter*/
828 CommonBuffer = HalAllocateCommonBuffer(DeviceExtension->AdapterObject,
829 CommonBufferLength,
830 &DeviceExtension->PhysicalAddress,
831 FALSE );
832 }
833
834 /* Fail in case of error */
835 if (!CommonBuffer)
836 return STATUS_INSUFFICIENT_RESOURCES;
837
838 /* Zero it */
839 RtlZeroMemory(CommonBuffer, CommonBufferLength);
840
841 /* Store its size in Device Extension */
842 DeviceExtension->CommonBufferLength = CommonBufferLength;
843
844 /* SrbExtension buffer is located at the beginning of the buffer */
845 DeviceExtension->SrbExtensionBuffer = CommonBuffer;
846
847 /* Non-cached extension buffer is located at the end of
848 the common buffer */
849 if (NonCachedSize)
850 {
851 CommonBufferLength -= NonCachedSize;
852 DeviceExtension->NonCachedExtension = (PUCHAR)CommonBuffer + CommonBufferLength;
853 }
854 else
855 {
856 DeviceExtension->NonCachedExtension = NULL;
857 }
858
859 if (DeviceExtension->NeedSrbExtensionAlloc)
860 {
861 /* Look up how many SRB data structures we need */
862 DeviceExtension->SrbDataCount = CommonBufferLength / BufSize;
863
864 /* Initialize the free SRB extensions list */
865 SrbExtension = (PVOID *)CommonBuffer;
866 DeviceExtension->FreeSrbExtensions = SrbExtension;
867
868 /* Fill the remaining pointers (if we have more than 1 SRB) */
869 while (CommonBufferLength >= 2 * BufSize)
870 {
871 *SrbExtension = (PVOID*)((PCHAR)SrbExtension + BufSize);
872 SrbExtension = *SrbExtension;
873
874 CommonBufferLength -= BufSize;
875 }
876 }
877
878 return STATUS_SUCCESS;
879 }
880
881
882
883 /*
884 * @implemented
885 */
886 PVOID NTAPI
887 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension,
888 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress)
889 {
890 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
891 ULONG Offset;
892
893 DPRINT("ScsiPortGetVirtualAddress(%p %I64x)\n",
894 HwDeviceExtension, PhysicalAddress.QuadPart);
895
896 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
897 SCSI_PORT_DEVICE_EXTENSION,
898 MiniPortDeviceExtension);
899
900 if (DeviceExtension->PhysicalAddress.QuadPart > PhysicalAddress.QuadPart)
901 return NULL;
902
903 Offset = (ULONG)(PhysicalAddress.QuadPart - DeviceExtension->PhysicalAddress.QuadPart);
904
905 if (Offset >= DeviceExtension->CommonBufferLength)
906 return NULL;
907
908 return (PVOID)((ULONG_PTR)DeviceExtension->SrbExtensionBuffer + Offset);
909 }
910
911 static VOID
912 SpiInitOpenKeys(PCONFIGURATION_INFO ConfigInfo, PUNICODE_STRING RegistryPath)
913 {
914 OBJECT_ATTRIBUTES ObjectAttributes;
915 UNICODE_STRING KeyName;
916 NTSTATUS Status;
917
918 /* Open the service key */
919 InitializeObjectAttributes(&ObjectAttributes,
920 RegistryPath,
921 OBJ_CASE_INSENSITIVE,
922 NULL,
923 NULL);
924
925 Status = ZwOpenKey(&ConfigInfo->ServiceKey,
926 KEY_READ,
927 &ObjectAttributes);
928
929 if (!NT_SUCCESS(Status))
930 {
931 DPRINT("Unable to open driver's registry key %wZ, status 0x%08x\n", RegistryPath, Status);
932 ConfigInfo->ServiceKey = NULL;
933 }
934
935 /* If we could open driver's service key, then proceed to the Parameters key */
936 if (ConfigInfo->ServiceKey != NULL)
937 {
938 RtlInitUnicodeString(&KeyName, L"Parameters");
939 InitializeObjectAttributes(&ObjectAttributes,
940 &KeyName,
941 OBJ_CASE_INSENSITIVE,
942 ConfigInfo->ServiceKey,
943 (PSECURITY_DESCRIPTOR) NULL);
944
945 /* Try to open it */
946 Status = ZwOpenKey(&ConfigInfo->DeviceKey,
947 KEY_READ,
948 &ObjectAttributes);
949
950 if (NT_SUCCESS(Status))
951 {
952 /* Yes, Parameters key exist, and it must be used instead of
953 the Service key */
954 ZwClose(ConfigInfo->ServiceKey);
955 ConfigInfo->ServiceKey = ConfigInfo->DeviceKey;
956 ConfigInfo->DeviceKey = NULL;
957 }
958 }
959
960 if (ConfigInfo->ServiceKey != NULL)
961 {
962 /* Open the Device key */
963 RtlInitUnicodeString(&KeyName, L"Device");
964 InitializeObjectAttributes(&ObjectAttributes,
965 &KeyName,
966 OBJ_CASE_INSENSITIVE,
967 ConfigInfo->ServiceKey,
968 NULL);
969
970 /* We don't check for failure here - not needed */
971 ZwOpenKey(&ConfigInfo->DeviceKey,
972 KEY_READ,
973 &ObjectAttributes);
974 }
975 }
976
977
978 /**********************************************************************
979 * NAME EXPORTED
980 * ScsiPortInitialize
981 *
982 * DESCRIPTION
983 * Initializes SCSI port driver specific data.
984 *
985 * RUN LEVEL
986 * PASSIVE_LEVEL
987 *
988 * ARGUMENTS
989 * Argument1
990 * Pointer to the miniport driver's driver object.
991 *
992 * Argument2
993 * Pointer to the miniport driver's registry path.
994 *
995 * HwInitializationData
996 * Pointer to port driver specific configuration data.
997 *
998 * HwContext
999 Miniport driver specific context.
1000 *
1001 * RETURN VALUE
1002 * Status.
1003 *
1004 * @implemented
1005 */
1006
1007 ULONG NTAPI
1008 ScsiPortInitialize(IN PVOID Argument1,
1009 IN PVOID Argument2,
1010 IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
1011 IN PVOID HwContext)
1012 {
1013 PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Argument1;
1014 PUNICODE_STRING RegistryPath = (PUNICODE_STRING)Argument2;
1015 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = NULL;
1016 PCONFIGURATION_INFORMATION SystemConfig;
1017 PPORT_CONFIGURATION_INFORMATION PortConfig;
1018 PORT_CONFIGURATION_INFORMATION InitialPortConfig;
1019 CONFIGURATION_INFO ConfigInfo;
1020 ULONG DeviceExtensionSize;
1021 ULONG PortConfigSize;
1022 BOOLEAN Again;
1023 BOOLEAN DeviceFound = FALSE;
1024 BOOLEAN FirstConfigCall = TRUE;
1025 ULONG Result;
1026 NTSTATUS Status;
1027 ULONG MaxBus;
1028 PCI_SLOT_NUMBER SlotNumber;
1029
1030 PDEVICE_OBJECT PortDeviceObject;
1031 WCHAR NameBuffer[80];
1032 UNICODE_STRING DeviceName;
1033 WCHAR DosNameBuffer[80];
1034 UNICODE_STRING DosDeviceName;
1035 PIO_SCSI_CAPABILITIES PortCapabilities;
1036
1037 KIRQL OldIrql;
1038 PCM_RESOURCE_LIST ResourceList;
1039 BOOLEAN Conflict;
1040 SIZE_T BusConfigSize;
1041
1042
1043 DPRINT ("ScsiPortInitialize() called!\n");
1044
1045 /* Check params for validity */
1046 if ((HwInitializationData->HwInitialize == NULL) ||
1047 (HwInitializationData->HwStartIo == NULL) ||
1048 (HwInitializationData->HwInterrupt == NULL) ||
1049 (HwInitializationData->HwFindAdapter == NULL) ||
1050 (HwInitializationData->HwResetBus == NULL))
1051 {
1052 return STATUS_INVALID_PARAMETER;
1053 }
1054
1055 /* Set handlers */
1056 DriverObject->DriverStartIo = ScsiPortStartIo;
1057 DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiPortCreateClose;
1058 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiPortCreateClose;
1059 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiPortDeviceControl;
1060 DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiPortDispatchScsi;
1061
1062 /* Obtain configuration information */
1063 SystemConfig = IoGetConfigurationInformation();
1064
1065 /* Zero the internal configuration info structure */
1066 RtlZeroMemory(&ConfigInfo, sizeof(CONFIGURATION_INFO));
1067
1068 /* Zero starting slot number */
1069 SlotNumber.u.AsULONG = 0;
1070
1071 /* Allocate space for access ranges */
1072 if (HwInitializationData->NumberOfAccessRanges)
1073 {
1074 ConfigInfo.AccessRanges =
1075 ExAllocatePoolWithTag(PagedPool,
1076 HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE), TAG_SCSIPORT);
1077
1078 /* Fail if failed */
1079 if (ConfigInfo.AccessRanges == NULL)
1080 return STATUS_INSUFFICIENT_RESOURCES;
1081 }
1082
1083 /* Open registry keys */
1084 SpiInitOpenKeys(&ConfigInfo, (PUNICODE_STRING)Argument2);
1085
1086 /* Last adapter number = not known */
1087 ConfigInfo.LastAdapterNumber = SP_UNINITIALIZED_VALUE;
1088
1089 /* Calculate sizes of DeviceExtension and PortConfig */
1090 DeviceExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) +
1091 HwInitializationData->DeviceExtensionSize;
1092
1093 MaxBus = (HwInitializationData->AdapterInterfaceType == PCIBus) ? 8 : 1;
1094 DPRINT("MaxBus: %lu\n", MaxBus);
1095
1096 while (TRUE)
1097 {
1098 /* Create a unicode device name */
1099 swprintf(NameBuffer,
1100 L"\\Device\\ScsiPort%lu",
1101 SystemConfig->ScsiPortCount);
1102 RtlInitUnicodeString(&DeviceName, NameBuffer);
1103
1104 DPRINT("Creating device: %wZ\n", &DeviceName);
1105
1106 /* Create the port device */
1107 Status = IoCreateDevice(DriverObject,
1108 DeviceExtensionSize,
1109 &DeviceName,
1110 FILE_DEVICE_CONTROLLER,
1111 0,
1112 FALSE,
1113 &PortDeviceObject);
1114
1115 if (!NT_SUCCESS(Status))
1116 {
1117 DPRINT1("IoCreateDevice call failed! (Status 0x%lX)\n", Status);
1118 PortDeviceObject = NULL;
1119 break;
1120 }
1121
1122 DPRINT ("Created device: %wZ (%p)\n", &DeviceName, PortDeviceObject);
1123
1124 /* Set the buffering strategy here... */
1125 PortDeviceObject->Flags |= DO_DIRECT_IO;
1126 PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT; /* FIXME: Is this really needed? */
1127
1128 /* Fill Device Extension */
1129 DeviceExtension = PortDeviceObject->DeviceExtension;
1130 RtlZeroMemory(DeviceExtension, DeviceExtensionSize);
1131 DeviceExtension->Length = DeviceExtensionSize;
1132 DeviceExtension->DeviceObject = PortDeviceObject;
1133 DeviceExtension->PortNumber = SystemConfig->ScsiPortCount;
1134
1135 /* Driver's routines... */
1136 DeviceExtension->HwInitialize = HwInitializationData->HwInitialize;
1137 DeviceExtension->HwStartIo = HwInitializationData->HwStartIo;
1138 DeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
1139 DeviceExtension->HwResetBus = HwInitializationData->HwResetBus;
1140 DeviceExtension->HwDmaStarted = HwInitializationData->HwDmaStarted;
1141
1142 /* Extensions sizes */
1143 DeviceExtension->MiniPortExtensionSize = HwInitializationData->DeviceExtensionSize;
1144 DeviceExtension->LunExtensionSize = HwInitializationData->SpecificLuExtensionSize;
1145 DeviceExtension->SrbExtensionSize = HwInitializationData->SrbExtensionSize;
1146
1147 /* Round Srb extension size to the quadword */
1148 DeviceExtension->SrbExtensionSize =
1149 ~(sizeof(LONGLONG) - 1) & (DeviceExtension->SrbExtensionSize +
1150 sizeof(LONGLONG) - 1);
1151
1152 /* Fill some numbers (bus count, lun count, etc) */
1153 DeviceExtension->MaxLunCount = SCSI_MAXIMUM_LOGICAL_UNITS;
1154 DeviceExtension->RequestsNumber = 16;
1155
1156 /* Initialize the spin lock in the controller extension */
1157 KeInitializeSpinLock(&DeviceExtension->IrqLock);
1158 KeInitializeSpinLock(&DeviceExtension->SpinLock);
1159
1160 /* Initialize the DPC object */
1161 IoInitializeDpcRequest(PortDeviceObject,
1162 ScsiPortDpcForIsr);
1163
1164 /* Initialize the device timer */
1165 DeviceExtension->TimerCount = -1;
1166 IoInitializeTimer(PortDeviceObject,
1167 ScsiPortIoTimer,
1168 DeviceExtension);
1169
1170 /* Initialize miniport timer */
1171 KeInitializeTimer(&DeviceExtension->MiniportTimer);
1172 KeInitializeDpc(&DeviceExtension->MiniportTimerDpc,
1173 SpiMiniportTimerDpc,
1174 PortDeviceObject);
1175
1176 CreatePortConfig:
1177
1178 Status = SpiCreatePortConfig(DeviceExtension,
1179 HwInitializationData,
1180 &ConfigInfo,
1181 &InitialPortConfig,
1182 FirstConfigCall);
1183
1184 if (!NT_SUCCESS(Status))
1185 {
1186 DPRINT("SpiCreatePortConfig() failed with Status 0x%08X\n", Status);
1187 break;
1188 }
1189
1190 /* Allocate and initialize port configuration info */
1191 PortConfigSize = (sizeof(PORT_CONFIGURATION_INFORMATION) +
1192 HwInitializationData->NumberOfAccessRanges *
1193 sizeof(ACCESS_RANGE) + 7) & ~7;
1194 DeviceExtension->PortConfig = ExAllocatePoolWithTag(NonPagedPool, PortConfigSize, TAG_SCSIPORT);
1195
1196 /* Fail if failed */
1197 if (DeviceExtension->PortConfig == NULL)
1198 {
1199 Status = STATUS_INSUFFICIENT_RESOURCES;
1200 break;
1201 }
1202
1203 PortConfig = DeviceExtension->PortConfig;
1204
1205 /* Copy information here */
1206 RtlCopyMemory(PortConfig,
1207 &InitialPortConfig,
1208 sizeof(PORT_CONFIGURATION_INFORMATION));
1209
1210
1211 /* Copy extension sizes into the PortConfig */
1212 PortConfig->SpecificLuExtensionSize = DeviceExtension->LunExtensionSize;
1213 PortConfig->SrbExtensionSize = DeviceExtension->SrbExtensionSize;
1214
1215 /* Initialize Access ranges */
1216 if (HwInitializationData->NumberOfAccessRanges != 0)
1217 {
1218 PortConfig->AccessRanges = (PVOID)(PortConfig+1);
1219
1220 /* Align to LONGLONG */
1221 PortConfig->AccessRanges = (PVOID)((ULONG_PTR)(PortConfig->AccessRanges) + 7);
1222 PortConfig->AccessRanges = (PVOID)((ULONG_PTR)(PortConfig->AccessRanges) & ~7);
1223
1224 /* Copy the data */
1225 RtlCopyMemory(PortConfig->AccessRanges,
1226 ConfigInfo.AccessRanges,
1227 HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE));
1228 }
1229
1230 /* Search for matching PCI device */
1231 if ((HwInitializationData->AdapterInterfaceType == PCIBus) &&
1232 (HwInitializationData->VendorIdLength > 0) &&
1233 (HwInitializationData->VendorId != NULL) &&
1234 (HwInitializationData->DeviceIdLength > 0) &&
1235 (HwInitializationData->DeviceId != NULL))
1236 {
1237 PortConfig->BusInterruptLevel = 0;
1238
1239 /* Get PCI device data */
1240 DPRINT("VendorId '%.*s' DeviceId '%.*s'\n",
1241 HwInitializationData->VendorIdLength,
1242 HwInitializationData->VendorId,
1243 HwInitializationData->DeviceIdLength,
1244 HwInitializationData->DeviceId);
1245
1246 if (!SpiGetPciConfigData(DriverObject,
1247 PortDeviceObject,
1248 HwInitializationData,
1249 PortConfig,
1250 RegistryPath,
1251 ConfigInfo.BusNumber,
1252 &SlotNumber))
1253 {
1254 /* Continue to the next bus, nothing here */
1255 ConfigInfo.BusNumber++;
1256 DeviceExtension->PortConfig = NULL;
1257 ExFreePool(PortConfig);
1258 Again = FALSE;
1259 goto CreatePortConfig;
1260 }
1261
1262 if (!PortConfig->BusInterruptLevel)
1263 {
1264 /* Bypass this slot, because no interrupt was assigned */
1265 DeviceExtension->PortConfig = NULL;
1266 ExFreePool(PortConfig);
1267 goto CreatePortConfig;
1268 }
1269 }
1270 else
1271 {
1272 DPRINT("Non-pci bus\n");
1273 }
1274
1275 /* Note: HwFindAdapter is called once for each bus */
1276 Again = FALSE;
1277 DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber);
1278 Result = (HwInitializationData->HwFindAdapter)(&DeviceExtension->MiniPortDeviceExtension,
1279 HwContext,
1280 0, /* BusInformation */
1281 ConfigInfo.Parameter, /* ArgumentString */
1282 PortConfig,
1283 &Again);
1284
1285 DPRINT("HwFindAdapter() Result: %lu Again: %s\n",
1286 Result, (Again) ? "True" : "False");
1287
1288 /* Free MapRegisterBase, it's not needed anymore */
1289 if (DeviceExtension->MapRegisterBase != NULL)
1290 {
1291 ExFreePool(DeviceExtension->MapRegisterBase);
1292 DeviceExtension->MapRegisterBase = NULL;
1293 }
1294
1295 /* If result is nothing good... */
1296 if (Result != SP_RETURN_FOUND)
1297 {
1298 DPRINT("HwFindAdapter() Result: %lu\n", Result);
1299
1300 if (Result == SP_RETURN_NOT_FOUND)
1301 {
1302 /* We can continue on the next bus */
1303 ConfigInfo.BusNumber++;
1304 Again = FALSE;
1305
1306 DeviceExtension->PortConfig = NULL;
1307 ExFreePool(PortConfig);
1308 goto CreatePortConfig;
1309 }
1310
1311 /* Otherwise, break */
1312 Status = STATUS_INTERNAL_ERROR;
1313 break;
1314 }
1315
1316 DPRINT("ScsiPortInitialize(): Found HBA! (%x), adapter Id %d\n",
1317 PortConfig->BusInterruptVector, PortConfig->InitiatorBusId[0]);
1318
1319 /* If the SRB extension size was updated */
1320 if (!DeviceExtension->NonCachedExtension &&
1321 (PortConfig->SrbExtensionSize != DeviceExtension->SrbExtensionSize))
1322 {
1323 /* Set it (rounding to LONGLONG again) */
1324 DeviceExtension->SrbExtensionSize =
1325 (PortConfig->SrbExtensionSize +
1326 sizeof(LONGLONG)) & ~(sizeof(LONGLONG) - 1);
1327 }
1328
1329 /* The same with LUN extension size */
1330 if (PortConfig->SpecificLuExtensionSize != DeviceExtension->LunExtensionSize)
1331 DeviceExtension->LunExtensionSize = PortConfig->SpecificLuExtensionSize;
1332
1333
1334 if (!((HwInitializationData->AdapterInterfaceType == PCIBus) &&
1335 (HwInitializationData->VendorIdLength > 0) &&
1336 (HwInitializationData->VendorId != NULL) &&
1337 (HwInitializationData->DeviceIdLength > 0) &&
1338 (HwInitializationData->DeviceId != NULL)))
1339 {
1340 /* Construct a resource list */
1341 ResourceList = SpiConfigToResource(DeviceExtension,
1342 PortConfig);
1343
1344 if (ResourceList)
1345 {
1346 UNICODE_STRING UnicodeString;
1347 RtlInitUnicodeString(&UnicodeString, L"ScsiAdapter");
1348 DPRINT("Reporting resources\n");
1349 Status = IoReportResourceUsage(&UnicodeString,
1350 DriverObject,
1351 NULL,
1352 0,
1353 PortDeviceObject,
1354 ResourceList,
1355 FIELD_OFFSET(CM_RESOURCE_LIST,
1356 List[0].PartialResourceList.PartialDescriptors) +
1357 ResourceList->List[0].PartialResourceList.Count
1358 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
1359 FALSE,
1360 &Conflict);
1361 ExFreePool(ResourceList);
1362
1363 /* In case of a failure or a conflict, break */
1364 if (Conflict || (!NT_SUCCESS(Status)))
1365 {
1366 if (Conflict)
1367 Status = STATUS_CONFLICTING_ADDRESSES;
1368 break;
1369 }
1370 }
1371 }
1372
1373 /* Reset the Conflict var */
1374 Conflict = FALSE;
1375
1376 /* Copy all stuff which we ever need from PortConfig to the DeviceExtension */
1377 if (PortConfig->MaximumNumberOfTargets > SCSI_MAXIMUM_TARGETS_PER_BUS)
1378 DeviceExtension->MaxTargedIds = SCSI_MAXIMUM_TARGETS_PER_BUS;
1379 else
1380 DeviceExtension->MaxTargedIds = PortConfig->MaximumNumberOfTargets;
1381
1382 DeviceExtension->BusNum = PortConfig->NumberOfBuses;
1383 DeviceExtension->CachesData = PortConfig->CachesData;
1384 DeviceExtension->ReceiveEvent = PortConfig->ReceiveEvent;
1385 DeviceExtension->SupportsTaggedQueuing = PortConfig->TaggedQueuing;
1386 DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu;
1387
1388 /* If something was disabled via registry - apply it */
1389 if (ConfigInfo.DisableMultipleLun)
1390 DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu = FALSE;
1391
1392 if (ConfigInfo.DisableTaggedQueueing)
1393 DeviceExtension->SupportsTaggedQueuing = PortConfig->MultipleRequestPerLu = FALSE;
1394
1395 /* Check if we need to alloc SRB data */
1396 if (DeviceExtension->SupportsTaggedQueuing ||
1397 DeviceExtension->MultipleReqsPerLun)
1398 {
1399 DeviceExtension->NeedSrbDataAlloc = TRUE;
1400 }
1401 else
1402 {
1403 DeviceExtension->NeedSrbDataAlloc = FALSE;
1404 }
1405
1406 /* Get a pointer to the port capabilities */
1407 PortCapabilities = &DeviceExtension->PortCapabilities;
1408
1409 /* Copy one field there */
1410 DeviceExtension->MapBuffers = PortConfig->MapBuffers;
1411 PortCapabilities->AdapterUsesPio = PortConfig->MapBuffers;
1412
1413 if (DeviceExtension->AdapterObject == NULL &&
1414 (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE || PortConfig->Master))
1415 {
1416 DPRINT1("DMA is not supported yet\n");
1417 ASSERT(FALSE);
1418 }
1419
1420 if (DeviceExtension->SrbExtensionBuffer == NULL &&
1421 (DeviceExtension->SrbExtensionSize != 0 ||
1422 PortConfig->AutoRequestSense))
1423 {
1424 DeviceExtension->SupportsAutoSense = PortConfig->AutoRequestSense;
1425 DeviceExtension->NeedSrbExtensionAlloc = TRUE;
1426
1427 /* Allocate common buffer */
1428 Status = SpiAllocateCommonBuffer(DeviceExtension, 0);
1429
1430 /* Check for failure */
1431 if (!NT_SUCCESS(Status))
1432 break;
1433 }
1434
1435 /* Allocate SrbData, if needed */
1436 if (DeviceExtension->NeedSrbDataAlloc)
1437 {
1438 ULONG Count;
1439 PSCSI_REQUEST_BLOCK_INFO SrbData;
1440
1441 if (DeviceExtension->SrbDataCount != 0)
1442 Count = DeviceExtension->SrbDataCount;
1443 else
1444 Count = DeviceExtension->RequestsNumber * 2;
1445
1446 /* Allocate the data */
1447 SrbData = ExAllocatePoolWithTag(NonPagedPool, Count * sizeof(SCSI_REQUEST_BLOCK_INFO), TAG_SCSIPORT);
1448 if (SrbData == NULL)
1449 return STATUS_INSUFFICIENT_RESOURCES;
1450
1451 RtlZeroMemory(SrbData, Count * sizeof(SCSI_REQUEST_BLOCK_INFO));
1452
1453 DeviceExtension->SrbInfo = SrbData;
1454 DeviceExtension->FreeSrbInfo = SrbData;
1455 DeviceExtension->SrbDataCount = Count;
1456
1457 /* Link it to the list */
1458 while (Count > 0)
1459 {
1460 SrbData->Requests.Flink = (PLIST_ENTRY)(SrbData + 1);
1461 SrbData++;
1462 Count--;
1463 }
1464
1465 /* Mark the last entry of the list */
1466 SrbData--;
1467 SrbData->Requests.Flink = NULL;
1468 }
1469
1470 /* Initialize port capabilities */
1471 PortCapabilities = &DeviceExtension->PortCapabilities;
1472 PortCapabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
1473 PortCapabilities->MaximumTransferLength = PortConfig->MaximumTransferLength;
1474
1475 if (PortConfig->ReceiveEvent)
1476 PortCapabilities->SupportedAsynchronousEvents |= SRBEV_SCSI_ASYNC_NOTIFICATION;
1477
1478 PortCapabilities->TaggedQueuing = DeviceExtension->SupportsTaggedQueuing;
1479 PortCapabilities->AdapterScansDown = PortConfig->AdapterScansDown;
1480
1481 if (PortConfig->AlignmentMask > PortDeviceObject->AlignmentRequirement)
1482 PortDeviceObject->AlignmentRequirement = PortConfig->AlignmentMask;
1483
1484 PortCapabilities->AlignmentMask = PortDeviceObject->AlignmentRequirement;
1485
1486 if (PortCapabilities->MaximumPhysicalPages == 0)
1487 {
1488 PortCapabilities->MaximumPhysicalPages =
1489 BYTES_TO_PAGES(PortCapabilities->MaximumTransferLength);
1490
1491 /* Apply miniport's limits */
1492 if (PortConfig->NumberOfPhysicalBreaks < PortCapabilities->MaximumPhysicalPages)
1493 {
1494 PortCapabilities->MaximumPhysicalPages = PortConfig->NumberOfPhysicalBreaks;
1495 }
1496 }
1497
1498 /* Deal with interrupts */
1499 if (DeviceExtension->HwInterrupt == NULL ||
1500 (PortConfig->BusInterruptLevel == 0 && PortConfig->BusInterruptVector == 0))
1501 {
1502 /* No interrupts */
1503 DeviceExtension->InterruptCount = 0;
1504
1505 DPRINT1("Interrupt Count: 0\n");
1506
1507 UNIMPLEMENTED;
1508
1509 /* This code path will ALWAYS crash so stop it now */
1510 while(TRUE);
1511 }
1512 else
1513 {
1514 BOOLEAN InterruptShareable;
1515 KINTERRUPT_MODE InterruptMode[2];
1516 ULONG InterruptVector[2], i, MappedIrq[2];
1517 KIRQL Dirql[2], MaxDirql;
1518 KAFFINITY Affinity[2];
1519
1520 DeviceExtension->InterruptLevel[0] = PortConfig->BusInterruptLevel;
1521 DeviceExtension->InterruptLevel[1] = PortConfig->BusInterruptLevel2;
1522
1523 InterruptVector[0] = PortConfig->BusInterruptVector;
1524 InterruptVector[1] = PortConfig->BusInterruptVector2;
1525
1526 InterruptMode[0] = PortConfig->InterruptMode;
1527 InterruptMode[1] = PortConfig->InterruptMode2;
1528
1529 DeviceExtension->InterruptCount = (PortConfig->BusInterruptLevel2 != 0 || PortConfig->BusInterruptVector2 != 0) ? 2 : 1;
1530
1531 for (i = 0; i < DeviceExtension->InterruptCount; i++)
1532 {
1533 /* Register an interrupt handler for this device */
1534 MappedIrq[i] = HalGetInterruptVector(PortConfig->AdapterInterfaceType,
1535 PortConfig->SystemIoBusNumber,
1536 DeviceExtension->InterruptLevel[i],
1537 InterruptVector[i],
1538 &Dirql[i],
1539 &Affinity[i]);
1540 }
1541
1542 if (DeviceExtension->InterruptCount == 1 || Dirql[0] > Dirql[1])
1543 MaxDirql = Dirql[0];
1544 else
1545 MaxDirql = Dirql[1];
1546
1547 for (i = 0; i < DeviceExtension->InterruptCount; i++)
1548 {
1549 /* Determine IRQ sharability as usual */
1550 if (PortConfig->AdapterInterfaceType == MicroChannel ||
1551 InterruptMode[i] == LevelSensitive)
1552 {
1553 InterruptShareable = TRUE;
1554 }
1555 else
1556 {
1557 InterruptShareable = FALSE;
1558 }
1559
1560 Status = IoConnectInterrupt(&DeviceExtension->Interrupt[i],
1561 (PKSERVICE_ROUTINE)ScsiPortIsr,
1562 DeviceExtension,
1563 &DeviceExtension->IrqLock,
1564 MappedIrq[i],
1565 Dirql[i],
1566 MaxDirql,
1567 InterruptMode[i],
1568 InterruptShareable,
1569 Affinity[i],
1570 FALSE);
1571
1572 if (!(NT_SUCCESS(Status)))
1573 {
1574 DPRINT1("Could not connect interrupt %d\n",
1575 InterruptVector[i]);
1576 DeviceExtension->Interrupt[i] = NULL;
1577 break;
1578 }
1579 }
1580
1581 if (!NT_SUCCESS(Status))
1582 break;
1583 }
1584
1585 /* Save IoAddress (from access ranges) */
1586 if (HwInitializationData->NumberOfAccessRanges != 0)
1587 {
1588 DeviceExtension->IoAddress =
1589 ((*(PortConfig->AccessRanges))[0]).RangeStart.LowPart;
1590
1591 DPRINT("Io Address %x\n", DeviceExtension->IoAddress);
1592 }
1593
1594 /* Set flag that it's allowed to disconnect during this command */
1595 DeviceExtension->Flags |= SCSI_PORT_DISCONNECT_ALLOWED;
1596
1597 /* Initialize counter of active requests (-1 means there are none) */
1598 DeviceExtension->ActiveRequestCounter = -1;
1599
1600 /* Analyze what we have about DMA */
1601 if (DeviceExtension->AdapterObject != NULL &&
1602 PortConfig->Master &&
1603 PortConfig->NeedPhysicalAddresses)
1604 {
1605 DeviceExtension->MapRegisters = TRUE;
1606 }
1607 else
1608 {
1609 DeviceExtension->MapRegisters = FALSE;
1610 }
1611
1612 /* Call HwInitialize at DISPATCH_LEVEL */
1613 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
1614
1615 if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0],
1616 DeviceExtension->HwInitialize,
1617 DeviceExtension->MiniPortDeviceExtension))
1618 {
1619 DPRINT1("HwInitialize() failed!\n");
1620 KeLowerIrql(OldIrql);
1621 Status = STATUS_ADAPTER_HARDWARE_ERROR;
1622 break;
1623 }
1624
1625 /* Check if a notification is needed */
1626 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
1627 {
1628 /* Call DPC right away, because we're already at DISPATCH_LEVEL */
1629 ScsiPortDpcForIsr(NULL,
1630 DeviceExtension->DeviceObject,
1631 NULL,
1632 NULL);
1633 }
1634
1635 /* Lower irql back to what it was */
1636 KeLowerIrql(OldIrql);
1637
1638 /* Start our timer */
1639 IoStartTimer(PortDeviceObject);
1640
1641 /* Initialize bus scanning information */
1642 BusConfigSize = FIELD_OFFSET(BUSES_CONFIGURATION_INFORMATION,
1643 BusScanInfo[DeviceExtension->PortConfig->NumberOfBuses]);
1644 DeviceExtension->BusesConfig = ExAllocatePoolWithTag(PagedPool,
1645 BusConfigSize,
1646 TAG_SCSIPORT);
1647 if (!DeviceExtension->BusesConfig)
1648 {
1649 DPRINT1("Out of resources!\n");
1650 Status = STATUS_INSUFFICIENT_RESOURCES;
1651 break;
1652 }
1653
1654 /* Zero it */
1655 RtlZeroMemory(DeviceExtension->BusesConfig, BusConfigSize);
1656
1657 /* Store number of buses there */
1658 DeviceExtension->BusesConfig->NumberOfBuses = (UCHAR)DeviceExtension->BusNum;
1659
1660 /* Scan the adapter for devices */
1661 SpiScanAdapter(DeviceExtension);
1662
1663 /* Build the registry device map */
1664 SpiBuildDeviceMap(DeviceExtension,
1665 (PUNICODE_STRING)Argument2);
1666
1667 /* Create the dos device link */
1668 swprintf(DosNameBuffer,
1669 L"\\??\\Scsi%lu:",
1670 SystemConfig->ScsiPortCount);
1671 RtlInitUnicodeString(&DosDeviceName, DosNameBuffer);
1672 IoCreateSymbolicLink(&DosDeviceName, &DeviceName);
1673
1674 /* Increase the port count */
1675 SystemConfig->ScsiPortCount++;
1676 FirstConfigCall = FALSE;
1677
1678 /* Increase adapter number and bus number respectively */
1679 ConfigInfo.AdapterNumber++;
1680
1681 if (!Again)
1682 ConfigInfo.BusNumber++;
1683
1684 DPRINT("Bus: %lu MaxBus: %lu\n", ConfigInfo.BusNumber, MaxBus);
1685
1686 DeviceFound = TRUE;
1687 }
1688
1689 /* Clean up the mess */
1690 SpiCleanupAfterInit(DeviceExtension);
1691
1692 /* Close registry keys */
1693 if (ConfigInfo.ServiceKey != NULL)
1694 ZwClose(ConfigInfo.ServiceKey);
1695
1696 if (ConfigInfo.DeviceKey != NULL)
1697 ZwClose(ConfigInfo.DeviceKey);
1698
1699 if (ConfigInfo.BusKey != NULL)
1700 ZwClose(ConfigInfo.BusKey);
1701
1702 if (ConfigInfo.AccessRanges != NULL)
1703 ExFreePool(ConfigInfo.AccessRanges);
1704
1705 if (ConfigInfo.Parameter != NULL)
1706 ExFreePool(ConfigInfo.Parameter);
1707
1708 DPRINT("ScsiPortInitialize() done, Status = 0x%08X, DeviceFound = %d!\n",
1709 Status, DeviceFound);
1710
1711 return (DeviceFound == FALSE) ? Status : STATUS_SUCCESS;
1712 }
1713
1714 static VOID
1715 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
1716 {
1717 PSCSI_LUN_INFO LunInfo;
1718 PVOID Ptr;
1719 ULONG Bus, Lun;
1720
1721 /* Check if we have something to clean up */
1722 if (DeviceExtension == NULL)
1723 return;
1724
1725 /* Stop the timer */
1726 IoStopTimer(DeviceExtension->DeviceObject);
1727
1728 /* Disconnect the interrupts */
1729 while (DeviceExtension->InterruptCount)
1730 {
1731 if (DeviceExtension->Interrupt[--DeviceExtension->InterruptCount])
1732 IoDisconnectInterrupt(DeviceExtension->Interrupt[DeviceExtension->InterruptCount]);
1733 }
1734
1735 /* Delete ConfigInfo */
1736 if (DeviceExtension->BusesConfig)
1737 {
1738 for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
1739 {
1740 if (!DeviceExtension->BusesConfig->BusScanInfo[Bus])
1741 continue;
1742
1743 LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
1744
1745 while (LunInfo)
1746 {
1747 /* Free current, but save pointer to the next one */
1748 Ptr = LunInfo->Next;
1749 ExFreePool(LunInfo);
1750 LunInfo = Ptr;
1751 }
1752
1753 ExFreePool(DeviceExtension->BusesConfig->BusScanInfo[Bus]);
1754 }
1755
1756 ExFreePool(DeviceExtension->BusesConfig);
1757 }
1758
1759 /* Free PortConfig */
1760 if (DeviceExtension->PortConfig)
1761 ExFreePool(DeviceExtension->PortConfig);
1762
1763 /* Free LUNs*/
1764 for(Lun = 0; Lun < LUS_NUMBER; Lun++)
1765 {
1766 while (DeviceExtension->LunExtensionList[Lun])
1767 {
1768 Ptr = DeviceExtension->LunExtensionList[Lun];
1769 DeviceExtension->LunExtensionList[Lun] = DeviceExtension->LunExtensionList[Lun]->Next;
1770
1771 ExFreePool(Ptr);
1772 }
1773 }
1774
1775 /* Free common buffer (if it exists) */
1776 if (DeviceExtension->SrbExtensionBuffer != NULL &&
1777 DeviceExtension->CommonBufferLength != 0)
1778 {
1779 if (!DeviceExtension->AdapterObject)
1780 {
1781 ExFreePool(DeviceExtension->SrbExtensionBuffer);
1782 }
1783 else
1784 {
1785 HalFreeCommonBuffer(DeviceExtension->AdapterObject,
1786 DeviceExtension->CommonBufferLength,
1787 DeviceExtension->PhysicalAddress,
1788 DeviceExtension->SrbExtensionBuffer,
1789 FALSE);
1790 }
1791 }
1792
1793 /* Free SRB info */
1794 if (DeviceExtension->SrbInfo != NULL)
1795 ExFreePool(DeviceExtension->SrbInfo);
1796
1797 /* Unmap mapped addresses */
1798 while (DeviceExtension->MappedAddressList != NULL)
1799 {
1800 MmUnmapIoSpace(DeviceExtension->MappedAddressList->MappedAddress,
1801 DeviceExtension->MappedAddressList->NumberOfBytes);
1802
1803 Ptr = DeviceExtension->MappedAddressList;
1804 DeviceExtension->MappedAddressList = DeviceExtension->MappedAddressList->NextMappedAddress;
1805
1806 ExFreePool(Ptr);
1807 }
1808
1809 /* Finally delete the device object */
1810 DPRINT("Deleting device %p\n", DeviceExtension->DeviceObject);
1811 IoDeleteDevice(DeviceExtension->DeviceObject);
1812 }
1813
1814 /*
1815 * @unimplemented
1816 */
1817 VOID NTAPI
1818 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension,
1819 IN PSCSI_REQUEST_BLOCK Srb,
1820 IN PVOID LogicalAddress,
1821 IN ULONG Length)
1822 {
1823 DPRINT1("ScsiPortIoMapTransfer()\n");
1824 UNIMPLEMENTED;
1825 }
1826
1827 /*
1828 * @unimplemented
1829 */
1830 VOID NTAPI
1831 ScsiPortLogError(IN PVOID HwDeviceExtension,
1832 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
1833 IN UCHAR PathId,
1834 IN UCHAR TargetId,
1835 IN UCHAR Lun,
1836 IN ULONG ErrorCode,
1837 IN ULONG UniqueId)
1838 {
1839 //PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1840
1841 DPRINT1("ScsiPortLogError() called\n");
1842 DPRINT1("PathId: 0x%02x TargetId: 0x%02x Lun: 0x%02x ErrorCode: 0x%08lx UniqueId: 0x%08lx\n",
1843 PathId, TargetId, Lun, ErrorCode, UniqueId);
1844
1845 //DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, SCSI_PORT_DEVICE_EXTENSION, MiniPortDeviceExtension);
1846
1847
1848 DPRINT("ScsiPortLogError() done\n");
1849 }
1850
1851 /*
1852 * @implemented
1853 */
1854 VOID NTAPI
1855 ScsiPortMoveMemory(OUT PVOID Destination,
1856 IN PVOID Source,
1857 IN ULONG Length)
1858 {
1859 RtlMoveMemory(Destination,
1860 Source,
1861 Length);
1862 }
1863
1864
1865 /*
1866 * @implemented
1867 */
1868 VOID
1869 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType,
1870 IN PVOID HwDeviceExtension,
1871 ...)
1872 {
1873 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1874 va_list ap;
1875
1876 DPRINT("ScsiPortNotification() called\n");
1877
1878 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
1879 SCSI_PORT_DEVICE_EXTENSION,
1880 MiniPortDeviceExtension);
1881
1882 DPRINT("DeviceExtension %p\n", DeviceExtension);
1883
1884 va_start(ap, HwDeviceExtension);
1885
1886 switch (NotificationType)
1887 {
1888 case RequestComplete:
1889 {
1890 PSCSI_REQUEST_BLOCK Srb;
1891 PSCSI_REQUEST_BLOCK_INFO SrbData;
1892
1893 Srb = (PSCSI_REQUEST_BLOCK) va_arg (ap, PSCSI_REQUEST_BLOCK);
1894
1895 DPRINT("Notify: RequestComplete (Srb %p)\n", Srb);
1896
1897 /* Make sure Srb is alright */
1898 ASSERT(Srb->SrbStatus != SRB_STATUS_PENDING);
1899 ASSERT(Srb->Function != SRB_FUNCTION_EXECUTE_SCSI || Srb->SrbStatus != SRB_STATUS_SUCCESS || Srb->ScsiStatus == SCSISTAT_GOOD);
1900
1901 if (!(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE))
1902 {
1903 /* It's been already completed */
1904 va_end(ap);
1905 return;
1906 }
1907
1908 /* It's not active anymore */
1909 Srb->SrbFlags &= ~SRB_FLAGS_IS_ACTIVE;
1910
1911 if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
1912 {
1913 /* TODO: Treat it specially */
1914 ASSERT(FALSE);
1915 }
1916 else
1917 {
1918 /* Get the SRB data */
1919 SrbData = SpiGetSrbData(DeviceExtension,
1920 Srb->PathId,
1921 Srb->TargetId,
1922 Srb->Lun,
1923 Srb->QueueTag);
1924
1925 /* Make sure there are no CompletedRequests and there is a Srb */
1926 ASSERT(SrbData->CompletedRequests == NULL && SrbData->Srb != NULL);
1927
1928 /* If it's a read/write request, make sure it has data inside it */
1929 if ((Srb->SrbStatus == SRB_STATUS_SUCCESS) &&
1930 ((Srb->Cdb[0] == SCSIOP_READ) || (Srb->Cdb[0] == SCSIOP_WRITE)))
1931 {
1932 ASSERT(Srb->DataTransferLength);
1933 }
1934
1935 SrbData->CompletedRequests = DeviceExtension->InterruptData.CompletedRequests;
1936 DeviceExtension->InterruptData.CompletedRequests = SrbData;
1937 }
1938 }
1939 break;
1940
1941 case NextRequest:
1942 DPRINT("Notify: NextRequest\n");
1943 DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY;
1944 break;
1945
1946 case NextLuRequest:
1947 {
1948 UCHAR PathId;
1949 UCHAR TargetId;
1950 UCHAR Lun;
1951 PSCSI_PORT_LUN_EXTENSION LunExtension;
1952
1953 PathId = (UCHAR) va_arg (ap, int);
1954 TargetId = (UCHAR) va_arg (ap, int);
1955 Lun = (UCHAR) va_arg (ap, int);
1956
1957 DPRINT("Notify: NextLuRequest(PathId %u TargetId %u Lun %u)\n",
1958 PathId, TargetId, Lun);
1959
1960 /* Mark it in the flags field */
1961 DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY;
1962
1963 /* Get the LUN extension */
1964 LunExtension = SpiGetLunExtension(DeviceExtension,
1965 PathId,
1966 TargetId,
1967 Lun);
1968
1969 /* If returned LunExtension is NULL, break out */
1970 if (!LunExtension) break;
1971
1972 /* This request should not be processed if */
1973 if ((LunExtension->ReadyLun) ||
1974 (LunExtension->SrbInfo.Srb))
1975 {
1976 /* Nothing to do here */
1977 break;
1978 }
1979
1980 /* Add this LUN to the list */
1981 LunExtension->ReadyLun = DeviceExtension->InterruptData.ReadyLun;
1982 DeviceExtension->InterruptData.ReadyLun = LunExtension;
1983 }
1984 break;
1985
1986 case ResetDetected:
1987 DPRINT("Notify: ResetDetected\n");
1988 /* Add RESET flags */
1989 DeviceExtension->InterruptData.Flags |=
1990 SCSI_PORT_RESET | SCSI_PORT_RESET_REPORTED;
1991 break;
1992
1993 case CallDisableInterrupts:
1994 DPRINT1("UNIMPLEMENTED SCSI Notification called: CallDisableInterrupts!\n");
1995 break;
1996
1997 case CallEnableInterrupts:
1998 DPRINT1("UNIMPLEMENTED SCSI Notification called: CallEnableInterrupts!\n");
1999 break;
2000
2001 case RequestTimerCall:
2002 DPRINT("Notify: RequestTimerCall\n");
2003 DeviceExtension->InterruptData.Flags |= SCSI_PORT_TIMER_NEEDED;
2004 DeviceExtension->InterruptData.HwScsiTimer = (PHW_TIMER)va_arg(ap, PHW_TIMER);
2005 DeviceExtension->InterruptData.MiniportTimerValue = (ULONG)va_arg(ap, ULONG);
2006 break;
2007
2008 case BusChangeDetected:
2009 DPRINT1("UNIMPLEMENTED SCSI Notification called: BusChangeDetected!\n");
2010 break;
2011
2012 default:
2013 DPRINT1 ("Unsupported notification from WMI: %lu\n", NotificationType);
2014 break;
2015 }
2016
2017 va_end(ap);
2018
2019 /* Request a DPC after we're done with the interrupt */
2020 DeviceExtension->InterruptData.Flags |= SCSI_PORT_NOTIFICATION_NEEDED;
2021 }
2022
2023 /*
2024 * @implemented
2025 */
2026 BOOLEAN NTAPI
2027 ScsiPortValidateRange(IN PVOID HwDeviceExtension,
2028 IN INTERFACE_TYPE BusType,
2029 IN ULONG SystemIoBusNumber,
2030 IN SCSI_PHYSICAL_ADDRESS IoAddress,
2031 IN ULONG NumberOfBytes,
2032 IN BOOLEAN InIoSpace)
2033 {
2034 DPRINT("ScsiPortValidateRange()\n");
2035 return(TRUE);
2036 }
2037
2038
2039 /* INTERNAL FUNCTIONS ********************************************************/
2040
2041 static VOID
2042 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData,
2043 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor,
2044 IN PPORT_CONFIGURATION_INFORMATION PortConfig)
2045 {
2046 PACCESS_RANGE AccessRange;
2047 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialData;
2048 ULONG RangeNumber;
2049 ULONG Index;
2050 ULONG Interrupt = 0;
2051 ULONG Dma = 0;
2052
2053 RangeNumber = 0;
2054
2055 /* Loop through all entries */
2056 for (Index = 0; Index < ResourceDescriptor->PartialResourceList.Count; Index++)
2057 {
2058 PartialData = &ResourceDescriptor->PartialResourceList.PartialDescriptors[Index];
2059
2060 switch (PartialData->Type)
2061 {
2062 case CmResourceTypePort:
2063 /* Copy access ranges */
2064 if (RangeNumber < HwInitializationData->NumberOfAccessRanges)
2065 {
2066 AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]);
2067
2068 AccessRange->RangeStart = PartialData->u.Port.Start;
2069 AccessRange->RangeLength = PartialData->u.Port.Length;
2070
2071 AccessRange->RangeInMemory = FALSE;
2072 RangeNumber++;
2073 }
2074 break;
2075
2076 case CmResourceTypeMemory:
2077 /* Copy access ranges */
2078 if (RangeNumber < HwInitializationData->NumberOfAccessRanges)
2079 {
2080 AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]);
2081
2082 AccessRange->RangeStart = PartialData->u.Memory.Start;
2083 AccessRange->RangeLength = PartialData->u.Memory.Length;
2084
2085 AccessRange->RangeInMemory = TRUE;
2086 RangeNumber++;
2087 }
2088 break;
2089
2090 case CmResourceTypeInterrupt:
2091
2092 if (Interrupt == 0)
2093 {
2094 /* Copy interrupt data */
2095 PortConfig->BusInterruptLevel = PartialData->u.Interrupt.Level;
2096 PortConfig->BusInterruptVector = PartialData->u.Interrupt.Vector;
2097
2098 /* Set interrupt mode accordingly to the resource */
2099 if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
2100 {
2101 PortConfig->InterruptMode = Latched;
2102 }
2103 else if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
2104 {
2105 PortConfig->InterruptMode = LevelSensitive;
2106 }
2107 }
2108 else if (Interrupt == 1)
2109 {
2110 /* Copy interrupt data */
2111 PortConfig->BusInterruptLevel2 = PartialData->u.Interrupt.Level;
2112 PortConfig->BusInterruptVector2 = PartialData->u.Interrupt.Vector;
2113
2114 /* Set interrupt mode accordingly to the resource */
2115 if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
2116 {
2117 PortConfig->InterruptMode2 = Latched;
2118 }
2119 else if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
2120 {
2121 PortConfig->InterruptMode2 = LevelSensitive;
2122 }
2123 }
2124
2125 Interrupt++;
2126 break;
2127
2128 case CmResourceTypeDma:
2129
2130 if (Dma == 0)
2131 {
2132 PortConfig->DmaChannel = PartialData->u.Dma.Channel;
2133 PortConfig->DmaPort = PartialData->u.Dma.Port;
2134
2135 if (PartialData->Flags & CM_RESOURCE_DMA_8)
2136 PortConfig->DmaWidth = Width8Bits;
2137 else if ((PartialData->Flags & CM_RESOURCE_DMA_16) ||
2138 (PartialData->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
2139 PortConfig->DmaWidth = Width16Bits;
2140 else if (PartialData->Flags & CM_RESOURCE_DMA_32)
2141 PortConfig->DmaWidth = Width32Bits;
2142 }
2143 else if (Dma == 1)
2144 {
2145 PortConfig->DmaChannel2 = PartialData->u.Dma.Channel;
2146 PortConfig->DmaPort2 = PartialData->u.Dma.Port;
2147
2148 if (PartialData->Flags & CM_RESOURCE_DMA_8)
2149 PortConfig->DmaWidth2 = Width8Bits;
2150 else if ((PartialData->Flags & CM_RESOURCE_DMA_16) ||
2151 (PartialData->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
2152 PortConfig->DmaWidth2 = Width16Bits;
2153 else if (PartialData->Flags & CM_RESOURCE_DMA_32)
2154 PortConfig->DmaWidth2 = Width32Bits;
2155 }
2156 break;
2157 }
2158 }
2159 }
2160
2161 static PCM_RESOURCE_LIST
2162 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
2163 PPORT_CONFIGURATION_INFORMATION PortConfig)
2164 {
2165 PCONFIGURATION_INFORMATION ConfigInfo;
2166 PCM_RESOURCE_LIST ResourceList;
2167 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor;
2168 PACCESS_RANGE AccessRange;
2169 ULONG ListLength = 0, i, FullSize;
2170 ULONG Interrupt, Dma;
2171
2172 /* Get current Atdisk usage from the system */
2173 ConfigInfo = IoGetConfigurationInformation();
2174
2175 if (PortConfig->AtdiskPrimaryClaimed)
2176 ConfigInfo->AtDiskPrimaryAddressClaimed = TRUE;
2177
2178 if (PortConfig->AtdiskSecondaryClaimed)
2179 ConfigInfo->AtDiskSecondaryAddressClaimed = TRUE;
2180
2181 /* Do we use DMA? */
2182 if (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE ||
2183 PortConfig->DmaPort != SP_UNINITIALIZED_VALUE)
2184 {
2185 Dma = 1;
2186
2187 if (PortConfig->DmaChannel2 != SP_UNINITIALIZED_VALUE ||
2188 PortConfig->DmaPort2 != SP_UNINITIALIZED_VALUE)
2189 Dma++;
2190 }
2191 else
2192 {
2193 Dma = 0;
2194 }
2195 ListLength += Dma;
2196
2197 /* How many interrupts to we have? */
2198 Interrupt = DeviceExtension->InterruptCount;
2199 ListLength += Interrupt;
2200
2201 /* How many access ranges do we use? */
2202 AccessRange = &((*(PortConfig->AccessRanges))[0]);
2203 for (i = 0; i < PortConfig->NumberOfAccessRanges; i++)
2204 {
2205 if (AccessRange->RangeLength != 0)
2206 ListLength++;
2207
2208 AccessRange++;
2209 }
2210
2211 /* Allocate the resource list, since we know its size now */
2212 FullSize = sizeof(CM_RESOURCE_LIST) + (ListLength - 1) *
2213 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
2214
2215 ResourceList = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(PagedPool, FullSize, TAG_SCSIPORT);
2216
2217 if (!ResourceList)
2218 return NULL;
2219
2220 /* Zero it */
2221 RtlZeroMemory(ResourceList, FullSize);
2222
2223 /* Initialize it */
2224 ResourceList->Count = 1;
2225 ResourceList->List[0].InterfaceType = PortConfig->AdapterInterfaceType;
2226 ResourceList->List[0].BusNumber = PortConfig->SystemIoBusNumber;
2227 ResourceList->List[0].PartialResourceList.Count = ListLength;
2228 ResourceDescriptor = ResourceList->List[0].PartialResourceList.PartialDescriptors;
2229
2230 /* Copy access ranges array over */
2231 for (i = 0; i < PortConfig->NumberOfAccessRanges; i++)
2232 {
2233 AccessRange = &((*(PortConfig->AccessRanges))[i]);
2234
2235 /* If the range is empty - skip it */
2236 if (AccessRange->RangeLength == 0)
2237 continue;
2238
2239 if (AccessRange->RangeInMemory)
2240 {
2241 ResourceDescriptor->Type = CmResourceTypeMemory;
2242 ResourceDescriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
2243 }
2244 else
2245 {
2246 ResourceDescriptor->Type = CmResourceTypePort;
2247 ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
2248 }
2249
2250 ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
2251
2252 ResourceDescriptor->u.Memory.Start = AccessRange->RangeStart;
2253 ResourceDescriptor->u.Memory.Length = AccessRange->RangeLength;
2254
2255 ResourceDescriptor++;
2256 }
2257
2258 /* If we use interrupt(s), copy them */
2259 while (Interrupt)
2260 {
2261 ResourceDescriptor->Type = CmResourceTypeInterrupt;
2262
2263 if (PortConfig->AdapterInterfaceType == MicroChannel ||
2264 ((Interrupt == 2) ? PortConfig->InterruptMode2 : PortConfig->InterruptMode) == LevelSensitive)
2265 {
2266 ResourceDescriptor->ShareDisposition = CmResourceShareShared;
2267 ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
2268 }
2269 else
2270 {
2271 ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
2272 ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
2273 }
2274
2275 ResourceDescriptor->u.Interrupt.Level = (Interrupt == 2) ? PortConfig->BusInterruptLevel2 : PortConfig->BusInterruptLevel;
2276 ResourceDescriptor->u.Interrupt.Vector = (Interrupt == 2) ? PortConfig->BusInterruptVector2 : PortConfig->BusInterruptVector;
2277 ResourceDescriptor->u.Interrupt.Affinity = 0;
2278
2279 ResourceDescriptor++;
2280 Interrupt--;
2281 }
2282
2283 /* Copy DMA data */
2284 while (Dma)
2285 {
2286 ResourceDescriptor->Type = CmResourceTypeDma;
2287 ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
2288 ResourceDescriptor->u.Dma.Channel = (Dma == 2) ? PortConfig->DmaChannel2 : PortConfig->DmaChannel;
2289 ResourceDescriptor->u.Dma.Port = (Dma == 2) ? PortConfig->DmaPort2 : PortConfig->DmaPort;
2290 ResourceDescriptor->Flags = 0;
2291
2292 if (((Dma == 2) ? PortConfig->DmaWidth2 : PortConfig->DmaWidth) == Width8Bits)
2293 ResourceDescriptor->Flags |= CM_RESOURCE_DMA_8;
2294 else if (((Dma == 2) ? PortConfig->DmaWidth2 : PortConfig->DmaWidth) == Width16Bits)
2295 ResourceDescriptor->Flags |= CM_RESOURCE_DMA_16;
2296 else
2297 ResourceDescriptor->Flags |= CM_RESOURCE_DMA_32;
2298
2299 if (((Dma == 2) ? PortConfig->DmaChannel2 : PortConfig->DmaChannel) == SP_UNINITIALIZED_VALUE)
2300 ResourceDescriptor->u.Dma.Channel = 0;
2301
2302 if (((Dma == 2) ? PortConfig->DmaPort2 : PortConfig->DmaPort) == SP_UNINITIALIZED_VALUE)
2303 ResourceDescriptor->u.Dma.Port = 0;
2304
2305 ResourceDescriptor++;
2306 Dma--;
2307 }
2308
2309 return ResourceList;
2310 }
2311
2312
2313 static BOOLEAN
2314 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject,
2315 IN PDEVICE_OBJECT DeviceObject,
2316 IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
2317 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,
2318 IN PUNICODE_STRING RegistryPath,
2319 IN ULONG BusNumber,
2320 IN OUT PPCI_SLOT_NUMBER NextSlotNumber)
2321 {
2322 PCI_COMMON_CONFIG PciConfig;
2323 PCI_SLOT_NUMBER SlotNumber;
2324 ULONG DataSize;
2325 ULONG DeviceNumber;
2326 ULONG FunctionNumber;
2327 CHAR VendorIdString[8];
2328 CHAR DeviceIdString[8];
2329 UNICODE_STRING UnicodeStr;
2330 PCM_RESOURCE_LIST ResourceList = NULL;
2331 NTSTATUS Status;
2332
2333 DPRINT ("SpiGetPciConfiguration() called\n");
2334
2335 SlotNumber.u.AsULONG = 0;
2336
2337 /* Loop through all devices */
2338 for (DeviceNumber = NextSlotNumber->u.bits.DeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
2339 {
2340 SlotNumber.u.bits.DeviceNumber = DeviceNumber;
2341
2342 /* Loop through all functions */
2343 for (FunctionNumber = NextSlotNumber->u.bits.FunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
2344 {
2345 SlotNumber.u.bits.FunctionNumber = FunctionNumber;
2346
2347 /* Get PCI config bytes */
2348 DataSize = HalGetBusData(PCIConfiguration,
2349 BusNumber,
2350 SlotNumber.u.AsULONG,
2351 &PciConfig,
2352 sizeof(ULONG));
2353
2354 /* If result of HalGetBusData is 0, then the bus is wrong */
2355 if (DataSize == 0)
2356 return FALSE;
2357
2358 /* Check if result is PCI_INVALID_VENDORID or too small */
2359 if ((DataSize < sizeof(ULONG)) ||
2360 (PciConfig.VendorID == PCI_INVALID_VENDORID))
2361 {
2362 /* Continue to try the next function */
2363 continue;
2364 }
2365
2366 sprintf (VendorIdString, "%04hx", PciConfig.VendorID);
2367 sprintf (DeviceIdString, "%04hx", PciConfig.DeviceID);
2368
2369 if (_strnicmp(VendorIdString, HwInitializationData->VendorId, HwInitializationData->VendorIdLength) ||
2370 _strnicmp(DeviceIdString, HwInitializationData->DeviceId, HwInitializationData->DeviceIdLength))
2371 {
2372 /* It is not our device */
2373 continue;
2374 }
2375
2376 DPRINT("Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n",
2377 PciConfig.VendorID,
2378 PciConfig.DeviceID,
2379 BusNumber,
2380 SlotNumber.u.bits.DeviceNumber,
2381 SlotNumber.u.bits.FunctionNumber);
2382
2383
2384 RtlInitUnicodeString(&UnicodeStr, L"ScsiAdapter");
2385 Status = HalAssignSlotResources(RegistryPath,
2386 &UnicodeStr,
2387 DriverObject,
2388 DeviceObject,
2389 PCIBus,
2390 BusNumber,
2391 SlotNumber.u.AsULONG,
2392 &ResourceList);
2393
2394 if (!NT_SUCCESS(Status))
2395 break;
2396
2397 /* Create configuration information */
2398 SpiResourceToConfig(HwInitializationData,
2399 ResourceList->List,
2400 PortConfig);
2401
2402 /* Free the resource list */
2403 ExFreePool(ResourceList);
2404
2405 /* Set dev & fn numbers */
2406 NextSlotNumber->u.bits.DeviceNumber = DeviceNumber;
2407 NextSlotNumber->u.bits.FunctionNumber = FunctionNumber + 1;
2408
2409 /* Save the slot number */
2410 PortConfig->SlotNumber = SlotNumber.u.AsULONG;
2411
2412 return TRUE;
2413 }
2414 NextSlotNumber->u.bits.FunctionNumber = 0;
2415 }
2416
2417 NextSlotNumber->u.bits.DeviceNumber = 0;
2418 DPRINT ("No device found\n");
2419
2420 return FALSE;
2421 }
2422
2423
2424
2425 /**********************************************************************
2426 * NAME INTERNAL
2427 * ScsiPortCreateClose
2428 *
2429 * DESCRIPTION
2430 * Answer requests for Create/Close calls: a null operation.
2431 *
2432 * RUN LEVEL
2433 * PASSIVE_LEVEL
2434 *
2435 * ARGUMENTS
2436 * DeviceObject
2437 * Pointer to a device object.
2438 *
2439 * Irp
2440 * Pointer to an IRP.
2441 *
2442 * RETURN VALUE
2443 * Status.
2444 */
2445
2446 static NTSTATUS NTAPI
2447 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
2448 IN PIRP Irp)
2449 {
2450 DPRINT("ScsiPortCreateClose()\n");
2451
2452 Irp->IoStatus.Status = STATUS_SUCCESS;
2453 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2454
2455 return STATUS_SUCCESS;
2456 }
2457
2458 static NTSTATUS
2459 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
2460 PIRP Irp)
2461 {
2462 PSCSI_LUN_INFO LunInfo;
2463 PIO_STACK_LOCATION IrpStack;
2464 PDEVICE_OBJECT DeviceObject;
2465 PSCSI_REQUEST_BLOCK Srb;
2466 KIRQL Irql;
2467
2468 /* Get pointer to the SRB */
2469 IrpStack = IoGetCurrentIrpStackLocation(Irp);
2470 Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
2471
2472 /* Check if PathId matches number of buses */
2473 if (DeviceExtension->BusesConfig == NULL ||
2474 DeviceExtension->BusesConfig->NumberOfBuses <= Srb->PathId)
2475 {
2476 Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
2477 return STATUS_DEVICE_DOES_NOT_EXIST;
2478 }
2479
2480 /* Get pointer to LunInfo */
2481 LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Srb->PathId]->LunInfo;
2482
2483 /* Find matching LunInfo */
2484 while (LunInfo)
2485 {
2486 if (LunInfo->PathId == Srb->PathId &&
2487 LunInfo->TargetId == Srb->TargetId &&
2488 LunInfo->Lun == Srb->Lun)
2489 {
2490 break;
2491 }
2492
2493 LunInfo = LunInfo->Next;
2494 }
2495
2496 /* If we couldn't find it - exit */
2497 if (LunInfo == NULL)
2498 return STATUS_DEVICE_DOES_NOT_EXIST;
2499
2500
2501 /* Get spinlock */
2502 KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
2503
2504 /* Release, if asked */
2505 if (Srb->Function == SRB_FUNCTION_RELEASE_DEVICE)
2506 {
2507 LunInfo->DeviceClaimed = FALSE;
2508 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2509 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2510
2511 return STATUS_SUCCESS;
2512 }
2513
2514 /* Attach, if not already claimed */
2515 if (LunInfo->DeviceClaimed)
2516 {
2517 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2518 Srb->SrbStatus = SRB_STATUS_BUSY;
2519
2520 return STATUS_DEVICE_BUSY;
2521 }
2522
2523 /* Save the device object */
2524 DeviceObject = LunInfo->DeviceObject;
2525
2526 if (Srb->Function == SRB_FUNCTION_CLAIM_DEVICE)
2527 LunInfo->DeviceClaimed = TRUE;
2528
2529 if (Srb->Function == SRB_FUNCTION_ATTACH_DEVICE)
2530 LunInfo->DeviceObject = Srb->DataBuffer;
2531
2532 Srb->DataBuffer = DeviceObject;
2533
2534 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2535 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2536
2537 return STATUS_SUCCESS;
2538 }
2539
2540
2541 /**********************************************************************
2542 * NAME INTERNAL
2543 * ScsiPortDispatchScsi
2544 *
2545 * DESCRIPTION
2546 * Answer requests for SCSI calls
2547 *
2548 * RUN LEVEL
2549 * PASSIVE_LEVEL
2550 *
2551 * ARGUMENTS
2552 * Standard dispatch arguments
2553 *
2554 * RETURNS
2555 * NTSTATUS
2556 */
2557
2558 static NTSTATUS NTAPI
2559 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
2560 IN PIRP Irp)
2561 {
2562 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2563 PSCSI_PORT_LUN_EXTENSION LunExtension;
2564 PIO_STACK_LOCATION Stack;
2565 PSCSI_REQUEST_BLOCK Srb;
2566 KIRQL Irql;
2567 NTSTATUS Status = STATUS_SUCCESS;
2568 PIRP NextIrp, IrpList;
2569 PKDEVICE_QUEUE_ENTRY Entry;
2570
2571 DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n",
2572 DeviceObject, Irp);
2573
2574 DeviceExtension = DeviceObject->DeviceExtension;
2575 Stack = IoGetCurrentIrpStackLocation(Irp);
2576
2577 Srb = Stack->Parameters.Scsi.Srb;
2578 if (Srb == NULL)
2579 {
2580 DPRINT1("ScsiPortDispatchScsi() called with Srb = NULL!\n");
2581 Status = STATUS_UNSUCCESSFUL;
2582
2583 Irp->IoStatus.Status = Status;
2584 Irp->IoStatus.Information = 0;
2585
2586 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2587
2588 return(Status);
2589 }
2590
2591 DPRINT("Srb: %p\n", Srb);
2592 DPRINT("Srb->Function: %lu\n", Srb->Function);
2593 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
2594
2595 LunExtension = SpiGetLunExtension(DeviceExtension,
2596 Srb->PathId,
2597 Srb->TargetId,
2598 Srb->Lun);
2599 if (LunExtension == NULL)
2600 {
2601 DPRINT("ScsiPortDispatchScsi() called with an invalid LUN\n");
2602 Status = STATUS_NO_SUCH_DEVICE;
2603
2604 Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
2605 Irp->IoStatus.Status = Status;
2606 Irp->IoStatus.Information = 0;
2607
2608 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2609
2610 return(Status);
2611 }
2612
2613 switch (Srb->Function)
2614 {
2615 case SRB_FUNCTION_SHUTDOWN:
2616 case SRB_FUNCTION_FLUSH:
2617 DPRINT (" SRB_FUNCTION_SHUTDOWN or FLUSH\n");
2618 if (DeviceExtension->CachesData == FALSE)
2619 {
2620 /* All success here */
2621 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2622 Irp->IoStatus.Status = STATUS_SUCCESS;
2623 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2624 return STATUS_SUCCESS;
2625 }
2626 /* Fall through to a usual execute operation */
2627
2628 case SRB_FUNCTION_EXECUTE_SCSI:
2629 case SRB_FUNCTION_IO_CONTROL:
2630 DPRINT(" SRB_FUNCTION_EXECUTE_SCSI or SRB_FUNCTION_IO_CONTROL\n");
2631 /* Mark IRP as pending in all cases */
2632 IoMarkIrpPending(Irp);
2633
2634 if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
2635 {
2636 /* Start IO directly */
2637 IoStartPacket(DeviceObject, Irp, NULL, NULL);
2638 }
2639 else
2640 {
2641 KIRQL oldIrql;
2642
2643 /* We need to be at DISPATCH_LEVEL */
2644 KeRaiseIrql (DISPATCH_LEVEL, &oldIrql);
2645
2646 /* Insert IRP into the queue */
2647 if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue,
2648 &Irp->Tail.Overlay.DeviceQueueEntry,
2649 Srb->QueueSortKey))
2650 {
2651 /* It means the queue is empty, and we just start this request */
2652 IoStartPacket(DeviceObject, Irp, NULL, NULL);
2653 }
2654
2655 /* Back to the old IRQL */
2656 KeLowerIrql (oldIrql);
2657 }
2658 return STATUS_PENDING;
2659
2660 case SRB_FUNCTION_CLAIM_DEVICE:
2661 case SRB_FUNCTION_ATTACH_DEVICE:
2662 DPRINT (" SRB_FUNCTION_CLAIM_DEVICE or ATTACH\n");
2663
2664 /* Reference device object and keep the device object */
2665 Status = SpiHandleAttachRelease(DeviceExtension, Irp);
2666 break;
2667
2668 case SRB_FUNCTION_RELEASE_DEVICE:
2669 DPRINT (" SRB_FUNCTION_RELEASE_DEVICE\n");
2670
2671 /* Dereference device object and clear the device object */
2672 Status = SpiHandleAttachRelease(DeviceExtension, Irp);
2673 break;
2674
2675 case SRB_FUNCTION_RELEASE_QUEUE:
2676 DPRINT(" SRB_FUNCTION_RELEASE_QUEUE\n");
2677
2678 /* Guard with the spinlock */
2679 KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
2680
2681 if (!(LunExtension->Flags & LUNEX_FROZEN_QUEUE))
2682 {
2683 DPRINT("Queue is not frozen really\n");
2684
2685 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2686 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2687 Status = STATUS_SUCCESS;
2688 break;
2689
2690 }
2691
2692 /* Unfreeze the queue */
2693 LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
2694
2695 if (LunExtension->SrbInfo.Srb == NULL)
2696 {
2697 /* Get next logical unit request */
2698 SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
2699
2700 /* SpiGetNextRequestFromLun() releases the spinlock */
2701 KeLowerIrql(Irql);
2702 }
2703 else
2704 {
2705 DPRINT("The queue has active request\n");
2706 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2707 }
2708
2709
2710 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2711 Status = STATUS_SUCCESS;
2712 break;
2713
2714 case SRB_FUNCTION_FLUSH_QUEUE:
2715 DPRINT(" SRB_FUNCTION_FLUSH_QUEUE\n");
2716
2717 /* Guard with the spinlock */
2718 KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
2719
2720 if (!(LunExtension->Flags & LUNEX_FROZEN_QUEUE))
2721 {
2722 DPRINT("Queue is not frozen really\n");
2723
2724 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2725 Status = STATUS_INVALID_DEVICE_REQUEST;
2726 break;
2727 }
2728
2729 /* Make sure there is no active request */
2730 ASSERT(LunExtension->SrbInfo.Srb == NULL);
2731
2732 /* Compile a list from the device queue */
2733 IrpList = NULL;
2734 while ((Entry = KeRemoveDeviceQueue(&LunExtension->DeviceQueue)) != NULL)
2735 {
2736 NextIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
2737
2738 /* Get the Srb */
2739 Stack = IoGetCurrentIrpStackLocation(NextIrp);
2740 Srb = Stack->Parameters.Scsi.Srb;
2741
2742 /* Set statuse */
2743 Srb->SrbStatus = SRB_STATUS_REQUEST_FLUSHED;
2744 NextIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
2745
2746 /* Add then to the list */
2747 NextIrp->Tail.Overlay.ListEntry.Flink = (PLIST_ENTRY)IrpList;
2748 IrpList = NextIrp;
2749 }
2750
2751 /* Unfreeze the queue */
2752 LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
2753
2754 /* Release the spinlock */
2755 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2756
2757 /* Complete those requests */
2758 while (IrpList)
2759 {
2760 NextIrp = IrpList;
2761 IrpList = (PIRP)NextIrp->Tail.Overlay.ListEntry.Flink;
2762
2763 IoCompleteRequest(NextIrp, 0);
2764 }
2765
2766 Status = STATUS_SUCCESS;
2767 break;
2768
2769 default:
2770 DPRINT1("SRB function not implemented (Function %lu)\n", Srb->Function);
2771 Status = STATUS_NOT_IMPLEMENTED;
2772 break;
2773 }
2774
2775 Irp->IoStatus.Status = Status;
2776
2777 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2778
2779 return(Status);
2780 }
2781
2782
2783 /**********************************************************************
2784 * NAME INTERNAL
2785 * ScsiPortDeviceControl
2786 *
2787 * DESCRIPTION
2788 * Answer requests for device control calls
2789 *
2790 * RUN LEVEL
2791 * PASSIVE_LEVEL
2792 *
2793 * ARGUMENTS
2794 * Standard dispatch arguments
2795 *
2796 * RETURNS
2797 * NTSTATUS
2798 */
2799
2800 static NTSTATUS NTAPI
2801 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
2802 IN PIRP Irp)
2803 {
2804 PIO_STACK_LOCATION Stack;
2805 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2806 PDUMP_POINTERS DumpPointers;
2807 NTSTATUS Status;
2808
2809 DPRINT("ScsiPortDeviceControl()\n");
2810
2811 Irp->IoStatus.Information = 0;
2812
2813 Stack = IoGetCurrentIrpStackLocation(Irp);
2814 DeviceExtension = DeviceObject->DeviceExtension;
2815
2816 switch (Stack->Parameters.DeviceIoControl.IoControlCode)
2817 {
2818 case IOCTL_SCSI_GET_DUMP_POINTERS:
2819 DPRINT(" IOCTL_SCSI_GET_DUMP_POINTERS\n");
2820
2821 if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DUMP_POINTERS))
2822 {
2823 Status = STATUS_BUFFER_OVERFLOW;
2824 Irp->IoStatus.Information = sizeof(DUMP_POINTERS);
2825 break;
2826 }
2827
2828 DumpPointers = Irp->AssociatedIrp.SystemBuffer;
2829 DumpPointers->DeviceObject = DeviceObject;
2830 /* More data.. ? */
2831
2832 Status = STATUS_SUCCESS;
2833 Irp->IoStatus.Information = sizeof(DUMP_POINTERS);
2834 break;
2835
2836 case IOCTL_SCSI_GET_CAPABILITIES:
2837 DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
2838 if (Stack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(PVOID))
2839 {
2840 *((PVOID *)Irp->AssociatedIrp.SystemBuffer) = &DeviceExtension->PortCapabilities;
2841
2842 Irp->IoStatus.Information = sizeof(PVOID);
2843 Status = STATUS_SUCCESS;
2844 break;
2845 }
2846
2847 if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(IO_SCSI_CAPABILITIES))
2848 {
2849 Status = STATUS_BUFFER_TOO_SMALL;
2850 break;
2851 }
2852
2853 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
2854 &DeviceExtension->PortCapabilities,
2855 sizeof(IO_SCSI_CAPABILITIES));
2856
2857 Irp->IoStatus.Information = sizeof(IO_SCSI_CAPABILITIES);
2858 Status = STATUS_SUCCESS;
2859 break;
2860
2861 case IOCTL_SCSI_GET_INQUIRY_DATA:
2862 DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
2863
2864 /* Copy inquiry data to the port device extension */
2865 Status = SpiGetInquiryData(DeviceExtension, Irp);
2866 break;
2867
2868 case IOCTL_SCSI_MINIPORT:
2869 DPRINT1("IOCTL_SCSI_MINIPORT unimplemented!\n");
2870 Status = STATUS_NOT_IMPLEMENTED;
2871 break;
2872
2873 case IOCTL_SCSI_PASS_THROUGH:
2874 DPRINT1("IOCTL_SCSI_PASS_THROUGH unimplemented!\n");
2875 Status = STATUS_NOT_IMPLEMENTED;
2876 break;
2877
2878 default:
2879 if (DEVICE_TYPE_FROM_CTL_CODE(Stack->Parameters.DeviceIoControl.IoControlCode) == MOUNTDEVCONTROLTYPE)
2880 {
2881 switch (Stack->Parameters.DeviceIoControl.IoControlCode)
2882 {
2883 case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME:
2884 DPRINT1("Got unexpected IOCTL_MOUNTDEV_QUERY_DEVICE_NAME\n");
2885 break;
2886 case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID:
2887 DPRINT1("Got unexpected IOCTL_MOUNTDEV_QUERY_UNIQUE_ID\n");
2888 break;
2889 default:
2890 DPRINT1(" got ioctl intended for the mount manager: 0x%lX\n", Stack->Parameters.DeviceIoControl.IoControlCode);
2891 break;
2892 }
2893 } else {
2894 DPRINT1(" unknown ioctl code: 0x%lX\n", Stack->Parameters.DeviceIoControl.IoControlCode);
2895 }
2896 Status = STATUS_NOT_IMPLEMENTED;
2897 break;
2898 }
2899
2900 /* Complete the request with the given status */
2901 Irp->IoStatus.Status = Status;
2902 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2903
2904 return Status;
2905 }
2906
2907
2908 static VOID NTAPI
2909 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
2910 IN PIRP Irp)
2911 {
2912 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2913 PSCSI_PORT_LUN_EXTENSION LunExtension;
2914 PIO_STACK_LOCATION IrpStack;
2915 PSCSI_REQUEST_BLOCK Srb;
2916 PSCSI_REQUEST_BLOCK_INFO SrbInfo;
2917 LONG CounterResult;
2918 NTSTATUS Status;
2919
2920 DPRINT("ScsiPortStartIo() called!\n");
2921
2922 DeviceExtension = DeviceObject->DeviceExtension;
2923 IrpStack = IoGetCurrentIrpStackLocation(Irp);
2924
2925 DPRINT("DeviceExtension %p\n", DeviceExtension);
2926
2927 Srb = IrpStack->Parameters.Scsi.Srb;
2928
2929 /* Apply "default" flags */
2930 Srb->SrbFlags |= DeviceExtension->SrbFlags;
2931
2932 /* Get LUN extension */
2933 LunExtension = SpiGetLunExtension(DeviceExtension,
2934 Srb->PathId,
2935 Srb->TargetId,
2936 Srb->Lun);
2937
2938 if (DeviceExtension->NeedSrbDataAlloc ||
2939 DeviceExtension->NeedSrbExtensionAlloc)
2940 {
2941 /* Allocate them */
2942 SrbInfo = SpiAllocateSrbStructures(DeviceExtension,
2943 LunExtension,
2944 Srb);
2945
2946 /* Couldn't alloc one or both data structures, return */
2947 if (SrbInfo == NULL)
2948 {
2949 /* We have to call IoStartNextPacket, because this request
2950 was not started */
2951 if (LunExtension->Flags & LUNEX_REQUEST_PENDING)
2952 IoStartNextPacket(DeviceObject, FALSE);
2953
2954 return;
2955 }
2956 }
2957 else
2958 {
2959 /* No allocations are needed */
2960 SrbInfo = &LunExtension->SrbInfo;
2961 Srb->SrbExtension = NULL;
2962 Srb->QueueTag = SP_UNTAGGED;
2963 }
2964
2965 /* Increase sequence number of SRB */
2966 if (!SrbInfo->SequenceNumber)
2967 {
2968 /* Increase global sequence number */
2969 DeviceExtension->SequenceNumber++;
2970
2971 /* Assign it */
2972 SrbInfo->SequenceNumber = DeviceExtension->SequenceNumber;
2973 }
2974
2975 /* Check some special SRBs */
2976 if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
2977 {
2978 /* Some special handling */
2979 DPRINT1("Abort command! Unimplemented now\n");
2980 }
2981 else
2982 {
2983 SrbInfo->Srb = Srb;
2984 }
2985
2986 if (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION)
2987 {
2988 // Store the MDL virtual address in SrbInfo structure
2989 SrbInfo->DataOffset = MmGetMdlVirtualAddress(Irp->MdlAddress);
2990
2991 if (DeviceExtension->MapBuffers)
2992 {
2993 /* Calculate offset within DataBuffer */
2994 SrbInfo->DataOffset = MmGetSystemAddressForMdl(Irp->MdlAddress);
2995 Srb->DataBuffer = SrbInfo->DataOffset +
2996 (ULONG)((PUCHAR)Srb->DataBuffer -
2997 (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress));
2998 }
2999
3000 if (DeviceExtension->AdapterObject)
3001 {
3002 /* Flush buffers */
3003 KeFlushIoBuffers(Irp->MdlAddress,
3004 Srb->SrbFlags & SRB_FLAGS_DATA_IN ? TRUE : FALSE,
3005 TRUE);
3006 }
3007
3008 if (DeviceExtension->MapRegisters)
3009 {
3010 /* Calculate number of needed map registers */
3011 SrbInfo->NumberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
3012 Srb->DataBuffer,
3013 Srb->DataTransferLength);
3014
3015 /* Allocate adapter channel */
3016 Status = IoAllocateAdapterChannel(DeviceExtension->AdapterObject,
3017 DeviceExtension->DeviceObject,
3018 SrbInfo->NumberOfMapRegisters,
3019 SpiAdapterControl,
3020 SrbInfo);
3021
3022 if (!NT_SUCCESS(Status))
3023 {
3024 DPRINT1("IoAllocateAdapterChannel() failed!\n");
3025
3026 Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
3027 ScsiPortNotification(RequestComplete,
3028 DeviceExtension + 1,
3029 Srb);
3030
3031 ScsiPortNotification(NextRequest,
3032 DeviceExtension + 1);
3033
3034 /* Request DPC for that work */
3035 IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
3036 }
3037
3038 /* Control goes to SpiAdapterControl */
3039 return;
3040 }
3041 }
3042
3043 /* Increase active request counter */
3044 CounterResult = InterlockedIncrement(&DeviceExtension->ActiveRequestCounter);
3045
3046 if (CounterResult == 0 &&
3047 DeviceExtension->AdapterObject != NULL &&
3048 !DeviceExtension->MapRegisters)
3049 {
3050 IoAllocateAdapterChannel(
3051 DeviceExtension->AdapterObject,
3052 DeviceObject,
3053 DeviceExtension->PortCapabilities.MaximumPhysicalPages,
3054 ScsiPortAllocateAdapterChannel,
3055 LunExtension
3056 );
3057
3058 return;
3059 }
3060
3061 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
3062
3063 if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0],
3064 ScsiPortStartPacket,
3065 DeviceObject))
3066 {
3067 DPRINT("Synchronization failed!\n");
3068
3069 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
3070 Irp->IoStatus.Information = 0;
3071 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3072
3073 IoCompleteRequest(Irp, IO_NO_INCREMENT);
3074 }
3075 else
3076 {
3077 /* Release the spinlock only */
3078 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3079 }
3080
3081
3082 DPRINT("ScsiPortStartIo() done\n");
3083 }
3084
3085
3086 static BOOLEAN NTAPI
3087 ScsiPortStartPacket(IN OUT PVOID Context)
3088 {
3089 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
3090 PIO_STACK_LOCATION IrpStack;
3091 PSCSI_REQUEST_BLOCK Srb;
3092 PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)Context;
3093 PSCSI_PORT_LUN_EXTENSION LunExtension;
3094 PSCSI_REQUEST_BLOCK_INFO SrbInfo;
3095 BOOLEAN Result;
3096 BOOLEAN StartTimer;
3097
3098 DPRINT("ScsiPortStartPacket() called\n");
3099
3100 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
3101
3102 IrpStack = IoGetCurrentIrpStackLocation(DeviceObject->CurrentIrp);
3103 Srb = IrpStack->Parameters.Scsi.Srb;
3104
3105 /* Get LUN extension */
3106 LunExtension = SpiGetLunExtension(DeviceExtension,
3107 Srb->PathId,
3108 Srb->TargetId,
3109 Srb->Lun);
3110
3111 /* Check if we are in a reset state */
3112 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET)
3113 {
3114 /* Mark the we've got requests while being in the reset state */
3115 DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET_REQUEST;
3116 return TRUE;
3117 }
3118
3119 /* Set the time out value */
3120 DeviceExtension->TimerCount = Srb->TimeOutValue;
3121
3122 /* We are busy */
3123 DeviceExtension->Flags |= SCSI_PORT_DEVICE_BUSY;
3124
3125 if (LunExtension->RequestTimeout != -1)
3126 {
3127 /* Timer already active */
3128 StartTimer = FALSE;
3129 }
3130 else
3131 {
3132 /* It hasn't been initialized yet */
3133 LunExtension->RequestTimeout = Srb->TimeOutValue;
3134 StartTimer = TRUE;
3135 }
3136
3137 if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
3138 {
3139 /* Handle bypass-requests */
3140
3141 /* Is this an abort request? */
3142 if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
3143 {
3144 /* Get pointer to SRB info structure */
3145 SrbInfo = SpiGetSrbData(DeviceExtension,
3146 Srb->PathId,
3147 Srb->TargetId,
3148 Srb->Lun,
3149 Srb->QueueTag);
3150
3151 /* Check if the request is still "active" */
3152 if (SrbInfo == NULL ||
3153 SrbInfo->Srb == NULL ||
3154 !(SrbInfo->Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE))
3155 {
3156 /* It's not, mark it as active then */
3157 Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
3158
3159 if (StartTimer)
3160 LunExtension->RequestTimeout = -1;
3161
3162 DPRINT("Request has been already completed, but abort request came\n");
3163 Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
3164
3165 /* Notify about request complete */
3166 ScsiPortNotification(RequestComplete,
3167 DeviceExtension->MiniPortDeviceExtension,
3168 Srb);
3169
3170 /* and about readiness for the next request */
3171 ScsiPortNotification(NextRequest,
3172 DeviceExtension->MiniPortDeviceExtension);
3173
3174 /* They might ask for some work, so queue the DPC for them */
3175 IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
3176
3177 /* We're done in this branch */
3178 return TRUE;
3179 }
3180 }
3181 else
3182 {
3183 /* Add number of queued requests */
3184 LunExtension->QueueCount++;
3185 }
3186
3187 /* Bypass requests don't need request sense */
3188 LunExtension->Flags &= ~LUNEX_NEED_REQUEST_SENSE;
3189
3190 /* Is disconnect disabled for this request? */
3191 if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
3192 {
3193 /* Set the corresponding flag */
3194 DeviceExtension->Flags &= ~SCSI_PORT_DISCONNECT_ALLOWED;
3195 }
3196
3197 /* Transfer timeout value from Srb to Lun */
3198 LunExtension->RequestTimeout = Srb->TimeOutValue;
3199 }
3200 else
3201 {
3202 if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
3203 {
3204 /* It's a disconnect, so no more requests can go */
3205 DeviceExtension->Flags &= ~SCSI_PORT_DISCONNECT_ALLOWED;
3206 }
3207
3208 LunExtension->Flags |= SCSI_PORT_LU_ACTIVE;
3209
3210 /* Increment queue count */
3211 LunExtension->QueueCount++;
3212
3213 /* If it's tagged - special thing */
3214 if (Srb->QueueTag != SP_UNTAGGED)
3215 {
3216 SrbInfo = &DeviceExtension->SrbInfo[Srb->QueueTag - 1];
3217
3218 /* Chek for consistency */
3219 ASSERT(SrbInfo->Requests.Blink == NULL);
3220
3221 /* Insert it into the list of requests */
3222 InsertTailList(&LunExtension->SrbInfo.Requests, &SrbInfo->Requests);
3223 }
3224 }
3225
3226 /* Mark this Srb active */
3227 Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
3228
3229 /* Call HwStartIo routine */
3230 Result = DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
3231 Srb);
3232
3233 /* If notification is needed, then request a DPC */
3234 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
3235 IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
3236
3237 return Result;
3238 }
3239
3240 IO_ALLOCATION_ACTION
3241 NTAPI
3242 SpiAdapterControl(PDEVICE_OBJECT DeviceObject,
3243 PIRP Irp,
3244 PVOID MapRegisterBase,
3245 PVOID Context)
3246 {
3247 PSCSI_REQUEST_BLOCK Srb;
3248 PSCSI_SG_ADDRESS ScatterGatherList;
3249 KIRQL CurrentIrql;
3250 PIO_STACK_LOCATION IrpStack;
3251 ULONG TotalLength = 0;
3252 PSCSI_REQUEST_BLOCK_INFO SrbInfo;
3253 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
3254 PUCHAR DataVA;
3255 BOOLEAN WriteToDevice;
3256
3257 /* Get pointers to SrbInfo and DeviceExtension */
3258 SrbInfo = (PSCSI_REQUEST_BLOCK_INFO)Context;
3259 DeviceExtension = DeviceObject->DeviceExtension;
3260
3261 /* Get pointer to SRB */
3262 IrpStack = IoGetCurrentIrpStackLocation(Irp);
3263 Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
3264
3265 /* Depending on the map registers number, we allocate
3266 either from NonPagedPool, or from our static list */
3267 if (SrbInfo->NumberOfMapRegisters > MAX_SG_LIST)
3268 {
3269 SrbInfo->ScatterGather = ExAllocatePoolWithTag(
3270 NonPagedPool, SrbInfo->NumberOfMapRegisters * sizeof(SCSI_SG_ADDRESS), TAG_SCSIPORT);
3271
3272 if (SrbInfo->ScatterGather == NULL)
3273 ASSERT(FALSE);
3274
3275 Srb->SrbFlags |= SRB_FLAGS_SGLIST_FROM_POOL;
3276 }
3277 else
3278 {
3279 SrbInfo->ScatterGather = SrbInfo->ScatterGatherList;
3280 }
3281
3282 /* Use chosen SG list source */
3283 ScatterGatherList = SrbInfo->ScatterGather;
3284
3285 /* Save map registers base */
3286 SrbInfo->BaseOfMapRegister = MapRegisterBase;
3287
3288 /* Determine WriteToDevice flag */
3289 WriteToDevice = Srb->SrbFlags & SRB_FLAGS_DATA_OUT ? TRUE : FALSE;
3290
3291 /* Get virtual address of the data buffer */
3292 DataVA = (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress) +
3293 ((PCHAR)Srb->DataBuffer - SrbInfo->DataOffset);
3294
3295 /* Build the actual SG list */
3296 while (TotalLength < Srb->DataTransferLength)
3297 {
3298 if (!ScatterGatherList)
3299 break;
3300
3301 ScatterGatherList->Length = Srb->DataTransferLength - TotalLength;
3302 ScatterGatherList->PhysicalAddress = IoMapTransfer(DeviceExtension->AdapterObject,
3303 Irp->MdlAddress,
3304 MapRegisterBase,
3305 DataVA + TotalLength,
3306 &ScatterGatherList->Length,
3307 WriteToDevice);
3308
3309 TotalLength += ScatterGatherList->Length;
3310 ScatterGatherList++;
3311 }
3312
3313 /* Schedule an active request */
3314 InterlockedIncrement(&DeviceExtension->ActiveRequestCounter );
3315 KeAcquireSpinLock(&DeviceExtension->SpinLock, &CurrentIrql);
3316 KeSynchronizeExecution(DeviceExtension->Interrupt[0],
3317 ScsiPortStartPacket,
3318 DeviceObject);
3319 KeReleaseSpinLock(&DeviceExtension->SpinLock, CurrentIrql);
3320
3321 return DeallocateObjectKeepRegisters;
3322 }
3323
3324 static PSCSI_PORT_LUN_EXTENSION
3325 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
3326 {
3327 PSCSI_PORT_LUN_EXTENSION LunExtension;
3328 ULONG LunExtensionSize;
3329
3330 DPRINT("SpiAllocateLunExtension (%p)\n",
3331 DeviceExtension);
3332
3333 /* Round LunExtensionSize first to the sizeof LONGLONG */
3334 LunExtensionSize = (DeviceExtension->LunExtensionSize +
3335 sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1);
3336
3337 LunExtensionSize += sizeof(SCSI_PORT_LUN_EXTENSION);
3338 DPRINT("LunExtensionSize %lu\n", LunExtensionSize);
3339
3340 LunExtension = ExAllocatePoolWithTag(NonPagedPool, LunExtensionSize, TAG_SCSIPORT);
3341 if (LunExtension == NULL)
3342 {
3343 DPRINT1("Out of resources!\n");
3344 return NULL;
3345 }
3346
3347 /* Zero everything */
3348 RtlZeroMemory(LunExtension, LunExtensionSize);
3349
3350 /* Initialize a list of requests */
3351 InitializeListHead(&LunExtension->SrbInfo.Requests);
3352
3353 /* Initialize timeout counter */
3354 LunExtension->RequestTimeout = -1;
3355
3356 /* Set maximum queue size */
3357 LunExtension->MaxQueueCount = 256;
3358
3359 /* Initialize request queue */
3360 KeInitializeDeviceQueue (&LunExtension->DeviceQueue);
3361
3362 return LunExtension;
3363 }
3364
3365 static PSCSI_PORT_LUN_EXTENSION
3366 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
3367 IN UCHAR PathId,
3368 IN UCHAR TargetId,
3369 IN UCHAR Lun)
3370 {
3371 PSCSI_PORT_LUN_EXTENSION LunExtension;
3372
3373 DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
3374 DeviceExtension, PathId, TargetId, Lun);
3375
3376 /* Get appropriate list */
3377 LunExtension = DeviceExtension->LunExtensionList[(TargetId + Lun) % LUS_NUMBER];
3378
3379 /* Iterate it until we find what we need */
3380 while (LunExtension)
3381 {
3382 if (LunExtension->TargetId == TargetId &&
3383 LunExtension->Lun == Lun &&
3384 LunExtension->PathId == PathId)
3385 {
3386 /* All matches, return */
3387 return LunExtension;
3388 }
3389
3390 /* Advance to the next item */
3391 LunExtension = LunExtension->Next;
3392 }
3393
3394 /* We did not find anything */
3395 DPRINT("Nothing found\n");
3396 return NULL;
3397 }
3398
3399 static PSCSI_REQUEST_BLOCK_INFO
3400 SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
3401 PSCSI_PORT_LUN_EXTENSION LunExtension,
3402 PSCSI_REQUEST_BLOCK Srb)
3403 {
3404 PCHAR SrbExtension;
3405 PSCSI_REQUEST_BLOCK_INFO SrbInfo;
3406
3407 /* Spinlock must be held while this function executes */
3408 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
3409
3410 /* Allocate SRB data structure */
3411 if (DeviceExtension->NeedSrbDataAlloc)
3412 {
3413 /* Treat the abort request in a special way */
3414 if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
3415 {
3416 SrbInfo = SpiGetSrbData(DeviceExtension,
3417 Srb->PathId,
3418 Srb->TargetId,
3419 Srb->Lun,
3420 Srb->QueueTag);
3421 }
3422 else if (Srb->SrbFlags &
3423 (SRB_FLAGS_QUEUE_ACTION_ENABLE | SRB_FLAGS_NO_QUEUE_FREEZE) &&
3424 !(Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
3425 )
3426 {
3427 /* Do not process tagged commands if need request sense is set */
3428 if (LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE)
3429 {
3430 ASSERT(!(LunExtension->Flags & LUNEX_REQUEST_PENDING));
3431
3432 LunExtension->PendingRequest = Srb->OriginalRequest;
3433 LunExtension->Flags |= LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE;
3434
3435 /* Release the spinlock and return */
3436 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3437 return NULL;
3438 }
3439
3440 ASSERT(LunExtension->SrbInfo.Srb == NULL);
3441 SrbInfo = DeviceExtension->FreeSrbInfo;
3442
3443 if (SrbInfo == NULL)
3444 {
3445 /* No SRB structures left in the list. We have to leave
3446 and wait while we are called again */
3447
3448 DeviceExtension->Flags |= SCSI_PORT_REQUEST_PENDING;
3449 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3450 return NULL;
3451 }
3452
3453 DeviceExtension->FreeSrbInfo = (PSCSI_REQUEST_BLOCK_INFO)SrbInfo->Requests.Flink;
3454
3455 /* QueueTag must never be 0, so +1 to it */
3456 Srb->QueueTag = (UCHAR)(SrbInfo - DeviceExtension->SrbInfo) + 1;
3457 }
3458 else
3459 {
3460 /* Usual untagged command */
3461 if (
3462 (!IsListEmpty(&LunExtension->SrbInfo.Requests) ||
3463 LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE) &&
3464 !(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
3465 )
3466 {
3467 /* Mark it as pending and leave */
3468 ASSERT(!(LunExtension->Flags & LUNEX_REQUEST_PENDING));
3469 LunExtension->Flags |= LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE;
3470 LunExtension->PendingRequest = Srb->OriginalRequest;
3471
3472 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3473 return(NULL);
3474 }
3475
3476 Srb->QueueTag = SP_UNTAGGED;
3477 SrbInfo = &LunExtension->SrbInfo;
3478 }
3479 }
3480 else
3481 {
3482 Srb->QueueTag = SP_UNTAGGED;
3483 SrbInfo = &LunExtension->SrbInfo;
3484 }
3485
3486 /* Allocate SRB extension structure */
3487 if (DeviceExtension->NeedSrbExtensionAlloc)
3488 {
3489 /* Check the list of free extensions */
3490 SrbExtension = DeviceExtension->FreeSrbExtensions;
3491
3492 /* If no free extensions... */
3493 if (SrbExtension == NULL)
3494 {
3495 /* Free SRB data */
3496 if (Srb->Function != SRB_FUNCTION_ABORT_COMMAND &&
3497 Srb->QueueTag != SP_UNTAGGED)
3498 {
3499 SrbInfo->Requests.Blink = NULL;
3500 SrbInfo->Requests.Flink = (PLIST_ENTRY)DeviceExtension->FreeSrbInfo;
3501 DeviceExtension->FreeSrbInfo = SrbInfo;
3502 }
3503
3504 /* Return, in order to be called again later */
3505 DeviceExtension->Flags |= SCSI_PORT_REQUEST_PENDING;
3506 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3507 return NULL;
3508 }
3509
3510 /* Remove that free SRB extension from the list (since
3511 we're going to use it) */
3512 DeviceExtension->FreeSrbExtensions = *((PVOID *)SrbExtension);
3513
3514 /* Spinlock can be released now */
3515 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3516
3517 Srb->SrbExtension = SrbExtension;
3518
3519 if (Srb->SenseInfoBuffer != NULL &&
3520 DeviceExtension->SupportsAutoSense)
3521 {
3522 /* Store pointer to the SenseInfo buffer */
3523 SrbInfo->SaveSenseRequest = Srb->SenseInfoBuffer;
3524
3525 /* Does data fit the buffer? */
3526 if (Srb->SenseInfoBufferLength > sizeof(SENSE_DATA))
3527 {
3528 /* No, disabling autosense at all */
3529 Srb->SrbFlags |= SRB_FLAGS_DISABLE_AUTOSENSE;
3530 }
3531 else
3532 {
3533 /* Yes, update the buffer pointer */
3534 Srb->SenseInfoBuffer = SrbExtension + DeviceExtension->SrbExtensionSize;
3535 }
3536 }
3537 }
3538 else
3539 {
3540 /* Cleanup... */
3541 Srb->SrbExtension = NULL;
3542 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3543 }
3544
3545 return SrbInfo;
3546 }
3547
3548
3549 static NTSTATUS
3550 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject,
3551 IN PSCSI_LUN_INFO LunInfo)
3552 {
3553 IO_STATUS_BLOCK IoStatusBlock;
3554 PIO_STACK_LOCATION IrpStack;
3555 KEVENT Event;
3556 KIRQL Irql;
3557 PIRP Irp;
3558 NTSTATUS Status;
3559 PINQUIRYDATA InquiryBuffer;
3560 PSENSE_DATA SenseBuffer;
3561 BOOLEAN KeepTrying = TRUE;
3562 ULONG RetryCount = 0;
3563 SCSI_REQUEST_BLOCK Srb;
3564 PCDB Cdb;
3565 PSCSI_PORT_LUN_EXTENSION LunExtension;
3566 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
3567
3568 DPRINT("SpiSendInquiry() called\n");
3569
3570 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
3571
3572 InquiryBuffer = ExAllocatePoolWithTag(NonPagedPool, INQUIRYDATABUFFERSIZE, TAG_SCSIPORT);
3573 if (InquiryBuffer == NULL)
3574 return STATUS_INSUFFICIENT_RESOURCES;
3575
3576 SenseBuffer = ExAllocatePoolWithTag(NonPagedPool, SENSE_BUFFER_SIZE, TAG_SCSIPORT);
3577 if (SenseBuffer == NULL)
3578 {
3579 ExFreePoolWithTag(InquiryBuffer, TAG_SCSIPORT);
3580 return STATUS_INSUFFICIENT_RESOURCES;
3581 }
3582
3583 while (KeepTrying)
3584 {
3585 /* Initialize event for waiting */
3586 KeInitializeEvent(&Event,
3587 NotificationEvent,
3588 FALSE);
3589
3590 /* Create an IRP */
3591 Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_IN,
3592 DeviceObject,
3593 NULL,
3594 0,
3595 InquiryBuffer,
3596 INQUIRYDATABUFFERSIZE,
3597 TRUE,
3598 &Event,
3599 &IoStatusBlock);
3600 if (Irp == NULL)
3601 {
3602 DPRINT("IoBuildDeviceIoControlRequest() failed\n");
3603
3604 /* Quit the loop */
3605 Status = STATUS_INSUFFICIENT_RESOURCES;
3606 KeepTrying = FALSE;
3607 continue;
3608 }
3609
3610 /* Prepare SRB */
3611 RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
3612
3613 Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
3614 Srb.OriginalRequest = Irp;
3615 Srb.PathId = LunInfo->PathId;
3616 Srb.TargetId = LunInfo->TargetId;
3617 Srb.Lun = LunInfo->Lun;
3618 Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
3619 Srb.SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
3620 Srb.TimeOutValue = 4;
3621 Srb.CdbLength = 6;
3622
3623 Srb.SenseInfoBuffer = SenseBuffer;
3624 Srb.SenseInfoBufferLength = SENSE_BUFFER_SIZE;
3625
3626 Srb.DataBuffer = InquiryBuffer;
3627 Srb.DataTransferLength = INQUIRYDATABUFFERSIZE;
3628
3629 /* Attach Srb to the Irp */
3630 IrpStack = IoGetNextIrpStackLocation (Irp);
3631 IrpStack->Parameters.Scsi.Srb = &Srb;
3632
3633 /* Fill in CDB */
3634 Cdb = (PCDB)Srb.Cdb;
3635 Cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
3636 Cdb->CDB6INQUIRY.LogicalUnitNumber = LunInfo->Lun;
3637 Cdb->CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE;
3638
3639 /* Call the driver */
3640 Status = IoCallDriver(DeviceObject, Irp);
3641
3642 /* Wait for it to complete */
3643 if (Status == STATUS_PENDING)
3644 {
3645 DPRINT("SpiSendInquiry(): Waiting for the driver to process request...\n");
3646 KeWaitForSingleObject(&Event,
3647 Executive,
3648 KernelMode,
3649 FALSE,
3650 NULL);
3651 Status = IoStatusBlock.Status;
3652 }
3653
3654 DPRINT("SpiSendInquiry(): Request processed by driver, status = 0x%08X\n", Status);
3655
3656 if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_SUCCESS)
3657 {
3658 /* All fine, copy data over */
3659 RtlCopyMemory(LunInfo->InquiryData,
3660 InquiryBuffer,
3661 INQUIRYDATABUFFERSIZE);
3662
3663 /* Quit the loop */
3664 Status = STATUS_SUCCESS;
3665 KeepTrying = FALSE;
3666 continue;
3667 }
3668
3669 DPRINT("Inquiry SRB failed with SrbStatus 0x%08X\n", Srb.SrbStatus);
3670
3671 /* Check if the queue is frozen */
3672 if (Srb.SrbStatus & SRB_STATUS_QUEUE_FROZEN)
3673 {
3674 /* Something weird happened, deal with it (unfreeze the queue) */
3675 KeepTrying = FALSE;
3676
3677 DPRINT("SpiSendInquiry(): the queue is frozen at TargetId %d\n", Srb.TargetId);
3678
3679 LunExtension = SpiGetLunExtension(DeviceExtension,
3680 LunInfo->PathId,
3681 LunInfo->TargetId,
3682 LunInfo->Lun);
3683
3684 /* Clear frozen flag */
3685 LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
3686
3687 /* Acquire the spinlock */
3688 KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
3689
3690 /* Process the request */
3691 SpiGetNextRequestFromLun(DeviceObject->DeviceExtension, LunExtension);
3692
3693 /* SpiGetNextRequestFromLun() releases the spinlock,
3694 so we just lower irql back to what it was before */
3695 KeLowerIrql(Irql);
3696 }
3697
3698 /* Check if data overrun happened */
3699 if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN)
3700 {
3701 DPRINT("Data overrun at TargetId %d\n", LunInfo->TargetId);
3702
3703 /* Nothing dramatic, just copy data, but limiting the size */
3704 RtlCopyMemory(LunInfo->InquiryData,
3705 InquiryBuffer,
3706 (Srb.DataTransferLength > INQUIRYDATABUFFERSIZE) ?
3707 INQUIRYDATABUFFERSIZE : Srb.DataTransferLength);
3708
3709 /* Quit the loop */
3710 Status = STATUS_SUCCESS;
3711 KeepTrying = FALSE;
3712 }
3713 else if ((Srb.SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
3714 SenseBuffer->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST)
3715 {
3716 /* LUN is not valid, but some device responds there.
3717 Mark it as invalid anyway */
3718
3719 /* Quit the loop */
3720 Status = STATUS_INVALID_DEVICE_REQUEST;
3721 KeepTrying = FALSE;
3722 }
3723 else
3724 {
3725 /* Retry a couple of times if no timeout happened */
3726 if ((RetryCount < 2) &&
3727 (SRB_STATUS(Srb.SrbStatus) != SRB_STATUS_NO_DEVICE) &&
3728 (SRB_STATUS(Srb.SrbStatus) != SRB_STATUS_SELECTION_TIMEOUT))
3729 {
3730 RetryCount++;
3731 KeepTrying = TRUE;
3732 }
3733 else
3734 {
3735 /* That's all, quit the loop */
3736 KeepTrying = FALSE;
3737
3738 /* Set status according to SRB status */
3739 if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_BAD_FUNCTION ||
3740 SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_BAD_SRB_BLOCK_LENGTH)
3741 {
3742 Status = STATUS_INVALID_DEVICE_REQUEST;
3743 }
3744 else
3745 {
3746 Status = STATUS_IO_DEVICE_ERROR;
3747 }
3748 }
3749 }
3750 }
3751
3752 /* Free buffers */
3753 ExFreePoolWithTag(InquiryBuffer, TAG_SCSIPORT);
3754 ExFreePoolWithTag(SenseBuffer, TAG_SCSIPORT);
3755
3756 DPRINT("SpiSendInquiry() done with Status 0x%08X\n", Status);
3757
3758 return Status;
3759 }
3760
3761
3762 /* Scans all SCSI buses */
3763 static VOID
3764 SpiScanAdapter(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
3765 {
3766 PSCSI_PORT_LUN_EXTENSION LunExtension;
3767 ULONG Bus;
3768 ULONG Target;
3769 ULONG Lun;
3770 PSCSI_BUS_SCAN_INFO BusScanInfo;
3771 PSCSI_LUN_INFO LastLunInfo, LunInfo, LunInfoExists;
3772 BOOLEAN DeviceExists;
3773 ULONG Hint;
3774 NTSTATUS Status;
3775 ULONG DevicesFound;
3776
3777 DPRINT("SpiScanAdapter() called\n");
3778
3779 /* Scan all buses */
3780 for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
3781 {
3782 DPRINT(" Scanning bus %d\n", Bus);
3783 DevicesFound = 0;
3784
3785 /* Get pointer to the scan information */
3786 BusScanInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus];
3787
3788 if (BusScanInfo)
3789 {
3790 /* Find the last LUN info in the list */
3791 LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
3792 LastLunInfo = LunInfo;
3793
3794 while (LunInfo != NULL)
3795 {
3796 LastLunInfo = LunInfo;
3797 LunInfo = LunInfo->Next;
3798 }
3799 }
3800 else
3801 {
3802 /* We need to allocate this buffer */
3803 BusScanInfo = ExAllocatePoolWithTag(NonPagedPool, sizeof(SCSI_BUS_SCAN_INFO), TAG_SCSIPORT);
3804
3805 if (!BusScanInfo)
3806 {
3807 DPRINT1("Out of resources!\n");
3808 return;
3809 }
3810
3811 /* Store the pointer in the BusScanInfo array */
3812 DeviceExtension->BusesConfig->BusScanInfo[Bus] = BusScanInfo;
3813
3814 /* Fill this struct (length and bus ids for now) */
3815 BusScanInfo->Length = sizeof(SCSI_BUS_SCAN_INFO);
3816 BusScanInfo->LogicalUnitsCount = 0;
3817 BusScanInfo->BusIdentifier = DeviceExtension->PortConfig->InitiatorBusId[Bus];
3818 BusScanInfo->LunInfo = NULL;
3819
3820 /* Set pointer to the last LUN info to NULL */
3821 LastLunInfo = NULL;
3822 }
3823
3824 /* Create LUN information structure */
3825 LunInfo = ExAllocatePoolWithTag(PagedPool, sizeof(SCSI_LUN_INFO), TAG_SCSIPORT);
3826
3827 if (LunInfo == NULL)
3828 {
3829 DPRINT1("Out of resources!\n");
3830 return;
3831 }
3832
3833 RtlZeroMemory(LunInfo, sizeof(SCSI_LUN_INFO));
3834
3835 /* Create LunExtension */
3836 LunExtension = SpiAllocateLunExtension (DeviceExtension);
3837
3838 /* And send INQUIRY to every target */
3839 for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
3840 {
3841 /* TODO: Support scan bottom-up */
3842
3843 /* Skip if it's the same address */
3844 if (Target == BusScanInfo->BusIdentifier)
3845 continue;
3846
3847 /* Try to find an existing device here */
3848 DeviceExists = FALSE;
3849 LunInfoExists = BusScanInfo->LunInfo;
3850
3851 /* Find matching address on this bus */
3852 while (LunInfoExists)
3853 {
3854 if (LunInfoExists->TargetId == Target)
3855 {
3856 DeviceExists = TRUE;
3857 break;
3858 }
3859
3860 /* Advance to the next one */
3861 LunInfoExists = LunInfoExists->Next;
3862 }
3863
3864 /* No need to bother rescanning, since we already did that before */
3865 if (DeviceExists)
3866 continue;
3867
3868 /* Scan all logical units */
3869 for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
3870 {
3871 if ((!LunExtension) || (!LunInfo))
3872 break;
3873
3874 /* Add extension to the list */
3875 Hint = (Target + Lun) % LUS_NUMBER;
3876 LunExtension->Next = DeviceExtension->LunExtensionList[Hint];
3877 DeviceExtension->LunExtensionList[Hint] = LunExtension;
3878
3879 /* Fill Path, Target, Lun fields */
3880 LunExtension->PathId = LunInfo->PathId = (UCHAR)Bus;
3881 LunExtension->TargetId = LunInfo->TargetId = (UCHAR) Target;
3882 LunExtension->Lun = LunInfo->Lun = (UCHAR)Lun;
3883
3884 /* Set flag to prevent race conditions */
3885 LunExtension->Flags |= SCSI_PORT_SCAN_IN_PROGRESS;
3886
3887 /* Zero LU extension contents */
3888 if (DeviceExtension->LunExtensionSize)
3889 {
3890 RtlZeroMemory(LunExtension + 1,
3891 DeviceExtension->LunExtensionSize);
3892 }
3893
3894 /* Finally send the inquiry command */
3895 Status = SpiSendInquiry(DeviceExtension->DeviceObject, LunInfo);
3896
3897 if (NT_SUCCESS(Status))
3898 {
3899 /* Let's see if we really found a device */
3900 PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData;
3901
3902 /* Check if this device is unsupported */
3903 if (InquiryData->DeviceTypeQualifier == DEVICE_QUALIFIER_NOT_SUPPORTED)
3904 {
3905 DeviceExtension->LunExtensionList[Hint] =
3906 DeviceExtension->LunExtensionList[Hint]->Next;
3907
3908 continue;
3909 }
3910
3911 /* Clear the "in scan" flag */
3912 LunExtension->Flags &= ~SCSI_PORT_SCAN_IN_PROGRESS;
3913
3914 DPRINT("SpiScanAdapter(): Found device of type %d at bus %d tid %d lun %d\n",
3915 InquiryData->DeviceType, Bus, Target, Lun);
3916
3917 /* Add this info to the linked list */
3918 LunInfo->Next = NULL;
3919 if (LastLunInfo)
3920 LastLunInfo->Next = LunInfo;
3921 else
3922 BusScanInfo->LunInfo = LunInfo;
3923
3924 /* Store the last LUN info */
3925 LastLunInfo = LunInfo;
3926
3927 /* Store DeviceObject */
3928 LunInfo->DeviceObject = DeviceExtension->DeviceObject;
3929
3930 /* Allocate another buffer */
3931 LunInfo = ExAllocatePoolWithTag(PagedPool, sizeof(SCSI_LUN_INFO), TAG_SCSIPORT);
3932
3933 if (!LunInfo)
3934 {
3935 DPRINT1("Out of resources!\n");
3936 break;
3937 }
3938
3939 RtlZeroMemory(LunInfo, sizeof(SCSI_LUN_INFO));
3940
3941 /* Create a new LU extension */
3942 LunExtension = SpiAllocateLunExtension(DeviceExtension);
3943
3944 DevicesFound++;
3945 }
3946 else
3947 {
3948 /* Remove this LUN from the list */
3949 DeviceExtension->LunExtensionList[Hint] =
3950 DeviceExtension->LunExtensionList[Hint]->Next;
3951
3952 /* Decide whether we are continuing or not */
3953 if (Status == STATUS_INVALID_DEVICE_REQUEST)
3954 continue;
3955 else
3956 break;
3957 }
3958 }
3959 }
3960
3961 /* Free allocated buffers */
3962 if (LunExtension)
3963 ExFreePool(LunExtension);
3964
3965 if (LunInfo)
3966 ExFreePool(LunInfo);
3967
3968 /* Sum what we found */
3969 BusScanInfo->LogicalUnitsCount += (UCHAR) DevicesFound;
3970 DPRINT(" Found %d devices on bus %d\n", DevicesFound, Bus);
3971 }
3972
3973 DPRINT ("SpiScanAdapter() done\n");
3974 }
3975
3976
3977 static NTSTATUS
3978 SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
3979 IN PIRP Irp)
3980 {
3981 ULONG InquiryDataSize;
3982 PSCSI_LUN_INFO LunInfo;
3983 ULONG BusCount, LunCount, Length;
3984 PIO_STACK_LOCATION IrpStack;
3985 PSCSI_ADAPTER_BUS_INFO AdapterBusInfo;
3986 PSCSI_INQUIRY_DATA InquiryData;
3987 PSCSI_BUS_DATA BusData;
3988 ULONG Bus;
3989 PUCHAR Buffer;
3990
3991 DPRINT("SpiGetInquiryData() called\n");
3992
3993 /* Get pointer to the buffer */
3994 IrpStack = IoGetCurrentIrpStackLocation(Irp);
3995 Buffer = Irp->AssociatedIrp.SystemBuffer;
3996
3997 /* Initialize bus and LUN counters */
3998 BusCount = DeviceExtension->BusesConfig->NumberOfBuses;
3999 LunCount = 0;
4000
4001 /* Calculate total number of LUNs */
4002 for (Bus = 0; Bus < BusCount; Bus++)
4003 LunCount += DeviceExtension->BusesConfig->BusScanInfo[Bus]->LogicalUnitsCount;
4004
4005 /* Calculate size of inquiry data, rounding up to sizeof(ULONG) */
4006 InquiryDataSize =
4007 ((sizeof(SCSI_INQUIRY_DATA) - 1 + INQUIRYDATABUFFERSIZE +
4008 sizeof(ULONG) - 1) & ~(sizeof(ULONG) - 1));
4009
4010 /* Calculate data size */
4011 Length = sizeof(SCSI_ADAPTER_BUS_INFO) + (BusCount - 1) *
4012 sizeof(SCSI_BUS_DATA);
4013
4014 Length += InquiryDataSize * LunCount;
4015
4016 /* Check, if all data is going to fit into provided buffer */
4017 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < Length)
4018 {
4019 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
4020 return STATUS_BUFFER_TOO_SMALL;
4021 }
4022
4023 /* Store data size in the IRP */
4024 Irp->IoStatus.Information = Length;
4025
4026 DPRINT("Data size: %lu\n", Length);
4027
4028 AdapterBusInfo = (PSCSI_ADAPTER_BUS_INFO)Buffer;
4029
4030 AdapterBusInfo->NumberOfBuses = (UCHAR)BusCount;
4031
4032 /* Point InquiryData to the corresponding place inside Buffer */
4033 InquiryData = (PSCSI_INQUIRY_DATA)(Buffer + sizeof(SCSI_ADAPTER_BUS_INFO) +
4034 (BusCount - 1) * sizeof(SCSI_BUS_DATA));
4035
4036 /* Loop each bus */
4037 for (Bus = 0; Bus < BusCount; Bus++)
4038 {
4039 BusData = &AdapterBusInfo->BusData[Bus];
4040
4041 /* Calculate and save an offset of the inquiry data */
4042 BusData->InquiryDataOffset = (ULONG)((PUCHAR)InquiryData - Buffer);
4043
4044 /* Get a pointer to the LUN information structure */
4045 LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
4046
4047 /* Store Initiator Bus Id */
4048 BusData->InitiatorBusId =
4049 DeviceExtension->BusesConfig->BusScanInfo[Bus]->BusIdentifier;
4050
4051 /* Store LUN count */
4052 BusData->NumberOfLogicalUnits =
4053 DeviceExtension->BusesConfig->BusScanInfo[Bus]->LogicalUnitsCount;
4054
4055 /* Loop all LUNs */
4056 while (LunInfo != NULL)
4057 {
4058 DPRINT("(Bus %lu Target %lu Lun %lu)\n",
4059 Bus, LunInfo->TargetId, LunInfo->Lun);
4060
4061 /* Fill InquiryData with values */
4062 InquiryData->PathId = LunInfo->PathId;
4063 InquiryData->TargetId = LunInfo->TargetId;
4064 InquiryData->Lun = LunInfo->Lun;
4065 InquiryData->InquiryDataLength = INQUIRYDATABUFFERSIZE;
4066 InquiryData->DeviceClaimed = LunInfo->DeviceClaimed;
4067 InquiryData->NextInquiryDataOffset =
4068 (ULONG)((PUCHAR)InquiryData + InquiryDataSize - Buffer);
4069
4070 /* Copy data in it */
4071 RtlCopyMemory(InquiryData->InquiryData,
4072 LunInfo->InquiryData,
4073 INQUIRYDATABUFFERSIZE);
4074
4075 /* Move to the next LUN */
4076 LunInfo = LunInfo->Next;
4077 InquiryData = (PSCSI_INQUIRY_DATA) ((PCHAR)InquiryData + InquiryDataSize);
4078 }
4079
4080 /* Either mark the end, or set offset to 0 */
4081 if (BusData->NumberOfLogicalUnits != 0)
4082 ((PSCSI_INQUIRY_DATA) ((PCHAR) InquiryData - InquiryDataSize))->NextInquiryDataOffset = 0;
4083 else
4084 BusData->InquiryDataOffset = 0;
4085 }
4086
4087 /* Finish with success */
4088 Irp->IoStatus.Status = STATUS_SUCCESS;
4089 return STATUS_SUCCESS;
4090 }
4091
4092 static PSCSI_REQUEST_BLOCK_INFO
4093 SpiGetSrbData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
4094 IN UCHAR PathId,
4095 IN UCHAR TargetId,
4096 IN UCHAR Lun,
4097 IN UCHAR QueueTag)
4098 {
4099 PSCSI_PORT_LUN_EXTENSION LunExtension;
4100
4101 if (QueueTag == SP_UNTAGGED)
4102 {
4103 /* Untagged request, get LU and return pointer to SrbInfo */
4104 LunExtension = SpiGetLunExtension(DeviceExtension,
4105 PathId,
4106 TargetId,
4107 Lun);
4108
4109 /* Return NULL in case of error */
4110 if (!LunExtension)
4111 return(NULL);
4112
4113 /* Return the pointer to SrbInfo */
4114 return &LunExtension->SrbInfo;
4115 }
4116 else
4117 {
4118 /* Make sure the tag is valid, if it is - return the data */
4119 if (QueueTag > DeviceExtension->SrbDataCount || QueueTag < 1)
4120 return NULL;
4121 else
4122 return &DeviceExtension->SrbInfo[QueueTag -1];
4123 }
4124 }
4125
4126 static VOID
4127 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
4128 IN PSCSI_REQUEST_BLOCK InitialSrb)
4129 {
4130 PSCSI_REQUEST_BLOCK Srb;
4131 PCDB Cdb;
4132 PIRP Irp;
4133 PIO_STACK_LOCATION IrpStack;
4134 LARGE_INTEGER LargeInt;
4135 PVOID *Ptr;
4136
4137 DPRINT("SpiSendRequestSense() entered, InitialSrb %p\n", InitialSrb);
4138
4139 /* Allocate Srb */
4140 Srb = ExAllocatePoolWithTag(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK) + sizeof(PVOID), TAG_SCSIPORT);
4141 RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
4142
4143 /* Allocate IRP */
4144 LargeInt.QuadPart = (LONGLONG) 1;
4145 Irp = IoBuildAsynchronousFsdRequest(IRP_MJ_READ,
4146 DeviceExtension->DeviceObject,
4147 InitialSrb->SenseInfoBuffer,
4148 InitialSrb->SenseInfoBufferLength,
4149 &LargeInt,
4150 NULL);
4151
4152 IoSetCompletionRoutine(Irp,
4153 (PIO_COMPLETION_ROUTINE)SpiCompletionRoutine,
4154 Srb,
4155 TRUE,
4156 TRUE,
4157 TRUE);
4158
4159 if (!Srb)
4160 {
4161 DPRINT("SpiSendRequestSense() failed, Srb %p\n", Srb);
4162 return;
4163 }
4164
4165 IrpStack = IoGetNextIrpStackLocation(Irp);
4166 IrpStack->MajorFunction = IRP_MJ_SCSI;
4167
4168 /* Put Srb address into Irp... */
4169 IrpStack->Parameters.Others.Argument1 = (PVOID)Srb;
4170
4171 /* ...and vice versa */
4172 Srb->OriginalRequest = Irp;
4173
4174 /* Save Srb */
4175 Ptr = (PVOID *)(Srb+1);
4176 *Ptr = InitialSrb;
4177
4178 /* Build CDB for REQUEST SENSE */
4179 Srb->CdbLength = 6;
4180 Cdb = (PCDB)Srb->Cdb;
4181
4182 Cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE;
4183 Cdb->CDB6INQUIRY.LogicalUnitNumber = 0;
4184 Cdb->CDB6INQUIRY.Reserved1 = 0;
4185 Cdb->CDB6INQUIRY.PageCode = 0;
4186 Cdb->CDB6INQUIRY.IReserved = 0;
4187 Cdb->CDB6INQUIRY.AllocationLength = (UCHAR)InitialSrb->SenseInfoBufferLength;
4188 Cdb->CDB6INQUIRY.Control = 0;
4189
4190 /* Set address */
4191 Srb->TargetId = InitialSrb->TargetId;
4192 Srb->Lun = InitialSrb->Lun;
4193 Srb->PathId = InitialSrb->PathId;
4194
4195 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
4196 Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
4197
4198 /* Timeout will be 2 seconds */
4199 Srb->TimeOutValue = 2;
4200
4201 /* No auto request sense */
4202 Srb->SenseInfoBufferLength = 0;
4203 Srb->SenseInfoBuffer = NULL;
4204
4205 /* Set necessary flags */
4206 Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_BYPASS_FROZEN_QUEUE |
4207 SRB_FLAGS_DISABLE_DISCONNECT;
4208
4209 /* Transfer disable synch transfer flag */
4210 if (InitialSrb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER)
4211 Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
4212
4213 Srb->DataBuffer = InitialSrb->SenseInfoBuffer;
4214
4215 /* Fill the transfer length */
4216 Srb->DataTransferLength = InitialSrb->SenseInfoBufferLength;
4217
4218 /* Clear statuses */
4219 Srb->ScsiStatus = Srb->SrbStatus = 0;
4220 Srb->NextSrb = 0;
4221
4222 /* Call the driver */
4223 (VOID)IoCallDriver(DeviceExtension->DeviceObject, Irp);
4224
4225 DPRINT("SpiSendRequestSense() done\n");
4226 }
4227
4228
4229 static
4230 VOID
4231 NTAPI
4232 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
4233 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo,
4234 OUT PBOOLEAN NeedToCallStartIo)
4235 {
4236 PSCSI_REQUEST_BLOCK Srb;
4237 PSCSI_PORT_LUN_EXTENSION LunExtension;
4238 LONG Result;
4239 PIRP Irp;
4240 //ULONG SequenceNumber;
4241
4242 Srb = SrbInfo->Srb;
4243 Irp = Srb->OriginalRequest;
4244
4245 /* Get Lun extension */
4246 LunExtension = SpiGetLunExtension(DeviceExtension,
4247 Srb->PathId,
4248 Srb->TargetId,
4249 Srb->Lun);
4250
4251 if (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION &&
4252 DeviceExtension->MapBuffers &&
4253 Irp->MdlAddress)
4254 {
4255 /* MDL is shared if transfer is broken into smaller parts */
4256 Srb->DataBuffer = (PCCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress) +
4257 ((PCCHAR)Srb->DataBuffer - SrbInfo->DataOffset);
4258
4259 /* In case of data going in, flush the buffers */
4260 if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
4261 {
4262 KeFlushIoBuffers(Irp->MdlAddress,
4263 TRUE,
4264 FALSE);
4265 }
4266 }
4267
4268 /* Flush adapter if needed */
4269 if (SrbInfo->BaseOfMapRegister)
4270 {
4271 /* TODO: Implement */
4272 ASSERT(FALSE);
4273 }
4274
4275 /* Clear the request */
4276 SrbInfo->Srb = NULL;
4277
4278 /* If disconnect is disabled... */
4279 if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
4280 {
4281 /* Acquire the spinlock since we mess with flags */
4282 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
4283
4284 /* Set corresponding flag */
4285 DeviceExtension->Flags |= SCSI_PORT_DISCONNECT_ALLOWED;
4286
4287 /* Clear the timer if needed */
4288 if (!(DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET))
4289 DeviceExtension->TimerCount = -1;
4290
4291 /* Spinlock is not needed anymore */
4292 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4293
4294 if (!(DeviceExtension->Flags & SCSI_PORT_REQUEST_PENDING) &&
4295 !(DeviceExtension->Flags & SCSI_PORT_DEVICE_BUSY) &&
4296 !(*NeedToCallStartIo))
4297 {
4298 /* We're not busy, but we have a request pending */
4299 IoStartNextPacket(DeviceExtension->DeviceObject, FALSE);
4300 }
4301 }
4302
4303 /* Scatter/gather */
4304 if (Srb->SrbFlags & SRB_FLAGS_SGLIST_FROM_POOL)
4305 {
4306 /* TODO: Implement */
4307 ASSERT(FALSE);
4308 }
4309
4310 /* Acquire spinlock (we're freeing SrbExtension) */
4311 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
4312
4313 /* Free it (if needed) */
4314 if (Srb->SrbExtension)
4315 {
4316 if (Srb->SenseInfoBuffer != NULL && DeviceExtension->SupportsAutoSense)
4317 {
4318 ASSERT(Srb->SenseInfoBuffer == NULL || SrbInfo->SaveSenseRequest != NULL);
4319
4320 if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)
4321 {
4322 /* Copy sense data to the buffer */
4323 RtlCopyMemory(SrbInfo->SaveSenseRequest,
4324 Srb->SenseInfoBuffer,
4325 Srb->SenseInfoBufferLength);
4326 }
4327
4328 /* And restore the pointer */
4329 Srb->SenseInfoBuffer = SrbInfo->SaveSenseRequest;
4330 }
4331
4332 /* Put it into the free srb extensions list */
4333 *((PVOID *)Srb->SrbExtension) = DeviceExtension->FreeSrbExtensions;
4334 DeviceExtension->FreeSrbExtensions = Srb->SrbExtension;
4335 }
4336
4337 /* Save transfer length in the IRP */
4338 Irp->IoStatus.Information = Srb->DataTransferLength;
4339
4340 //SequenceNumber = SrbInfo->SequenceNumber;
4341 SrbInfo->SequenceNumber = 0;
4342
4343 /* Decrement the queue count */
4344 LunExtension->QueueCount--;
4345
4346 /* Free Srb, if needed*/
4347 if (Srb->QueueTag != SP_UNTAGGED)
4348 {
4349 /* Put it into the free list */
4350 SrbInfo->Requests.Blink = NULL;
4351 SrbInfo->Requests.Flink = (PLIST_ENTRY)DeviceExtension->FreeSrbInfo;
4352 DeviceExtension->FreeSrbInfo = SrbInfo;
4353 }
4354
4355 /* SrbInfo is not used anymore */
4356 SrbInfo = NULL;
4357
4358 if (DeviceExtension->Flags & SCSI_PORT_REQUEST_PENDING)
4359 {
4360 /* Clear the flag */
4361 DeviceExtension->Flags &= ~SCSI_PORT_REQUEST_PENDING;
4362
4363 /* Note the caller about StartIo */
4364 *NeedToCallStartIo = TRUE;
4365 }
4366
4367 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
4368 {
4369 /* Start the packet */
4370 Irp->IoStatus.Status = STATUS_SUCCESS;
4371
4372 if (!(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE) &&
4373 LunExtension->RequestTimeout == -1)
4374 {
4375 /* Start the next packet */
4376 SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
4377 }
4378 else
4379 {
4380 /* Release the spinlock */
4381 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4382 }
4383
4384 DPRINT("IoCompleting request IRP 0x%p\n", Irp);
4385
4386 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
4387
4388 /* Decrement number of active requests, and analyze the result */
4389 Result = InterlockedDecrement(&DeviceExtension->ActiveRequestCounter);
4390
4391 if (Result < 0 &&
4392 !DeviceExtension->MapRegisters &&
4393 DeviceExtension->AdapterObject != NULL)
4394 {
4395 /* Nullify map registers */
4396 DeviceExtension->MapRegisterBase = NULL;
4397 IoFreeAdapterChannel(DeviceExtension->AdapterObject);
4398 }
4399
4400 /* Exit, we're done */
4401 return;
4402 }
4403
4404 /* Decrement number of active requests, and analyze the result */
4405 Result = InterlockedDecrement(&DeviceExtension->ActiveRequestCounter);
4406
4407 if (Result < 0 &&
4408 !DeviceExtension->MapRegisters &&
4409 DeviceExtension->AdapterObject != NULL)
4410 {
4411 /* Result is negative, so this is a slave, free map registers */
4412 DeviceExtension->MapRegisterBase = NULL;
4413 IoFreeAdapterChannel(DeviceExtension->AdapterObject);
4414 }
4415
4416 /* Convert status */
4417 Irp->IoStatus.Status = SpiStatusSrbToNt(Srb->SrbStatus);
4418
4419 /* It's not a bypass, it's busy or the queue is full? */
4420 if ((Srb->ScsiStatus == SCSISTAT_BUSY ||
4421 Srb->SrbStatus == SRB_STATUS_BUSY ||
4422 Srb->ScsiStatus == SCSISTAT_QUEUE_FULL) &&
4423 !(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE))
4424 {
4425
4426 DPRINT("Busy SRB status %x\n", Srb->SrbStatus);
4427
4428 /* Requeue, if needed */
4429 if (LunExtension->Flags & (LUNEX_FROZEN_QUEUE | LUNEX_BUSY))
4430 {
4431 DPRINT("it's being requeued\n");
4432
4433 Srb->SrbStatus = SRB_STATUS_PENDING;
4434 Srb->ScsiStatus = 0;
4435
4436 if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue,
4437 &Irp->Tail.Overlay.DeviceQueueEntry,
4438 Srb->QueueSortKey))
4439 {
4440 /* It's a big f.ck up if we got here */
4441 Srb->SrbStatus = SRB_STATUS_ERROR;
4442 Srb->ScsiStatus = SCSISTAT_BUSY;
4443
4444 ASSERT(FALSE);
4445 goto Error;
4446 }
4447
4448 /* Release the spinlock */
4449 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4450
4451 }
4452 else if (LunExtension->AttemptCount++ < 20)
4453 {
4454 /* LUN is still busy */
4455 Srb->ScsiStatus = 0;
4456 Srb->SrbStatus = SRB_STATUS_PENDING;
4457
4458 LunExtension->BusyRequest = Irp;
4459 LunExtension->Flags |= LUNEX_BUSY;
4460
4461 /* Release the spinlock */
4462 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4463 }
4464 else
4465 {
4466 Error:
4467 /* Freeze the queue*/
4468 Srb->SrbStatus |= SRB_STATUS_QUEUE_FROZEN;
4469 LunExtension->Flags |= LUNEX_FROZEN_QUEUE;
4470
4471 /* "Unfull" the queue */
4472 LunExtension->Flags &= ~LUNEX_FULL_QUEUE;
4473
4474 /* Release the spinlock */
4475 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4476
4477 /* Return status that the device is not ready */
4478 Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
4479 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
4480 }
4481
4482 return;
4483 }
4484
4485 /* Start the next request, if LUN is idle, and this is sense request */
4486 if (((Srb->ScsiStatus != SCSISTAT_CHECK_CONDITION) ||
4487 (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) ||
4488 !Srb->SenseInfoBuffer || !Srb->SenseInfoBufferLength)
4489 && (Srb->SrbFlags & SRB_FLAGS_NO_QUEUE_FREEZE))
4490 {
4491 if (LunExtension->RequestTimeout == -1)
4492 SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
4493 else
4494 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4495 }
4496 else
4497 {
4498 /* Freeze the queue */
4499 Srb->SrbStatus |= SRB_STATUS_QUEUE_FROZEN;
4500 LunExtension->Flags |= LUNEX_FROZEN_QUEUE;
4501
4502 /* Do we need a request sense? */
4503 if (Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION &&
4504 !(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
4505 Srb->SenseInfoBuffer && Srb->SenseInfoBufferLength)
4506 {
4507 /* If LUN is busy, we have to requeue it in order to allow request sense */
4508 if (LunExtension->Flags & LUNEX_BUSY)
4509 {
4510 DPRINT("Requeuing busy request to allow request sense\n");
4511
4512 if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue,
4513 &LunExtension->BusyRequest->Tail.Overlay.DeviceQueueEntry,
4514 Srb->QueueSortKey))
4515 {
4516 /* We should never get here */
4517 ASSERT(FALSE);
4518
4519 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4520 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
4521 return;
4522
4523 }
4524
4525 /* Clear busy flags */
4526 LunExtension->Flags &= ~(LUNEX_FULL_QUEUE | LUNEX_BUSY);
4527 }
4528
4529 /* Release the spinlock */
4530 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4531
4532 /* Send RequestSense */
4533 SpiSendRequestSense(DeviceExtension, Srb);
4534
4535 /* Exit */
4536 return;
4537 }
4538
4539 /* Release the spinlock */
4540 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4541 }
4542
4543 /* Complete the request */
4544 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
4545 }
4546
4547 NTSTATUS
4548 NTAPI
4549 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject,
4550 PIRP Irp,
4551 PVOID Context)
4552 {
4553 PSCSI_REQUEST_BLOCK Srb = (PSCSI_REQUEST_BLOCK)Context;
4554 PSCSI_REQUEST_BLOCK InitialSrb;
4555 PIRP InitialIrp;
4556
4557 DPRINT("SpiCompletionRoutine() entered, IRP %p \n", Irp);
4558
4559 if ((Srb->Function == SRB_FUNCTION_RESET_BUS) ||
4560 (Srb->Function == SRB_FUNCTION_ABORT_COMMAND))
4561 {
4562 /* Deallocate SRB and IRP and exit */
4563 ExFreePool(Srb);
4564 IoFreeIrp(Irp);
4565
4566 return STATUS_MORE_PROCESSING_REQUIRED;
4567 }
4568
4569 /* Get a pointer to the SRB and IRP which were initially sent */
4570 InitialSrb = *((PVOID *)(Srb+1));
4571 InitialIrp = InitialSrb->OriginalRequest;
4572
4573 if ((SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS) ||
4574 (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN))
4575 {
4576 /* Sense data is OK */
4577 InitialSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
4578
4579 /* Set length to be the same */
4580 InitialSrb->SenseInfoBufferLength = (UCHAR)Srb->DataTransferLength;
4581 }
4582
4583 /* Make sure initial SRB's queue is frozen */
4584 ASSERT(InitialSrb->SrbStatus & SRB_STATUS_QUEUE_FROZEN);
4585
4586 /* Complete this request */
4587 IoCompleteRequest(InitialIrp, IO_DISK_INCREMENT);
4588
4589 /* Deallocate everything (internal) */
4590 ExFreePool(Srb);
4591
4592 if (Irp->MdlAddress != NULL)
4593 {
4594 MmUnlockPages(Irp->MdlAddress);
4595 IoFreeMdl(Irp->MdlAddress);
4596 Irp->MdlAddress = NULL;
4597 }
4598
4599 IoFreeIrp(Irp);
4600 return STATUS_MORE_PROCESSING_REQUIRED;
4601 }
4602
4603 static BOOLEAN NTAPI
4604 ScsiPortIsr(IN PKINTERRUPT Interrupt,
4605 IN PVOID ServiceContext)
4606 {
4607 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
4608
4609 DPRINT("ScsiPortIsr() called!\n");
4610
4611 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext;
4612
4613 /* If interrupts are disabled - we don't expect any */
4614 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_DISABLE_INTERRUPTS)
4615 return FALSE;
4616
4617 /* Call miniport's HwInterrupt routine */
4618 if (DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension) == FALSE)
4619 {
4620 /* This interrupt doesn't belong to us */
4621 return FALSE;
4622 }
4623
4624 /* If flag of notification is set - queue a DPC */
4625 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
4626 {
4627 IoRequestDpc(DeviceExtension->DeviceObject,
4628 DeviceExtension->CurrentIrp,
4629 DeviceExtension);
4630 }
4631
4632 return TRUE;
4633 }
4634
4635 BOOLEAN
4636 NTAPI
4637 SpiSaveInterruptData(IN PVOID Context)
4638 {
4639 PSCSI_PORT_SAVE_INTERRUPT InterruptContext = Context;
4640 PSCSI_PORT_LUN_EXTENSION LunExtension;
4641 PSCSI_REQUEST_BLOCK Srb;
4642 PSCSI_REQUEST_BLOCK_INFO SrbInfo, NextSrbInfo;
4643 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
4644 BOOLEAN IsTimed;
4645
4646 /* Get pointer to the device extension */
4647 DeviceExtension = InterruptContext->DeviceExtension;
4648
4649 /* If we don't have anything pending - return */
4650 if (!(DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED))
4651 return FALSE;
4652
4653 /* Actually save the interrupt data */
4654 *InterruptContext->InterruptData = DeviceExtension->InterruptData;
4655
4656 /* Clear the data stored in the device extension */
4657 DeviceExtension->InterruptData.Flags &=
4658 (SCSI_PORT_RESET | SCSI_PORT_RESET_REQUEST | SCSI_PORT_DISABLE_INTERRUPTS);
4659 DeviceExtension->InterruptData.CompletedAbort = NULL;
4660 DeviceExtension->InterruptData.ReadyLun = NULL;
4661 DeviceExtension->InterruptData.CompletedRequests = NULL;
4662
4663 /* Loop through the list of completed requests */
4664 SrbInfo = InterruptContext->InterruptData->CompletedRequests;
4665
4666 while (SrbInfo)
4667 {
4668 /* Make sure we have SRV */
4669 ASSERT(SrbInfo->Srb);
4670
4671 /* Get SRB and LunExtension */
4672 Srb = SrbInfo->Srb;
4673
4674 LunExtension = SpiGetLunExtension(DeviceExtension,
4675 Srb->PathId,
4676 Srb->TargetId,
4677 Srb->Lun);
4678
4679 /* We have to check special cases if request is unsuccessful*/
4680 if (Srb->SrbStatus != SRB_STATUS_SUCCESS)
4681 {
4682 /* Check if we need request sense by a few conditions */
4683 if (Srb->SenseInfoBuffer && Srb->SenseInfoBufferLength &&
4684 Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION &&
4685 !(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID))
4686 {
4687 if (LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE)
4688 {
4689 /* It means: we tried to send REQUEST SENSE, but failed */
4690
4691 Srb->ScsiStatus = 0;
4692 Srb->SrbStatus = SRB_STATUS_REQUEST_SENSE_FAILED;
4693 }
4694 else
4695 {
4696 /* Set the corresponding flag, so that REQUEST SENSE
4697 will be sent */
4698 LunExtension->Flags |= LUNEX_NEED_REQUEST_SENSE;
4699 }
4700
4701 }
4702
4703 /* Check for a full queue */
4704 if (Srb->ScsiStatus == SCSISTAT_QUEUE_FULL)
4705 {
4706 /* TODO: Implement when it's encountered */
4707 ASSERT(FALSE);
4708 }
4709 }
4710
4711 /* Let's decide if we need to watch timeout or not */
4712 if (Srb->QueueTag == SP_UNTAGGED)
4713 {
4714 IsTimed = TRUE;
4715 }
4716 else
4717 {
4718 if (LunExtension->SrbInfo.Requests.Flink == &SrbInfo->Requests)
4719 IsTimed = TRUE;
4720 else
4721 IsTimed = FALSE;
4722
4723 /* Remove it from the queue */
4724 RemoveEntryList(&SrbInfo->Requests);
4725 }
4726
4727 if (IsTimed)
4728 {
4729 /* We have to maintain timeout counter */
4730 if (IsListEmpty(&LunExtension->SrbInfo.Requests))
4731 {
4732 LunExtension->RequestTimeout = -1;
4733 }
4734 else
4735 {
4736 NextSrbInfo = CONTAINING_RECORD(LunExtension->SrbInfo.Requests.Flink,
4737 SCSI_REQUEST_BLOCK_INFO,
4738 Requests);
4739
4740 Srb = NextSrbInfo->Srb;
4741
4742 /* Update timeout counter */
4743 LunExtension->RequestTimeout = Srb->TimeOutValue;
4744 }
4745 }
4746
4747 SrbInfo = SrbInfo->CompletedRequests;
4748 }
4749
4750 return TRUE;
4751 }
4752
4753 VOID
4754 NTAPI
4755 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
4756 IN PSCSI_PORT_LUN_EXTENSION LunExtension)
4757 {
4758 PIO_STACK_LOCATION IrpStack;
4759 PIRP NextIrp;
4760 PKDEVICE_QUEUE_ENTRY Entry;
4761 PSCSI_REQUEST_BLOCK Srb;
4762
4763
4764 /* If LUN is not active or queue is more than maximum allowed */
4765 if (LunExtension->QueueCount >= LunExtension->MaxQueueCount ||
4766 !(LunExtension->Flags & SCSI_PORT_LU_ACTIVE))
4767 {
4768 /* Release the spinlock and exit */
4769 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4770 return;
4771 }
4772
4773 /* Check if we can get a next request */
4774 if (LunExtension->Flags &
4775 (LUNEX_NEED_REQUEST_SENSE | LUNEX_BUSY |
4776 LUNEX_FULL_QUEUE | LUNEX_FROZEN_QUEUE | LUNEX_REQUEST_PENDING))
4777 {
4778 /* Pending requests can only be started if the queue is empty */
4779 if (IsListEmpty(&LunExtension->SrbInfo.Requests) &&
4780 !(LunExtension->Flags &
4781 (LUNEX_BUSY | LUNEX_FROZEN_QUEUE | LUNEX_FULL_QUEUE | LUNEX_NEED_REQUEST_SENSE)))
4782 {
4783 /* Make sure we have SRB */
4784 ASSERT(LunExtension->SrbInfo.Srb == NULL);
4785
4786 /* Clear active and pending flags */
4787 LunExtension->Flags &= ~(LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE);
4788
4789 /* Get next Irp, and clear pending requests list */
4790 NextIrp = LunExtension->PendingRequest;
4791 LunExtension->PendingRequest = NULL;
4792
4793 /* Set attempt counter to zero */
4794 LunExtension->AttemptCount = 0;
4795
4796 /* Release the spinlock */
4797 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4798
4799 /* Start the next pending request */
4800 IoStartPacket(DeviceExtension->DeviceObject, NextIrp, (PULONG)NULL, NULL);
4801
4802 return;
4803 }
4804 else
4805 {
4806 /* Release the spinlock, without clearing any flags and exit */
4807 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4808
4809 return;
4810 }
4811 }
4812
4813 /* Reset active flag */
4814 LunExtension->Flags &= ~SCSI_PORT_LU_ACTIVE;
4815
4816 /* Set attempt counter to zero */
4817 LunExtension->AttemptCount = 0;
4818
4819 /* Remove packet from the device queue */
4820 Entry = KeRemoveByKeyDeviceQueue(&LunExtension->DeviceQueue, LunExtension->SortKey);
4821
4822 if (Entry != NULL)
4823 {
4824 /* Get pointer to the next irp */
4825 NextIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
4826
4827 /* Get point to the SRB */
4828 IrpStack = IoGetCurrentIrpStackLocation(NextIrp);
4829 Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
4830
4831 /* Set new key*/
4832 LunExtension->SortKey = Srb->QueueSortKey;
4833 LunExtension->SortKey++;
4834
4835 /* Release the spinlock */
4836 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4837
4838 /* Start the next pending request */
4839 IoStartPacket(DeviceExtension->DeviceObject, NextIrp, (PULONG)NULL, NULL);
4840 }
4841 else
4842 {
4843 /* Release the spinlock */
4844 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4845 }
4846 }
4847
4848
4849
4850 // ScsiPortDpcForIsr
4851 // DESCRIPTION:
4852 //
4853 // RUN LEVEL:
4854 //
4855 // ARGUMENTS:
4856 // IN PKDPC Dpc
4857 // IN PDEVICE_OBJECT DpcDeviceObject
4858 // IN PIRP DpcIrp
4859 // IN PVOID DpcContext
4860 //
4861 static VOID NTAPI
4862 ScsiPortDpcForIsr(IN PKDPC Dpc,
4863 IN PDEVICE_OBJECT DpcDeviceObject,
4864 IN PIRP DpcIrp,
4865 IN PVOID DpcContext)
4866 {
4867 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DpcDeviceObject->DeviceExtension;
4868 SCSI_PORT_INTERRUPT_DATA InterruptData;
4869 SCSI_PORT_SAVE_INTERRUPT Context;
4870 PSCSI_PORT_LUN_EXTENSION LunExtension;
4871 BOOLEAN NeedToStartIo;
4872 PSCSI_REQUEST_BLOCK_INFO SrbInfo;
4873 LARGE_INTEGER TimerValue;
4874
4875 DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
4876 Dpc, DpcDeviceObject, DpcIrp, DpcContext);
4877
4878 /* We need to acquire spinlock */
4879 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
4880
4881 RtlZeroMemory(&InterruptData, sizeof(SCSI_PORT_INTERRUPT_DATA));
4882
4883 TryAgain:
4884
4885 /* Interrupt structure must be snapshotted, and only then analyzed */
4886 Context.InterruptData = &InterruptData;
4887 Context.DeviceExtension = DeviceExtension;
4888
4889 if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0],
4890 SpiSaveInterruptData,
4891 &Context))
4892 {
4893 /* Nothing - just return (don't forget to release the spinlock */
4894 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4895 DPRINT("ScsiPortDpcForIsr() done\n");
4896 return;
4897 }
4898
4899 /* If flush of adapters is needed - do it */
4900 if (InterruptData.Flags & SCSI_PORT_FLUSH_ADAPTERS)
4901 {
4902 /* TODO: Implement */
4903 ASSERT(FALSE);
4904 }
4905
4906 /* Check for IoMapTransfer */
4907 if (InterruptData.Flags & SCSI_PORT_MAP_TRANSFER)
4908 {
4909 /* TODO: Implement */
4910 ASSERT(FALSE);
4911 }
4912
4913 /* Check if timer is needed */
4914 if (InterruptData.Flags & SCSI_PORT_TIMER_NEEDED)
4915 {
4916 /* Save the timer routine */
4917 DeviceExtension->HwScsiTimer = InterruptData.HwScsiTimer;
4918
4919 if (InterruptData.MiniportTimerValue == 0)
4920 {
4921 /* Cancel the timer */
4922 KeCancelTimer(&DeviceExtension->MiniportTimer);
4923 }
4924 else
4925 {
4926 /* Convert timer value */
4927 TimerValue.QuadPart = Int32x32To64(InterruptData.MiniportTimerValue, -10);
4928
4929 /* Set the timer */
4930 KeSetTimer(&DeviceExtension->MiniportTimer,
4931 TimerValue,
4932 &DeviceExtension->MiniportTimerDpc);
4933 }
4934 }
4935
4936 /* If it's ready for the next request */
4937 if (InterruptData.Flags & SCSI_PORT_NEXT_REQUEST_READY)
4938 {
4939 /* Check for a duplicate request (NextRequest+NextLuRequest) */
4940 if ((DeviceExtension->Flags &
4941 (SCSI_PORT_DEVICE_BUSY | SCSI_PORT_DISCONNECT_ALLOWED)) ==
4942 (SCSI_PORT_DEVICE_BUSY | SCSI_PORT_DISCONNECT_ALLOWED))
4943 {
4944 /* Clear busy flag set by ScsiPortStartPacket() */
4945 DeviceExtension->Flags &= ~SCSI_PORT_DEVICE_BUSY;
4946
4947 if (!(InterruptData.Flags & SCSI_PORT_RESET))
4948 {
4949 /* Ready for next, and no reset is happening */
4950 DeviceExtension->TimerCount = -1;
4951 }
4952 }
4953 else
4954 {
4955 /* Not busy, but not ready for the next request */
4956 DeviceExtension->Flags &= ~SCSI_PORT_DEVICE_BUSY;
4957 InterruptData.Flags &= ~SCSI_PORT_NEXT_REQUEST_READY;
4958 }
4959 }
4960
4961 /* Any resets? */
4962 if (InterruptData.Flags & SCSI_PORT_RESET_REPORTED)
4963 {
4964 /* Hold for a bit */
4965 DeviceExtension->TimerCount = 4;
4966 }
4967
4968 /* Any ready LUN? */
4969 if (InterruptData.ReadyLun != NULL)
4970 {
4971
4972 /* Process all LUNs from the list*/
4973 while (TRUE)
4974 {
4975 /* Remove it from the list first (as processed) */
4976 LunExtension = InterruptData.ReadyLun;
4977 InterruptData.ReadyLun = LunExtension->ReadyLun;
4978 LunExtension->ReadyLun = NULL;
4979
4980 /* Get next request for this LUN */
4981 SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
4982
4983 /* Still ready requests exist?
4984 If yes - get spinlock, if no - stop here */
4985 if (InterruptData.ReadyLun != NULL)
4986 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
4987 else
4988 break;
4989 }
4990 }
4991 else
4992 {
4993 /* Release the spinlock */
4994 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4995 }
4996
4997 /* If we ready for next packet, start it */
4998 if (InterruptData.Flags & SCSI_PORT_NEXT_REQUEST_READY)
4999 IoStartNextPacket(DeviceExtension->DeviceObject, FALSE);
5000
5001 NeedToStartIo = FALSE;
5002
5003 /* Loop the completed request list */
5004 while (InterruptData.CompletedRequests)
5005 {
5006 /* Remove the request */
5007 SrbInfo = InterruptData.CompletedRequests;
5008 InterruptData.CompletedRequests = SrbInfo->CompletedRequests;
5009 SrbInfo->CompletedRequests = NULL;
5010
5011 /* Process it */
5012 SpiProcessCompletedRequest(DeviceExtension,
5013 SrbInfo,
5014 &NeedToStartIo);
5015 }
5016
5017 /* Loop abort request list */
5018 while (InterruptData.CompletedAbort)
5019 {
5020 LunExtension = InterruptData.CompletedAbort;
5021
5022 /* Remove the request */
5023 InterruptData.CompletedAbort = LunExtension->CompletedAbortRequests;
5024
5025 /* Get spinlock since we're going to change flags */
5026 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
5027
5028 /* TODO: Put SrbExtension to the list of free extensions */
5029 ASSERT(FALSE);
5030 }
5031
5032 /* If we need - call StartIo routine */
5033 if (NeedToStartIo)
5034 {
5035 /* Make sure CurrentIrp is not null! */
5036 ASSERT(DpcDeviceObject->CurrentIrp != NULL);
5037 ScsiPortStartIo(DpcDeviceObject, DpcDeviceObject->CurrentIrp);
5038 }
5039
5040 /* Everything has been done, check */
5041 if (InterruptData.Flags & SCSI_PORT_ENABLE_INT_REQUEST)
5042 {
5043 /* Synchronize using spinlock */
5044 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
5045
5046 /* Request an interrupt */
5047 DeviceExtension->HwInterrupt(DeviceExtension->MiniPortDeviceExtension);
5048
5049 ASSERT(DeviceExtension->Flags & SCSI_PORT_DISABLE_INT_REQUESET);
5050
5051 /* Should interrupts be enabled again? */
5052 if (DeviceExtension->Flags & SCSI_PORT_DISABLE_INT_REQUESET)
5053 {
5054 /* Clear this flag */
5055 DeviceExtension->Flags &= ~SCSI_PORT_DISABLE_INT_REQUESET;
5056
5057 /* Call a special routine to do this */
5058 ASSERT(FALSE);
5059 #if 0
5060 KeSynchronizeExecution(DeviceExtension->Interrupt,
5061 SpiEnableInterrupts,
5062 DeviceExtension);
5063 #endif
5064 }
5065
5066 /* If we need a notification again - loop */
5067 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
5068 goto TryAgain;
5069
5070 /* Release the spinlock */
5071 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
5072 }
5073
5074 DPRINT("ScsiPortDpcForIsr() done\n");
5075 }
5076
5077 BOOLEAN
5078 NTAPI
5079 SpiProcessTimeout(PVOID ServiceContext)
5080 {
5081 PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)ServiceContext;
5082 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
5083 ULONG Bus;
5084
5085 DPRINT("SpiProcessTimeout() entered\n");
5086
5087 DeviceExtension->TimerCount = -1;
5088
5089 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET)
5090 {
5091 DeviceExtension->InterruptData.Flags &= ~SCSI_PORT_RESET;
5092
5093 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET_REQUEST)
5094 {
5095 DeviceExtension->InterruptData.Flags &= ~SCSI_PORT_RESET_REQUEST;
5096 ScsiPortStartPacket(ServiceContext);
5097 }
5098
5099 return FALSE;
5100 }
5101 else
5102 {
5103 DPRINT("Resetting the bus\n");
5104
5105 for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
5106 {
5107 DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension, Bus);
5108
5109 /* Reset flags and set reset timeout to 4 seconds */
5110 DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET;
5111 DeviceExtension->TimerCount = 4;
5112 }
5113
5114 /* If miniport requested - request a dpc for it */
5115 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
5116 IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
5117 }
5118
5119 return TRUE;
5120 }
5121
5122
5123 BOOLEAN
5124 NTAPI
5125 SpiResetBus(PVOID ServiceContext)
5126 {
5127 PRESETBUS_PARAMS ResetParams = (PRESETBUS_PARAMS)ServiceContext;
5128 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
5129
5130 /* Perform the bus reset */
5131 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ResetParams->DeviceExtension;
5132 DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension,
5133 ResetParams->PathId);
5134
5135 /* Set flags and start the timer */
5136 DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET;
5137 DeviceExtension->TimerCount = 4;
5138
5139 /* If miniport requested - give him a DPC */
5140 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
5141 IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
5142
5143 return TRUE;
5144 }
5145
5146 // ScsiPortIoTimer
5147 // DESCRIPTION:
5148 // This function handles timeouts and other time delayed processing
5149 //
5150 // RUN LEVEL:
5151 //
5152 // ARGUMENTS:
5153 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
5154 // IN PVOID Context the Controller extension for the
5155 // controller the device is on
5156 //
5157 static VOID NTAPI
5158 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
5159 PVOID Context)
5160 {
5161 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
5162 PSCSI_PORT_LUN_EXTENSION LunExtension;
5163 ULONG Lun;
5164 PIRP Irp;
5165
5166 DPRINT("ScsiPortIoTimer()\n");
5167
5168 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
5169
5170 /* Protect with the spinlock */
5171 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
5172
5173 /* Check timeouts */
5174 if (DeviceExtension->TimerCount > 0)
5175 {
5176 /* Decrease the timeout counter */
5177 DeviceExtension->TimerCount--;
5178
5179 if (DeviceExtension->TimerCount == 0)
5180 {
5181 /* Timeout, process it */
5182 if (KeSynchronizeExecution(DeviceExtension->Interrupt[0],
5183 SpiProcessTimeout,
5184 DeviceExtension->DeviceObject))
5185 {
5186 DPRINT("Error happened during processing timeout, but nothing critical\n");
5187 }
5188 }
5189
5190 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
5191
5192 /* We should exit now, since timeout is processed */
5193 return;
5194 }
5195
5196 /* Per-Lun scanning of timeouts is needed... */
5197 for (Lun = 0; Lun < LUS_NUMBER; Lun++)
5198 {
5199 LunExtension = DeviceExtension->LunExtensionList[Lun];
5200
5201 while (LunExtension)
5202 {
5203 if (LunExtension->Flags & LUNEX_BUSY)
5204 {
5205 if (!(LunExtension->Flags &
5206 (LUNEX_NEED_REQUEST_SENSE | LUNEX_FROZEN_QUEUE)))
5207 {
5208 DPRINT("Retrying busy request\n");
5209
5210 /* Clear flags, and retry busy request */
5211 LunExtension->Flags &= ~(LUNEX_BUSY | LUNEX_FULL_QUEUE);
5212 Irp = LunExtension->BusyRequest;
5213
5214 /* Clearing busy request */
5215 LunExtension->BusyRequest = NULL;
5216
5217 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
5218
5219 IoStartPacket(DeviceObject, Irp, (PULONG)NULL, NULL);
5220
5221 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
5222 }
5223 }
5224 else if (LunExtension->RequestTimeout == 0)
5225 {
5226 RESETBUS_PARAMS ResetParams;
5227
5228 LunExtension->RequestTimeout = -1;
5229
5230 DPRINT("Request timed out, resetting bus\n");
5231
5232 /* Pass params to the bus reset routine */
5233 ResetParams.PathId = LunExtension->PathId;
5234 ResetParams.DeviceExtension = DeviceExtension;
5235
5236 if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0],
5237 SpiResetBus,
5238 &ResetParams))
5239 {
5240 DPRINT1("Reset failed\n");
5241 }
5242 }
5243 else if (LunExtension->RequestTimeout > 0)
5244 {
5245 /* Decrement the timeout counter */
5246 LunExtension->RequestTimeout--;
5247 }
5248
5249 LunExtension = LunExtension->Next;
5250 }
5251 }
5252
5253 /* Release the spinlock */
5254 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
5255 }
5256
5257 /**********************************************************************
5258 * NAME INTERNAL
5259 * SpiBuildDeviceMap
5260 *
5261 * DESCRIPTION
5262 * Builds the registry device map of all device which are attached
5263 * to the given SCSI HBA port. The device map is located at:
5264 * \Registry\Machine\DeviceMap\Scsi
5265 *
5266 * RUN LEVEL
5267 * PASSIVE_LEVEL
5268 *
5269 * ARGUMENTS
5270 * DeviceExtension
5271 * ...
5272 *
5273 * RegistryPath
5274 * Name of registry driver service key.
5275 *
5276 * RETURNS
5277 * NTSTATUS
5278 */
5279
5280 static NTSTATUS
5281 SpiBuildDeviceMap(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
5282 IN PUNICODE_STRING RegistryPath)
5283 {
5284 PSCSI_PORT_LUN_EXTENSION LunExtension;
5285 OBJECT_ATTRIBUTES ObjectAttributes;
5286 UNICODE_STRING KeyName;
5287 UNICODE_STRING ValueName;
5288 WCHAR NameBuffer[64];
5289 ULONG Disposition;
5290 HANDLE ScsiKey;
5291 HANDLE ScsiPortKey = NULL;
5292 HANDLE ScsiBusKey = NULL;
5293 HANDLE ScsiInitiatorKey = NULL;
5294 HANDLE ScsiTargetKey = NULL;
5295 HANDLE ScsiLunKey = NULL;
5296 ULONG BusNumber;
5297 ULONG Target;
5298 ULONG CurrentTarget;
5299 ULONG Lun;
5300 PWCHAR DriverName;
5301 ULONG UlongData;
5302 PWCHAR TypeName;
5303 NTSTATUS Status;
5304
5305 DPRINT("SpiBuildDeviceMap() called\n");
5306
5307 if (DeviceExtension == NULL || RegistryPath == NULL)
5308 {
5309 DPRINT1("Invalid parameter\n");
5310 return STATUS_INVALID_PARAMETER;
5311 }
5312
5313 /* Open or create the 'Scsi' subkey */
5314 RtlInitUnicodeString(&KeyName,
5315 L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
5316 InitializeObjectAttributes(&ObjectAttributes,
5317 &KeyName,
5318 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_KERNEL_HANDLE,
5319 0,
5320 NULL);
5321 Status = ZwCreateKey(&ScsiKey,
5322 KEY_ALL_ACCESS,
5323 &ObjectAttributes,
5324 0,
5325 NULL,
5326 REG_OPTION_VOLATILE,
5327 &Disposition);
5328 if (!NT_SUCCESS(Status))
5329 {
5330 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
5331 return Status;
5332 }
5333
5334 /* Create new 'Scsi Port X' subkey */
5335 DPRINT("Scsi Port %lu\n", DeviceExtension->PortNumber);
5336
5337 swprintf(NameBuffer,
5338 L"Scsi Port %lu",
5339 DeviceExtension->PortNumber);
5340 RtlInitUnicodeString(&KeyName, NameBuffer);
5341 InitializeObjectAttributes(&ObjectAttributes,
5342 &KeyName,
5343 OBJ_KERNEL_HANDLE,
5344 ScsiKey,
5345 NULL);
5346 Status = ZwCreateKey(&ScsiPortKey,
5347 KEY_ALL_ACCESS,
5348 &ObjectAttributes,
5349 0,
5350 NULL,
5351 REG_OPTION_VOLATILE,
5352 &Disposition);
5353 ZwClose(ScsiKey);
5354 if (!NT_SUCCESS(Status))
5355 {
5356 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
5357 return Status;
5358 }
5359
5360 /*
5361 * Create port-specific values
5362 */
5363
5364 /* Set 'DMA Enabled' (REG_DWORD) value */
5365 UlongData = (ULONG)!DeviceExtension->PortCapabilities.AdapterUsesPio;
5366 DPRINT(" DMA Enabled = %s\n", UlongData ? "TRUE" : "FALSE");
5367 RtlInitUnicodeString(&ValueName, L"DMA Enabled");
5368 Status = ZwSetValueKey(ScsiPortKey,
5369 &ValueName,
5370 0,
5371 REG_DWORD,
5372 &UlongData,
5373 sizeof(UlongData));
5374 if (!NT_SUCCESS(Status))
5375 {
5376 DPRINT("ZwSetValueKey('DMA Enabled') failed (Status %lx)\n", Status);
5377 ZwClose(ScsiPortKey);
5378 return Status;
5379 }
5380
5381 /* Set 'Driver' (REG_SZ) value */
5382 DriverName = wcsrchr(RegistryPath->Buffer, L'\\') + 1;
5383 RtlInitUnicodeString(&ValueName, L"Driver");
5384 Status = ZwSetValueKey(ScsiPortKey,
5385 &ValueName,
5386 0,
5387 REG_SZ,
5388 DriverName,
5389 (ULONG)((wcslen(DriverName) + 1) * sizeof(WCHAR)));
5390 if (!NT_SUCCESS(Status))
5391 {
5392 DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status);
5393 ZwClose(ScsiPortKey);
5394 return Status;
5395 }
5396
5397 /* Set 'Interrupt' (REG_DWORD) value (NT4 only) */
5398 UlongData = (ULONG)DeviceExtension->PortConfig->BusInterruptLevel;
5399 DPRINT(" Interrupt = %lu\n", UlongData);
5400 RtlInitUnicodeString(&ValueName, L"Interrupt");
5401 Status = ZwSetValueKey(ScsiPortKey,
5402 &ValueName,
5403 0,
5404 REG_DWORD,
5405 &UlongData,
5406 sizeof(UlongData));
5407 if (!NT_SUCCESS(Status))
5408 {
5409 DPRINT("ZwSetValueKey('Interrupt') failed (Status %lx)\n", Status);
5410 ZwClose(ScsiPortKey);
5411 return Status;
5412 }
5413
5414 /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
5415 UlongData = ScsiPortConvertPhysicalAddressToUlong((*DeviceExtension->PortConfig->AccessRanges)[0].RangeStart);
5416 DPRINT(" IOAddress = %lx\n", UlongData);
5417 RtlInitUnicodeString(&ValueName, L"IOAddress");
5418 Status = ZwSetValueKey(ScsiPortKey,
5419 &ValueName,
5420 0,
5421 REG_DWORD,
5422 &UlongData,
5423 sizeof(UlongData));
5424 if (!NT_SUCCESS(Status))
5425 {
5426 DPRINT("ZwSetValueKey('IOAddress') failed (Status %lx)\n", Status);
5427 ZwClose(ScsiPortKey);
5428 return Status;
5429 }
5430
5431 /* Enumerate buses */
5432 for (BusNumber = 0; BusNumber < DeviceExtension->PortConfig->NumberOfBuses; BusNumber++)
5433 {
5434 /* Create 'Scsi Bus X' key */
5435 DPRINT(" Scsi Bus %lu\n", BusNumber);
5436 swprintf(NameBuffer,
5437 L"Scsi Bus %lu",
5438 BusNumber);
5439 RtlInitUnicodeString(&KeyName, NameBuffer);
5440 InitializeObjectAttributes(&ObjectAttributes,
5441 &KeyName,
5442 0,
5443 ScsiPortKey,
5444 NULL);
5445 Status = ZwCreateKey(&ScsiBusKey,
5446 KEY_ALL_ACCESS,
5447 &ObjectAttributes,
5448 0,
5449 NULL,
5450 REG_OPTION_VOLATILE,
5451 &Disposition);
5452 if (!NT_SUCCESS(Status))
5453 {
5454 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
5455 goto ByeBye;
5456 }
5457
5458 /* Create 'Initiator Id X' key */
5459 DPRINT(" Initiator Id %lu\n",
5460 DeviceExtension->PortConfig->InitiatorBusId[BusNumber]);
5461 swprintf(NameBuffer,
5462 L"Initiator Id %lu",
5463 (ULONG)(UCHAR)DeviceExtension->PortConfig->InitiatorBusId[BusNumber]);
5464 RtlInitUnicodeString(&KeyName, NameBuffer);
5465 InitializeObjectAttributes(&ObjectAttributes,
5466 &KeyName,
5467 0,
5468 ScsiBusKey,
5469 NULL);
5470 Status = ZwCreateKey(&ScsiInitiatorKey,
5471 KEY_ALL_ACCESS,
5472 &ObjectAttributes,
5473 0,
5474 NULL,
5475 REG_OPTION_VOLATILE,
5476 &Disposition);
5477 if (!NT_SUCCESS(Status))
5478 {
5479 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
5480 goto ByeBye;
5481 }
5482
5483 /* FIXME: Are there any initiator values (??) */
5484
5485 ZwClose(ScsiInitiatorKey);
5486 ScsiInitiatorKey = NULL;
5487
5488
5489 /* Enumerate targets */
5490 CurrentTarget = (ULONG)-1;
5491 ScsiTargetKey = NULL;
5492 for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
5493 {
5494 for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
5495 {
5496 LunExtension = SpiGetLunExtension(DeviceExtension,
5497 (UCHAR)BusNumber,
5498 (UCHAR)Target,
5499 (UCHAR)Lun);
5500 if (LunExtension == NULL)
5501 continue;
5502
5503 if (Target != CurrentTarget)
5504 {
5505 /* Close old target key */
5506 if (ScsiTargetKey != NULL)
5507 {
5508 ZwClose(ScsiTargetKey);
5509 ScsiTargetKey = NULL;
5510 }
5511
5512 /* Create 'Target Id X' key */
5513 DPRINT(" Target Id %lu\n", Target);
5514 swprintf(NameBuffer,
5515 L"Target Id %lu",
5516 Target);
5517 RtlInitUnicodeString(&KeyName, NameBuffer);
5518 InitializeObjectAttributes(&ObjectAttributes,
5519 &KeyName,
5520 0,
5521 ScsiBusKey,
5522 NULL);
5523 Status = ZwCreateKey(&ScsiTargetKey,
5524 KEY_ALL_ACCESS,
5525 &ObjectAttributes,
5526 0,
5527 NULL,
5528 REG_OPTION_VOLATILE,
5529 &Disposition);
5530 if (!NT_SUCCESS(Status))
5531 {
5532 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
5533 goto ByeBye;
5534 }
5535
5536 CurrentTarget = Target;
5537 }
5538
5539 /* Create 'Logical Unit Id X' key */
5540 DPRINT(" Logical Unit Id %lu\n", Lun);
5541 swprintf(NameBuffer,
5542 L"Logical Unit Id %lu",
5543 Lun);
5544 RtlInitUnicodeString(&KeyName, NameBuffer);
5545 InitializeObjectAttributes(&ObjectAttributes,
5546 &KeyName,
5547 0,
5548 ScsiTargetKey,
5549 NULL);
5550 Status = ZwCreateKey(&ScsiLunKey,
5551 KEY_ALL_ACCESS,
5552 &ObjectAttributes,
5553 0,
5554 NULL,
5555 REG_OPTION_VOLATILE,
5556 &Disposition);
5557 if (!NT_SUCCESS(Status))
5558 {
5559 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
5560 goto ByeBye;
5561 }
5562
5563 /* Set 'Identifier' (REG_SZ) value */
5564 swprintf(NameBuffer,
5565 L"%.8S%.16S%.4S",
5566 LunExtension->InquiryData.VendorId,
5567 LunExtension->InquiryData.ProductId,
5568 LunExtension->InquiryData.ProductRevisionLevel);
5569 DPRINT(" Identifier = '%S'\n", NameBuffer);
5570 RtlInitUnicodeString(&ValueName, L"Identifier");
5571 Status = ZwSetValueKey(ScsiLunKey,
5572 &ValueName,
5573 0,
5574 REG_SZ,
5575 NameBuffer,
5576 (ULONG)((wcslen(NameBuffer) + 1) * sizeof(WCHAR)));
5577 if (!NT_SUCCESS(Status))
5578 {
5579 DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", Status);
5580 goto ByeBye;
5581 }
5582
5583 /* Set 'Type' (REG_SZ) value */
5584 /*
5585 * See https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-ide-devices
5586 * and https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-scsi-devices
5587 * for a list of types with their human-readable forms.
5588 */
5589 switch (LunExtension->InquiryData.DeviceType)
5590 {
5591 case 0:
5592 TypeName = L"DiskPeripheral";
5593 break;
5594 case 1:
5595 TypeName = L"TapePeripheral";
5596 break;
5597 case 2:
5598 TypeName = L"PrinterPeripheral";
5599 break;
5600 // case 3: "ProcessorPeripheral", classified as 'other': fall back to default case.
5601 case 4:
5602 TypeName = L"WormPeripheral";
5603 break;
5604 case 5:
5605 TypeName = L"CdRomPeripheral";
5606 break;
5607 case 6:
5608 TypeName = L"ScannerPeripheral";
5609 break;
5610 case 7:
5611 TypeName = L"OpticalDiskPeripheral";
5612 break;
5613 case 8:
5614 TypeName = L"MediumChangerPeripheral";
5615 break;
5616 case 9:
5617 TypeName = L"CommunicationsPeripheral";
5618 break;
5619
5620 /* New peripheral types (SCSI only) */
5621 case 10: case 11:
5622 TypeName = L"ASCPrePressGraphicsPeripheral";
5623 break;
5624 case 12:
5625 TypeName = L"ArrayPeripheral";
5626 break;
5627 case 13:
5628 TypeName = L"EnclosurePeripheral";
5629 break;
5630 case 14:
5631 TypeName = L"RBCPeripheral";
5632 break;
5633 case 15:
5634 TypeName = L"CardReaderPeripheral";
5635 break;
5636 case 16:
5637 TypeName = L"BridgePeripheral";
5638 break;
5639
5640 default:
5641 TypeName = L"OtherPeripheral";
5642 break;
5643 }
5644 DPRINT(" Type = '%S'\n", TypeName);
5645 RtlInitUnicodeString(&ValueName, L"Type");
5646 Status = ZwSetValueKey(ScsiLunKey,
5647 &ValueName,
5648 0,
5649 REG_SZ,
5650 TypeName,
5651 (ULONG)((wcslen(TypeName) + 1) * sizeof(WCHAR)));
5652 if (!NT_SUCCESS(Status))
5653 {
5654 DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status);
5655 goto ByeBye;
5656 }
5657
5658 ZwClose(ScsiLunKey);
5659 ScsiLunKey = NULL;
5660 }
5661
5662 /* Close old target key */
5663 if (ScsiTargetKey != NULL)
5664 {
5665 ZwClose(ScsiTargetKey);
5666 ScsiTargetKey = NULL;
5667 }
5668 }
5669
5670 ZwClose(ScsiBusKey);
5671 ScsiBusKey = NULL;
5672 }
5673
5674 ByeBye:
5675 if (ScsiLunKey != NULL)
5676 ZwClose(ScsiLunKey);
5677
5678 if (ScsiInitiatorKey != NULL)
5679 ZwClose(ScsiInitiatorKey);
5680
5681 if (ScsiTargetKey != NULL)
5682 ZwClose(ScsiTargetKey);
5683
5684 if (ScsiBusKey != NULL)
5685 ZwClose(ScsiBusKey);
5686
5687 if (ScsiPortKey != NULL)
5688 ZwClose(ScsiPortKey);
5689
5690 DPRINT("SpiBuildDeviceMap() done\n");
5691
5692 return Status;
5693 }
5694
5695 VOID
5696 NTAPI
5697 SpiMiniportTimerDpc(IN struct _KDPC *Dpc,
5698 IN PVOID DeviceObject,
5699 IN PVOID SystemArgument1,
5700 IN PVOID SystemArgument2)
5701 {
5702 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
5703
5704 DPRINT("Miniport timer DPC\n");
5705
5706 DeviceExtension = ((PDEVICE_OBJECT)DeviceObject)->DeviceExtension;
5707
5708 /* Acquire the spinlock */
5709 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
5710
5711 /* Call the timer routine */
5712 if (DeviceExtension->HwScsiTimer != NULL)
5713 {
5714 DeviceExtension->HwScsiTimer(&DeviceExtension->MiniPortDeviceExtension);
5715 }
5716
5717 /* Release the spinlock */
5718 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
5719
5720 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
5721 {
5722 ScsiPortDpcForIsr(NULL,
5723 DeviceExtension->DeviceObject,
5724 NULL,
5725 NULL);
5726 }
5727 }
5728
5729 static NTSTATUS
5730 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
5731 PHW_INITIALIZATION_DATA HwInitData,
5732 PCONFIGURATION_INFO InternalConfigInfo,
5733 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
5734 BOOLEAN ZeroStruct)
5735 {
5736 UNICODE_STRING UnicodeString;
5737 OBJECT_ATTRIBUTES ObjectAttributes;
5738 PCONFIGURATION_INFORMATION DdkConfigInformation;
5739 HANDLE RootKey, Key;
5740 BOOLEAN Found;
5741 WCHAR DeviceBuffer[16];
5742 WCHAR StrBuffer[512];
5743 ULONG Bus;
5744 NTSTATUS Status;
5745
5746 /* Zero out the struct if told so */
5747 if (ZeroStruct)
5748 {
5749 /* First zero the portconfig */
5750 RtlZeroMemory(ConfigInfo, sizeof(PORT_CONFIGURATION_INFORMATION));
5751
5752 /* Then access ranges */
5753 RtlZeroMemory(InternalConfigInfo->AccessRanges,
5754 HwInitData->NumberOfAccessRanges * sizeof(ACCESS_RANGE));
5755
5756 /* Initialize the struct */
5757 ConfigInfo->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
5758 ConfigInfo->AdapterInterfaceType = HwInitData->AdapterInterfaceType;
5759 ConfigInfo->InterruptMode = Latched;
5760 ConfigInfo->DmaChannel = SP_UNINITIALIZED_VALUE;
5761 ConfigInfo->DmaPort = SP_UNINITIALIZED_VALUE;
5762 ConfigInfo->DmaChannel2 = SP_UNINITIALIZED_VALUE;
5763 ConfigInfo->DmaPort2 = SP_UNINITIALIZED_VALUE;
5764 ConfigInfo->MaximumTransferLength = SP_UNINITIALIZED_VALUE;
5765 ConfigInfo->NumberOfAccessRanges = HwInitData->NumberOfAccessRanges;
5766 ConfigInfo->MaximumNumberOfTargets = 8;
5767
5768 /* Store parameters */
5769 ConfigInfo->NeedPhysicalAddresses = HwInitData->NeedPhysicalAddresses;
5770 ConfigInfo->MapBuffers = HwInitData->MapBuffers;
5771 ConfigInfo->AutoRequestSense = HwInitData->AutoRequestSense;
5772 ConfigInfo->ReceiveEvent = HwInitData->ReceiveEvent;
5773 ConfigInfo->TaggedQueuing = HwInitData->TaggedQueuing;
5774 ConfigInfo->MultipleRequestPerLu = HwInitData->MultipleRequestPerLu;
5775
5776 /* Get the disk usage */
5777 DdkConfigInformation = IoGetConfigurationInformation();
5778 ConfigInfo->AtdiskPrimaryClaimed = DdkConfigInformation->AtDiskPrimaryAddressClaimed;
5779 ConfigInfo->AtdiskSecondaryClaimed = DdkConfigInformation->AtDiskSecondaryAddressClaimed;
5780
5781 /* Initiator bus id is not set */
5782 for (Bus = 0; Bus < 8; Bus++)
5783 ConfigInfo->InitiatorBusId[Bus] = (CCHAR)SP_UNINITIALIZED_VALUE;
5784 }
5785
5786 ConfigInfo->NumberOfPhysicalBreaks = 17;
5787
5788 /* Clear this information */
5789 InternalConfigInfo->DisableTaggedQueueing = FALSE;
5790 InternalConfigInfo->DisableMultipleLun = FALSE;
5791
5792 /* Store Bus Number */
5793 ConfigInfo->SystemIoBusNumber = InternalConfigInfo->BusNumber;
5794
5795 TryNextAd:
5796
5797 if (ConfigInfo->AdapterInterfaceType == Internal)
5798 {
5799 /* Open registry key for HW database */
5800 InitializeObjectAttributes(&ObjectAttributes,
5801 DeviceExtension->DeviceObject->DriverObject->HardwareDatabase,
5802 OBJ_CASE_INSENSITIVE,
5803 NULL,
5804 NULL);
5805
5806 Status = ZwOpenKey(&RootKey,
5807 KEY_READ,
5808 &ObjectAttributes);
5809
5810 if (NT_SUCCESS(Status))
5811 {
5812 /* Create name for it */
5813 swprintf(StrBuffer, L"ScsiAdapter\\%lu",
5814 InternalConfigInfo->AdapterNumber);
5815
5816 RtlInitUnicodeString(&UnicodeString, StrBuffer);
5817
5818 /* Open device key */
5819 InitializeObjectAttributes(&ObjectAttributes,
5820 &UnicodeString,
5821 OBJ_CASE_INSENSITIVE,
5822 RootKey,
5823 NULL);
5824
5825 Status = ZwOpenKey(&Key,
5826 KEY_READ,
5827 &ObjectAttributes);
5828
5829 ZwClose(RootKey);
5830
5831 if (NT_SUCCESS(Status))
5832 {
5833 if (InternalConfigInfo->LastAdapterNumber != InternalConfigInfo->AdapterNumber)
5834 {
5835 DPRINT("Hardware info found at %S\n", StrBuffer);
5836
5837 /* Parse it */
5838 SpiParseDeviceInfo(DeviceExtension,
5839 Key,
5840 ConfigInfo,
5841 InternalConfigInfo,
5842 (PUCHAR)StrBuffer);
5843
5844 InternalConfigInfo->BusNumber = 0;
5845 }
5846 else
5847 {
5848 /* Try the next adapter */
5849 InternalConfigInfo->AdapterNumber++;
5850 goto TryNextAd;
5851 }
5852 }
5853 else
5854 {
5855 /* Info was not found, exit */
5856 DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status);
5857 return STATUS_DEVICE_DOES_NOT_EXIST;
5858 }
5859 }
5860 else
5861 {
5862 DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status);
5863 }
5864 }
5865
5866 /* Look at device params */
5867 Key = NULL;
5868 if (InternalConfigInfo->Parameter)
5869 {
5870 ExFreePool(InternalConfigInfo->Parameter);
5871 InternalConfigInfo->Parameter = NULL;
5872 }
5873
5874 if (InternalConfigInfo->ServiceKey != NULL)
5875 {
5876 swprintf(DeviceBuffer, L"Device%lu", InternalConfigInfo->AdapterNumber);
5877 RtlInitUnicodeString(&UnicodeString, DeviceBuffer);
5878
5879 /* Open the service key */
5880 InitializeObjectAttributes(&ObjectAttributes,
5881 &UnicodeString,
5882 OBJ_CASE_INSENSITIVE,
5883 InternalConfigInfo->ServiceKey,
5884 NULL);
5885
5886 Status = ZwOpenKey(&Key,
5887 KEY_READ,
5888 &ObjectAttributes);
5889 }
5890
5891 /* Parse device key */
5892 if (InternalConfigInfo->DeviceKey != NULL)
5893 {
5894 SpiParseDeviceInfo(DeviceExtension,
5895 InternalConfigInfo->DeviceKey,
5896 ConfigInfo,
5897 InternalConfigInfo,
5898 (PUCHAR)StrBuffer);
5899 }
5900
5901 /* Then parse hw info */
5902 if (Key != NULL)
5903 {
5904 if (InternalConfigInfo->LastAdapterNumber != InternalConfigInfo->AdapterNumber)
5905 {
5906 SpiParseDeviceInfo(DeviceExtension,
5907 Key,
5908 ConfigInfo,
5909 InternalConfigInfo,
5910 (PUCHAR)StrBuffer);
5911
5912 /* Close the key */
5913 ZwClose(Key);
5914 }
5915 else
5916 {
5917 /* Adapter not found, go try the next one */
5918 InternalConfigInfo->AdapterNumber++;
5919
5920 /* Close the key */
5921 ZwClose(Key);
5922
5923 goto TryNextAd;
5924 }
5925 }
5926
5927 /* Update the last adapter number */
5928 InternalConfigInfo->LastAdapterNumber = InternalConfigInfo->AdapterNumber;
5929
5930 /* Do we have this kind of bus at all? */
5931 Found = FALSE;
5932 Status = IoQueryDeviceDescription(&HwInitData->AdapterInterfaceType,
5933 &InternalConfigInfo->BusNumber,
5934 NULL,
5935 NULL,
5936 NULL,
5937 NULL,
5938 SpQueryDeviceCallout,
5939 &Found);
5940
5941 /* This bus was not found */
5942 if (!Found)
5943 {
5944 INTERFACE_TYPE InterfaceType = Eisa;
5945
5946 /* Check for EISA */
5947 if (HwInitData->AdapterInterfaceType == Isa)
5948 {
5949 Status = IoQueryDeviceDescription(&InterfaceType,
5950 &InternalConfigInfo->BusNumber,
5951 NULL,
5952 NULL,
5953 NULL,
5954 NULL,
5955 SpQueryDeviceCallout,
5956 &Found);
5957
5958 /* Return respectively */
5959 if (Found)
5960 return STATUS_SUCCESS;
5961 else
5962 return STATUS_DEVICE_DOES_NOT_EXIST;
5963 }
5964 else
5965 {
5966 return STATUS_DEVICE_DOES_NOT_EXIST;
5967 }
5968 }
5969 else
5970 {
5971 return STATUS_SUCCESS;
5972 }
5973 }
5974
5975 static VOID
5976 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
5977 IN HANDLE Key,
5978 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
5979 IN PCONFIGURATION_INFO InternalConfigInfo,
5980 IN PUCHAR Buffer)
5981 {
5982 PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
5983 PCM_FULL_RESOURCE_DESCRIPTOR FullResource;
5984 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
5985 PCM_SCSI_DEVICE_DATA ScsiDeviceData;
5986 ULONG Length, Count, Dma = 0, Interrupt = 0;
5987 ULONG Index = 0, RangeCount = 0;
5988 UNICODE_STRING UnicodeString;
5989 ANSI_STRING AnsiString;
5990 NTSTATUS Status = STATUS_SUCCESS;
5991
5992
5993 KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION) Buffer;
5994
5995 /* Loop through all values in the device node */
5996 while(TRUE)
5997 {
5998 Status = ZwEnumerateValueKey(Key,
5999 Index,
6000 KeyValueFullInformation,
6001 Buffer,
6002 512,
6003 &Length);
6004
6005 if (!NT_SUCCESS(Status))
6006 return;
6007
6008 Index++;
6009
6010 /* Length for DWORD is ok? */
6011 if (KeyValueInformation->Type == REG_DWORD &&
6012 KeyValueInformation->DataLength != sizeof(ULONG))
6013 {
6014 continue;
6015 }
6016
6017 /* Get MaximumLogicalUnit */
6018 if (_wcsnicmp(KeyValueInformation->Name, L"MaximumLogicalUnit",
6019 KeyValueInformation->NameLength/2) == 0)
6020 {
6021
6022 if (KeyValueInformation->Type != REG_DWORD)
6023 {
6024 DPRINT("Bad data type for MaximumLogicalUnit\n");
6025 continue;
6026 }
6027
6028 DeviceExtension->MaxLunCount = *((PUCHAR)
6029 (Buffer + KeyValueInformation->DataOffset));
6030
6031 /* Check / reset if needed */
6032 if (DeviceExtension->MaxLunCount > SCSI_MAXIMUM_LOGICAL_UNITS)
6033 DeviceExtension->MaxLunCount = SCSI_MAXIMUM_LOGICAL_UNITS;
6034
6035 DPRINT("MaximumLogicalUnit = %d\n", DeviceExtension->MaxLunCount);
6036 }
6037
6038 /* Get InitiatorTargetId */
6039 if (_wcsnicmp(KeyValueInformation->Name, L"InitiatorTargetId",
6040 KeyValueInformation->NameLength / 2) == 0)
6041 {
6042
6043 if (KeyValueInformation->Type != REG_DWORD)
6044 {
6045 DPRINT("Bad data type for InitiatorTargetId\n");
6046 continue;
6047 }
6048
6049 ConfigInfo->InitiatorBusId[0] = *((PUCHAR)
6050 (Buffer + KeyValueInformation->DataOffset));
6051
6052 /* Check / reset if needed */
6053 if (ConfigInfo->InitiatorBusId[0] > ConfigInfo->MaximumNumberOfTargets - 1)
6054 ConfigInfo->InitiatorBusId[0] = (CCHAR)-1;
6055
6056 DPRINT("InitiatorTargetId = %d\n", ConfigInfo->InitiatorBusId[0]);
6057 }
6058
6059 /* Get ScsiDebug */
6060 if (_wcsnicmp(KeyValueInformation->Name, L"ScsiDebug",
6061 KeyValueInformation->NameLength/2) == 0)
6062 {
6063 DPRINT("ScsiDebug key not supported\n");
6064 }
6065
6066 /* Check for a breakpoint */
6067 if (_wcsnicmp(KeyValueInformation->Name, L"BreakPointOnEntry",
6068 KeyValueInformation->NameLength/2) == 0)
6069 {
6070 DPRINT1("Breakpoint on entry requested!\n");
6071 DbgBreakPoint();
6072 }
6073
6074 /* Get DisableSynchronousTransfers */
6075 if (_wcsnicmp(KeyValueInformation->Name, L"DisableSynchronousTransfers",
6076 KeyValueInformation->NameLength/2) == 0)
6077 {
6078 DeviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
6079 DPRINT("Synch transfers disabled\n");
6080 }
6081
6082 /* Get DisableDisconnects */
6083 if (_wcsnicmp(KeyValueInformation->Name, L"DisableDisconnects",
6084 KeyValueInformation->NameLength/2) == 0)
6085 {
6086 DeviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT;
6087 DPRINT("Disconnects disabled\n");
6088 }
6089
6090 /* Get DisableTaggedQueuing */
6091 if (_wcsnicmp(KeyValueInformation->Name, L"DisableTaggedQueuing",
6092 KeyValueInformation->NameLength/2) == 0)
6093 {
6094 InternalConfigInfo->DisableTaggedQueueing = TRUE;
6095 DPRINT("Tagged queueing disabled\n");
6096 }
6097
6098 /* Get DisableMultipleRequests */
6099 if (_wcsnicmp(KeyValueInformation->Name, L"DisableMultipleRequests",
6100 KeyValueInformation->NameLength/2) == 0)
6101 {
6102 InternalConfigInfo->DisableMultipleLun = TRUE;
6103 DPRINT("Multiple requests disabled\n");
6104 }
6105
6106 /* Get DriverParameters */
6107 if (_wcsnicmp(KeyValueInformation->Name, L"DriverParameters",
6108 KeyValueInformation->NameLength/2) == 0)
6109 {
6110 /* Skip if nothing */
6111 if (KeyValueInformation->DataLength == 0)
6112 continue;
6113
6114 /* If there was something previously allocated - free it */
6115 if (InternalConfigInfo->Parameter != NULL)
6116 ExFreePool(InternalConfigInfo->Parameter);
6117
6118 /* Allocate it */
6119 InternalConfigInfo->Parameter = ExAllocatePoolWithTag(NonPagedPool,
6120 KeyValueInformation->DataLength, TAG_SCSIPORT);
6121
6122 if (InternalConfigInfo->Parameter != NULL)
6123 {
6124 if (KeyValueInformation->Type != REG_SZ)
6125 {
6126 /* Just copy */
6127 RtlCopyMemory(
6128 InternalConfigInfo->Parameter,
6129 (PCCHAR)KeyValueInformation + KeyValueInformation->DataOffset,
6130 KeyValueInformation->DataLength);
6131 }
6132 else
6133 {
6134 /* If it's a unicode string, convert it to ansi */
6135 UnicodeString.Length = (USHORT)KeyValueInformation->DataLength;
6136 UnicodeString.MaximumLength = (USHORT)KeyValueInformation->DataLength;
6137 UnicodeString.Buffer =
6138 (PWSTR)((PCCHAR)KeyValueInformation + KeyValueInformation->DataOffset);
6139
6140 AnsiString.Length = 0;
6141 AnsiString.MaximumLength = (USHORT)KeyValueInformation->DataLength;
6142 AnsiString.Buffer = (PCHAR)InternalConfigInfo->Parameter;
6143
6144 Status = RtlUnicodeStringToAnsiString(&AnsiString,
6145 &UnicodeString,
6146 FALSE);
6147
6148 /* In case of error, free the allocated space */
6149 if (!NT_SUCCESS(Status))
6150 {
6151 ExFreePool(InternalConfigInfo->Parameter);
6152 InternalConfigInfo->Parameter = NULL;
6153 }
6154
6155 }
6156 }
6157
6158 DPRINT("Found driver parameter\n");
6159 }
6160
6161 /* Get MaximumSGList */
6162 if (_wcsnicmp(KeyValueInformation->Name, L"MaximumSGList",
6163 KeyValueInformation->NameLength/2) == 0)
6164 {
6165 if (KeyValueInformation->Type != REG_DWORD)
6166 {
6167 DPRINT("Bad data type for MaximumSGList\n");
6168 continue;
6169 }
6170
6171 ConfigInfo->NumberOfPhysicalBreaks = *((PUCHAR)(Buffer + KeyValueInformation->DataOffset));
6172
6173 /* Check / fix */
6174 if (ConfigInfo->NumberOfPhysicalBreaks > SCSI_MAXIMUM_PHYSICAL_BREAKS)
6175 {
6176 ConfigInfo->NumberOfPhysicalBreaks = SCSI_MAXIMUM_PHYSICAL_BREAKS;
6177 }
6178 else if (ConfigInfo->NumberOfPhysicalBreaks < SCSI_MINIMUM_PHYSICAL_BREAKS)
6179 {
6180 ConfigInfo->NumberOfPhysicalBreaks = SCSI_MINIMUM_PHYSICAL_BREAKS;
6181 }
6182
6183 DPRINT("MaximumSGList = %d\n", ConfigInfo->NumberOfPhysicalBreaks);
6184 }
6185
6186 /* Get NumberOfRequests */
6187 if (_wcsnicmp(KeyValueInformation->Name, L"NumberOfRequests",
6188 KeyValueInformation->NameLength/2) == 0)
6189 {
6190 if (KeyValueInformation->Type != REG_DWORD)
6191 {
6192 DPRINT("NumberOfRequests has wrong data type\n");
6193 continue;
6194 }
6195
6196 DeviceExtension->RequestsNumber = *((PUCHAR)(Buffer + KeyValueInformation->DataOffset));
6197
6198 /* Check / fix */
6199 if (DeviceExtension->RequestsNumber < 16)
6200 {
6201 DeviceExtension->RequestsNumber = 16;
6202 }
6203 else if (DeviceExtension->RequestsNumber > 512)
6204 {
6205 DeviceExtension->RequestsNumber = 512;
6206 }
6207
6208 DPRINT("Number Of Requests = %d\n", DeviceExtension->RequestsNumber);
6209 }
6210
6211 /* Get resource list */
6212 if (_wcsnicmp(KeyValueInformation->Name, L"ResourceList",
6213 KeyValueInformation->NameLength/2) == 0 ||
6214 _wcsnicmp(KeyValueInformation->Name, L"Configuration Data",
6215 KeyValueInformation->NameLength/2) == 0 )
6216 {
6217 if (KeyValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR ||
6218 KeyValueInformation->DataLength < sizeof(REG_FULL_RESOURCE_DESCRIPTOR))
6219 {
6220 DPRINT("Bad data type for ResourceList\n");
6221 continue;
6222 }
6223 else
6224 {
6225 DPRINT("Found ResourceList\n");
6226 }
6227
6228 FullResource = (PCM_FULL_RESOURCE_DESCRIPTOR)(Buffer + KeyValueInformation->DataOffset);
6229
6230 /* Copy some info from it */
6231 InternalConfigInfo->BusNumber = FullResource->BusNumber;
6232 ConfigInfo->SystemIoBusNumber = FullResource->BusNumber;
6233
6234 /* Loop through it */
6235 for (Count = 0; Count < FullResource->PartialResourceList.Count; Count++)
6236 {
6237 /* Get partial descriptor */
6238 PartialDescriptor =
6239 &FullResource->PartialResourceList.PartialDescriptors[Count];
6240
6241 /* Check datalength */
6242 if ((ULONG)((PCHAR)(PartialDescriptor + 1) -
6243 (PCHAR)FullResource) > KeyValueInformation->DataLength)
6244 {
6245 DPRINT("Resource data is of incorrect size\n");
6246 break;
6247 }
6248
6249 switch (PartialDescriptor->Type)
6250 {
6251 case CmResourceTypePort:
6252 if (RangeCount >= ConfigInfo->NumberOfAccessRanges)
6253 {
6254 DPRINT("Too many access ranges\n");
6255 continue;
6256 }
6257
6258 InternalConfigInfo->AccessRanges[RangeCount].RangeInMemory = FALSE;
6259 InternalConfigInfo->AccessRanges[RangeCount].RangeStart = PartialDescriptor->u.Port.Start;
6260 InternalConfigInfo->AccessRanges[RangeCount].RangeLength = PartialDescriptor->u.Port.Length;
6261 RangeCount++;
6262
6263 break;
6264
6265 case CmResourceTypeMemory:
6266 if (RangeCount >= ConfigInfo->NumberOfAccessRanges)
6267 {
6268 DPRINT("Too many access ranges\n");
6269 continue;
6270 }
6271
6272 InternalConfigInfo->AccessRanges[RangeCount].RangeInMemory = TRUE;
6273 InternalConfigInfo->AccessRanges[RangeCount].RangeStart = PartialDescriptor->u.Memory.Start;
6274 InternalConfigInfo->AccessRanges[RangeCount].RangeLength = PartialDescriptor->u.Memory.Length;
6275 RangeCount++;
6276
6277 break;
6278
6279 case CmResourceTypeInterrupt:
6280
6281 if (Interrupt == 0)
6282 {
6283 ConfigInfo->BusInterruptLevel =
6284 PartialDescriptor->u.Interrupt.Level;
6285
6286 ConfigInfo->BusInterruptVector =
6287 PartialDescriptor->u.Interrupt.Vector;
6288
6289 ConfigInfo->InterruptMode = (PartialDescriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive;
6290 }
6291 else if (Interrupt == 1)
6292 {
6293 ConfigInfo->BusInterruptLevel2 =
6294 PartialDescriptor->u.Interrupt.Level;
6295
6296 ConfigInfo->BusInterruptVector2 =
6297 PartialDescriptor->u.Interrupt.Vector;
6298
6299 ConfigInfo->InterruptMode2 = (PartialDescriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive;
6300 }
6301
6302 Interrupt++;
6303 break;
6304
6305 case CmResourceTypeDma:
6306
6307 if (Dma == 0)
6308 {
6309 ConfigInfo->DmaChannel = PartialDescriptor->u.Dma.Channel;
6310 ConfigInfo->DmaPort = PartialDescriptor->u.Dma.Port;
6311
6312 if (PartialDescriptor->Flags & CM_RESOURCE_DMA_8)
6313 ConfigInfo->DmaWidth = Width8Bits;
6314 else if ((PartialDescriptor->Flags & CM_RESOURCE_DMA_16) ||
6315 (PartialDescriptor->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
6316 ConfigInfo->DmaWidth = Width16Bits;
6317 else if (PartialDescriptor->Flags & CM_RESOURCE_DMA_32)
6318 ConfigInfo->DmaWidth = Width32Bits;
6319 }
6320 else if (Dma == 1)
6321 {
6322 ConfigInfo->DmaChannel2 = PartialDescriptor->u.Dma.Channel;
6323 ConfigInfo->DmaPort2 = PartialDescriptor->u.Dma.Port;
6324
6325 if (PartialDescriptor->Flags & CM_RESOURCE_DMA_8)
6326 ConfigInfo->DmaWidth2 = Width8Bits;
6327 else if ((PartialDescriptor->Flags & CM_RESOURCE_DMA_16) ||
6328 (PartialDescriptor->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
6329 ConfigInfo->DmaWidth2 = Width16Bits;
6330 else if (PartialDescriptor->Flags & CM_RESOURCE_DMA_32)
6331 ConfigInfo->DmaWidth2 = Width32Bits;
6332 }
6333
6334 Dma++;
6335 break;
6336
6337 case CmResourceTypeDeviceSpecific:
6338 if (PartialDescriptor->u.DeviceSpecificData.DataSize <
6339 sizeof(CM_SCSI_DEVICE_DATA) ||
6340 (PCHAR) (PartialDescriptor + 1) - (PCHAR)FullResource +
6341 PartialDescriptor->u.DeviceSpecificData.DataSize >
6342 KeyValueInformation->DataLength)
6343 {
6344 DPRINT("Resource data length is incorrect");
6345 break;
6346 }
6347
6348 /* Set only one field from it */
6349 ScsiDeviceData = (PCM_SCSI_DEVICE_DATA) (PartialDescriptor+1);
6350 ConfigInfo->InitiatorBusId[0] = ScsiDeviceData->HostIdentifier;
6351 break;
6352 }
6353 }
6354 }
6355 }
6356 }
6357
6358 NTSTATUS
6359 NTAPI
6360 SpQueryDeviceCallout(IN PVOID Context,
6361 IN PUNICODE_STRING PathName,
6362 IN INTERFACE_TYPE BusType,
6363 IN ULONG BusNumber,
6364 IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
6365 IN CONFIGURATION_TYPE ControllerType,
6366 IN ULONG ControllerNumber,
6367 IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
6368 IN CONFIGURATION_TYPE PeripheralType,
6369 IN ULONG PeripheralNumber,
6370 IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation)
6371 {
6372 PBOOLEAN Found = (PBOOLEAN)Context;
6373 /* We just set our Found variable to TRUE */
6374
6375 *Found = TRUE;
6376 return STATUS_SUCCESS;
6377 }
6378
6379 IO_ALLOCATION_ACTION
6380 NTAPI
6381 ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject,
6382 IN PIRP Irp,
6383 IN PVOID MapRegisterBase,
6384 IN PVOID Context)
6385 {
6386 KIRQL Irql;
6387 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
6388
6389 /* Guard access with the spinlock */
6390 KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
6391
6392 /* Save MapRegisterBase we've got here */
6393 DeviceExtension->MapRegisterBase = MapRegisterBase;
6394
6395 /* Start pending request */
6396 KeSynchronizeExecution(DeviceExtension->Interrupt[0],
6397 ScsiPortStartPacket, DeviceObject);
6398
6399 /* Release spinlock we took */
6400 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
6401
6402 return KeepObject;
6403 }
6404
6405 static
6406 NTSTATUS
6407 SpiStatusSrbToNt(UCHAR SrbStatus)
6408 {
6409 switch (SRB_STATUS(SrbStatus))
6410 {
6411 case SRB_STATUS_TIMEOUT:
6412 case SRB_STATUS_COMMAND_TIMEOUT:
6413 return STATUS_IO_TIMEOUT;
6414
6415 case SRB_STATUS_BAD_SRB_BLOCK_LENGTH:
6416 case SRB_STATUS_BAD_FUNCTION:
6417 return STATUS_INVALID_DEVICE_REQUEST;
6418
6419 case SRB_STATUS_NO_DEVICE:
6420 case SRB_STATUS_INVALID_LUN:
6421 case SRB_STATUS_INVALID_TARGET_ID:
6422 case SRB_STATUS_NO_HBA:
6423 return STATUS_DEVICE_DOES_NOT_EXIST;
6424
6425 case SRB_STATUS_DATA_OVERRUN:
6426 return STATUS_BUFFER_OVERFLOW;
6427
6428 case SRB_STATUS_SELECTION_TIMEOUT:
6429 return STATUS_DEVICE_NOT_CONNECTED;
6430
6431 default:
6432 return STATUS_IO_DEVICE_ERROR;
6433 }
6434
6435 return STATUS_IO_DEVICE_ERROR;
6436 }
6437
6438
6439 #undef ScsiPortConvertPhysicalAddressToUlong
6440 /*
6441 * @implemented
6442 */
6443 ULONG NTAPI
6444 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address)
6445 {
6446 DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
6447 return(Address.u.LowPart);
6448 }
6449
6450 /* EOF */