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