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