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