bc4fe7d85e6c0c7354f6d8577879b498e7577aa4
[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 OUT 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(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
140 IN 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", DeviceExtension);
3331
3332 /* Round LunExtensionSize first to the sizeof LONGLONG */
3333 LunExtensionSize = (DeviceExtension->LunExtensionSize +
3334 sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1);
3335
3336 LunExtensionSize += sizeof(SCSI_PORT_LUN_EXTENSION);
3337 DPRINT("LunExtensionSize %lu\n", LunExtensionSize);
3338
3339 LunExtension = ExAllocatePoolWithTag(NonPagedPool, LunExtensionSize, TAG_SCSIPORT);
3340 if (LunExtension == NULL)
3341 {
3342 DPRINT1("Out of resources!\n");
3343 return NULL;
3344 }
3345
3346 /* Zero everything */
3347 RtlZeroMemory(LunExtension, LunExtensionSize);
3348
3349 /* Initialize a list of requests */
3350 InitializeListHead(&LunExtension->SrbInfo.Requests);
3351
3352 /* Initialize timeout counter */
3353 LunExtension->RequestTimeout = -1;
3354
3355 /* Set maximum queue size */
3356 LunExtension->MaxQueueCount = 256;
3357
3358 /* Initialize request queue */
3359 KeInitializeDeviceQueue(&LunExtension->DeviceQueue);
3360
3361 return LunExtension;
3362 }
3363
3364 static PSCSI_PORT_LUN_EXTENSION
3365 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
3366 IN UCHAR PathId,
3367 IN UCHAR TargetId,
3368 IN UCHAR Lun)
3369 {
3370 PSCSI_PORT_LUN_EXTENSION LunExtension;
3371
3372 DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
3373 DeviceExtension, PathId, TargetId, Lun);
3374
3375 /* Get appropriate list */
3376 LunExtension = DeviceExtension->LunExtensionList[(TargetId + Lun) % LUS_NUMBER];
3377
3378 /* Iterate it until we find what we need */
3379 while (LunExtension)
3380 {
3381 if (LunExtension->TargetId == TargetId &&
3382 LunExtension->Lun == Lun &&
3383 LunExtension->PathId == PathId)
3384 {
3385 /* All matches, return */
3386 return LunExtension;
3387 }
3388
3389 /* Advance to the next item */
3390 LunExtension = LunExtension->Next;
3391 }
3392
3393 /* We did not find anything */
3394 DPRINT("Nothing found\n");
3395 return NULL;
3396 }
3397
3398 static PSCSI_REQUEST_BLOCK_INFO
3399 SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
3400 PSCSI_PORT_LUN_EXTENSION LunExtension,
3401 PSCSI_REQUEST_BLOCK Srb)
3402 {
3403 PCHAR SrbExtension;
3404 PSCSI_REQUEST_BLOCK_INFO SrbInfo;
3405
3406 /* Spinlock must be held while this function executes */
3407 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
3408
3409 /* Allocate SRB data structure */
3410 if (DeviceExtension->NeedSrbDataAlloc)
3411 {
3412 /* Treat the abort request in a special way */
3413 if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
3414 {
3415 SrbInfo = SpiGetSrbData(DeviceExtension,
3416 Srb->PathId,
3417 Srb->TargetId,
3418 Srb->Lun,
3419 Srb->QueueTag);
3420 }
3421 else if (Srb->SrbFlags &
3422 (SRB_FLAGS_QUEUE_ACTION_ENABLE | SRB_FLAGS_NO_QUEUE_FREEZE) &&
3423 !(Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
3424 )
3425 {
3426 /* Do not process tagged commands if need request sense is set */
3427 if (LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE)
3428 {
3429 ASSERT(!(LunExtension->Flags & LUNEX_REQUEST_PENDING));
3430
3431 LunExtension->PendingRequest = Srb->OriginalRequest;
3432 LunExtension->Flags |= LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE;
3433
3434 /* Release the spinlock and return */
3435 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3436 return NULL;
3437 }
3438
3439 ASSERT(LunExtension->SrbInfo.Srb == NULL);
3440 SrbInfo = DeviceExtension->FreeSrbInfo;
3441
3442 if (SrbInfo == NULL)
3443 {
3444 /* No SRB structures left in the list. We have to leave
3445 and wait while we are called again */
3446
3447 DeviceExtension->Flags |= SCSI_PORT_REQUEST_PENDING;
3448 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3449 return NULL;
3450 }
3451
3452 DeviceExtension->FreeSrbInfo = (PSCSI_REQUEST_BLOCK_INFO)SrbInfo->Requests.Flink;
3453
3454 /* QueueTag must never be 0, so +1 to it */
3455 Srb->QueueTag = (UCHAR)(SrbInfo - DeviceExtension->SrbInfo) + 1;
3456 }
3457 else
3458 {
3459 /* Usual untagged command */
3460 if (
3461 (!IsListEmpty(&LunExtension->SrbInfo.Requests) ||
3462 LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE) &&
3463 !(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
3464 )
3465 {
3466 /* Mark it as pending and leave */
3467 ASSERT(!(LunExtension->Flags & LUNEX_REQUEST_PENDING));
3468 LunExtension->Flags |= LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE;
3469 LunExtension->PendingRequest = Srb->OriginalRequest;
3470
3471 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3472 return(NULL);
3473 }
3474
3475 Srb->QueueTag = SP_UNTAGGED;
3476 SrbInfo = &LunExtension->SrbInfo;
3477 }
3478 }
3479 else
3480 {
3481 Srb->QueueTag = SP_UNTAGGED;
3482 SrbInfo = &LunExtension->SrbInfo;
3483 }
3484
3485 /* Allocate SRB extension structure */
3486 if (DeviceExtension->NeedSrbExtensionAlloc)
3487 {
3488 /* Check the list of free extensions */
3489 SrbExtension = DeviceExtension->FreeSrbExtensions;
3490
3491 /* If no free extensions... */
3492 if (SrbExtension == NULL)
3493 {
3494 /* Free SRB data */
3495 if (Srb->Function != SRB_FUNCTION_ABORT_COMMAND &&
3496 Srb->QueueTag != SP_UNTAGGED)
3497 {
3498 SrbInfo->Requests.Blink = NULL;
3499 SrbInfo->Requests.Flink = (PLIST_ENTRY)DeviceExtension->FreeSrbInfo;
3500 DeviceExtension->FreeSrbInfo = SrbInfo;
3501 }
3502
3503 /* Return, in order to be called again later */
3504 DeviceExtension->Flags |= SCSI_PORT_REQUEST_PENDING;
3505 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3506 return NULL;
3507 }
3508
3509 /* Remove that free SRB extension from the list (since
3510 we're going to use it) */
3511 DeviceExtension->FreeSrbExtensions = *((PVOID *)SrbExtension);
3512
3513 /* Spinlock can be released now */
3514 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3515
3516 Srb->SrbExtension = SrbExtension;
3517
3518 if (Srb->SenseInfoBuffer != NULL &&
3519 DeviceExtension->SupportsAutoSense)
3520 {
3521 /* Store pointer to the SenseInfo buffer */
3522 SrbInfo->SaveSenseRequest = Srb->SenseInfoBuffer;
3523
3524 /* Does data fit the buffer? */
3525 if (Srb->SenseInfoBufferLength > sizeof(SENSE_DATA))
3526 {
3527 /* No, disabling autosense at all */
3528 Srb->SrbFlags |= SRB_FLAGS_DISABLE_AUTOSENSE;
3529 }
3530 else
3531 {
3532 /* Yes, update the buffer pointer */
3533 Srb->SenseInfoBuffer = SrbExtension + DeviceExtension->SrbExtensionSize;
3534 }
3535 }
3536 }
3537 else
3538 {
3539 /* Cleanup... */
3540 Srb->SrbExtension = NULL;
3541 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3542 }
3543
3544 return SrbInfo;
3545 }
3546
3547
3548 static NTSTATUS
3549 SpiSendInquiry(IN PDEVICE_OBJECT DeviceObject,
3550 IN OUT PSCSI_LUN_INFO LunInfo)
3551 {
3552 IO_STATUS_BLOCK IoStatusBlock;
3553 PIO_STACK_LOCATION IrpStack;
3554 KEVENT Event;
3555 KIRQL Irql;
3556 PIRP Irp;
3557 NTSTATUS Status;
3558 PINQUIRYDATA InquiryBuffer;
3559 PSENSE_DATA SenseBuffer;
3560 BOOLEAN KeepTrying = TRUE;
3561 ULONG RetryCount = 0;
3562 SCSI_REQUEST_BLOCK Srb;
3563 PCDB Cdb;
3564 PSCSI_PORT_LUN_EXTENSION LunExtension;
3565 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
3566
3567 DPRINT("SpiSendInquiry() called\n");
3568
3569 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
3570
3571 InquiryBuffer = ExAllocatePoolWithTag(NonPagedPool, INQUIRYDATABUFFERSIZE, TAG_SCSIPORT);
3572 if (InquiryBuffer == NULL)
3573 return STATUS_INSUFFICIENT_RESOURCES;
3574
3575 SenseBuffer = ExAllocatePoolWithTag(NonPagedPool, SENSE_BUFFER_SIZE, TAG_SCSIPORT);
3576 if (SenseBuffer == NULL)
3577 {
3578 ExFreePoolWithTag(InquiryBuffer, TAG_SCSIPORT);
3579 return STATUS_INSUFFICIENT_RESOURCES;
3580 }
3581
3582 while (KeepTrying)
3583 {
3584 /* Initialize event for waiting */
3585 KeInitializeEvent(&Event,
3586 NotificationEvent,
3587 FALSE);
3588
3589 /* Create an IRP */
3590 Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_IN,
3591 DeviceObject,
3592 NULL,
3593 0,
3594 InquiryBuffer,
3595 INQUIRYDATABUFFERSIZE,
3596 TRUE,
3597 &Event,
3598 &IoStatusBlock);
3599 if (Irp == NULL)
3600 {
3601 DPRINT("IoBuildDeviceIoControlRequest() failed\n");
3602
3603 /* Quit the loop */
3604 Status = STATUS_INSUFFICIENT_RESOURCES;
3605 KeepTrying = FALSE;
3606 continue;
3607 }
3608
3609 /* Prepare SRB */
3610 RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
3611
3612 Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
3613 Srb.OriginalRequest = Irp;
3614 Srb.PathId = LunInfo->PathId;
3615 Srb.TargetId = LunInfo->TargetId;
3616 Srb.Lun = LunInfo->Lun;
3617 Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
3618 Srb.SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
3619 Srb.TimeOutValue = 4;
3620 Srb.CdbLength = 6;
3621
3622 Srb.SenseInfoBuffer = SenseBuffer;
3623 Srb.SenseInfoBufferLength = SENSE_BUFFER_SIZE;
3624
3625 Srb.DataBuffer = InquiryBuffer;
3626 Srb.DataTransferLength = INQUIRYDATABUFFERSIZE;
3627
3628 /* Attach Srb to the Irp */
3629 IrpStack = IoGetNextIrpStackLocation (Irp);
3630 IrpStack->Parameters.Scsi.Srb = &Srb;
3631
3632 /* Fill in CDB */
3633 Cdb = (PCDB)Srb.Cdb;
3634 Cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
3635 Cdb->CDB6INQUIRY.LogicalUnitNumber = LunInfo->Lun;
3636 Cdb->CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE;
3637
3638 /* Call the driver */
3639 Status = IoCallDriver(DeviceObject, Irp);
3640
3641 /* Wait for it to complete */
3642 if (Status == STATUS_PENDING)
3643 {
3644 DPRINT("SpiSendInquiry(): Waiting for the driver to process request...\n");
3645 KeWaitForSingleObject(&Event,
3646 Executive,
3647 KernelMode,
3648 FALSE,
3649 NULL);
3650 Status = IoStatusBlock.Status;
3651 }
3652
3653 DPRINT("SpiSendInquiry(): Request processed by driver, status = 0x%08X\n", Status);
3654
3655 if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_SUCCESS)
3656 {
3657 /* All fine, copy data over */
3658 RtlCopyMemory(LunInfo->InquiryData,
3659 InquiryBuffer,
3660 INQUIRYDATABUFFERSIZE);
3661
3662 /* Quit the loop */
3663 Status = STATUS_SUCCESS;
3664 KeepTrying = FALSE;
3665 continue;
3666 }
3667
3668 DPRINT("Inquiry SRB failed with SrbStatus 0x%08X\n", Srb.SrbStatus);
3669
3670 /* Check if the queue is frozen */
3671 if (Srb.SrbStatus & SRB_STATUS_QUEUE_FROZEN)
3672 {
3673 /* Something weird happened, deal with it (unfreeze the queue) */
3674 KeepTrying = FALSE;
3675
3676 DPRINT("SpiSendInquiry(): the queue is frozen at TargetId %d\n", Srb.TargetId);
3677
3678 LunExtension = SpiGetLunExtension(DeviceExtension,
3679 LunInfo->PathId,
3680 LunInfo->TargetId,
3681 LunInfo->Lun);
3682
3683 /* Clear frozen flag */
3684 LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
3685
3686 /* Acquire the spinlock */
3687 KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
3688
3689 /* Process the request */
3690 SpiGetNextRequestFromLun(DeviceObject->DeviceExtension, LunExtension);
3691
3692 /* SpiGetNextRequestFromLun() releases the spinlock,
3693 so we just lower irql back to what it was before */
3694 KeLowerIrql(Irql);
3695 }
3696
3697 /* Check if data overrun happened */
3698 if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN)
3699 {
3700 DPRINT("Data overrun at TargetId %d\n", LunInfo->TargetId);
3701
3702 /* Nothing dramatic, just copy data, but limiting the size */
3703 RtlCopyMemory(LunInfo->InquiryData,
3704 InquiryBuffer,
3705 (Srb.DataTransferLength > INQUIRYDATABUFFERSIZE) ?
3706 INQUIRYDATABUFFERSIZE : Srb.DataTransferLength);
3707
3708 /* Quit the loop */
3709 Status = STATUS_SUCCESS;
3710 KeepTrying = FALSE;
3711 }
3712 else if ((Srb.SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
3713 SenseBuffer->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST)
3714 {
3715 /* LUN is not valid, but some device responds there.
3716 Mark it as invalid anyway */
3717
3718 /* Quit the loop */
3719 Status = STATUS_INVALID_DEVICE_REQUEST;
3720 KeepTrying = FALSE;
3721 }
3722 else
3723 {
3724 /* Retry a couple of times if no timeout happened */
3725 if ((RetryCount < 2) &&
3726 (SRB_STATUS(Srb.SrbStatus) != SRB_STATUS_NO_DEVICE) &&
3727 (SRB_STATUS(Srb.SrbStatus) != SRB_STATUS_SELECTION_TIMEOUT))
3728 {
3729 RetryCount++;
3730 KeepTrying = TRUE;
3731 }
3732 else
3733 {
3734 /* That's all, quit the loop */
3735 KeepTrying = FALSE;
3736
3737 /* Set status according to SRB status */
3738 if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_BAD_FUNCTION ||
3739 SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_BAD_SRB_BLOCK_LENGTH)
3740 {
3741 Status = STATUS_INVALID_DEVICE_REQUEST;
3742 }
3743 else
3744 {
3745 Status = STATUS_IO_DEVICE_ERROR;
3746 }
3747 }
3748 }
3749 }
3750
3751 /* Free buffers */
3752 ExFreePoolWithTag(InquiryBuffer, TAG_SCSIPORT);
3753 ExFreePoolWithTag(SenseBuffer, TAG_SCSIPORT);
3754
3755 DPRINT("SpiSendInquiry() done with Status 0x%08X\n", Status);
3756
3757 return Status;
3758 }
3759
3760
3761 /* Scans all SCSI buses */
3762 static VOID
3763 SpiScanAdapter(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
3764 {
3765 PSCSI_PORT_LUN_EXTENSION LunExtension;
3766 ULONG Bus;
3767 ULONG Target;
3768 ULONG Lun;
3769 PSCSI_BUS_SCAN_INFO BusScanInfo;
3770 PSCSI_LUN_INFO LastLunInfo, LunInfo, LunInfoExists;
3771 BOOLEAN DeviceExists;
3772 ULONG Hint;
3773 NTSTATUS Status;
3774 ULONG DevicesFound;
3775
3776 DPRINT("SpiScanAdapter() called\n");
3777
3778 /* Scan all buses */
3779 for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
3780 {
3781 DPRINT(" Scanning bus %d\n", Bus);
3782 DevicesFound = 0;
3783
3784 /* Get pointer to the scan information */
3785 BusScanInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus];
3786
3787 if (BusScanInfo)
3788 {
3789 /* Find the last LUN info in the list */
3790 LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
3791 LastLunInfo = LunInfo;
3792
3793 while (LunInfo != NULL)
3794 {
3795 LastLunInfo = LunInfo;
3796 LunInfo = LunInfo->Next;
3797 }
3798 }
3799 else
3800 {
3801 /* We need to allocate this buffer */
3802 BusScanInfo = ExAllocatePoolWithTag(NonPagedPool, sizeof(SCSI_BUS_SCAN_INFO), TAG_SCSIPORT);
3803 if (!BusScanInfo)
3804 {
3805 DPRINT1("Out of resources!\n");
3806 return;
3807 }
3808
3809 /* Store the pointer in the BusScanInfo array */
3810 DeviceExtension->BusesConfig->BusScanInfo[Bus] = BusScanInfo;
3811
3812 /* Fill this struct (length and bus ids for now) */
3813 BusScanInfo->Length = sizeof(SCSI_BUS_SCAN_INFO);
3814 BusScanInfo->LogicalUnitsCount = 0;
3815 BusScanInfo->BusIdentifier = DeviceExtension->PortConfig->InitiatorBusId[Bus];
3816 BusScanInfo->LunInfo = NULL;
3817
3818 /* Set pointer to the last LUN info to NULL */
3819 LastLunInfo = NULL;
3820 }
3821
3822 /* Create LUN information structure */
3823 LunInfo = ExAllocatePoolWithTag(PagedPool, sizeof(SCSI_LUN_INFO), TAG_SCSIPORT);
3824 if (!LunInfo)
3825 {
3826 DPRINT1("Out of resources!\n");
3827 return;
3828 }
3829
3830 RtlZeroMemory(LunInfo, sizeof(SCSI_LUN_INFO));
3831
3832 /* Create LunExtension */
3833 LunExtension = SpiAllocateLunExtension(DeviceExtension);
3834
3835 /* And send INQUIRY to every target */
3836 for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
3837 {
3838 /* TODO: Support scan bottom-up */
3839
3840 /* Skip if it's the same address */
3841 if (Target == BusScanInfo->BusIdentifier)
3842 continue;
3843
3844 /* Try to find an existing device here */
3845 DeviceExists = FALSE;
3846 LunInfoExists = BusScanInfo->LunInfo;
3847
3848 /* Find matching address on this bus */
3849 while (LunInfoExists)
3850 {
3851 if (LunInfoExists->TargetId == Target)
3852 {
3853 DeviceExists = TRUE;
3854 break;
3855 }
3856
3857 /* Advance to the next one */
3858 LunInfoExists = LunInfoExists->Next;
3859 }
3860
3861 /* No need to bother rescanning, since we already did that before */
3862 if (DeviceExists)
3863 continue;
3864
3865 /* Scan all logical units */
3866 for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
3867 {
3868 if ((!LunExtension) || (!LunInfo))
3869 break;
3870
3871 /* Add extension to the list */
3872 Hint = (Target + Lun) % LUS_NUMBER;
3873 LunExtension->Next = DeviceExtension->LunExtensionList[Hint];
3874 DeviceExtension->LunExtensionList[Hint] = LunExtension;
3875
3876 /* Fill Path, Target, Lun fields */
3877 LunExtension->PathId = LunInfo->PathId = (UCHAR)Bus;
3878 LunExtension->TargetId = LunInfo->TargetId = (UCHAR)Target;
3879 LunExtension->Lun = LunInfo->Lun = (UCHAR)Lun;
3880
3881 /* Set flag to prevent race conditions */
3882 LunExtension->Flags |= SCSI_PORT_SCAN_IN_PROGRESS;
3883
3884 /* Zero LU extension contents */
3885 if (DeviceExtension->LunExtensionSize)
3886 {
3887 RtlZeroMemory(LunExtension + 1,
3888 DeviceExtension->LunExtensionSize);
3889 }
3890
3891 /* Finally send the inquiry command */
3892 Status = SpiSendInquiry(DeviceExtension->DeviceObject, LunInfo);
3893
3894 if (NT_SUCCESS(Status))
3895 {
3896 /* Let's see if we really found a device */
3897 PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData;
3898
3899 /* Check if this device is unsupported */
3900 if (InquiryData->DeviceTypeQualifier == DEVICE_QUALIFIER_NOT_SUPPORTED)
3901 {
3902 DeviceExtension->LunExtensionList[Hint] =
3903 DeviceExtension->LunExtensionList[Hint]->Next;
3904
3905 continue;
3906 }
3907
3908 /* Clear the "in scan" flag */
3909 LunExtension->Flags &= ~SCSI_PORT_SCAN_IN_PROGRESS;
3910
3911 DPRINT("SpiScanAdapter(): Found device of type %d at bus %d tid %d lun %d\n",
3912 InquiryData->DeviceType, Bus, Target, Lun);
3913
3914 /*
3915 * Cache the inquiry data into the LUN extension (or alternatively
3916 * we could save a pointer to LunInfo within the LunExtension?)
3917 */
3918 RtlCopyMemory(&LunExtension->InquiryData,
3919 InquiryData,
3920 INQUIRYDATABUFFERSIZE);
3921
3922 /* Add this info to the linked list */
3923 LunInfo->Next = NULL;
3924 if (LastLunInfo)
3925 LastLunInfo->Next = LunInfo;
3926 else
3927 BusScanInfo->LunInfo = LunInfo;
3928
3929 /* Store the last LUN info */
3930 LastLunInfo = LunInfo;
3931
3932 /* Store DeviceObject */
3933 LunInfo->DeviceObject = DeviceExtension->DeviceObject;
3934
3935 /* Allocate another buffer */
3936 LunInfo = ExAllocatePoolWithTag(PagedPool, sizeof(SCSI_LUN_INFO), TAG_SCSIPORT);
3937 if (!LunInfo)
3938 {
3939 DPRINT1("Out of resources!\n");
3940 break;
3941 }
3942
3943 RtlZeroMemory(LunInfo, sizeof(SCSI_LUN_INFO));
3944
3945 /* Create a new LU extension */
3946 LunExtension = SpiAllocateLunExtension(DeviceExtension);
3947
3948 DevicesFound++;
3949 }
3950 else
3951 {
3952 /* Remove this LUN from the list */
3953 DeviceExtension->LunExtensionList[Hint] =
3954 DeviceExtension->LunExtensionList[Hint]->Next;
3955
3956 /* Decide whether we are continuing or not */
3957 if (Status == STATUS_INVALID_DEVICE_REQUEST)
3958 continue;
3959 else
3960 break;
3961 }
3962 }
3963 }
3964
3965 /* Free allocated buffers */
3966 if (LunExtension)
3967 ExFreePoolWithTag(LunExtension, TAG_SCSIPORT);
3968
3969 if (LunInfo)
3970 ExFreePoolWithTag(LunInfo, TAG_SCSIPORT);
3971
3972 /* Sum what we found */
3973 BusScanInfo->LogicalUnitsCount += (UCHAR)DevicesFound;
3974 DPRINT(" Found %d devices on bus %d\n", DevicesFound, Bus);
3975 }
3976
3977 DPRINT("SpiScanAdapter() done\n");
3978 }
3979
3980
3981 static NTSTATUS
3982 SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
3983 IN PIRP Irp)
3984 {
3985 ULONG InquiryDataSize;
3986 PSCSI_LUN_INFO LunInfo;
3987 ULONG BusCount, LunCount, Length;
3988 PIO_STACK_LOCATION IrpStack;
3989 PSCSI_ADAPTER_BUS_INFO AdapterBusInfo;
3990 PSCSI_INQUIRY_DATA InquiryData;
3991 PSCSI_BUS_DATA BusData;
3992 ULONG Bus;
3993 PUCHAR Buffer;
3994
3995 DPRINT("SpiGetInquiryData() called\n");
3996
3997 /* Get pointer to the buffer */
3998 IrpStack = IoGetCurrentIrpStackLocation(Irp);
3999 Buffer = Irp->AssociatedIrp.SystemBuffer;
4000
4001 /* Initialize bus and LUN counters */
4002 BusCount = DeviceExtension->BusesConfig->NumberOfBuses;
4003 LunCount = 0;
4004
4005 /* Calculate total number of LUNs */
4006 for (Bus = 0; Bus < BusCount; Bus++)
4007 LunCount += DeviceExtension->BusesConfig->BusScanInfo[Bus]->LogicalUnitsCount;
4008
4009 /* Calculate size of inquiry data, rounding up to sizeof(ULONG) */
4010 InquiryDataSize =
4011 ((sizeof(SCSI_INQUIRY_DATA) - 1 + INQUIRYDATABUFFERSIZE +
4012 sizeof(ULONG) - 1) & ~(sizeof(ULONG) - 1));
4013
4014 /* Calculate data size */
4015 Length = sizeof(SCSI_ADAPTER_BUS_INFO) + (BusCount - 1) * sizeof(SCSI_BUS_DATA);
4016
4017 Length += InquiryDataSize * LunCount;
4018
4019 /* Check, if all data is going to fit into provided buffer */
4020 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < Length)
4021 {
4022 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
4023 return STATUS_BUFFER_TOO_SMALL;
4024 }
4025
4026 /* Store data size in the IRP */
4027 Irp->IoStatus.Information = Length;
4028
4029 DPRINT("Data size: %lu\n", Length);
4030
4031 AdapterBusInfo = (PSCSI_ADAPTER_BUS_INFO)Buffer;
4032
4033 AdapterBusInfo->NumberOfBuses = (UCHAR)BusCount;
4034
4035 /* Point InquiryData to the corresponding place inside Buffer */
4036 InquiryData = (PSCSI_INQUIRY_DATA)(Buffer + sizeof(SCSI_ADAPTER_BUS_INFO) +
4037 (BusCount - 1) * sizeof(SCSI_BUS_DATA));
4038
4039 /* Loop each bus */
4040 for (Bus = 0; Bus < BusCount; Bus++)
4041 {
4042 BusData = &AdapterBusInfo->BusData[Bus];
4043
4044 /* Calculate and save an offset of the inquiry data */
4045 BusData->InquiryDataOffset = (ULONG)((PUCHAR)InquiryData - Buffer);
4046
4047 /* Get a pointer to the LUN information structure */
4048 LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
4049
4050 /* Store Initiator Bus Id */
4051 BusData->InitiatorBusId =
4052 DeviceExtension->BusesConfig->BusScanInfo[Bus]->BusIdentifier;
4053
4054 /* Store LUN count */
4055 BusData->NumberOfLogicalUnits =
4056 DeviceExtension->BusesConfig->BusScanInfo[Bus]->LogicalUnitsCount;
4057
4058 /* Loop all LUNs */
4059 while (LunInfo != NULL)
4060 {
4061 DPRINT("(Bus %lu Target %lu Lun %lu)\n",
4062 Bus, LunInfo->TargetId, LunInfo->Lun);
4063
4064 /* Fill InquiryData with values */
4065 InquiryData->PathId = LunInfo->PathId;
4066 InquiryData->TargetId = LunInfo->TargetId;
4067 InquiryData->Lun = LunInfo->Lun;
4068 InquiryData->InquiryDataLength = INQUIRYDATABUFFERSIZE;
4069 InquiryData->DeviceClaimed = LunInfo->DeviceClaimed;
4070 InquiryData->NextInquiryDataOffset =
4071 (ULONG)((PUCHAR)InquiryData + InquiryDataSize - Buffer);
4072
4073 /* Copy data in it */
4074 RtlCopyMemory(InquiryData->InquiryData,
4075 LunInfo->InquiryData,
4076 INQUIRYDATABUFFERSIZE);
4077
4078 /* Move to the next LUN */
4079 LunInfo = LunInfo->Next;
4080 InquiryData = (PSCSI_INQUIRY_DATA) ((PCHAR)InquiryData + InquiryDataSize);
4081 }
4082
4083 /* Either mark the end, or set offset to 0 */
4084 if (BusData->NumberOfLogicalUnits != 0)
4085 ((PSCSI_INQUIRY_DATA) ((PCHAR)InquiryData - InquiryDataSize))->NextInquiryDataOffset = 0;
4086 else
4087 BusData->InquiryDataOffset = 0;
4088 }
4089
4090 /* Finish with success */
4091 Irp->IoStatus.Status = STATUS_SUCCESS;
4092 return STATUS_SUCCESS;
4093 }
4094
4095 static PSCSI_REQUEST_BLOCK_INFO
4096 SpiGetSrbData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
4097 IN UCHAR PathId,
4098 IN UCHAR TargetId,
4099 IN UCHAR Lun,
4100 IN UCHAR QueueTag)
4101 {
4102 PSCSI_PORT_LUN_EXTENSION LunExtension;
4103
4104 if (QueueTag == SP_UNTAGGED)
4105 {
4106 /* Untagged request, get LU and return pointer to SrbInfo */
4107 LunExtension = SpiGetLunExtension(DeviceExtension,
4108 PathId,
4109 TargetId,
4110 Lun);
4111
4112 /* Return NULL in case of error */
4113 if (!LunExtension)
4114 return(NULL);
4115
4116 /* Return the pointer to SrbInfo */
4117 return &LunExtension->SrbInfo;
4118 }
4119 else
4120 {
4121 /* Make sure the tag is valid, if it is - return the data */
4122 if (QueueTag > DeviceExtension->SrbDataCount || QueueTag < 1)
4123 return NULL;
4124 else
4125 return &DeviceExtension->SrbInfo[QueueTag -1];
4126 }
4127 }
4128
4129 static VOID
4130 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
4131 IN PSCSI_REQUEST_BLOCK InitialSrb)
4132 {
4133 PSCSI_REQUEST_BLOCK Srb;
4134 PCDB Cdb;
4135 PIRP Irp;
4136 PIO_STACK_LOCATION IrpStack;
4137 LARGE_INTEGER LargeInt;
4138 PVOID *Ptr;
4139
4140 DPRINT("SpiSendRequestSense() entered, InitialSrb %p\n", InitialSrb);
4141
4142 /* Allocate Srb */
4143 Srb = ExAllocatePoolWithTag(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK) + sizeof(PVOID), TAG_SCSIPORT);
4144 RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
4145
4146 /* Allocate IRP */
4147 LargeInt.QuadPart = (LONGLONG) 1;
4148 Irp = IoBuildAsynchronousFsdRequest(IRP_MJ_READ,
4149 DeviceExtension->DeviceObject,
4150 InitialSrb->SenseInfoBuffer,
4151 InitialSrb->SenseInfoBufferLength,
4152 &LargeInt,
4153 NULL);
4154
4155 IoSetCompletionRoutine(Irp,
4156 (PIO_COMPLETION_ROUTINE)SpiCompletionRoutine,
4157 Srb,
4158 TRUE,
4159 TRUE,
4160 TRUE);
4161
4162 if (!Srb)
4163 {
4164 DPRINT("SpiSendRequestSense() failed, Srb %p\n", Srb);
4165 return;
4166 }
4167
4168 IrpStack = IoGetNextIrpStackLocation(Irp);
4169 IrpStack->MajorFunction = IRP_MJ_SCSI;
4170
4171 /* Put Srb address into Irp... */
4172 IrpStack->Parameters.Others.Argument1 = (PVOID)Srb;
4173
4174 /* ...and vice versa */
4175 Srb->OriginalRequest = Irp;
4176
4177 /* Save Srb */
4178 Ptr = (PVOID *)(Srb+1);
4179 *Ptr = InitialSrb;
4180
4181 /* Build CDB for REQUEST SENSE */
4182 Srb->CdbLength = 6;
4183 Cdb = (PCDB)Srb->Cdb;
4184
4185 Cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE;
4186 Cdb->CDB6INQUIRY.LogicalUnitNumber = 0;
4187 Cdb->CDB6INQUIRY.Reserved1 = 0;
4188 Cdb->CDB6INQUIRY.PageCode = 0;
4189 Cdb->CDB6INQUIRY.IReserved = 0;
4190 Cdb->CDB6INQUIRY.AllocationLength = (UCHAR)InitialSrb->SenseInfoBufferLength;
4191 Cdb->CDB6INQUIRY.Control = 0;
4192
4193 /* Set address */
4194 Srb->TargetId = InitialSrb->TargetId;
4195 Srb->Lun = InitialSrb->Lun;
4196 Srb->PathId = InitialSrb->PathId;
4197
4198 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
4199 Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
4200
4201 /* Timeout will be 2 seconds */
4202 Srb->TimeOutValue = 2;
4203
4204 /* No auto request sense */
4205 Srb->SenseInfoBufferLength = 0;
4206 Srb->SenseInfoBuffer = NULL;
4207
4208 /* Set necessary flags */
4209 Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_BYPASS_FROZEN_QUEUE |
4210 SRB_FLAGS_DISABLE_DISCONNECT;
4211
4212 /* Transfer disable synch transfer flag */
4213 if (InitialSrb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER)
4214 Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
4215
4216 Srb->DataBuffer = InitialSrb->SenseInfoBuffer;
4217
4218 /* Fill the transfer length */
4219 Srb->DataTransferLength = InitialSrb->SenseInfoBufferLength;
4220
4221 /* Clear statuses */
4222 Srb->ScsiStatus = Srb->SrbStatus = 0;
4223 Srb->NextSrb = 0;
4224
4225 /* Call the driver */
4226 (VOID)IoCallDriver(DeviceExtension->DeviceObject, Irp);
4227
4228 DPRINT("SpiSendRequestSense() done\n");
4229 }
4230
4231
4232 static
4233 VOID
4234 NTAPI
4235 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
4236 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo,
4237 OUT PBOOLEAN NeedToCallStartIo)
4238 {
4239 PSCSI_REQUEST_BLOCK Srb;
4240 PSCSI_PORT_LUN_EXTENSION LunExtension;
4241 LONG Result;
4242 PIRP Irp;
4243 //ULONG SequenceNumber;
4244
4245 Srb = SrbInfo->Srb;
4246 Irp = Srb->OriginalRequest;
4247
4248 /* Get Lun extension */
4249 LunExtension = SpiGetLunExtension(DeviceExtension,
4250 Srb->PathId,
4251 Srb->TargetId,
4252 Srb->Lun);
4253
4254 if (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION &&
4255 DeviceExtension->MapBuffers &&
4256 Irp->MdlAddress)
4257 {
4258 /* MDL is shared if transfer is broken into smaller parts */
4259 Srb->DataBuffer = (PCCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress) +
4260 ((PCCHAR)Srb->DataBuffer - SrbInfo->DataOffset);
4261
4262 /* In case of data going in, flush the buffers */
4263 if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
4264 {
4265 KeFlushIoBuffers(Irp->MdlAddress,
4266 TRUE,
4267 FALSE);
4268 }
4269 }
4270
4271 /* Flush adapter if needed */
4272 if (SrbInfo->BaseOfMapRegister)
4273 {
4274 /* TODO: Implement */
4275 ASSERT(FALSE);
4276 }
4277
4278 /* Clear the request */
4279 SrbInfo->Srb = NULL;
4280
4281 /* If disconnect is disabled... */
4282 if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
4283 {
4284 /* Acquire the spinlock since we mess with flags */
4285 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
4286
4287 /* Set corresponding flag */
4288 DeviceExtension->Flags |= SCSI_PORT_DISCONNECT_ALLOWED;
4289
4290 /* Clear the timer if needed */
4291 if (!(DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET))
4292 DeviceExtension->TimerCount = -1;
4293
4294 /* Spinlock is not needed anymore */
4295 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4296
4297 if (!(DeviceExtension->Flags & SCSI_PORT_REQUEST_PENDING) &&
4298 !(DeviceExtension->Flags & SCSI_PORT_DEVICE_BUSY) &&
4299 !(*NeedToCallStartIo))
4300 {
4301 /* We're not busy, but we have a request pending */
4302 IoStartNextPacket(DeviceExtension->DeviceObject, FALSE);
4303 }
4304 }
4305
4306 /* Scatter/gather */
4307 if (Srb->SrbFlags & SRB_FLAGS_SGLIST_FROM_POOL)
4308 {
4309 /* TODO: Implement */
4310 ASSERT(FALSE);
4311 }
4312
4313 /* Acquire spinlock (we're freeing SrbExtension) */
4314 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
4315
4316 /* Free it (if needed) */
4317 if (Srb->SrbExtension)
4318 {
4319 if (Srb->SenseInfoBuffer != NULL && DeviceExtension->SupportsAutoSense)
4320 {
4321 ASSERT(Srb->SenseInfoBuffer == NULL || SrbInfo->SaveSenseRequest != NULL);
4322
4323 if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)
4324 {
4325 /* Copy sense data to the buffer */
4326 RtlCopyMemory(SrbInfo->SaveSenseRequest,
4327 Srb->SenseInfoBuffer,
4328 Srb->SenseInfoBufferLength);
4329 }
4330
4331 /* And restore the pointer */
4332 Srb->SenseInfoBuffer = SrbInfo->SaveSenseRequest;
4333 }
4334
4335 /* Put it into the free srb extensions list */
4336 *((PVOID *)Srb->SrbExtension) = DeviceExtension->FreeSrbExtensions;
4337 DeviceExtension->FreeSrbExtensions = Srb->SrbExtension;
4338 }
4339
4340 /* Save transfer length in the IRP */
4341 Irp->IoStatus.Information = Srb->DataTransferLength;
4342
4343 //SequenceNumber = SrbInfo->SequenceNumber;
4344 SrbInfo->SequenceNumber = 0;
4345
4346 /* Decrement the queue count */
4347 LunExtension->QueueCount--;
4348
4349 /* Free Srb, if needed*/
4350 if (Srb->QueueTag != SP_UNTAGGED)
4351 {
4352 /* Put it into the free list */
4353 SrbInfo->Requests.Blink = NULL;
4354 SrbInfo->Requests.Flink = (PLIST_ENTRY)DeviceExtension->FreeSrbInfo;
4355 DeviceExtension->FreeSrbInfo = SrbInfo;
4356 }
4357
4358 /* SrbInfo is not used anymore */
4359 SrbInfo = NULL;
4360
4361 if (DeviceExtension->Flags & SCSI_PORT_REQUEST_PENDING)
4362 {
4363 /* Clear the flag */
4364 DeviceExtension->Flags &= ~SCSI_PORT_REQUEST_PENDING;
4365
4366 /* Note the caller about StartIo */
4367 *NeedToCallStartIo = TRUE;
4368 }
4369
4370 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
4371 {
4372 /* Start the packet */
4373 Irp->IoStatus.Status = STATUS_SUCCESS;
4374
4375 if (!(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE) &&
4376 LunExtension->RequestTimeout == -1)
4377 {
4378 /* Start the next packet */
4379 SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
4380 }
4381 else
4382 {
4383 /* Release the spinlock */
4384 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4385 }
4386
4387 DPRINT("IoCompleting request IRP 0x%p\n", Irp);
4388
4389 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
4390
4391 /* Decrement number of active requests, and analyze the result */
4392 Result = InterlockedDecrement(&DeviceExtension->ActiveRequestCounter);
4393
4394 if (Result < 0 &&
4395 !DeviceExtension->MapRegisters &&
4396 DeviceExtension->AdapterObject != NULL)
4397 {
4398 /* Nullify map registers */
4399 DeviceExtension->MapRegisterBase = NULL;
4400 IoFreeAdapterChannel(DeviceExtension->AdapterObject);
4401 }
4402
4403 /* Exit, we're done */
4404 return;
4405 }
4406
4407 /* Decrement number of active requests, and analyze the result */
4408 Result = InterlockedDecrement(&DeviceExtension->ActiveRequestCounter);
4409
4410 if (Result < 0 &&
4411 !DeviceExtension->MapRegisters &&
4412 DeviceExtension->AdapterObject != NULL)
4413 {
4414 /* Result is negative, so this is a slave, free map registers */
4415 DeviceExtension->MapRegisterBase = NULL;
4416 IoFreeAdapterChannel(DeviceExtension->AdapterObject);
4417 }
4418
4419 /* Convert status */
4420 Irp->IoStatus.Status = SpiStatusSrbToNt(Srb->SrbStatus);
4421
4422 /* It's not a bypass, it's busy or the queue is full? */
4423 if ((Srb->ScsiStatus == SCSISTAT_BUSY ||
4424 Srb->SrbStatus == SRB_STATUS_BUSY ||
4425 Srb->ScsiStatus == SCSISTAT_QUEUE_FULL) &&
4426 !(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE))
4427 {
4428
4429 DPRINT("Busy SRB status %x\n", Srb->SrbStatus);
4430
4431 /* Requeue, if needed */
4432 if (LunExtension->Flags & (LUNEX_FROZEN_QUEUE | LUNEX_BUSY))
4433 {
4434 DPRINT("it's being requeued\n");
4435
4436 Srb->SrbStatus = SRB_STATUS_PENDING;
4437 Srb->ScsiStatus = 0;
4438
4439 if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue,
4440 &Irp->Tail.Overlay.DeviceQueueEntry,
4441 Srb->QueueSortKey))
4442 {
4443 /* It's a big f.ck up if we got here */
4444 Srb->SrbStatus = SRB_STATUS_ERROR;
4445 Srb->ScsiStatus = SCSISTAT_BUSY;
4446
4447 ASSERT(FALSE);
4448 goto Error;
4449 }
4450
4451 /* Release the spinlock */
4452 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4453
4454 }
4455 else if (LunExtension->AttemptCount++ < 20)
4456 {
4457 /* LUN is still busy */
4458 Srb->ScsiStatus = 0;
4459 Srb->SrbStatus = SRB_STATUS_PENDING;
4460
4461 LunExtension->BusyRequest = Irp;
4462 LunExtension->Flags |= LUNEX_BUSY;
4463
4464 /* Release the spinlock */
4465 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4466 }
4467 else
4468 {
4469 Error:
4470 /* Freeze the queue*/
4471 Srb->SrbStatus |= SRB_STATUS_QUEUE_FROZEN;
4472 LunExtension->Flags |= LUNEX_FROZEN_QUEUE;
4473
4474 /* "Unfull" the queue */
4475 LunExtension->Flags &= ~LUNEX_FULL_QUEUE;
4476
4477 /* Release the spinlock */
4478 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4479
4480 /* Return status that the device is not ready */
4481 Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
4482 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
4483 }
4484
4485 return;
4486 }
4487
4488 /* Start the next request, if LUN is idle, and this is sense request */
4489 if (((Srb->ScsiStatus != SCSISTAT_CHECK_CONDITION) ||
4490 (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) ||
4491 !Srb->SenseInfoBuffer || !Srb->SenseInfoBufferLength)
4492 && (Srb->SrbFlags & SRB_FLAGS_NO_QUEUE_FREEZE))
4493 {
4494 if (LunExtension->RequestTimeout == -1)
4495 SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
4496 else
4497 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4498 }
4499 else
4500 {
4501 /* Freeze the queue */
4502 Srb->SrbStatus |= SRB_STATUS_QUEUE_FROZEN;
4503 LunExtension->Flags |= LUNEX_FROZEN_QUEUE;
4504
4505 /* Do we need a request sense? */
4506 if (Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION &&
4507 !(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
4508 Srb->SenseInfoBuffer && Srb->SenseInfoBufferLength)
4509 {
4510 /* If LUN is busy, we have to requeue it in order to allow request sense */
4511 if (LunExtension->Flags & LUNEX_BUSY)
4512 {
4513 DPRINT("Requeuing busy request to allow request sense\n");
4514
4515 if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue,
4516 &LunExtension->BusyRequest->Tail.Overlay.DeviceQueueEntry,
4517 Srb->QueueSortKey))
4518 {
4519 /* We should never get here */
4520 ASSERT(FALSE);
4521
4522 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4523 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
4524 return;
4525
4526 }
4527
4528 /* Clear busy flags */
4529 LunExtension->Flags &= ~(LUNEX_FULL_QUEUE | LUNEX_BUSY);
4530 }
4531
4532 /* Release the spinlock */
4533 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4534
4535 /* Send RequestSense */
4536 SpiSendRequestSense(DeviceExtension, Srb);
4537
4538 /* Exit */
4539 return;
4540 }
4541
4542 /* Release the spinlock */
4543 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4544 }
4545
4546 /* Complete the request */
4547 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
4548 }
4549
4550 NTSTATUS
4551 NTAPI
4552 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject,
4553 PIRP Irp,
4554 PVOID Context)
4555 {
4556 PSCSI_REQUEST_BLOCK Srb = (PSCSI_REQUEST_BLOCK)Context;
4557 PSCSI_REQUEST_BLOCK InitialSrb;
4558 PIRP InitialIrp;
4559
4560 DPRINT("SpiCompletionRoutine() entered, IRP %p \n", Irp);
4561
4562 if ((Srb->Function == SRB_FUNCTION_RESET_BUS) ||
4563 (Srb->Function == SRB_FUNCTION_ABORT_COMMAND))
4564 {
4565 /* Deallocate SRB and IRP and exit */
4566 ExFreePool(Srb);
4567 IoFreeIrp(Irp);
4568
4569 return STATUS_MORE_PROCESSING_REQUIRED;
4570 }
4571
4572 /* Get a pointer to the SRB and IRP which were initially sent */
4573 InitialSrb = *((PVOID *)(Srb+1));
4574 InitialIrp = InitialSrb->OriginalRequest;
4575
4576 if ((SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS) ||
4577 (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN))
4578 {
4579 /* Sense data is OK */
4580 InitialSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
4581
4582 /* Set length to be the same */
4583 InitialSrb->SenseInfoBufferLength = (UCHAR)Srb->DataTransferLength;
4584 }
4585
4586 /* Make sure initial SRB's queue is frozen */
4587 ASSERT(InitialSrb->SrbStatus & SRB_STATUS_QUEUE_FROZEN);
4588
4589 /* Complete this request */
4590 IoCompleteRequest(InitialIrp, IO_DISK_INCREMENT);
4591
4592 /* Deallocate everything (internal) */
4593 ExFreePool(Srb);
4594
4595 if (Irp->MdlAddress != NULL)
4596 {
4597 MmUnlockPages(Irp->MdlAddress);
4598 IoFreeMdl(Irp->MdlAddress);
4599 Irp->MdlAddress = NULL;
4600 }
4601
4602 IoFreeIrp(Irp);
4603 return STATUS_MORE_PROCESSING_REQUIRED;
4604 }
4605
4606 static BOOLEAN NTAPI
4607 ScsiPortIsr(IN PKINTERRUPT Interrupt,
4608 IN PVOID ServiceContext)
4609 {
4610 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
4611
4612 DPRINT("ScsiPortIsr() called!\n");
4613
4614 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext;
4615
4616 /* If interrupts are disabled - we don't expect any */
4617 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_DISABLE_INTERRUPTS)
4618 return FALSE;
4619
4620 /* Call miniport's HwInterrupt routine */
4621 if (DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension) == FALSE)
4622 {
4623 /* This interrupt doesn't belong to us */
4624 return FALSE;
4625 }
4626
4627 /* If flag of notification is set - queue a DPC */
4628 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
4629 {
4630 IoRequestDpc(DeviceExtension->DeviceObject,
4631 DeviceExtension->CurrentIrp,
4632 DeviceExtension);
4633 }
4634
4635 return TRUE;
4636 }
4637
4638 BOOLEAN
4639 NTAPI
4640 SpiSaveInterruptData(IN PVOID Context)
4641 {
4642 PSCSI_PORT_SAVE_INTERRUPT InterruptContext = Context;
4643 PSCSI_PORT_LUN_EXTENSION LunExtension;
4644 PSCSI_REQUEST_BLOCK Srb;
4645 PSCSI_REQUEST_BLOCK_INFO SrbInfo, NextSrbInfo;
4646 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
4647 BOOLEAN IsTimed;
4648
4649 /* Get pointer to the device extension */
4650 DeviceExtension = InterruptContext->DeviceExtension;
4651
4652 /* If we don't have anything pending - return */
4653 if (!(DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED))
4654 return FALSE;
4655
4656 /* Actually save the interrupt data */
4657 *InterruptContext->InterruptData = DeviceExtension->InterruptData;
4658
4659 /* Clear the data stored in the device extension */
4660 DeviceExtension->InterruptData.Flags &=
4661 (SCSI_PORT_RESET | SCSI_PORT_RESET_REQUEST | SCSI_PORT_DISABLE_INTERRUPTS);
4662 DeviceExtension->InterruptData.CompletedAbort = NULL;
4663 DeviceExtension->InterruptData.ReadyLun = NULL;
4664 DeviceExtension->InterruptData.CompletedRequests = NULL;
4665
4666 /* Loop through the list of completed requests */
4667 SrbInfo = InterruptContext->InterruptData->CompletedRequests;
4668
4669 while (SrbInfo)
4670 {
4671 /* Make sure we have SRV */
4672 ASSERT(SrbInfo->Srb);
4673
4674 /* Get SRB and LunExtension */
4675 Srb = SrbInfo->Srb;
4676
4677 LunExtension = SpiGetLunExtension(DeviceExtension,
4678 Srb->PathId,
4679 Srb->TargetId,
4680 Srb->Lun);
4681
4682 /* We have to check special cases if request is unsuccessful*/
4683 if (Srb->SrbStatus != SRB_STATUS_SUCCESS)
4684 {
4685 /* Check if we need request sense by a few conditions */
4686 if (Srb->SenseInfoBuffer && Srb->SenseInfoBufferLength &&
4687 Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION &&
4688 !(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID))
4689 {
4690 if (LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE)
4691 {
4692 /* It means: we tried to send REQUEST SENSE, but failed */
4693
4694 Srb->ScsiStatus = 0;
4695 Srb->SrbStatus = SRB_STATUS_REQUEST_SENSE_FAILED;
4696 }
4697 else
4698 {
4699 /* Set the corresponding flag, so that REQUEST SENSE
4700 will be sent */
4701 LunExtension->Flags |= LUNEX_NEED_REQUEST_SENSE;
4702 }
4703
4704 }
4705
4706 /* Check for a full queue */
4707 if (Srb->ScsiStatus == SCSISTAT_QUEUE_FULL)
4708 {
4709 /* TODO: Implement when it's encountered */
4710 ASSERT(FALSE);
4711 }
4712 }
4713
4714 /* Let's decide if we need to watch timeout or not */
4715 if (Srb->QueueTag == SP_UNTAGGED)
4716 {
4717 IsTimed = TRUE;
4718 }
4719 else
4720 {
4721 if (LunExtension->SrbInfo.Requests.Flink == &SrbInfo->Requests)
4722 IsTimed = TRUE;
4723 else
4724 IsTimed = FALSE;
4725
4726 /* Remove it from the queue */
4727 RemoveEntryList(&SrbInfo->Requests);
4728 }
4729
4730 if (IsTimed)
4731 {
4732 /* We have to maintain timeout counter */
4733 if (IsListEmpty(&LunExtension->SrbInfo.Requests))
4734 {
4735 LunExtension->RequestTimeout = -1;
4736 }
4737 else
4738 {
4739 NextSrbInfo = CONTAINING_RECORD(LunExtension->SrbInfo.Requests.Flink,
4740 SCSI_REQUEST_BLOCK_INFO,
4741 Requests);
4742
4743 Srb = NextSrbInfo->Srb;
4744
4745 /* Update timeout counter */
4746 LunExtension->RequestTimeout = Srb->TimeOutValue;
4747 }
4748 }
4749
4750 SrbInfo = SrbInfo->CompletedRequests;
4751 }
4752
4753 return TRUE;
4754 }
4755
4756 VOID
4757 NTAPI
4758 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
4759 IN PSCSI_PORT_LUN_EXTENSION LunExtension)
4760 {
4761 PIO_STACK_LOCATION IrpStack;
4762 PIRP NextIrp;
4763 PKDEVICE_QUEUE_ENTRY Entry;
4764 PSCSI_REQUEST_BLOCK Srb;
4765
4766
4767 /* If LUN is not active or queue is more than maximum allowed */
4768 if (LunExtension->QueueCount >= LunExtension->MaxQueueCount ||
4769 !(LunExtension->Flags & SCSI_PORT_LU_ACTIVE))
4770 {
4771 /* Release the spinlock and exit */
4772 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4773 return;
4774 }
4775
4776 /* Check if we can get a next request */
4777 if (LunExtension->Flags &
4778 (LUNEX_NEED_REQUEST_SENSE | LUNEX_BUSY |
4779 LUNEX_FULL_QUEUE | LUNEX_FROZEN_QUEUE | LUNEX_REQUEST_PENDING))
4780 {
4781 /* Pending requests can only be started if the queue is empty */
4782 if (IsListEmpty(&LunExtension->SrbInfo.Requests) &&
4783 !(LunExtension->Flags &
4784 (LUNEX_BUSY | LUNEX_FROZEN_QUEUE | LUNEX_FULL_QUEUE | LUNEX_NEED_REQUEST_SENSE)))
4785 {
4786 /* Make sure we have SRB */
4787 ASSERT(LunExtension->SrbInfo.Srb == NULL);
4788
4789 /* Clear active and pending flags */
4790 LunExtension->Flags &= ~(LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE);
4791
4792 /* Get next Irp, and clear pending requests list */
4793 NextIrp = LunExtension->PendingRequest;
4794 LunExtension->PendingRequest = NULL;
4795
4796 /* Set attempt counter to zero */
4797 LunExtension->AttemptCount = 0;
4798
4799 /* Release the spinlock */
4800 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4801
4802 /* Start the next pending request */
4803 IoStartPacket(DeviceExtension->DeviceObject, NextIrp, (PULONG)NULL, NULL);
4804
4805 return;
4806 }
4807 else
4808 {
4809 /* Release the spinlock, without clearing any flags and exit */
4810 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4811
4812 return;
4813 }
4814 }
4815
4816 /* Reset active flag */
4817 LunExtension->Flags &= ~SCSI_PORT_LU_ACTIVE;
4818
4819 /* Set attempt counter to zero */
4820 LunExtension->AttemptCount = 0;
4821
4822 /* Remove packet from the device queue */
4823 Entry = KeRemoveByKeyDeviceQueue(&LunExtension->DeviceQueue, LunExtension->SortKey);
4824
4825 if (Entry != NULL)
4826 {
4827 /* Get pointer to the next irp */
4828 NextIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
4829
4830 /* Get point to the SRB */
4831 IrpStack = IoGetCurrentIrpStackLocation(NextIrp);
4832 Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
4833
4834 /* Set new key*/
4835 LunExtension->SortKey = Srb->QueueSortKey;
4836 LunExtension->SortKey++;
4837
4838 /* Release the spinlock */
4839 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4840
4841 /* Start the next pending request */
4842 IoStartPacket(DeviceExtension->DeviceObject, NextIrp, (PULONG)NULL, NULL);
4843 }
4844 else
4845 {
4846 /* Release the spinlock */
4847 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4848 }
4849 }
4850
4851
4852
4853 // ScsiPortDpcForIsr
4854 // DESCRIPTION:
4855 //
4856 // RUN LEVEL:
4857 //
4858 // ARGUMENTS:
4859 // IN PKDPC Dpc
4860 // IN PDEVICE_OBJECT DpcDeviceObject
4861 // IN PIRP DpcIrp
4862 // IN PVOID DpcContext
4863 //
4864 static VOID NTAPI
4865 ScsiPortDpcForIsr(IN PKDPC Dpc,
4866 IN PDEVICE_OBJECT DpcDeviceObject,
4867 IN PIRP DpcIrp,
4868 IN PVOID DpcContext)
4869 {
4870 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DpcDeviceObject->DeviceExtension;
4871 SCSI_PORT_INTERRUPT_DATA InterruptData;
4872 SCSI_PORT_SAVE_INTERRUPT Context;
4873 PSCSI_PORT_LUN_EXTENSION LunExtension;
4874 BOOLEAN NeedToStartIo;
4875 PSCSI_REQUEST_BLOCK_INFO SrbInfo;
4876 LARGE_INTEGER TimerValue;
4877
4878 DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
4879 Dpc, DpcDeviceObject, DpcIrp, DpcContext);
4880
4881 /* We need to acquire spinlock */
4882 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
4883
4884 RtlZeroMemory(&InterruptData, sizeof(SCSI_PORT_INTERRUPT_DATA));
4885
4886 TryAgain:
4887
4888 /* Interrupt structure must be snapshotted, and only then analyzed */
4889 Context.InterruptData = &InterruptData;
4890 Context.DeviceExtension = DeviceExtension;
4891
4892 if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0],
4893 SpiSaveInterruptData,
4894 &Context))
4895 {
4896 /* Nothing - just return (don't forget to release the spinlock */
4897 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4898 DPRINT("ScsiPortDpcForIsr() done\n");
4899 return;
4900 }
4901
4902 /* If flush of adapters is needed - do it */
4903 if (InterruptData.Flags & SCSI_PORT_FLUSH_ADAPTERS)
4904 {
4905 /* TODO: Implement */
4906 ASSERT(FALSE);
4907 }
4908
4909 /* Check for IoMapTransfer */
4910 if (InterruptData.Flags & SCSI_PORT_MAP_TRANSFER)
4911 {
4912 /* TODO: Implement */
4913 ASSERT(FALSE);
4914 }
4915
4916 /* Check if timer is needed */
4917 if (InterruptData.Flags & SCSI_PORT_TIMER_NEEDED)
4918 {
4919 /* Save the timer routine */
4920 DeviceExtension->HwScsiTimer = InterruptData.HwScsiTimer;
4921
4922 if (InterruptData.MiniportTimerValue == 0)
4923 {
4924 /* Cancel the timer */
4925 KeCancelTimer(&DeviceExtension->MiniportTimer);
4926 }
4927 else
4928 {
4929 /* Convert timer value */
4930 TimerValue.QuadPart = Int32x32To64(InterruptData.MiniportTimerValue, -10);
4931
4932 /* Set the timer */
4933 KeSetTimer(&DeviceExtension->MiniportTimer,
4934 TimerValue,
4935 &DeviceExtension->MiniportTimerDpc);
4936 }
4937 }
4938
4939 /* If it's ready for the next request */
4940 if (InterruptData.Flags & SCSI_PORT_NEXT_REQUEST_READY)
4941 {
4942 /* Check for a duplicate request (NextRequest+NextLuRequest) */
4943 if ((DeviceExtension->Flags &
4944 (SCSI_PORT_DEVICE_BUSY | SCSI_PORT_DISCONNECT_ALLOWED)) ==
4945 (SCSI_PORT_DEVICE_BUSY | SCSI_PORT_DISCONNECT_ALLOWED))
4946 {
4947 /* Clear busy flag set by ScsiPortStartPacket() */
4948 DeviceExtension->Flags &= ~SCSI_PORT_DEVICE_BUSY;
4949
4950 if (!(InterruptData.Flags & SCSI_PORT_RESET))
4951 {
4952 /* Ready for next, and no reset is happening */
4953 DeviceExtension->TimerCount = -1;
4954 }
4955 }
4956 else
4957 {
4958 /* Not busy, but not ready for the next request */
4959 DeviceExtension->Flags &= ~SCSI_PORT_DEVICE_BUSY;
4960 InterruptData.Flags &= ~SCSI_PORT_NEXT_REQUEST_READY;
4961 }
4962 }
4963
4964 /* Any resets? */
4965 if (InterruptData.Flags & SCSI_PORT_RESET_REPORTED)
4966 {
4967 /* Hold for a bit */
4968 DeviceExtension->TimerCount = 4;
4969 }
4970
4971 /* Any ready LUN? */
4972 if (InterruptData.ReadyLun != NULL)
4973 {
4974
4975 /* Process all LUNs from the list*/
4976 while (TRUE)
4977 {
4978 /* Remove it from the list first (as processed) */
4979 LunExtension = InterruptData.ReadyLun;
4980 InterruptData.ReadyLun = LunExtension->ReadyLun;
4981 LunExtension->ReadyLun = NULL;
4982
4983 /* Get next request for this LUN */
4984 SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
4985
4986 /* Still ready requests exist?
4987 If yes - get spinlock, if no - stop here */
4988 if (InterruptData.ReadyLun != NULL)
4989 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
4990 else
4991 break;
4992 }
4993 }
4994 else
4995 {
4996 /* Release the spinlock */
4997 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4998 }
4999
5000 /* If we ready for next packet, start it */
5001 if (InterruptData.Flags & SCSI_PORT_NEXT_REQUEST_READY)
5002 IoStartNextPacket(DeviceExtension->DeviceObject, FALSE);
5003
5004 NeedToStartIo = FALSE;
5005
5006 /* Loop the completed request list */
5007 while (InterruptData.CompletedRequests)
5008 {
5009 /* Remove the request */
5010 SrbInfo = InterruptData.CompletedRequests;
5011 InterruptData.CompletedRequests = SrbInfo->CompletedRequests;
5012 SrbInfo->CompletedRequests = NULL;
5013
5014 /* Process it */
5015 SpiProcessCompletedRequest(DeviceExtension,
5016 SrbInfo,
5017 &NeedToStartIo);
5018 }
5019
5020 /* Loop abort request list */
5021 while (InterruptData.CompletedAbort)
5022 {
5023 LunExtension = InterruptData.CompletedAbort;
5024
5025 /* Remove the request */
5026 InterruptData.CompletedAbort = LunExtension->CompletedAbortRequests;
5027
5028 /* Get spinlock since we're going to change flags */
5029 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
5030
5031 /* TODO: Put SrbExtension to the list of free extensions */
5032 ASSERT(FALSE);
5033 }
5034
5035 /* If we need - call StartIo routine */
5036 if (NeedToStartIo)
5037 {
5038 /* Make sure CurrentIrp is not null! */
5039 ASSERT(DpcDeviceObject->CurrentIrp != NULL);
5040 ScsiPortStartIo(DpcDeviceObject, DpcDeviceObject->CurrentIrp);
5041 }
5042
5043 /* Everything has been done, check */
5044 if (InterruptData.Flags & SCSI_PORT_ENABLE_INT_REQUEST)
5045 {
5046 /* Synchronize using spinlock */
5047 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
5048
5049 /* Request an interrupt */
5050 DeviceExtension->HwInterrupt(DeviceExtension->MiniPortDeviceExtension);
5051
5052 ASSERT(DeviceExtension->Flags & SCSI_PORT_DISABLE_INT_REQUESET);
5053
5054 /* Should interrupts be enabled again? */
5055 if (DeviceExtension->Flags & SCSI_PORT_DISABLE_INT_REQUESET)
5056 {
5057 /* Clear this flag */
5058 DeviceExtension->Flags &= ~SCSI_PORT_DISABLE_INT_REQUESET;
5059
5060 /* Call a special routine to do this */
5061 ASSERT(FALSE);
5062 #if 0
5063 KeSynchronizeExecution(DeviceExtension->Interrupt,
5064 SpiEnableInterrupts,
5065 DeviceExtension);
5066 #endif
5067 }
5068
5069 /* If we need a notification again - loop */
5070 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
5071 goto TryAgain;
5072
5073 /* Release the spinlock */
5074 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
5075 }
5076
5077 DPRINT("ScsiPortDpcForIsr() done\n");
5078 }
5079
5080 BOOLEAN
5081 NTAPI
5082 SpiProcessTimeout(PVOID ServiceContext)
5083 {
5084 PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)ServiceContext;
5085 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
5086 ULONG Bus;
5087
5088 DPRINT("SpiProcessTimeout() entered\n");
5089
5090 DeviceExtension->TimerCount = -1;
5091
5092 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET)
5093 {
5094 DeviceExtension->InterruptData.Flags &= ~SCSI_PORT_RESET;
5095
5096 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET_REQUEST)
5097 {
5098 DeviceExtension->InterruptData.Flags &= ~SCSI_PORT_RESET_REQUEST;
5099 ScsiPortStartPacket(ServiceContext);
5100 }
5101
5102 return FALSE;
5103 }
5104 else
5105 {
5106 DPRINT("Resetting the bus\n");
5107
5108 for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
5109 {
5110 DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension, Bus);
5111
5112 /* Reset flags and set reset timeout to 4 seconds */
5113 DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET;
5114 DeviceExtension->TimerCount = 4;
5115 }
5116
5117 /* If miniport requested - request a dpc for it */
5118 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
5119 IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
5120 }
5121
5122 return TRUE;
5123 }
5124
5125
5126 BOOLEAN
5127 NTAPI
5128 SpiResetBus(PVOID ServiceContext)
5129 {
5130 PRESETBUS_PARAMS ResetParams = (PRESETBUS_PARAMS)ServiceContext;
5131 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
5132
5133 /* Perform the bus reset */
5134 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ResetParams->DeviceExtension;
5135 DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension,
5136 ResetParams->PathId);
5137
5138 /* Set flags and start the timer */
5139 DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET;
5140 DeviceExtension->TimerCount = 4;
5141
5142 /* If miniport requested - give him a DPC */
5143 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
5144 IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
5145
5146 return TRUE;
5147 }
5148
5149 // ScsiPortIoTimer
5150 // DESCRIPTION:
5151 // This function handles timeouts and other time delayed processing
5152 //
5153 // RUN LEVEL:
5154 //
5155 // ARGUMENTS:
5156 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
5157 // IN PVOID Context the Controller extension for the
5158 // controller the device is on
5159 //
5160 static VOID NTAPI
5161 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
5162 PVOID Context)
5163 {
5164 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
5165 PSCSI_PORT_LUN_EXTENSION LunExtension;
5166 ULONG Lun;
5167 PIRP Irp;
5168
5169 DPRINT("ScsiPortIoTimer()\n");
5170
5171 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
5172
5173 /* Protect with the spinlock */
5174 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
5175
5176 /* Check timeouts */
5177 if (DeviceExtension->TimerCount > 0)
5178 {
5179 /* Decrease the timeout counter */
5180 DeviceExtension->TimerCount--;
5181
5182 if (DeviceExtension->TimerCount == 0)
5183 {
5184 /* Timeout, process it */
5185 if (KeSynchronizeExecution(DeviceExtension->Interrupt[0],
5186 SpiProcessTimeout,
5187 DeviceExtension->DeviceObject))
5188 {
5189 DPRINT("Error happened during processing timeout, but nothing critical\n");
5190 }
5191 }
5192
5193 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
5194
5195 /* We should exit now, since timeout is processed */
5196 return;
5197 }
5198
5199 /* Per-Lun scanning of timeouts is needed... */
5200 for (Lun = 0; Lun < LUS_NUMBER; Lun++)
5201 {
5202 LunExtension = DeviceExtension->LunExtensionList[Lun];
5203
5204 while (LunExtension)
5205 {
5206 if (LunExtension->Flags & LUNEX_BUSY)
5207 {
5208 if (!(LunExtension->Flags &
5209 (LUNEX_NEED_REQUEST_SENSE | LUNEX_FROZEN_QUEUE)))
5210 {
5211 DPRINT("Retrying busy request\n");
5212
5213 /* Clear flags, and retry busy request */
5214 LunExtension->Flags &= ~(LUNEX_BUSY | LUNEX_FULL_QUEUE);
5215 Irp = LunExtension->BusyRequest;
5216
5217 /* Clearing busy request */
5218 LunExtension->BusyRequest = NULL;
5219
5220 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
5221
5222 IoStartPacket(DeviceObject, Irp, (PULONG)NULL, NULL);
5223
5224 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
5225 }
5226 }
5227 else if (LunExtension->RequestTimeout == 0)
5228 {
5229 RESETBUS_PARAMS ResetParams;
5230
5231 LunExtension->RequestTimeout = -1;
5232
5233 DPRINT("Request timed out, resetting bus\n");
5234
5235 /* Pass params to the bus reset routine */
5236 ResetParams.PathId = LunExtension->PathId;
5237 ResetParams.DeviceExtension = DeviceExtension;
5238
5239 if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0],
5240 SpiResetBus,
5241 &ResetParams))
5242 {
5243 DPRINT1("Reset failed\n");
5244 }
5245 }
5246 else if (LunExtension->RequestTimeout > 0)
5247 {
5248 /* Decrement the timeout counter */
5249 LunExtension->RequestTimeout--;
5250 }
5251
5252 LunExtension = LunExtension->Next;
5253 }
5254 }
5255
5256 /* Release the spinlock */
5257 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
5258 }
5259
5260 /**********************************************************************
5261 * NAME INTERNAL
5262 * SpiBuildDeviceMap
5263 *
5264 * DESCRIPTION
5265 * Builds the registry device map of all device which are attached
5266 * to the given SCSI HBA port. The device map is located at:
5267 * \Registry\Machine\DeviceMap\Scsi
5268 *
5269 * RUN LEVEL
5270 * PASSIVE_LEVEL
5271 *
5272 * ARGUMENTS
5273 * DeviceExtension
5274 * ...
5275 *
5276 * RegistryPath
5277 * Name of registry driver service key.
5278 *
5279 * RETURNS
5280 * NTSTATUS
5281 */
5282
5283 static NTSTATUS
5284 SpiBuildDeviceMap(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
5285 IN PUNICODE_STRING RegistryPath)
5286 {
5287 PSCSI_PORT_LUN_EXTENSION LunExtension;
5288 OBJECT_ATTRIBUTES ObjectAttributes;
5289 UNICODE_STRING KeyName;
5290 UNICODE_STRING ValueName;
5291 WCHAR NameBuffer[64];
5292 ULONG Disposition;
5293 HANDLE ScsiKey;
5294 HANDLE ScsiPortKey = NULL;
5295 HANDLE ScsiBusKey = NULL;
5296 HANDLE ScsiInitiatorKey = NULL;
5297 HANDLE ScsiTargetKey = NULL;
5298 HANDLE ScsiLunKey = NULL;
5299 ULONG BusNumber;
5300 ULONG Target;
5301 ULONG CurrentTarget;
5302 ULONG Lun;
5303 PWCHAR DriverName;
5304 ULONG UlongData;
5305 PWCHAR TypeName;
5306 NTSTATUS Status;
5307
5308 DPRINT("SpiBuildDeviceMap() called\n");
5309
5310 if (DeviceExtension == NULL || RegistryPath == NULL)
5311 {
5312 DPRINT1("Invalid parameter\n");
5313 return STATUS_INVALID_PARAMETER;
5314 }
5315
5316 /* Open or create the 'Scsi' subkey */
5317 RtlInitUnicodeString(&KeyName,
5318 L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
5319 InitializeObjectAttributes(&ObjectAttributes,
5320 &KeyName,
5321 OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_KERNEL_HANDLE,
5322 0,
5323 NULL);
5324 Status = ZwCreateKey(&ScsiKey,
5325 KEY_ALL_ACCESS,
5326 &ObjectAttributes,
5327 0,
5328 NULL,
5329 REG_OPTION_VOLATILE,
5330 &Disposition);
5331 if (!NT_SUCCESS(Status))
5332 {
5333 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
5334 return Status;
5335 }
5336
5337 /* Create new 'Scsi Port X' subkey */
5338 DPRINT("Scsi Port %lu\n", DeviceExtension->PortNumber);
5339
5340 swprintf(NameBuffer,
5341 L"Scsi Port %lu",
5342 DeviceExtension->PortNumber);
5343 RtlInitUnicodeString(&KeyName, NameBuffer);
5344 InitializeObjectAttributes(&ObjectAttributes,
5345 &KeyName,
5346 OBJ_KERNEL_HANDLE,
5347 ScsiKey,
5348 NULL);
5349 Status = ZwCreateKey(&ScsiPortKey,
5350 KEY_ALL_ACCESS,
5351 &ObjectAttributes,
5352 0,
5353 NULL,
5354 REG_OPTION_VOLATILE,
5355 &Disposition);
5356 ZwClose(ScsiKey);
5357 if (!NT_SUCCESS(Status))
5358 {
5359 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
5360 return Status;
5361 }
5362
5363 /*
5364 * Create port-specific values
5365 */
5366
5367 /* Set 'DMA Enabled' (REG_DWORD) value */
5368 UlongData = (ULONG)!DeviceExtension->PortCapabilities.AdapterUsesPio;
5369 DPRINT(" DMA Enabled = %s\n", UlongData ? "TRUE" : "FALSE");
5370 RtlInitUnicodeString(&ValueName, L"DMA Enabled");
5371 Status = ZwSetValueKey(ScsiPortKey,
5372 &ValueName,
5373 0,
5374 REG_DWORD,
5375 &UlongData,
5376 sizeof(UlongData));
5377 if (!NT_SUCCESS(Status))
5378 {
5379 DPRINT("ZwSetValueKey('DMA Enabled') failed (Status %lx)\n", Status);
5380 ZwClose(ScsiPortKey);
5381 return Status;
5382 }
5383
5384 /* Set 'Driver' (REG_SZ) value */
5385 DriverName = wcsrchr(RegistryPath->Buffer, L'\\') + 1;
5386 RtlInitUnicodeString(&ValueName, L"Driver");
5387 Status = ZwSetValueKey(ScsiPortKey,
5388 &ValueName,
5389 0,
5390 REG_SZ,
5391 DriverName,
5392 (ULONG)((wcslen(DriverName) + 1) * sizeof(WCHAR)));
5393 if (!NT_SUCCESS(Status))
5394 {
5395 DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status);
5396 ZwClose(ScsiPortKey);
5397 return Status;
5398 }
5399
5400 /* Set 'Interrupt' (REG_DWORD) value (NT4 only) */
5401 UlongData = (ULONG)DeviceExtension->PortConfig->BusInterruptLevel;
5402 DPRINT(" Interrupt = %lu\n", UlongData);
5403 RtlInitUnicodeString(&ValueName, L"Interrupt");
5404 Status = ZwSetValueKey(ScsiPortKey,
5405 &ValueName,
5406 0,
5407 REG_DWORD,
5408 &UlongData,
5409 sizeof(UlongData));
5410 if (!NT_SUCCESS(Status))
5411 {
5412 DPRINT("ZwSetValueKey('Interrupt') failed (Status %lx)\n", Status);
5413 ZwClose(ScsiPortKey);
5414 return Status;
5415 }
5416
5417 /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
5418 UlongData = ScsiPortConvertPhysicalAddressToUlong((*DeviceExtension->PortConfig->AccessRanges)[0].RangeStart);
5419 DPRINT(" IOAddress = %lx\n", UlongData);
5420 RtlInitUnicodeString(&ValueName, L"IOAddress");
5421 Status = ZwSetValueKey(ScsiPortKey,
5422 &ValueName,
5423 0,
5424 REG_DWORD,
5425 &UlongData,
5426 sizeof(UlongData));
5427 if (!NT_SUCCESS(Status))
5428 {
5429 DPRINT("ZwSetValueKey('IOAddress') failed (Status %lx)\n", Status);
5430 ZwClose(ScsiPortKey);
5431 return Status;
5432 }
5433
5434 /* Enumerate buses */
5435 for (BusNumber = 0; BusNumber < DeviceExtension->PortConfig->NumberOfBuses; BusNumber++)
5436 {
5437 /* Create 'Scsi Bus X' key */
5438 DPRINT(" Scsi Bus %lu\n", BusNumber);
5439 swprintf(NameBuffer,
5440 L"Scsi Bus %lu",
5441 BusNumber);
5442 RtlInitUnicodeString(&KeyName, NameBuffer);
5443 InitializeObjectAttributes(&ObjectAttributes,
5444 &KeyName,
5445 0,
5446 ScsiPortKey,
5447 NULL);
5448 Status = ZwCreateKey(&ScsiBusKey,
5449 KEY_ALL_ACCESS,
5450 &ObjectAttributes,
5451 0,
5452 NULL,
5453 REG_OPTION_VOLATILE,
5454 &Disposition);
5455 if (!NT_SUCCESS(Status))
5456 {
5457 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
5458 goto ByeBye;
5459 }
5460
5461 /* Create 'Initiator Id X' key */
5462 DPRINT(" Initiator Id %lu\n",
5463 DeviceExtension->PortConfig->InitiatorBusId[BusNumber]);
5464 swprintf(NameBuffer,
5465 L"Initiator Id %lu",
5466 (ULONG)(UCHAR)DeviceExtension->PortConfig->InitiatorBusId[BusNumber]);
5467 RtlInitUnicodeString(&KeyName, NameBuffer);
5468 InitializeObjectAttributes(&ObjectAttributes,
5469 &KeyName,
5470 0,
5471 ScsiBusKey,
5472 NULL);
5473 Status = ZwCreateKey(&ScsiInitiatorKey,
5474 KEY_ALL_ACCESS,
5475 &ObjectAttributes,
5476 0,
5477 NULL,
5478 REG_OPTION_VOLATILE,
5479 &Disposition);
5480 if (!NT_SUCCESS(Status))
5481 {
5482 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
5483 goto ByeBye;
5484 }
5485
5486 /* FIXME: Are there any initiator values (??) */
5487
5488 ZwClose(ScsiInitiatorKey);
5489 ScsiInitiatorKey = NULL;
5490
5491
5492 /* Enumerate targets */
5493 CurrentTarget = (ULONG)-1;
5494 ScsiTargetKey = NULL;
5495 for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
5496 {
5497 for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
5498 {
5499 LunExtension = SpiGetLunExtension(DeviceExtension,
5500 (UCHAR)BusNumber,
5501 (UCHAR)Target,
5502 (UCHAR)Lun);
5503 if (LunExtension == NULL)
5504 continue;
5505
5506 if (Target != CurrentTarget)
5507 {
5508 /* Close old target key */
5509 if (ScsiTargetKey != NULL)
5510 {
5511 ZwClose(ScsiTargetKey);
5512 ScsiTargetKey = NULL;
5513 }
5514
5515 /* Create 'Target Id X' key */
5516 DPRINT(" Target Id %lu\n", Target);
5517 swprintf(NameBuffer,
5518 L"Target Id %lu",
5519 Target);
5520 RtlInitUnicodeString(&KeyName, NameBuffer);
5521 InitializeObjectAttributes(&ObjectAttributes,
5522 &KeyName,
5523 0,
5524 ScsiBusKey,
5525 NULL);
5526 Status = ZwCreateKey(&ScsiTargetKey,
5527 KEY_ALL_ACCESS,
5528 &ObjectAttributes,
5529 0,
5530 NULL,
5531 REG_OPTION_VOLATILE,
5532 &Disposition);
5533 if (!NT_SUCCESS(Status))
5534 {
5535 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
5536 goto ByeBye;
5537 }
5538
5539 CurrentTarget = Target;
5540 }
5541
5542 /* Create 'Logical Unit Id X' key */
5543 DPRINT(" Logical Unit Id %lu\n", Lun);
5544 swprintf(NameBuffer,
5545 L"Logical Unit Id %lu",
5546 Lun);
5547 RtlInitUnicodeString(&KeyName, NameBuffer);
5548 InitializeObjectAttributes(&ObjectAttributes,
5549 &KeyName,
5550 0,
5551 ScsiTargetKey,
5552 NULL);
5553 Status = ZwCreateKey(&ScsiLunKey,
5554 KEY_ALL_ACCESS,
5555 &ObjectAttributes,
5556 0,
5557 NULL,
5558 REG_OPTION_VOLATILE,
5559 &Disposition);
5560 if (!NT_SUCCESS(Status))
5561 {
5562 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
5563 goto ByeBye;
5564 }
5565
5566 /* Set 'Identifier' (REG_SZ) value */
5567 swprintf(NameBuffer,
5568 L"%.8S%.16S%.4S",
5569 LunExtension->InquiryData.VendorId,
5570 LunExtension->InquiryData.ProductId,
5571 LunExtension->InquiryData.ProductRevisionLevel);
5572 DPRINT(" Identifier = '%S'\n", NameBuffer);
5573 RtlInitUnicodeString(&ValueName, L"Identifier");
5574 Status = ZwSetValueKey(ScsiLunKey,
5575 &ValueName,
5576 0,
5577 REG_SZ,
5578 NameBuffer,
5579 (ULONG)((wcslen(NameBuffer) + 1) * sizeof(WCHAR)));
5580 if (!NT_SUCCESS(Status))
5581 {
5582 DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", Status);
5583 goto ByeBye;
5584 }
5585
5586 /* Set 'Type' (REG_SZ) value */
5587 /*
5588 * See https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-ide-devices
5589 * and https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifiers-for-scsi-devices
5590 * for a list of types with their human-readable forms.
5591 */
5592 switch (LunExtension->InquiryData.DeviceType)
5593 {
5594 case 0:
5595 TypeName = L"DiskPeripheral";
5596 break;
5597 case 1:
5598 TypeName = L"TapePeripheral";
5599 break;
5600 case 2:
5601 TypeName = L"PrinterPeripheral";
5602 break;
5603 // case 3: "ProcessorPeripheral", classified as 'other': fall back to default case.
5604 case 4:
5605 TypeName = L"WormPeripheral";
5606 break;
5607 case 5:
5608 TypeName = L"CdRomPeripheral";
5609 break;
5610 case 6:
5611 TypeName = L"ScannerPeripheral";
5612 break;
5613 case 7:
5614 TypeName = L"OpticalDiskPeripheral";
5615 break;
5616 case 8:
5617 TypeName = L"MediumChangerPeripheral";
5618 break;
5619 case 9:
5620 TypeName = L"CommunicationsPeripheral";
5621 break;
5622
5623 /* New peripheral types (SCSI only) */
5624 case 10: case 11:
5625 TypeName = L"ASCPrePressGraphicsPeripheral";
5626 break;
5627 case 12:
5628 TypeName = L"ArrayPeripheral";
5629 break;
5630 case 13:
5631 TypeName = L"EnclosurePeripheral";
5632 break;
5633 case 14:
5634 TypeName = L"RBCPeripheral";
5635 break;
5636 case 15:
5637 TypeName = L"CardReaderPeripheral";
5638 break;
5639 case 16:
5640 TypeName = L"BridgePeripheral";
5641 break;
5642
5643 default:
5644 TypeName = L"OtherPeripheral";
5645 break;
5646 }
5647 DPRINT(" Type = '%S'\n", TypeName);
5648 RtlInitUnicodeString(&ValueName, L"Type");
5649 Status = ZwSetValueKey(ScsiLunKey,
5650 &ValueName,
5651 0,
5652 REG_SZ,
5653 TypeName,
5654 (ULONG)((wcslen(TypeName) + 1) * sizeof(WCHAR)));
5655 if (!NT_SUCCESS(Status))
5656 {
5657 DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status);
5658 goto ByeBye;
5659 }
5660
5661 ZwClose(ScsiLunKey);
5662 ScsiLunKey = NULL;
5663 }
5664
5665 /* Close old target key */
5666 if (ScsiTargetKey != NULL)
5667 {
5668 ZwClose(ScsiTargetKey);
5669 ScsiTargetKey = NULL;
5670 }
5671 }
5672
5673 ZwClose(ScsiBusKey);
5674 ScsiBusKey = NULL;
5675 }
5676
5677 ByeBye:
5678 if (ScsiLunKey != NULL)
5679 ZwClose(ScsiLunKey);
5680
5681 if (ScsiInitiatorKey != NULL)
5682 ZwClose(ScsiInitiatorKey);
5683
5684 if (ScsiTargetKey != NULL)
5685 ZwClose(ScsiTargetKey);
5686
5687 if (ScsiBusKey != NULL)
5688 ZwClose(ScsiBusKey);
5689
5690 if (ScsiPortKey != NULL)
5691 ZwClose(ScsiPortKey);
5692
5693 DPRINT("SpiBuildDeviceMap() done\n");
5694
5695 return Status;
5696 }
5697
5698 VOID
5699 NTAPI
5700 SpiMiniportTimerDpc(IN struct _KDPC *Dpc,
5701 IN PVOID DeviceObject,
5702 IN PVOID SystemArgument1,
5703 IN PVOID SystemArgument2)
5704 {
5705 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
5706
5707 DPRINT("Miniport timer DPC\n");
5708
5709 DeviceExtension = ((PDEVICE_OBJECT)DeviceObject)->DeviceExtension;
5710
5711 /* Acquire the spinlock */
5712 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
5713
5714 /* Call the timer routine */
5715 if (DeviceExtension->HwScsiTimer != NULL)
5716 {
5717 DeviceExtension->HwScsiTimer(&DeviceExtension->MiniPortDeviceExtension);
5718 }
5719
5720 /* Release the spinlock */
5721 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
5722
5723 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
5724 {
5725 ScsiPortDpcForIsr(NULL,
5726 DeviceExtension->DeviceObject,
5727 NULL,
5728 NULL);
5729 }
5730 }
5731
5732 static NTSTATUS
5733 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
5734 PHW_INITIALIZATION_DATA HwInitData,
5735 PCONFIGURATION_INFO InternalConfigInfo,
5736 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
5737 BOOLEAN ZeroStruct)
5738 {
5739 UNICODE_STRING UnicodeString;
5740 OBJECT_ATTRIBUTES ObjectAttributes;
5741 PCONFIGURATION_INFORMATION DdkConfigInformation;
5742 HANDLE RootKey, Key;
5743 BOOLEAN Found;
5744 WCHAR DeviceBuffer[16];
5745 WCHAR StrBuffer[512];
5746 ULONG Bus;
5747 NTSTATUS Status;
5748
5749 /* Zero out the struct if told so */
5750 if (ZeroStruct)
5751 {
5752 /* First zero the portconfig */
5753 RtlZeroMemory(ConfigInfo, sizeof(PORT_CONFIGURATION_INFORMATION));
5754
5755 /* Then access ranges */
5756 RtlZeroMemory(InternalConfigInfo->AccessRanges,
5757 HwInitData->NumberOfAccessRanges * sizeof(ACCESS_RANGE));
5758
5759 /* Initialize the struct */
5760 ConfigInfo->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
5761 ConfigInfo->AdapterInterfaceType = HwInitData->AdapterInterfaceType;
5762 ConfigInfo->InterruptMode = Latched;
5763 ConfigInfo->DmaChannel = SP_UNINITIALIZED_VALUE;
5764 ConfigInfo->DmaPort = SP_UNINITIALIZED_VALUE;
5765 ConfigInfo->DmaChannel2 = SP_UNINITIALIZED_VALUE;
5766 ConfigInfo->DmaPort2 = SP_UNINITIALIZED_VALUE;
5767 ConfigInfo->MaximumTransferLength = SP_UNINITIALIZED_VALUE;
5768 ConfigInfo->NumberOfAccessRanges = HwInitData->NumberOfAccessRanges;
5769 ConfigInfo->MaximumNumberOfTargets = 8;
5770
5771 /* Store parameters */
5772 ConfigInfo->NeedPhysicalAddresses = HwInitData->NeedPhysicalAddresses;
5773 ConfigInfo->MapBuffers = HwInitData->MapBuffers;
5774 ConfigInfo->AutoRequestSense = HwInitData->AutoRequestSense;
5775 ConfigInfo->ReceiveEvent = HwInitData->ReceiveEvent;
5776 ConfigInfo->TaggedQueuing = HwInitData->TaggedQueuing;
5777 ConfigInfo->MultipleRequestPerLu = HwInitData->MultipleRequestPerLu;
5778
5779 /* Get the disk usage */
5780 DdkConfigInformation = IoGetConfigurationInformation();
5781 ConfigInfo->AtdiskPrimaryClaimed = DdkConfigInformation->AtDiskPrimaryAddressClaimed;
5782 ConfigInfo->AtdiskSecondaryClaimed = DdkConfigInformation->AtDiskSecondaryAddressClaimed;
5783
5784 /* Initiator bus id is not set */
5785 for (Bus = 0; Bus < 8; Bus++)
5786 ConfigInfo->InitiatorBusId[Bus] = (CCHAR)SP_UNINITIALIZED_VALUE;
5787 }
5788
5789 ConfigInfo->NumberOfPhysicalBreaks = 17;
5790
5791 /* Clear this information */
5792 InternalConfigInfo->DisableTaggedQueueing = FALSE;
5793 InternalConfigInfo->DisableMultipleLun = FALSE;
5794
5795 /* Store Bus Number */
5796 ConfigInfo->SystemIoBusNumber = InternalConfigInfo->BusNumber;
5797
5798 TryNextAd:
5799
5800 if (ConfigInfo->AdapterInterfaceType == Internal)
5801 {
5802 /* Open registry key for HW database */
5803 InitializeObjectAttributes(&ObjectAttributes,
5804 DeviceExtension->DeviceObject->DriverObject->HardwareDatabase,
5805 OBJ_CASE_INSENSITIVE,
5806 NULL,
5807 NULL);
5808
5809 Status = ZwOpenKey(&RootKey,
5810 KEY_READ,
5811 &ObjectAttributes);
5812
5813 if (NT_SUCCESS(Status))
5814 {
5815 /* Create name for it */
5816 swprintf(StrBuffer, L"ScsiAdapter\\%lu",
5817 InternalConfigInfo->AdapterNumber);
5818
5819 RtlInitUnicodeString(&UnicodeString, StrBuffer);
5820
5821 /* Open device key */
5822 InitializeObjectAttributes(&ObjectAttributes,
5823 &UnicodeString,
5824 OBJ_CASE_INSENSITIVE,
5825 RootKey,
5826 NULL);
5827
5828 Status = ZwOpenKey(&Key,
5829 KEY_READ,
5830 &ObjectAttributes);
5831
5832 ZwClose(RootKey);
5833
5834 if (NT_SUCCESS(Status))
5835 {
5836 if (InternalConfigInfo->LastAdapterNumber != InternalConfigInfo->AdapterNumber)
5837 {
5838 DPRINT("Hardware info found at %S\n", StrBuffer);
5839
5840 /* Parse it */
5841 SpiParseDeviceInfo(DeviceExtension,
5842 Key,
5843 ConfigInfo,
5844 InternalConfigInfo,
5845 (PUCHAR)StrBuffer);
5846
5847 InternalConfigInfo->BusNumber = 0;
5848 }
5849 else
5850 {
5851 /* Try the next adapter */
5852 InternalConfigInfo->AdapterNumber++;
5853 goto TryNextAd;
5854 }
5855 }
5856 else
5857 {
5858 /* Info was not found, exit */
5859 DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status);
5860 return STATUS_DEVICE_DOES_NOT_EXIST;
5861 }
5862 }
5863 else
5864 {
5865 DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status);
5866 }
5867 }
5868
5869 /* Look at device params */
5870 Key = NULL;
5871 if (InternalConfigInfo->Parameter)
5872 {
5873 ExFreePool(InternalConfigInfo->Parameter);
5874 InternalConfigInfo->Parameter = NULL;
5875 }
5876
5877 if (InternalConfigInfo->ServiceKey != NULL)
5878 {
5879 swprintf(DeviceBuffer, L"Device%lu", InternalConfigInfo->AdapterNumber);
5880 RtlInitUnicodeString(&UnicodeString, DeviceBuffer);
5881
5882 /* Open the service key */
5883 InitializeObjectAttributes(&ObjectAttributes,
5884 &UnicodeString,
5885 OBJ_CASE_INSENSITIVE,
5886 InternalConfigInfo->ServiceKey,
5887 NULL);
5888
5889 Status = ZwOpenKey(&Key,
5890 KEY_READ,
5891 &ObjectAttributes);
5892 }
5893
5894 /* Parse device key */
5895 if (InternalConfigInfo->DeviceKey != NULL)
5896 {
5897 SpiParseDeviceInfo(DeviceExtension,
5898 InternalConfigInfo->DeviceKey,
5899 ConfigInfo,
5900 InternalConfigInfo,
5901 (PUCHAR)StrBuffer);
5902 }
5903
5904 /* Then parse hw info */
5905 if (Key != NULL)
5906 {
5907 if (InternalConfigInfo->LastAdapterNumber != InternalConfigInfo->AdapterNumber)
5908 {
5909 SpiParseDeviceInfo(DeviceExtension,
5910 Key,
5911 ConfigInfo,
5912 InternalConfigInfo,
5913 (PUCHAR)StrBuffer);
5914
5915 /* Close the key */
5916 ZwClose(Key);
5917 }
5918 else
5919 {
5920 /* Adapter not found, go try the next one */
5921 InternalConfigInfo->AdapterNumber++;
5922
5923 /* Close the key */
5924 ZwClose(Key);
5925
5926 goto TryNextAd;
5927 }
5928 }
5929
5930 /* Update the last adapter number */
5931 InternalConfigInfo->LastAdapterNumber = InternalConfigInfo->AdapterNumber;
5932
5933 /* Do we have this kind of bus at all? */
5934 Found = FALSE;
5935 Status = IoQueryDeviceDescription(&HwInitData->AdapterInterfaceType,
5936 &InternalConfigInfo->BusNumber,
5937 NULL,
5938 NULL,
5939 NULL,
5940 NULL,
5941 SpQueryDeviceCallout,
5942 &Found);
5943
5944 /* This bus was not found */
5945 if (!Found)
5946 {
5947 INTERFACE_TYPE InterfaceType = Eisa;
5948
5949 /* Check for EISA */
5950 if (HwInitData->AdapterInterfaceType == Isa)
5951 {
5952 Status = IoQueryDeviceDescription(&InterfaceType,
5953 &InternalConfigInfo->BusNumber,
5954 NULL,
5955 NULL,
5956 NULL,
5957 NULL,
5958 SpQueryDeviceCallout,
5959 &Found);
5960
5961 /* Return respectively */
5962 if (Found)
5963 return STATUS_SUCCESS;
5964 else
5965 return STATUS_DEVICE_DOES_NOT_EXIST;
5966 }
5967 else
5968 {
5969 return STATUS_DEVICE_DOES_NOT_EXIST;
5970 }
5971 }
5972 else
5973 {
5974 return STATUS_SUCCESS;
5975 }
5976 }
5977
5978 static VOID
5979 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
5980 IN HANDLE Key,
5981 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
5982 IN PCONFIGURATION_INFO InternalConfigInfo,
5983 IN PUCHAR Buffer)
5984 {
5985 PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
5986 PCM_FULL_RESOURCE_DESCRIPTOR FullResource;
5987 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
5988 PCM_SCSI_DEVICE_DATA ScsiDeviceData;
5989 ULONG Length, Count, Dma = 0, Interrupt = 0;
5990 ULONG Index = 0, RangeCount = 0;
5991 UNICODE_STRING UnicodeString;
5992 ANSI_STRING AnsiString;
5993 NTSTATUS Status = STATUS_SUCCESS;
5994
5995
5996 KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION) Buffer;
5997
5998 /* Loop through all values in the device node */
5999 while(TRUE)
6000 {
6001 Status = ZwEnumerateValueKey(Key,
6002 Index,
6003 KeyValueFullInformation,
6004 Buffer,
6005 512,
6006 &Length);
6007
6008 if (!NT_SUCCESS(Status))
6009 return;
6010
6011 Index++;
6012
6013 /* Length for DWORD is ok? */
6014 if (KeyValueInformation->Type == REG_DWORD &&
6015 KeyValueInformation->DataLength != sizeof(ULONG))
6016 {
6017 continue;
6018 }
6019
6020 /* Get MaximumLogicalUnit */
6021 if (_wcsnicmp(KeyValueInformation->Name, L"MaximumLogicalUnit",
6022 KeyValueInformation->NameLength/2) == 0)
6023 {
6024
6025 if (KeyValueInformation->Type != REG_DWORD)
6026 {
6027 DPRINT("Bad data type for MaximumLogicalUnit\n");
6028 continue;
6029 }
6030
6031 DeviceExtension->MaxLunCount = *((PUCHAR)
6032 (Buffer + KeyValueInformation->DataOffset));
6033
6034 /* Check / reset if needed */
6035 if (DeviceExtension->MaxLunCount > SCSI_MAXIMUM_LOGICAL_UNITS)
6036 DeviceExtension->MaxLunCount = SCSI_MAXIMUM_LOGICAL_UNITS;
6037
6038 DPRINT("MaximumLogicalUnit = %d\n", DeviceExtension->MaxLunCount);
6039 }
6040
6041 /* Get InitiatorTargetId */
6042 if (_wcsnicmp(KeyValueInformation->Name, L"InitiatorTargetId",
6043 KeyValueInformation->NameLength / 2) == 0)
6044 {
6045
6046 if (KeyValueInformation->Type != REG_DWORD)
6047 {
6048 DPRINT("Bad data type for InitiatorTargetId\n");
6049 continue;
6050 }
6051
6052 ConfigInfo->InitiatorBusId[0] = *((PUCHAR)
6053 (Buffer + KeyValueInformation->DataOffset));
6054
6055 /* Check / reset if needed */
6056 if (ConfigInfo->InitiatorBusId[0] > ConfigInfo->MaximumNumberOfTargets - 1)
6057 ConfigInfo->InitiatorBusId[0] = (CCHAR)-1;
6058
6059 DPRINT("InitiatorTargetId = %d\n", ConfigInfo->InitiatorBusId[0]);
6060 }
6061
6062 /* Get ScsiDebug */
6063 if (_wcsnicmp(KeyValueInformation->Name, L"ScsiDebug",
6064 KeyValueInformation->NameLength/2) == 0)
6065 {
6066 DPRINT("ScsiDebug key not supported\n");
6067 }
6068
6069 /* Check for a breakpoint */
6070 if (_wcsnicmp(KeyValueInformation->Name, L"BreakPointOnEntry",
6071 KeyValueInformation->NameLength/2) == 0)
6072 {
6073 DPRINT1("Breakpoint on entry requested!\n");
6074 DbgBreakPoint();
6075 }
6076
6077 /* Get DisableSynchronousTransfers */
6078 if (_wcsnicmp(KeyValueInformation->Name, L"DisableSynchronousTransfers",
6079 KeyValueInformation->NameLength/2) == 0)
6080 {
6081 DeviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
6082 DPRINT("Synch transfers disabled\n");
6083 }
6084
6085 /* Get DisableDisconnects */
6086 if (_wcsnicmp(KeyValueInformation->Name, L"DisableDisconnects",
6087 KeyValueInformation->NameLength/2) == 0)
6088 {
6089 DeviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT;
6090 DPRINT("Disconnects disabled\n");
6091 }
6092
6093 /* Get DisableTaggedQueuing */
6094 if (_wcsnicmp(KeyValueInformation->Name, L"DisableTaggedQueuing",
6095 KeyValueInformation->NameLength/2) == 0)
6096 {
6097 InternalConfigInfo->DisableTaggedQueueing = TRUE;
6098 DPRINT("Tagged queueing disabled\n");
6099 }
6100
6101 /* Get DisableMultipleRequests */
6102 if (_wcsnicmp(KeyValueInformation->Name, L"DisableMultipleRequests",
6103 KeyValueInformation->NameLength/2) == 0)
6104 {
6105 InternalConfigInfo->DisableMultipleLun = TRUE;
6106 DPRINT("Multiple requests disabled\n");
6107 }
6108
6109 /* Get DriverParameters */
6110 if (_wcsnicmp(KeyValueInformation->Name, L"DriverParameters",
6111 KeyValueInformation->NameLength/2) == 0)
6112 {
6113 /* Skip if nothing */
6114 if (KeyValueInformation->DataLength == 0)
6115 continue;
6116
6117 /* If there was something previously allocated - free it */
6118 if (InternalConfigInfo->Parameter != NULL)
6119 ExFreePool(InternalConfigInfo->Parameter);
6120
6121 /* Allocate it */
6122 InternalConfigInfo->Parameter = ExAllocatePoolWithTag(NonPagedPool,
6123 KeyValueInformation->DataLength, TAG_SCSIPORT);
6124
6125 if (InternalConfigInfo->Parameter != NULL)
6126 {
6127 if (KeyValueInformation->Type != REG_SZ)
6128 {
6129 /* Just copy */
6130 RtlCopyMemory(
6131 InternalConfigInfo->Parameter,
6132 (PCCHAR)KeyValueInformation + KeyValueInformation->DataOffset,
6133 KeyValueInformation->DataLength);
6134 }
6135 else
6136 {
6137 /* If it's a unicode string, convert it to ansi */
6138 UnicodeString.Length = (USHORT)KeyValueInformation->DataLength;
6139 UnicodeString.MaximumLength = (USHORT)KeyValueInformation->DataLength;
6140 UnicodeString.Buffer =
6141 (PWSTR)((PCCHAR)KeyValueInformation + KeyValueInformation->DataOffset);
6142
6143 AnsiString.Length = 0;
6144 AnsiString.MaximumLength = (USHORT)KeyValueInformation->DataLength;
6145 AnsiString.Buffer = (PCHAR)InternalConfigInfo->Parameter;
6146
6147 Status = RtlUnicodeStringToAnsiString(&AnsiString,
6148 &UnicodeString,
6149 FALSE);
6150
6151 /* In case of error, free the allocated space */
6152 if (!NT_SUCCESS(Status))
6153 {
6154 ExFreePool(InternalConfigInfo->Parameter);
6155 InternalConfigInfo->Parameter = NULL;
6156 }
6157
6158 }
6159 }
6160
6161 DPRINT("Found driver parameter\n");
6162 }
6163
6164 /* Get MaximumSGList */
6165 if (_wcsnicmp(KeyValueInformation->Name, L"MaximumSGList",
6166 KeyValueInformation->NameLength/2) == 0)
6167 {
6168 if (KeyValueInformation->Type != REG_DWORD)
6169 {
6170 DPRINT("Bad data type for MaximumSGList\n");
6171 continue;
6172 }
6173
6174 ConfigInfo->NumberOfPhysicalBreaks = *((PUCHAR)(Buffer + KeyValueInformation->DataOffset));
6175
6176 /* Check / fix */
6177 if (ConfigInfo->NumberOfPhysicalBreaks > SCSI_MAXIMUM_PHYSICAL_BREAKS)
6178 {
6179 ConfigInfo->NumberOfPhysicalBreaks = SCSI_MAXIMUM_PHYSICAL_BREAKS;
6180 }
6181 else if (ConfigInfo->NumberOfPhysicalBreaks < SCSI_MINIMUM_PHYSICAL_BREAKS)
6182 {
6183 ConfigInfo->NumberOfPhysicalBreaks = SCSI_MINIMUM_PHYSICAL_BREAKS;
6184 }
6185
6186 DPRINT("MaximumSGList = %d\n", ConfigInfo->NumberOfPhysicalBreaks);
6187 }
6188
6189 /* Get NumberOfRequests */
6190 if (_wcsnicmp(KeyValueInformation->Name, L"NumberOfRequests",
6191 KeyValueInformation->NameLength/2) == 0)
6192 {
6193 if (KeyValueInformation->Type != REG_DWORD)
6194 {
6195 DPRINT("NumberOfRequests has wrong data type\n");
6196 continue;
6197 }
6198
6199 DeviceExtension->RequestsNumber = *((PUCHAR)(Buffer + KeyValueInformation->DataOffset));
6200
6201 /* Check / fix */
6202 if (DeviceExtension->RequestsNumber < 16)
6203 {
6204 DeviceExtension->RequestsNumber = 16;
6205 }
6206 else if (DeviceExtension->RequestsNumber > 512)
6207 {
6208 DeviceExtension->RequestsNumber = 512;
6209 }
6210
6211 DPRINT("Number Of Requests = %d\n", DeviceExtension->RequestsNumber);
6212 }
6213
6214 /* Get resource list */
6215 if (_wcsnicmp(KeyValueInformation->Name, L"ResourceList",
6216 KeyValueInformation->NameLength/2) == 0 ||
6217 _wcsnicmp(KeyValueInformation->Name, L"Configuration Data",
6218 KeyValueInformation->NameLength/2) == 0 )
6219 {
6220 if (KeyValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR ||
6221 KeyValueInformation->DataLength < sizeof(REG_FULL_RESOURCE_DESCRIPTOR))
6222 {
6223 DPRINT("Bad data type for ResourceList\n");
6224 continue;
6225 }
6226 else
6227 {
6228 DPRINT("Found ResourceList\n");
6229 }
6230
6231 FullResource = (PCM_FULL_RESOURCE_DESCRIPTOR)(Buffer + KeyValueInformation->DataOffset);
6232
6233 /* Copy some info from it */
6234 InternalConfigInfo->BusNumber = FullResource->BusNumber;
6235 ConfigInfo->SystemIoBusNumber = FullResource->BusNumber;
6236
6237 /* Loop through it */
6238 for (Count = 0; Count < FullResource->PartialResourceList.Count; Count++)
6239 {
6240 /* Get partial descriptor */
6241 PartialDescriptor =
6242 &FullResource->PartialResourceList.PartialDescriptors[Count];
6243
6244 /* Check datalength */
6245 if ((ULONG)((PCHAR)(PartialDescriptor + 1) -
6246 (PCHAR)FullResource) > KeyValueInformation->DataLength)
6247 {
6248 DPRINT("Resource data is of incorrect size\n");
6249 break;
6250 }
6251
6252 switch (PartialDescriptor->Type)
6253 {
6254 case CmResourceTypePort:
6255 if (RangeCount >= ConfigInfo->NumberOfAccessRanges)
6256 {
6257 DPRINT("Too many access ranges\n");
6258 continue;
6259 }
6260
6261 InternalConfigInfo->AccessRanges[RangeCount].RangeInMemory = FALSE;
6262 InternalConfigInfo->AccessRanges[RangeCount].RangeStart = PartialDescriptor->u.Port.Start;
6263 InternalConfigInfo->AccessRanges[RangeCount].RangeLength = PartialDescriptor->u.Port.Length;
6264 RangeCount++;
6265
6266 break;
6267
6268 case CmResourceTypeMemory:
6269 if (RangeCount >= ConfigInfo->NumberOfAccessRanges)
6270 {
6271 DPRINT("Too many access ranges\n");
6272 continue;
6273 }
6274
6275 InternalConfigInfo->AccessRanges[RangeCount].RangeInMemory = TRUE;
6276 InternalConfigInfo->AccessRanges[RangeCount].RangeStart = PartialDescriptor->u.Memory.Start;
6277 InternalConfigInfo->AccessRanges[RangeCount].RangeLength = PartialDescriptor->u.Memory.Length;
6278 RangeCount++;
6279
6280 break;
6281
6282 case CmResourceTypeInterrupt:
6283
6284 if (Interrupt == 0)
6285 {
6286 ConfigInfo->BusInterruptLevel =
6287 PartialDescriptor->u.Interrupt.Level;
6288
6289 ConfigInfo->BusInterruptVector =
6290 PartialDescriptor->u.Interrupt.Vector;
6291
6292 ConfigInfo->InterruptMode = (PartialDescriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive;
6293 }
6294 else if (Interrupt == 1)
6295 {
6296 ConfigInfo->BusInterruptLevel2 =
6297 PartialDescriptor->u.Interrupt.Level;
6298
6299 ConfigInfo->BusInterruptVector2 =
6300 PartialDescriptor->u.Interrupt.Vector;
6301
6302 ConfigInfo->InterruptMode2 = (PartialDescriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive;
6303 }
6304
6305 Interrupt++;
6306 break;
6307
6308 case CmResourceTypeDma:
6309
6310 if (Dma == 0)
6311 {
6312 ConfigInfo->DmaChannel = PartialDescriptor->u.Dma.Channel;
6313 ConfigInfo->DmaPort = PartialDescriptor->u.Dma.Port;
6314
6315 if (PartialDescriptor->Flags & CM_RESOURCE_DMA_8)
6316 ConfigInfo->DmaWidth = Width8Bits;
6317 else if ((PartialDescriptor->Flags & CM_RESOURCE_DMA_16) ||
6318 (PartialDescriptor->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
6319 ConfigInfo->DmaWidth = Width16Bits;
6320 else if (PartialDescriptor->Flags & CM_RESOURCE_DMA_32)
6321 ConfigInfo->DmaWidth = Width32Bits;
6322 }
6323 else if (Dma == 1)
6324 {
6325 ConfigInfo->DmaChannel2 = PartialDescriptor->u.Dma.Channel;
6326 ConfigInfo->DmaPort2 = PartialDescriptor->u.Dma.Port;
6327
6328 if (PartialDescriptor->Flags & CM_RESOURCE_DMA_8)
6329 ConfigInfo->DmaWidth2 = Width8Bits;
6330 else if ((PartialDescriptor->Flags & CM_RESOURCE_DMA_16) ||
6331 (PartialDescriptor->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
6332 ConfigInfo->DmaWidth2 = Width16Bits;
6333 else if (PartialDescriptor->Flags & CM_RESOURCE_DMA_32)
6334 ConfigInfo->DmaWidth2 = Width32Bits;
6335 }
6336
6337 Dma++;
6338 break;
6339
6340 case CmResourceTypeDeviceSpecific:
6341 if (PartialDescriptor->u.DeviceSpecificData.DataSize <
6342 sizeof(CM_SCSI_DEVICE_DATA) ||
6343 (PCHAR) (PartialDescriptor + 1) - (PCHAR)FullResource +
6344 PartialDescriptor->u.DeviceSpecificData.DataSize >
6345 KeyValueInformation->DataLength)
6346 {
6347 DPRINT("Resource data length is incorrect");
6348 break;
6349 }
6350
6351 /* Set only one field from it */
6352 ScsiDeviceData = (PCM_SCSI_DEVICE_DATA) (PartialDescriptor+1);
6353 ConfigInfo->InitiatorBusId[0] = ScsiDeviceData->HostIdentifier;
6354 break;
6355 }
6356 }
6357 }
6358 }
6359 }
6360
6361 NTSTATUS
6362 NTAPI
6363 SpQueryDeviceCallout(IN PVOID Context,
6364 IN PUNICODE_STRING PathName,
6365 IN INTERFACE_TYPE BusType,
6366 IN ULONG BusNumber,
6367 IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
6368 IN CONFIGURATION_TYPE ControllerType,
6369 IN ULONG ControllerNumber,
6370 IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
6371 IN CONFIGURATION_TYPE PeripheralType,
6372 IN ULONG PeripheralNumber,
6373 IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation)
6374 {
6375 PBOOLEAN Found = (PBOOLEAN)Context;
6376 /* We just set our Found variable to TRUE */
6377
6378 *Found = TRUE;
6379 return STATUS_SUCCESS;
6380 }
6381
6382 IO_ALLOCATION_ACTION
6383 NTAPI
6384 ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject,
6385 IN PIRP Irp,
6386 IN PVOID MapRegisterBase,
6387 IN PVOID Context)
6388 {
6389 KIRQL Irql;
6390 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
6391
6392 /* Guard access with the spinlock */
6393 KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
6394
6395 /* Save MapRegisterBase we've got here */
6396 DeviceExtension->MapRegisterBase = MapRegisterBase;
6397
6398 /* Start pending request */
6399 KeSynchronizeExecution(DeviceExtension->Interrupt[0],
6400 ScsiPortStartPacket, DeviceObject);
6401
6402 /* Release spinlock we took */
6403 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
6404
6405 return KeepObject;
6406 }
6407
6408 static
6409 NTSTATUS
6410 SpiStatusSrbToNt(UCHAR SrbStatus)
6411 {
6412 switch (SRB_STATUS(SrbStatus))
6413 {
6414 case SRB_STATUS_TIMEOUT:
6415 case SRB_STATUS_COMMAND_TIMEOUT:
6416 return STATUS_IO_TIMEOUT;
6417
6418 case SRB_STATUS_BAD_SRB_BLOCK_LENGTH:
6419 case SRB_STATUS_BAD_FUNCTION:
6420 return STATUS_INVALID_DEVICE_REQUEST;
6421
6422 case SRB_STATUS_NO_DEVICE:
6423 case SRB_STATUS_INVALID_LUN:
6424 case SRB_STATUS_INVALID_TARGET_ID:
6425 case SRB_STATUS_NO_HBA:
6426 return STATUS_DEVICE_DOES_NOT_EXIST;
6427
6428 case SRB_STATUS_DATA_OVERRUN:
6429 return STATUS_BUFFER_OVERFLOW;
6430
6431 case SRB_STATUS_SELECTION_TIMEOUT:
6432 return STATUS_DEVICE_NOT_CONNECTED;
6433
6434 default:
6435 return STATUS_IO_DEVICE_ERROR;
6436 }
6437
6438 return STATUS_IO_DEVICE_ERROR;
6439 }
6440
6441
6442 #undef ScsiPortConvertPhysicalAddressToUlong
6443 /*
6444 * @implemented
6445 */
6446 ULONG NTAPI
6447 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address)
6448 {
6449 DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
6450 return(Address.u.LowPart);
6451 }
6452
6453 /* EOF */