migrate substitution keywords to SVN
[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 kernel
23 * FILE: services/storage/scsiport/scsiport.c
24 * PURPOSE: SCSI port driver
25 * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
26 * Hartmut Birr
27 */
28
29 /* INCLUDES *****************************************************************/
30
31 #include <ddk/ntddk.h>
32 #include <ddk/srb.h>
33 #include <ddk/scsi.h>
34 #include <ddk/ntddscsi.h>
35 #include <ntos/minmax.h>
36 #include <rosrtl/string.h>
37
38 #define NDEBUG
39 #include <debug.h>
40
41 #include "scsiport_int.h"
42
43 /* TYPES *********************************************************************/
44
45 #define IRP_FLAG_COMPLETE 0x00000001
46 #define IRP_FLAG_NEXT 0x00000002
47 #define IRP_FLAG_NEXT_LU 0x00000004
48
49 /* GLOBALS *******************************************************************/
50
51 static ULONG InternalDebugLevel = 0;
52
53 static VOID
54 SpiProcessRequests(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
55 PIRP NextIrp);
56
57 static VOID
58 SpiStartIo(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
59 PIRP Irp);
60
61 static BOOLEAN
62 SpiGetPciConfigData (IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
63 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,
64 IN ULONG BusNumber,
65 IN OUT PPCI_SLOT_NUMBER NextSlotNumber);
66
67 static NTSTATUS STDCALL
68 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
69 IN PIRP Irp);
70
71 static NTSTATUS STDCALL
72 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
73 IN PIRP Irp);
74
75 static NTSTATUS STDCALL
76 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
77 IN PIRP Irp);
78
79 static BOOLEAN STDCALL
80 ScsiPortStartPacket(IN OUT PVOID Context);
81
82
83 static PSCSI_PORT_LUN_EXTENSION
84 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
85 IN UCHAR PathId,
86 IN UCHAR TargetId,
87 IN UCHAR Lun);
88
89 static VOID
90 SpiRemoveLunExtension (IN PSCSI_PORT_LUN_EXTENSION LunExtension);
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 OUT PSCSI_REQUEST_BLOCK Srb,
101 IN OUT PIO_STATUS_BLOCK IoStatusBlock,
102 IN OUT PKEVENT Event);
103
104 static VOID
105 SpiScanAdapter (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
106
107 static ULONG
108 SpiGetInquiryData (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
109 OUT PSCSI_ADAPTER_BUS_INFO AdapterBusInfo);
110
111 static BOOLEAN STDCALL
112 ScsiPortIsr(IN PKINTERRUPT Interrupt,
113 IN PVOID ServiceContext);
114
115 static VOID STDCALL
116 ScsiPortDpc(IN PKDPC Dpc,
117 IN PDEVICE_OBJECT DpcDeviceObject,
118 IN PIRP DpcIrp,
119 IN PVOID DpcContext);
120
121 static VOID STDCALL
122 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
123 PVOID Context);
124
125 static PSCSI_REQUEST_BLOCK
126 ScsiPortInitSenseRequestSrb(PSCSI_REQUEST_BLOCK OriginalSrb);
127
128 static NTSTATUS
129 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
130 PUNICODE_STRING RegistryPath);
131
132 static VOID
133 SpiAllocateSrbExtension(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
134 PSCSI_REQUEST_BLOCK Srb);
135
136 static VOID
137 SpiFreeSrbExtension(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
138 PSCSI_REQUEST_BLOCK Srb);
139
140
141 /* FUNCTIONS *****************************************************************/
142
143 /**********************************************************************
144 * NAME EXPORTED
145 * DriverEntry
146 *
147 * DESCRIPTION
148 * This function initializes the driver.
149 *
150 * RUN LEVEL
151 * PASSIVE_LEVEL
152 *
153 * ARGUMENTS
154 * DriverObject
155 * System allocated Driver Object for this driver.
156 *
157 * RegistryPath
158 * Name of registry driver service key.
159 *
160 * RETURN VALUE
161 * Status.
162 */
163
164 NTSTATUS STDCALL
165 DriverEntry(IN PDRIVER_OBJECT DriverObject,
166 IN PUNICODE_STRING RegistryPath)
167 {
168 DPRINT("ScsiPort Driver %s\n", VERSION);
169 return(STATUS_SUCCESS);
170 }
171
172
173 /**********************************************************************
174 * NAME EXPORTED
175 * ScsiDebugPrint
176 *
177 * DESCRIPTION
178 * Prints debugging messages.
179 *
180 * RUN LEVEL
181 * PASSIVE_LEVEL
182 *
183 * ARGUMENTS
184 * DebugPrintLevel
185 * Debug level of the given message.
186 *
187 * DebugMessage
188 * Pointer to printf()-compatible format string.
189 *
190 * ...
191 Additional output data (see printf()).
192 *
193 * RETURN VALUE
194 * None.
195 *
196 * @implemented
197 */
198
199 VOID
200 ScsiDebugPrint(IN ULONG DebugPrintLevel,
201 IN PCHAR DebugMessage,
202 ...)
203 {
204 char Buffer[256];
205 va_list ap;
206
207 if (DebugPrintLevel >= InternalDebugLevel)
208 return;
209
210 va_start(ap, DebugMessage);
211 vsprintf(Buffer, DebugMessage, ap);
212 va_end(ap);
213
214 DbgPrint(Buffer);
215 }
216
217
218 /*
219 * @unimplemented
220 */
221 VOID STDCALL
222 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension,
223 IN UCHAR PathId,
224 IN UCHAR TargetId,
225 IN UCHAR Lun,
226 IN UCHAR SrbStatus)
227 {
228 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
229 PSCSI_PORT_LUN_EXTENSION LunExtension;
230 PLIST_ENTRY Entry;
231 PIRP Irp;
232 PSCSI_REQUEST_BLOCK Srb;
233
234 DPRINT("ScsiPortCompleteRequest(HwDeviceExtension %x, PathId %d, TargetId %d, Lun %d, SrbStatus %x)\n",
235 HwDeviceExtension, PathId, TargetId, Lun, SrbStatus);
236
237 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
238 SCSI_PORT_DEVICE_EXTENSION,
239 MiniPortDeviceExtension);
240
241 Entry = DeviceExtension->LunExtensionListHead.Flink;
242 while (Entry != &DeviceExtension->LunExtensionListHead)
243 {
244 LunExtension = CONTAINING_RECORD(Entry,
245 SCSI_PORT_LUN_EXTENSION,
246 List);
247
248
249
250 if (PathId == (UCHAR)SP_UNTAGGED ||
251 (PathId == LunExtension->PathId && TargetId == (UCHAR)SP_UNTAGGED) ||
252 (PathId == LunExtension->PathId && TargetId == LunExtension->TargetId && Lun == (UCHAR)SP_UNTAGGED) ||
253 (PathId == LunExtension->PathId && TargetId == LunExtension->TargetId && Lun == LunExtension->Lun))
254 {
255 Irp = LunExtension->NextIrp;
256 while (Irp)
257 {
258 Srb = (PSCSI_REQUEST_BLOCK)Irp->Tail.Overlay.DriverContext[3];
259 if (Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE)
260 {
261 Srb->SrbStatus = SrbStatus;
262 ScsiPortNotification(RequestComplete,
263 HwDeviceExtension,
264 Srb);
265 }
266 Irp = Irp->Tail.Overlay.DriverContext[1];
267 }
268 }
269 Entry = Entry->Flink;
270 }
271 }
272
273
274 /*
275 * @implemented
276 */
277 ULONG STDCALL
278 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address)
279 {
280 DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
281 return(Address.u.LowPart);
282 }
283
284
285 /*
286 * @unimplemented
287 */
288 VOID STDCALL
289 ScsiPortFlushDma(IN PVOID HwDeviceExtension)
290 {
291 DPRINT("ScsiPortFlushDma()\n");
292 UNIMPLEMENTED;
293 }
294
295
296 /*
297 * @implemented
298 */
299 VOID STDCALL
300 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension,
301 IN PVOID MappedAddress)
302 {
303 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
304 PSCSI_PORT_DEVICE_BASE DeviceBase;
305 PLIST_ENTRY Entry;
306
307 DPRINT("ScsiPortFreeDeviceBase() called\n");
308
309 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
310 SCSI_PORT_DEVICE_EXTENSION,
311 MiniPortDeviceExtension);
312 if (IsListEmpty(&DeviceExtension->DeviceBaseListHead))
313 return;
314
315 Entry = DeviceExtension->DeviceBaseListHead.Flink;
316 while (Entry != &DeviceExtension->DeviceBaseListHead)
317 {
318 DeviceBase = CONTAINING_RECORD(Entry,
319 SCSI_PORT_DEVICE_BASE,
320 List);
321 if (DeviceBase->MappedAddress == MappedAddress)
322 {
323 MmUnmapIoSpace(DeviceBase->MappedAddress,
324 DeviceBase->NumberOfBytes);
325 RemoveEntryList(Entry);
326 ExFreePool(DeviceBase);
327
328 return;
329 }
330
331 Entry = Entry->Flink;
332 }
333 }
334
335
336 /*
337 * @implemented
338 */
339 ULONG STDCALL
340 ScsiPortGetBusData(IN PVOID DeviceExtension,
341 IN ULONG BusDataType,
342 IN ULONG SystemIoBusNumber,
343 IN ULONG SlotNumber,
344 IN PVOID Buffer,
345 IN ULONG Length)
346 {
347 return(HalGetBusData(BusDataType,
348 SystemIoBusNumber,
349 SlotNumber,
350 Buffer,
351 Length));
352 }
353
354
355 /*
356 * @implemented
357 */
358 PVOID STDCALL
359 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension,
360 IN INTERFACE_TYPE BusType,
361 IN ULONG SystemIoBusNumber,
362 IN SCSI_PHYSICAL_ADDRESS IoAddress,
363 IN ULONG NumberOfBytes,
364 IN BOOLEAN InIoSpace)
365 {
366 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
367 PHYSICAL_ADDRESS TranslatedAddress;
368 PSCSI_PORT_DEVICE_BASE DeviceBase;
369 ULONG AddressSpace;
370 PVOID MappedAddress;
371
372 DPRINT ("ScsiPortGetDeviceBase() called\n");
373
374 AddressSpace = (ULONG)InIoSpace;
375 if (HalTranslateBusAddress(BusType,
376 SystemIoBusNumber,
377 IoAddress,
378 &AddressSpace,
379 &TranslatedAddress) == FALSE)
380 return NULL;
381
382 /* i/o space */
383 if (AddressSpace != 0)
384 return((PVOID)TranslatedAddress.u.LowPart);
385
386 MappedAddress = MmMapIoSpace(TranslatedAddress,
387 NumberOfBytes,
388 MmNonCached);
389
390 DeviceBase = ExAllocatePool(NonPagedPool,
391 sizeof(SCSI_PORT_DEVICE_BASE));
392 if (DeviceBase == NULL)
393 return(MappedAddress);
394
395 DeviceBase->MappedAddress = MappedAddress;
396 DeviceBase->NumberOfBytes = NumberOfBytes;
397 DeviceBase->IoAddress = IoAddress;
398 DeviceBase->SystemIoBusNumber = SystemIoBusNumber;
399
400 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
401 SCSI_PORT_DEVICE_EXTENSION,
402 MiniPortDeviceExtension);
403
404 InsertHeadList(&DeviceExtension->DeviceBaseListHead,
405 &DeviceBase->List);
406
407 return(MappedAddress);
408 }
409
410
411 /*
412 * @implemented
413 */
414 PVOID STDCALL
415 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension,
416 IN UCHAR PathId,
417 IN UCHAR TargetId,
418 IN UCHAR Lun)
419 {
420 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
421 PSCSI_PORT_LUN_EXTENSION LunExtension;
422 PLIST_ENTRY Entry;
423
424 DPRINT("ScsiPortGetLogicalUnit() called\n");
425
426 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
427 SCSI_PORT_DEVICE_EXTENSION,
428 MiniPortDeviceExtension);
429 if (IsListEmpty(&DeviceExtension->LunExtensionListHead))
430 return NULL;
431
432 Entry = DeviceExtension->LunExtensionListHead.Flink;
433 while (Entry != &DeviceExtension->LunExtensionListHead)
434 {
435 LunExtension = CONTAINING_RECORD(Entry,
436 SCSI_PORT_LUN_EXTENSION,
437 List);
438 if (LunExtension->PathId == PathId &&
439 LunExtension->TargetId == TargetId &&
440 LunExtension->Lun == Lun)
441 {
442 return (PVOID)&LunExtension->MiniportLunExtension;
443 }
444
445 Entry = Entry->Flink;
446 }
447
448 return NULL;
449 }
450
451
452 /*
453 * @unimplemented
454 */
455 SCSI_PHYSICAL_ADDRESS STDCALL
456 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension,
457 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
458 IN PVOID VirtualAddress,
459 OUT ULONG *Length)
460 {
461 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
462 SCSI_PHYSICAL_ADDRESS PhysicalAddress;
463 SCSI_PHYSICAL_ADDRESS NextPhysicalAddress;
464 ULONG BufferLength = 0;
465 ULONG Offset;
466 PVOID EndAddress;
467
468 DPRINT("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
469 HwDeviceExtension, Srb, VirtualAddress, Length);
470
471 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
472 SCSI_PORT_DEVICE_EXTENSION,
473 MiniPortDeviceExtension);
474
475 if (Length != NULL)
476 {
477 *Length = 0;
478 }
479 if (Srb == NULL)
480 {
481 EndAddress = DeviceExtension->VirtualAddress + DeviceExtension->CommonBufferLength;
482 if (VirtualAddress >= DeviceExtension->VirtualAddress && VirtualAddress < EndAddress)
483 {
484 Offset = (ULONG_PTR)VirtualAddress - (ULONG_PTR)DeviceExtension->VirtualAddress;
485 PhysicalAddress.QuadPart = DeviceExtension->PhysicalAddress.QuadPart + Offset;
486 BufferLength = (ULONG_PTR)EndAddress - (ULONG_PTR)VirtualAddress;
487 }
488 else
489 {
490 /*
491 * The given virtual address is not within the range
492 * of the drivers uncached extension or srb extension.
493 */
494 /*
495 * FIXME:
496 * Check if the address is a sense info buffer of an active srb.
497 */
498 PhysicalAddress = MmGetPhysicalAddress(VirtualAddress);
499 if (PhysicalAddress.QuadPart == 0LL)
500 {
501 CHECKPOINT;
502 return PhysicalAddress;
503 }
504 BufferLength = PAGE_SIZE - PhysicalAddress.u.LowPart % PAGE_SIZE;
505 }
506 }
507 else
508 {
509 EndAddress = Srb->DataBuffer + Srb->DataTransferLength;
510 if (VirtualAddress == NULL)
511 {
512 VirtualAddress = Srb->DataBuffer;
513 }
514 else if (VirtualAddress < Srb->DataBuffer || VirtualAddress >= EndAddress)
515 {
516 EndAddress = Srb->SenseInfoBuffer + Srb->SenseInfoBufferLength;
517 if (VirtualAddress < Srb->SenseInfoBuffer || VirtualAddress >= EndAddress)
518 {
519 PhysicalAddress.QuadPart = 0LL;
520 CHECKPOINT;
521 return PhysicalAddress;
522 }
523 }
524
525 PhysicalAddress = MmGetPhysicalAddress(VirtualAddress);
526 if (PhysicalAddress.QuadPart == 0LL)
527 {
528 CHECKPOINT;
529 return PhysicalAddress;
530 }
531
532 BufferLength = PAGE_SIZE - (ULONG_PTR)VirtualAddress % PAGE_SIZE;
533 while (VirtualAddress + BufferLength < EndAddress)
534 {
535 NextPhysicalAddress = MmGetPhysicalAddress(VirtualAddress + BufferLength);
536 if (PhysicalAddress.QuadPart + BufferLength != NextPhysicalAddress.QuadPart)
537 {
538 break;
539 }
540 BufferLength += PAGE_SIZE;
541 }
542 if (VirtualAddress + BufferLength >= EndAddress)
543 {
544 BufferLength = EndAddress - VirtualAddress;
545 }
546 }
547 if (Length != NULL)
548 {
549 *Length = BufferLength;
550 }
551 DPRINT("Address %I64x, Length %d\n", PhysicalAddress.QuadPart, BufferLength);
552 return PhysicalAddress;
553 }
554
555
556 /*
557 * @unimplemented
558 */
559 PSCSI_REQUEST_BLOCK STDCALL
560 ScsiPortGetSrb(IN PVOID HwDeviceExtension,
561 IN UCHAR PathId,
562 IN UCHAR TargetId,
563 IN UCHAR Lun,
564 IN LONG QueueTag)
565 {
566 DPRINT1("ScsiPortGetSrb() unimplemented\n");
567 UNIMPLEMENTED;
568 return NULL;
569 }
570
571
572 /*
573 * @implemented
574 */
575 PVOID STDCALL
576 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension,
577 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
578 IN ULONG NumberOfBytes)
579 {
580 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
581 DEVICE_DESCRIPTION DeviceDescription;
582
583 DPRINT("ScsiPortGetUncachedExtension(%p %p %lu)\n",
584 HwDeviceExtension, ConfigInfo, NumberOfBytes);
585
586 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
587 SCSI_PORT_DEVICE_EXTENSION,
588 MiniPortDeviceExtension);
589
590 /* Check for allocated common DMA buffer */
591 if (DeviceExtension->VirtualAddress != NULL)
592 {
593 DPRINT1("The HBA has already got a common DMA buffer!\n");
594 return NULL;
595 }
596
597 /* Check for DMA adapter object */
598 if (DeviceExtension->AdapterObject == NULL)
599 {
600 /* Initialize DMA adapter description */
601 RtlZeroMemory(&DeviceDescription,
602 sizeof(DEVICE_DESCRIPTION));
603 DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
604 DeviceDescription.Master = ConfigInfo->Master;
605 DeviceDescription.ScatterGather = ConfigInfo->ScatterGather;
606 DeviceDescription.DemandMode = ConfigInfo->DemandMode;
607 DeviceDescription.Dma32BitAddresses = ConfigInfo->Dma32BitAddresses;
608 DeviceDescription.BusNumber = ConfigInfo->SystemIoBusNumber;
609 DeviceDescription.DmaChannel = ConfigInfo->DmaChannel;
610 DeviceDescription.InterfaceType = ConfigInfo->AdapterInterfaceType;
611 DeviceDescription.DmaWidth = ConfigInfo->DmaWidth;
612 DeviceDescription.DmaSpeed = ConfigInfo->DmaSpeed;
613 DeviceDescription.MaximumLength = ConfigInfo->MaximumTransferLength;
614 DeviceDescription.DmaPort = ConfigInfo->DmaPort;
615
616 /* Get a DMA adapter object */
617 DeviceExtension->AdapterObject = HalGetAdapter(&DeviceDescription,
618 &DeviceExtension->MapRegisterCount);
619 if (DeviceExtension->AdapterObject == NULL)
620 {
621 DPRINT1("HalGetAdapter() failed\n");
622 return NULL;
623 }
624 }
625 if (DeviceExtension->SrbExtensionSize > 0)
626 {
627 PVOID Buffer;
628 DeviceExtension->CurrentSrbExtensions = 0;
629 if (DeviceExtension->PortConfig->MultipleRequestPerLu)
630 {
631 DeviceExtension->MaxSrbExtensions = 1024;
632 }
633 else
634 {
635 DeviceExtension->MaxSrbExtensions = 32;
636 }
637 Buffer = ExAllocatePool(NonPagedPool, ROUND_UP(DeviceExtension->MaxSrbExtensions / 8, sizeof(ULONG)));
638 if (Buffer == NULL)
639 {
640 KEBUGCHECK(0);
641 return NULL;
642 }
643 RtlInitializeBitMap(&DeviceExtension->SrbExtensionAllocMap, Buffer, DeviceExtension->MaxSrbExtensions);
644 RtlClearAllBits(&DeviceExtension->SrbExtensionAllocMap);
645 }
646
647 /* Allocate a common DMA buffer */
648 DeviceExtension->CommonBufferLength =
649 NumberOfBytes + PAGE_ROUND_UP(DeviceExtension->SrbExtensionSize * DeviceExtension->MaxSrbExtensions);
650 DeviceExtension->VirtualAddress =
651 HalAllocateCommonBuffer(DeviceExtension->AdapterObject,
652 DeviceExtension->CommonBufferLength,
653 &DeviceExtension->PhysicalAddress,
654 FALSE);
655 if (DeviceExtension->VirtualAddress == NULL)
656 {
657 DPRINT1("HalAllocateCommonBuffer() failed!\n");
658 DeviceExtension->CommonBufferLength = 0;
659 return NULL;
660 }
661
662 return (PVOID)((ULONG_PTR)DeviceExtension->VirtualAddress +
663 PAGE_ROUND_UP(DeviceExtension->SrbExtensionSize * DeviceExtension->MaxSrbExtensions));
664 }
665
666
667 /*
668 * @implemented
669 */
670 PVOID STDCALL
671 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension,
672 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress)
673 {
674 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
675 ULONG Offset;
676
677 DPRINT("ScsiPortGetVirtualAddress(%p %I64x)\n",
678 HwDeviceExtension, PhysicalAddress.QuadPart);
679
680 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
681 SCSI_PORT_DEVICE_EXTENSION,
682 MiniPortDeviceExtension);
683
684 if (DeviceExtension->PhysicalAddress.QuadPart > PhysicalAddress.QuadPart)
685 return NULL;
686
687 Offset = (ULONG)(PhysicalAddress.QuadPart - DeviceExtension->PhysicalAddress.QuadPart);
688 if (Offset >= DeviceExtension->CommonBufferLength)
689 return NULL;
690
691 return (PVOID)((ULONG_PTR)DeviceExtension->VirtualAddress + Offset);
692 }
693
694
695 /**********************************************************************
696 * NAME EXPORTED
697 * ScsiPortInitialize
698 *
699 * DESCRIPTION
700 * Initializes SCSI port driver specific data.
701 *
702 * RUN LEVEL
703 * PASSIVE_LEVEL
704 *
705 * ARGUMENTS
706 * Argument1
707 * Pointer to the miniport driver's driver object.
708 *
709 * Argument2
710 * Pointer to the miniport driver's registry path.
711 *
712 * HwInitializationData
713 * Pointer to port driver specific configuration data.
714 *
715 * HwContext
716 Miniport driver specific context.
717 *
718 * RETURN VALUE
719 * Status.
720 *
721 * @implemented
722 */
723
724 ULONG STDCALL
725 ScsiPortInitialize(IN PVOID Argument1,
726 IN PVOID Argument2,
727 IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
728 IN PVOID HwContext)
729 {
730 PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Argument1;
731 // PUNICODE_STRING RegistryPath = (PUNICODE_STRING)Argument2;
732 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
733 PCONFIGURATION_INFORMATION SystemConfig;
734 PPORT_CONFIGURATION_INFORMATION PortConfig;
735 ULONG DeviceExtensionSize;
736 ULONG PortConfigSize;
737 BOOLEAN Again;
738 BOOLEAN DeviceFound = FALSE;
739 ULONG i;
740 ULONG Result;
741 NTSTATUS Status;
742 ULONG MaxBus;
743 ULONG BusNumber;
744 PCI_SLOT_NUMBER SlotNumber;
745
746 PDEVICE_OBJECT PortDeviceObject;
747 WCHAR NameBuffer[80];
748 UNICODE_STRING DeviceName;
749 WCHAR DosNameBuffer[80];
750 UNICODE_STRING DosDeviceName;
751 PIO_SCSI_CAPABILITIES PortCapabilities;
752 ULONG MappedIrq;
753 KIRQL Dirql;
754 KAFFINITY Affinity;
755
756
757 DPRINT ("ScsiPortInitialize() called!\n");
758 #if 0
759 DPRINT1("HwInitializationDataSize: %d\n", HwInitializationData->HwInitializationDataSize);
760 DPRINT1("AdapterInterfaceType: %d\n", HwInitializationData->AdapterInterfaceType);
761 DPRINT1("HwInitialize: %x\n", HwInitializationData->HwInitialize);
762 DPRINT1("HwStartIo: %x\n", HwInitializationData->HwStartIo);
763 DPRINT1("HwInterrupt: %x\n", HwInitializationData->HwInterrupt);
764 DPRINT1("HwFindAdapter: %x\n", HwInitializationData->HwFindAdapter);
765 DPRINT1("HwResetBus: %x\n", HwInitializationData->HwResetBus);
766 DPRINT1("HwDmaStarted: %x\n", HwInitializationData->HwDmaStarted);
767 DPRINT1("HwAdapterState: %x\n", HwInitializationData->HwAdapterState);
768 DPRINT1("DeviceExtensionSize: %d\n", HwInitializationData->DeviceExtensionSize);
769 DPRINT1("SpecificLuExtensionSize: %d\n", HwInitializationData->SpecificLuExtensionSize);
770 DPRINT1("SrbExtensionSize: %d\n", HwInitializationData->SrbExtensionSize);
771 DPRINT1("NumberOfAccessRanges: %d\n", HwInitializationData->NumberOfAccessRanges);
772 DPRINT1("Reserved: %x\n", HwInitializationData->Reserved);
773 DPRINT1("MapBuffers: %d\n", HwInitializationData->MapBuffers);
774 DPRINT1("NeedPhysicalAddresses: %d\n", HwInitializationData->NeedPhysicalAddresses);
775 DPRINT1("TaggedQueueing: %d\n", HwInitializationData->TaggedQueueing);
776 DPRINT1("AutoRequestSense: %d\n", HwInitializationData->AutoRequestSense);
777 DPRINT1("MultipleRequestPerLu: %d\n", HwInitializationData->MultipleRequestPerLu);
778 DPRINT1("ReceiveEvent: %d\n", HwInitializationData->ReceiveEvent);
779 DPRINT1("VendorIdLength: %d\n", HwInitializationData->VendorIdLength);
780 DPRINT1("VendorId: %x\n", HwInitializationData->VendorId);
781 DPRINT1("ReservedUshort: %d\n", HwInitializationData->ReservedUshort);
782 DPRINT1("DeviceIdLength: %d\n", HwInitializationData->DeviceIdLength);
783 DPRINT1("DeviceId: %x\n", HwInitializationData->DeviceId);
784 #endif
785 if ((HwInitializationData->HwInitialize == NULL) ||
786 (HwInitializationData->HwStartIo == NULL) ||
787 (HwInitializationData->HwInterrupt == NULL) ||
788 (HwInitializationData->HwFindAdapter == NULL) ||
789 (HwInitializationData->HwResetBus == NULL))
790 return(STATUS_INVALID_PARAMETER);
791
792 DriverObject->DriverStartIo = NULL;
793 DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiPortCreateClose;
794 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiPortCreateClose;
795 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiPortDeviceControl;
796 DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiPortDispatchScsi;
797
798 SystemConfig = IoGetConfigurationInformation();
799
800 DeviceExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) +
801 HwInitializationData->DeviceExtensionSize;
802 PortConfigSize = sizeof(PORT_CONFIGURATION_INFORMATION) +
803 HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE);
804
805
806 MaxBus = (HwInitializationData->AdapterInterfaceType == PCIBus) ? 8 : 1;
807 DPRINT("MaxBus: %lu\n", MaxBus);
808
809 PortDeviceObject = NULL;
810 BusNumber = 0;
811 SlotNumber.u.AsULONG = 0;
812 while (TRUE)
813 {
814 /* Create a unicode device name */
815 swprintf (NameBuffer,
816 L"\\Device\\ScsiPort%lu",
817 SystemConfig->ScsiPortCount);
818 RtlInitUnicodeString (&DeviceName,
819 NameBuffer);
820
821 DPRINT("Creating device: %wZ\n", &DeviceName);
822
823 /* Create the port device */
824 Status = IoCreateDevice (DriverObject,
825 DeviceExtensionSize,
826 &DeviceName,
827 FILE_DEVICE_CONTROLLER,
828 0,
829 FALSE,
830 &PortDeviceObject);
831 if (!NT_SUCCESS(Status))
832 {
833 DbgPrint ("IoCreateDevice call failed! (Status 0x%lX)\n", Status);
834 PortDeviceObject = NULL;
835 goto ByeBye;
836 }
837
838 DPRINT ("Created device: %wZ (%p)\n", &DeviceName, PortDeviceObject);
839
840 /* Set the buffering strategy here... */
841 PortDeviceObject->Flags |= DO_DIRECT_IO;
842 PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
843
844 DeviceExtension = PortDeviceObject->DeviceExtension;
845 RtlZeroMemory(DeviceExtension, DeviceExtensionSize);
846 DeviceExtension->Length = DeviceExtensionSize;
847 DeviceExtension->DeviceObject = PortDeviceObject;
848 DeviceExtension->PortNumber = SystemConfig->ScsiPortCount;
849
850 DeviceExtension->MiniPortExtensionSize = HwInitializationData->DeviceExtensionSize;
851 DeviceExtension->LunExtensionSize = HwInitializationData->SpecificLuExtensionSize;
852 DeviceExtension->SrbExtensionSize = HwInitializationData->SrbExtensionSize;
853 DeviceExtension->HwStartIo = HwInitializationData->HwStartIo;
854 DeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
855
856 DeviceExtension->AdapterObject = NULL;
857 DeviceExtension->MapRegisterCount = 0;
858 DeviceExtension->PhysicalAddress.QuadPart = 0ULL;
859 DeviceExtension->VirtualAddress = NULL;
860 DeviceExtension->CommonBufferLength = 0;
861
862 /* Initialize the device base list */
863 InitializeListHead (&DeviceExtension->DeviceBaseListHead);
864
865 /* Initialize the irp lists */
866 InitializeListHead (&DeviceExtension->PendingIrpListHead);
867 DeviceExtension->NextIrp = NULL;
868 DeviceExtension->PendingIrpCount = 0;
869 DeviceExtension->ActiveIrpCount = 0;
870
871 /* Initialize LUN-Extension list */
872 InitializeListHead (&DeviceExtension->LunExtensionListHead);
873
874 /* Initialize the spin lock in the controller extension */
875 KeInitializeSpinLock (&DeviceExtension->Lock);
876
877 /* Initialize the DPC object */
878 IoInitializeDpcRequest (PortDeviceObject,
879 ScsiPortDpc);
880
881 /* Initialize the device timer */
882 DeviceExtension->TimerState = IDETimerIdle;
883 DeviceExtension->TimerCount = 0;
884 IoInitializeTimer (PortDeviceObject,
885 ScsiPortIoTimer,
886 DeviceExtension);
887
888 /* Allocate and initialize port configuration info */
889 DeviceExtension->PortConfig = ExAllocatePool (NonPagedPool,
890 PortConfigSize);
891 if (DeviceExtension->PortConfig == NULL)
892 {
893 Status = STATUS_INSUFFICIENT_RESOURCES;
894 goto ByeBye;
895 }
896 RtlZeroMemory (DeviceExtension->PortConfig,
897 PortConfigSize);
898
899 PortConfig = DeviceExtension->PortConfig;
900 PortConfig->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
901 PortConfig->SystemIoBusNumber = BusNumber;
902 PortConfig->AdapterInterfaceType = HwInitializationData->AdapterInterfaceType;
903 PortConfig->InterruptMode =
904 (PortConfig->AdapterInterfaceType == PCIBus) ? LevelSensitive : Latched;
905 PortConfig->MaximumTransferLength = SP_UNINITIALIZED_VALUE;
906 PortConfig->NumberOfPhysicalBreaks = SP_UNINITIALIZED_VALUE;
907 PortConfig->DmaChannel = SP_UNINITIALIZED_VALUE;
908 PortConfig->DmaPort = SP_UNINITIALIZED_VALUE;
909 PortConfig->DmaWidth = 0;
910 PortConfig->DmaSpeed = Compatible;
911 PortConfig->AlignmentMask = 0;
912 PortConfig->NumberOfAccessRanges = HwInitializationData->NumberOfAccessRanges;
913 PortConfig->NumberOfBuses = 0;
914
915 for (i = 0; i < SCSI_MAXIMUM_BUSES; i++)
916 PortConfig->InitiatorBusId[i] = 255;
917
918 PortConfig->ScatterGather = FALSE;
919 PortConfig->Master = FALSE;
920 PortConfig->CachesData = FALSE;
921 PortConfig->AdapterScansDown = FALSE;
922 PortConfig->AtdiskPrimaryClaimed = SystemConfig->AtDiskPrimaryAddressClaimed;
923 PortConfig->AtdiskSecondaryClaimed = SystemConfig->AtDiskSecondaryAddressClaimed;
924 PortConfig->Dma32BitAddresses = FALSE;
925 PortConfig->DemandMode = FALSE;
926 PortConfig->MapBuffers = HwInitializationData->MapBuffers;
927 PortConfig->NeedPhysicalAddresses = HwInitializationData->NeedPhysicalAddresses;
928 PortConfig->TaggedQueuing = HwInitializationData->TaggedQueueing;
929 PortConfig->AutoRequestSense = HwInitializationData->AutoRequestSense;
930 PortConfig->MultipleRequestPerLu = HwInitializationData->MultipleRequestPerLu;
931 PortConfig->ReceiveEvent = HwInitializationData->ReceiveEvent;
932 PortConfig->RealModeInitialized = FALSE;
933 PortConfig->BufferAccessScsiPortControlled = FALSE;
934 PortConfig->MaximumNumberOfTargets = SCSI_MAXIMUM_TARGETS;
935 // PortConfig->MaximumNumberOfLogicalUnits = SCSI_MAXIMUM_LOGICAL_UNITS;
936
937 PortConfig->SrbExtensionSize = HwInitializationData->SrbExtensionSize;
938 PortConfig->SpecificLuExtensionSize = HwInitializationData->SpecificLuExtensionSize;
939
940 PortConfig->AccessRanges = (PACCESS_RANGE)(PortConfig + 1);
941
942 /* Search for matching PCI device */
943 if ((HwInitializationData->AdapterInterfaceType == PCIBus) &&
944 (HwInitializationData->VendorIdLength > 0) &&
945 (HwInitializationData->VendorId != NULL) &&
946 (HwInitializationData->DeviceIdLength > 0) &&
947 (HwInitializationData->DeviceId != NULL))
948 {
949 /* Get PCI device data */
950 DPRINT("VendorId '%.*s' DeviceId '%.*s'\n",
951 HwInitializationData->VendorIdLength,
952 HwInitializationData->VendorId,
953 HwInitializationData->DeviceIdLength,
954 HwInitializationData->DeviceId);
955
956 if (!SpiGetPciConfigData (HwInitializationData,
957 PortConfig,
958 BusNumber,
959 &SlotNumber))
960 {
961 Status = STATUS_UNSUCCESSFUL;
962 goto ByeBye;
963 }
964 }
965
966 /* Note: HwFindAdapter is called once for each bus */
967 Again = FALSE;
968 DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber);
969 Result = (HwInitializationData->HwFindAdapter)(&DeviceExtension->MiniPortDeviceExtension,
970 HwContext,
971 0, /* BusInformation */
972 "", /* ArgumentString */
973 PortConfig,
974 &Again);
975 DPRINT("HwFindAdapter() Result: %lu Again: %s\n",
976 Result, (Again) ? "True" : "False");
977
978 if (Result == SP_RETURN_FOUND)
979 {
980 DPRINT("ScsiPortInitialize(): Found HBA! (%x)\n", PortConfig->BusInterruptVector);
981
982 #if 0
983 DPRINT1("SystemIoBusNumber: %x\n", PortConfig->SystemIoBusNumber);
984 DPRINT1("AdapterInterfaceType: %x\n", PortConfig->AdapterInterfaceType);
985 DPRINT1("BusInterruptLevel: %x\n", PortConfig->BusInterruptLevel);
986 DPRINT1("BusInterruptVector: %x\n", PortConfig->BusInterruptVector);
987 DPRINT1("InterruptMode: %x\n", PortConfig->InterruptMode);
988 DPRINT1("MaximumTransferLength: %x\n", PortConfig->MaximumTransferLength);
989 DPRINT1("NumberOfPhysicalBreaks: %x\n", PortConfig->NumberOfPhysicalBreaks);
990 DPRINT1("DmaChannel: %x\n", PortConfig->DmaChannel);
991 DPRINT1("DmaPort: %d\n", PortConfig->DmaPort);
992 DPRINT1("DmaWidth: %d\n", PortConfig->DmaWidth);
993 DPRINT1("DmaSpeed: %d\n", PortConfig->DmaSpeed);
994 DPRINT1("AlignmentMask: %d\n", PortConfig->AlignmentMask);
995 DPRINT1("NumberOfAccessRanges: %d\n", PortConfig->NumberOfAccessRanges);
996 DPRINT1("NumberOfBuses: %d\n", PortConfig->NumberOfBuses);
997 DPRINT1("ScatterGather: %d\n", PortConfig->ScatterGather);
998 DPRINT1("Master: %d\n", PortConfig->Master);
999 DPRINT1("CachesData: %d\n", PortConfig->CachesData);
1000 DPRINT1("AdapterScansDown: %d\n", PortConfig->AdapterScansDown);
1001 DPRINT1("AtdiskPrimaryClaimed: %d\n", PortConfig->AtdiskPrimaryClaimed);
1002 DPRINT1("AtdiskSecondaryClaimed: %d\n", PortConfig->AtdiskSecondaryClaimed);
1003 DPRINT1("Dma32BitAddresses: %d\n", PortConfig->Dma32BitAddresses);
1004 DPRINT1("DemandMode: %d\n", PortConfig->DemandMode);
1005 DPRINT1("MapBuffers: %d\n", PortConfig->MapBuffers);
1006 DPRINT1("NeedPhysicalAddresses: %d\n", PortConfig->NeedPhysicalAddresses);
1007 DPRINT1("TaggedQueuing: %d\n", PortConfig->TaggedQueuing);
1008 DPRINT1("AutoRequestSense: %d\n", PortConfig->AutoRequestSense);
1009 DPRINT1("MultipleRequestPerLu: %d\n", PortConfig->MultipleRequestPerLu);
1010 DPRINT1("ReceiveEvent: %d\n", PortConfig->ReceiveEvent);
1011 DPRINT1("RealModeInitialized: %d\n", PortConfig->RealModeInitialized);
1012 DPRINT1("BufferAccessScsiPortControlled: %d\n", PortConfig->BufferAccessScsiPortControlled);
1013 DPRINT1("MaximumNumberOfTargets: %d\n", PortConfig->MaximumNumberOfTargets);
1014 DPRINT1("SlotNumber: %d\n", PortConfig->SlotNumber);
1015 DPRINT1("BusInterruptLevel2: %x\n", PortConfig->BusInterruptLevel2);
1016 DPRINT1("BusInterruptVector2: %x\n", PortConfig->BusInterruptVector2);
1017 DPRINT1("InterruptMode2: %x\n", PortConfig->InterruptMode2);
1018 DPRINT1("DmaChannel2: %d\n", PortConfig->DmaChannel2);
1019 DPRINT1("DmaPort2: %d\n", PortConfig->DmaPort2);
1020 DPRINT1("DmaWidth2: %d\n", PortConfig->DmaWidth2);
1021 DPRINT1("DmaSpeed2: %d\n", PortConfig->DmaSpeed2);
1022 DPRINT1("DeviceExtensionSize: %d\n", PortConfig->DeviceExtensionSize);
1023 DPRINT1("SpecificLuExtensionSize: %d\n", PortConfig->SpecificLuExtensionSize);
1024 DPRINT1("SrbExtensionSize: %d\n", PortConfig->SrbExtensionSize);
1025
1026 #endif
1027
1028 if (DeviceExtension->VirtualAddress == NULL && DeviceExtension->SrbExtensionSize)
1029 {
1030 ScsiPortGetUncachedExtension(&DeviceExtension->MiniPortDeviceExtension,
1031 PortConfig,
1032 0);
1033 }
1034
1035 /* Register an interrupt handler for this device */
1036 MappedIrq = HalGetInterruptVector(PortConfig->AdapterInterfaceType,
1037 PortConfig->SystemIoBusNumber,
1038 PortConfig->BusInterruptLevel,
1039 #if 1
1040 /*
1041 * FIXME:
1042 * Something is wrong in our interrupt conecting code.
1043 * The promise Ultra100TX driver returns 0 for BusInterruptVector
1044 * and a nonzero value for BusInterruptLevel. The driver does only
1045 * work with this fix.
1046 */
1047 PortConfig->BusInterruptLevel,
1048 #else
1049 PortConfig->BusInterruptVector,
1050 #endif
1051 &Dirql,
1052 &Affinity);
1053 DPRINT("AdapterInterfaceType %x, SystemIoBusNumber %x, BusInterruptLevel %x, BusInterruptVector %x\n",
1054 PortConfig->AdapterInterfaceType, PortConfig->SystemIoBusNumber,
1055 PortConfig->BusInterruptLevel, PortConfig->BusInterruptVector);
1056 Status = IoConnectInterrupt(&DeviceExtension->Interrupt,
1057 ScsiPortIsr,
1058 DeviceExtension,
1059 NULL,
1060 MappedIrq,
1061 Dirql,
1062 Dirql,
1063 PortConfig->InterruptMode,
1064 TRUE,
1065 Affinity,
1066 FALSE);
1067 if (!NT_SUCCESS(Status))
1068 {
1069 DbgPrint("Could not connect interrupt %d\n",
1070 PortConfig->BusInterruptVector);
1071 goto ByeBye;
1072 }
1073
1074 if (!(HwInitializationData->HwInitialize)(&DeviceExtension->MiniPortDeviceExtension))
1075 {
1076 DbgPrint("HwInitialize() failed!");
1077 Status = STATUS_UNSUCCESSFUL;
1078 goto ByeBye;
1079 }
1080
1081 /* Initialize port capabilities */
1082 DeviceExtension->PortCapabilities = ExAllocatePool(NonPagedPool,
1083 sizeof(IO_SCSI_CAPABILITIES));
1084 if (DeviceExtension->PortCapabilities == NULL)
1085 {
1086 DbgPrint("Failed to allocate port capabilities!\n");
1087 Status = STATUS_INSUFFICIENT_RESOURCES;
1088 goto ByeBye;
1089 }
1090
1091 PortCapabilities = DeviceExtension->PortCapabilities;
1092 PortCapabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
1093 if (PortConfig->ScatterGather == FALSE ||
1094 PortConfig->NumberOfPhysicalBreaks >= (0x100000000LL >> PAGE_SHIFT) ||
1095 PortConfig->MaximumTransferLength < PortConfig->NumberOfPhysicalBreaks * PAGE_SIZE)
1096 {
1097 PortCapabilities->MaximumTransferLength =
1098 PortConfig->MaximumTransferLength;
1099 }
1100 else
1101 {
1102 PortCapabilities->MaximumTransferLength =
1103 PortConfig->NumberOfPhysicalBreaks * PAGE_SIZE;
1104 }
1105
1106 PortCapabilities->MaximumPhysicalPages =
1107 PortCapabilities->MaximumTransferLength / PAGE_SIZE;
1108 PortCapabilities->SupportedAsynchronousEvents = 0; /* FIXME */
1109 PortCapabilities->AlignmentMask =
1110 PortConfig->AlignmentMask;
1111 PortCapabilities->TaggedQueuing =
1112 PortConfig->TaggedQueuing;
1113 PortCapabilities->AdapterScansDown =
1114 PortConfig->AdapterScansDown;
1115 PortCapabilities->AdapterUsesPio = TRUE; /* FIXME */
1116
1117 /* Scan the adapter for devices */
1118 SpiScanAdapter (DeviceExtension);
1119
1120 /* Build the registry device map */
1121 SpiBuildDeviceMap (DeviceExtension,
1122 (PUNICODE_STRING)Argument2);
1123
1124 /* Create the dos device link */
1125 swprintf(DosNameBuffer,
1126 L"\\??\\Scsi%lu:",
1127 SystemConfig->ScsiPortCount);
1128 RtlInitUnicodeString(&DosDeviceName,
1129 DosNameBuffer);
1130 IoCreateSymbolicLink(&DosDeviceName,
1131 &DeviceName);
1132
1133 /* Update the system configuration info */
1134 if (PortConfig->AtdiskPrimaryClaimed == TRUE)
1135 SystemConfig->AtDiskPrimaryAddressClaimed = TRUE;
1136 if (PortConfig->AtdiskSecondaryClaimed == TRUE)
1137 SystemConfig->AtDiskSecondaryAddressClaimed = TRUE;
1138
1139 SystemConfig->ScsiPortCount++;
1140 PortDeviceObject = NULL;
1141 DeviceFound = TRUE;
1142 }
1143 else
1144 {
1145 DPRINT("HwFindAdapter() Result: %lu\n", Result);
1146
1147 ExFreePool (PortConfig);
1148 IoDeleteDevice (PortDeviceObject);
1149 PortDeviceObject = NULL;
1150 }
1151
1152 DPRINT("Bus: %lu MaxBus: %lu\n", BusNumber, MaxBus);
1153 if (BusNumber >= MaxBus)
1154 {
1155 DPRINT("Scanned all buses!\n");
1156 Status = STATUS_SUCCESS;
1157 goto ByeBye;
1158 }
1159
1160 if (Again == FALSE)
1161 {
1162 BusNumber++;
1163 SlotNumber.u.AsULONG = 0;
1164 }
1165 }
1166
1167 ByeBye:
1168 /* Clean up the mess */
1169 if (PortDeviceObject != NULL)
1170 {
1171 DPRINT("Delete device: %p\n", PortDeviceObject);
1172
1173 DeviceExtension = PortDeviceObject->DeviceExtension;
1174
1175 if (DeviceExtension->PortCapabilities != NULL)
1176 {
1177 IoDisconnectInterrupt (DeviceExtension->Interrupt);
1178 ExFreePool (DeviceExtension->PortCapabilities);
1179 }
1180
1181 if (DeviceExtension->PortConfig != NULL)
1182 {
1183 ExFreePool (DeviceExtension->PortConfig);
1184 }
1185
1186 IoDeleteDevice (PortDeviceObject);
1187 }
1188
1189 DPRINT("ScsiPortInitialize() done!\n");
1190
1191 return (DeviceFound == FALSE) ? Status : STATUS_SUCCESS;
1192 }
1193
1194
1195 /*
1196 * @unimplemented
1197 */
1198 VOID STDCALL
1199 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension,
1200 IN PSCSI_REQUEST_BLOCK Srb,
1201 IN ULONG LogicalAddress,
1202 IN ULONG Length)
1203 {
1204 DPRINT1("ScsiPortIoMapTransfer()\n");
1205 UNIMPLEMENTED;
1206 }
1207
1208
1209 /*
1210 * @unimplemented
1211 */
1212 VOID STDCALL
1213 ScsiPortLogError(IN PVOID HwDeviceExtension,
1214 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
1215 IN UCHAR PathId,
1216 IN UCHAR TargetId,
1217 IN UCHAR Lun,
1218 IN ULONG ErrorCode,
1219 IN ULONG UniqueId)
1220 {
1221 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1222
1223 DPRINT1("ScsiPortLogError() called\n");
1224 DPRINT1("Srb %x, PathId %d, TargetId %d, Lun %d, ErrorCode %x, UniqueId %x\n",
1225 Srb, PathId, TargetId, Lun, ErrorCode, UniqueId);
1226
1227 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
1228 SCSI_PORT_DEVICE_EXTENSION,
1229 MiniPortDeviceExtension);
1230
1231
1232 DPRINT("ScsiPortLogError() done\n");
1233 }
1234
1235
1236 /*
1237 * @implemented
1238 */
1239 VOID STDCALL
1240 ScsiPortMoveMemory(OUT PVOID Destination,
1241 IN PVOID Source,
1242 IN ULONG Length)
1243 {
1244 RtlMoveMemory(Destination,
1245 Source,
1246 Length);
1247 }
1248
1249
1250 /*
1251 * @implemented
1252 */
1253 VOID
1254 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType,
1255 IN PVOID HwDeviceExtension,
1256 ...)
1257 {
1258 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1259 va_list ap;
1260
1261 DPRINT("ScsiPortNotification() called\n");
1262
1263 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
1264 SCSI_PORT_DEVICE_EXTENSION,
1265 MiniPortDeviceExtension);
1266
1267 DPRINT("DeviceExtension %p\n", DeviceExtension);
1268
1269 va_start(ap, HwDeviceExtension);
1270
1271 switch (NotificationType)
1272 {
1273 case RequestComplete:
1274 {
1275 PSCSI_REQUEST_BLOCK Srb;
1276
1277 Srb = (PSCSI_REQUEST_BLOCK) va_arg (ap, PSCSI_REQUEST_BLOCK);
1278
1279 DPRINT("Notify: RequestComplete (Srb %p)\n", Srb);
1280 DeviceExtension->Flags |= IRP_FLAG_COMPLETE;
1281 Srb->SrbFlags &= ~SRB_FLAGS_IS_ACTIVE;
1282 }
1283 break;
1284
1285 case NextRequest:
1286 DPRINT("Notify: NextRequest\n");
1287 DeviceExtension->Flags |= IRP_FLAG_NEXT;
1288 break;
1289
1290 case NextLuRequest:
1291 {
1292 UCHAR PathId;
1293 UCHAR TargetId;
1294 UCHAR Lun;
1295 PSCSI_PORT_LUN_EXTENSION LunExtension;
1296
1297 PathId = (UCHAR) va_arg (ap, int);
1298 TargetId = (UCHAR) va_arg (ap, int);
1299 Lun = (UCHAR) va_arg (ap, int);
1300
1301 DPRINT ("Notify: NextLuRequest(PathId %u TargetId %u Lun %u)\n",
1302 PathId, TargetId, Lun);
1303
1304 LunExtension = SpiGetLunExtension(DeviceExtension,
1305 PathId,
1306 TargetId,
1307 Lun);
1308 if (LunExtension)
1309 {
1310 DeviceExtension->Flags |= IRP_FLAG_NEXT_LU;
1311 LunExtension->Flags |= IRP_FLAG_NEXT_LU;
1312 }
1313 }
1314 break;
1315
1316 case ResetDetected:
1317 DPRINT1("Notify: ResetDetected\n");
1318 /* FIXME: ??? */
1319 break;
1320
1321 default:
1322 DPRINT1 ("Unsupported notification %lu\n", NotificationType);
1323 break;
1324 }
1325 if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
1326 {
1327 IoRequestDpc(DeviceExtension->DeviceObject,
1328 NULL,
1329 DeviceExtension);
1330 }
1331 else
1332 {
1333 SpiProcessRequests(DeviceExtension, NULL);
1334 }
1335
1336 va_end(ap);
1337 }
1338
1339
1340 /*
1341 * @implemented
1342 */
1343 ULONG STDCALL
1344 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension,
1345 IN ULONG BusDataType,
1346 IN ULONG SystemIoBusNumber,
1347 IN ULONG SlotNumber,
1348 IN PVOID Buffer,
1349 IN ULONG Offset,
1350 IN ULONG Length)
1351 {
1352 DPRINT("ScsiPortSetBusDataByOffset()\n");
1353 return(HalSetBusDataByOffset(BusDataType,
1354 SystemIoBusNumber,
1355 SlotNumber,
1356 Buffer,
1357 Offset,
1358 Length));
1359 }
1360
1361
1362 /*
1363 * @implemented
1364 */
1365 BOOLEAN STDCALL
1366 ScsiPortValidateRange(IN PVOID HwDeviceExtension,
1367 IN INTERFACE_TYPE BusType,
1368 IN ULONG SystemIoBusNumber,
1369 IN SCSI_PHYSICAL_ADDRESS IoAddress,
1370 IN ULONG NumberOfBytes,
1371 IN BOOLEAN InIoSpace)
1372 {
1373 DPRINT("ScsiPortValidateRange()\n");
1374 return(TRUE);
1375 }
1376
1377
1378 /* INTERNAL FUNCTIONS ********************************************************/
1379
1380
1381 static BOOLEAN
1382 SpiGetPciConfigData (IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
1383 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,
1384 IN ULONG BusNumber,
1385 IN OUT PPCI_SLOT_NUMBER NextSlotNumber)
1386 {
1387 PCI_COMMON_CONFIG PciConfig;
1388 PCI_SLOT_NUMBER SlotNumber;
1389 ULONG DataSize;
1390 ULONG DeviceNumber;
1391 ULONG FunctionNumber;
1392 CHAR VendorIdString[8];
1393 CHAR DeviceIdString[8];
1394 ULONG i;
1395 ULONG RangeLength;
1396
1397 DPRINT ("SpiGetPciConfiguration() called\n");
1398
1399 if (NextSlotNumber->u.bits.FunctionNumber >= PCI_MAX_FUNCTION)
1400 {
1401 NextSlotNumber->u.bits.FunctionNumber = 0;
1402 NextSlotNumber->u.bits.DeviceNumber++;
1403 }
1404
1405 if (NextSlotNumber->u.bits.DeviceNumber >= PCI_MAX_DEVICES)
1406 {
1407 NextSlotNumber->u.bits.DeviceNumber = 0;
1408 return FALSE;
1409 }
1410
1411 for (DeviceNumber = NextSlotNumber->u.bits.DeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
1412 {
1413 SlotNumber.u.bits.DeviceNumber = DeviceNumber;
1414
1415 for (FunctionNumber = NextSlotNumber->u.bits.FunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
1416 {
1417 SlotNumber.u.bits.FunctionNumber = FunctionNumber;
1418
1419 DataSize = HalGetBusData (PCIConfiguration,
1420 BusNumber,
1421 SlotNumber.u.AsULONG,
1422 &PciConfig,
1423 PCI_COMMON_HDR_LENGTH);
1424 if (DataSize != PCI_COMMON_HDR_LENGTH)
1425 {
1426 if (FunctionNumber == 0)
1427 {
1428 break;
1429 }
1430 else
1431 {
1432 continue;
1433 }
1434 }
1435
1436 sprintf (VendorIdString, "%04hx", PciConfig.VendorID);
1437 sprintf (DeviceIdString, "%04hx", PciConfig.DeviceID);
1438
1439 if (!_strnicmp(VendorIdString, HwInitializationData->VendorId, HwInitializationData->VendorIdLength) &&
1440 !_strnicmp(DeviceIdString, HwInitializationData->DeviceId, HwInitializationData->DeviceIdLength))
1441 {
1442 DPRINT ("Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n",
1443 PciConfig.VendorID,
1444 PciConfig.DeviceID,
1445 BusNumber,
1446 SlotNumber.u.bits.DeviceNumber,
1447 SlotNumber.u.bits.FunctionNumber);
1448
1449 PortConfig->BusInterruptLevel =
1450 PortConfig->BusInterruptVector = PciConfig.u.type0.InterruptLine;
1451 PortConfig->SlotNumber = SlotNumber.u.AsULONG;
1452
1453 /* Initialize access ranges */
1454 if (PortConfig->NumberOfAccessRanges > 0)
1455 {
1456 if (PortConfig->NumberOfAccessRanges > PCI_TYPE0_ADDRESSES)
1457 PortConfig->NumberOfAccessRanges = PCI_TYPE0_ADDRESSES;
1458
1459 for (i = 0; i < PortConfig->NumberOfAccessRanges; i++)
1460 {
1461 PortConfig->AccessRanges[i].RangeStart.QuadPart =
1462 PciConfig.u.type0.BaseAddresses[i] & PCI_ADDRESS_IO_ADDRESS_MASK;
1463 if (PortConfig->AccessRanges[i].RangeStart.QuadPart != 0)
1464 {
1465 RangeLength = (ULONG)-1;
1466 HalSetBusDataByOffset (PCIConfiguration,
1467 BusNumber,
1468 SlotNumber.u.AsULONG,
1469 (PVOID)&RangeLength,
1470 0x10 + (i * sizeof(ULONG)),
1471 sizeof(ULONG));
1472
1473 HalGetBusDataByOffset (PCIConfiguration,
1474 BusNumber,
1475 SlotNumber.u.AsULONG,
1476 (PVOID)&RangeLength,
1477 0x10 + (i * sizeof(ULONG)),
1478 sizeof(ULONG));
1479
1480 HalSetBusDataByOffset (PCIConfiguration,
1481 BusNumber,
1482 SlotNumber.u.AsULONG,
1483 (PVOID)&PciConfig.u.type0.BaseAddresses[i],
1484 0x10 + (i * sizeof(ULONG)),
1485 sizeof(ULONG));
1486 if (RangeLength != 0)
1487 {
1488 PortConfig->AccessRanges[i].RangeLength =
1489 -(RangeLength & PCI_ADDRESS_IO_ADDRESS_MASK);
1490 PortConfig->AccessRanges[i].RangeInMemory =
1491 !(PciConfig.u.type0.BaseAddresses[i] & PCI_ADDRESS_IO_SPACE);
1492
1493 DPRINT("RangeStart 0x%lX RangeLength 0x%lX RangeInMemory %s\n",
1494 PciConfig.u.type0.BaseAddresses[i] & PCI_ADDRESS_IO_ADDRESS_MASK,
1495 -(RangeLength & PCI_ADDRESS_IO_ADDRESS_MASK),
1496 (PciConfig.u.type0.BaseAddresses[i] & PCI_ADDRESS_IO_SPACE)?"FALSE":"TRUE");
1497 }
1498 }
1499 }
1500 }
1501
1502 NextSlotNumber->u.bits.DeviceNumber = DeviceNumber;
1503 NextSlotNumber->u.bits.FunctionNumber = FunctionNumber;
1504
1505 PortConfig->SlotNumber = NextSlotNumber->u.AsULONG;
1506
1507 NextSlotNumber->u.bits.FunctionNumber += 1;
1508
1509 return TRUE;
1510 }
1511
1512
1513 if (FunctionNumber == 0 && !(PciConfig.HeaderType & PCI_MULTIFUNCTION))
1514 {
1515 break;
1516 }
1517 }
1518 NextSlotNumber->u.bits.FunctionNumber = 0;
1519 }
1520
1521 DPRINT ("No device found\n");
1522
1523 return FALSE;
1524 }
1525
1526
1527
1528 /**********************************************************************
1529 * NAME INTERNAL
1530 * ScsiPortCreateClose
1531 *
1532 * DESCRIPTION
1533 * Answer requests for Create/Close calls: a null operation.
1534 *
1535 * RUN LEVEL
1536 * PASSIVE_LEVEL
1537 *
1538 * ARGUMENTS
1539 * DeviceObject
1540 * Pointer to a device object.
1541 *
1542 * Irp
1543 * Pointer to an IRP.
1544 *
1545 * RETURN VALUE
1546 * Status.
1547 */
1548
1549 static NTSTATUS STDCALL
1550 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
1551 IN PIRP Irp)
1552 {
1553 DPRINT("ScsiPortCreateClose()\n");
1554
1555 Irp->IoStatus.Status = STATUS_SUCCESS;
1556 Irp->IoStatus.Information = FILE_OPENED;
1557
1558 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1559
1560 return(STATUS_SUCCESS);
1561 }
1562
1563
1564 /**********************************************************************
1565 * NAME INTERNAL
1566 * ScsiPortDispatchScsi
1567 *
1568 * DESCRIPTION
1569 * Answer requests for SCSI calls
1570 *
1571 * RUN LEVEL
1572 * PASSIVE_LEVEL
1573 *
1574 * ARGUMENTS
1575 * Standard dispatch arguments
1576 *
1577 * RETURNS
1578 * NTSTATUS
1579 */
1580
1581 static NTSTATUS STDCALL
1582 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
1583 IN PIRP Irp)
1584 {
1585 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1586 PSCSI_PORT_LUN_EXTENSION LunExtension;
1587 PIO_STACK_LOCATION Stack;
1588 PSCSI_REQUEST_BLOCK Srb;
1589 NTSTATUS Status = STATUS_SUCCESS;
1590 ULONG DataSize = 0;
1591
1592 DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n",
1593 DeviceObject, Irp);
1594
1595 DeviceExtension = DeviceObject->DeviceExtension;
1596 Stack = IoGetCurrentIrpStackLocation(Irp);
1597
1598 Srb = Stack->Parameters.Scsi.Srb;
1599 if (Srb == NULL)
1600 {
1601 Status = STATUS_UNSUCCESSFUL;
1602
1603 Irp->IoStatus.Status = Status;
1604 Irp->IoStatus.Information = 0;
1605
1606 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1607
1608 return(Status);
1609 }
1610
1611 DPRINT("Srb: %p\n", Srb);
1612 DPRINT("Srb->Function: %lu\n", Srb->Function);
1613 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
1614
1615 LunExtension = SpiGetLunExtension(DeviceExtension,
1616 Srb->PathId,
1617 Srb->TargetId,
1618 Srb->Lun);
1619 if (LunExtension == NULL)
1620 {
1621 Status = STATUS_NO_SUCH_DEVICE;
1622
1623 Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
1624 Irp->IoStatus.Status = Status;
1625 Irp->IoStatus.Information = 0;
1626
1627 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1628
1629 return(Status);
1630 }
1631
1632 switch (Srb->Function)
1633 {
1634 case SRB_FUNCTION_EXECUTE_SCSI:
1635 case SRB_FUNCTION_IO_CONTROL:
1636 IoMarkIrpPending(Irp);
1637 Srb->OriginalRequest = LunExtension;
1638 Irp->Tail.Overlay.DriverContext[3] = Srb;
1639 SpiProcessRequests(DeviceExtension, Irp);
1640 return(STATUS_PENDING);
1641
1642 case SRB_FUNCTION_SHUTDOWN:
1643 case SRB_FUNCTION_FLUSH:
1644 if (DeviceExtension->PortConfig->CachesData == TRUE)
1645 {
1646 IoMarkIrpPending(Irp);
1647 Srb->OriginalRequest = LunExtension;
1648 Irp->Tail.Overlay.DriverContext[3] = Srb;
1649 SpiProcessRequests(DeviceExtension, Irp);
1650 return(STATUS_PENDING);
1651 }
1652 break;
1653
1654 case SRB_FUNCTION_CLAIM_DEVICE:
1655 DPRINT (" SRB_FUNCTION_CLAIM_DEVICE\n");
1656
1657 /* Reference device object and keep the device object */
1658 ObReferenceObject(DeviceObject);
1659 LunExtension->DeviceObject = DeviceObject;
1660 LunExtension->DeviceClaimed = TRUE;
1661 Srb->DataBuffer = DeviceObject;
1662 break;
1663
1664 case SRB_FUNCTION_RELEASE_DEVICE:
1665 DPRINT (" SRB_FUNCTION_RELEASE_DEVICE\n");
1666 DPRINT ("PathId: %lu TargetId: %lu Lun: %lu\n",
1667 Srb->PathId, Srb->TargetId, Srb->Lun);
1668
1669 /* Dereference device object and clear the device object */
1670 ObDereferenceObject(LunExtension->DeviceObject);
1671 LunExtension->DeviceObject = NULL;
1672 LunExtension->DeviceClaimed = FALSE;
1673 break;
1674
1675 default:
1676 DPRINT1("SRB function not implemented (Function %lu)\n", Srb->Function);
1677 Status = STATUS_NOT_IMPLEMENTED;
1678 break;
1679 }
1680
1681 Irp->IoStatus.Status = Status;
1682 Irp->IoStatus.Information = DataSize;
1683
1684 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1685
1686 return(Status);
1687 }
1688
1689
1690 /**********************************************************************
1691 * NAME INTERNAL
1692 * ScsiPortDeviceControl
1693 *
1694 * DESCRIPTION
1695 * Answer requests for device control calls
1696 *
1697 * RUN LEVEL
1698 * PASSIVE_LEVEL
1699 *
1700 * ARGUMENTS
1701 * Standard dispatch arguments
1702 *
1703 * RETURNS
1704 * NTSTATUS
1705 */
1706
1707 static NTSTATUS STDCALL
1708 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
1709 IN PIRP Irp)
1710 {
1711 PIO_STACK_LOCATION Stack;
1712 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1713
1714 DPRINT("ScsiPortDeviceControl()\n");
1715
1716 Irp->IoStatus.Status = STATUS_SUCCESS;
1717 Irp->IoStatus.Information = 0;
1718
1719
1720 Stack = IoGetCurrentIrpStackLocation(Irp);
1721 DeviceExtension = DeviceObject->DeviceExtension;
1722
1723 switch (Stack->Parameters.DeviceIoControl.IoControlCode)
1724 {
1725 case IOCTL_SCSI_GET_DUMP_POINTERS:
1726 {
1727 PDUMP_POINTERS DumpPointers;
1728 DPRINT(" IOCTL_SCSI_GET_DUMP_POINTERS\n");
1729 DumpPointers = (PDUMP_POINTERS)Irp->AssociatedIrp.SystemBuffer;
1730 DumpPointers->DeviceObject = DeviceObject;
1731
1732 Irp->IoStatus.Information = sizeof(DUMP_POINTERS);
1733 }
1734 break;
1735
1736 case IOCTL_SCSI_GET_CAPABILITIES:
1737 {
1738 DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
1739
1740 *((PIO_SCSI_CAPABILITIES *)Irp->AssociatedIrp.SystemBuffer) =
1741 DeviceExtension->PortCapabilities;
1742
1743 Irp->IoStatus.Information = sizeof(PIO_SCSI_CAPABILITIES);
1744 }
1745 break;
1746
1747 case IOCTL_SCSI_GET_INQUIRY_DATA:
1748 {
1749 DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
1750
1751 /* Copy inquiry data to the port device extension */
1752 Irp->IoStatus.Information =
1753 SpiGetInquiryData(DeviceExtension,
1754 Irp->AssociatedIrp.SystemBuffer);
1755 DPRINT("Inquiry data size: %lu\n", Irp->IoStatus.Information);
1756 }
1757 break;
1758
1759 default:
1760 DPRINT1(" unknown ioctl code: 0x%lX\n",
1761 Stack->Parameters.DeviceIoControl.IoControlCode);
1762 break;
1763 }
1764
1765 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1766
1767 return(STATUS_SUCCESS);
1768 }
1769
1770 static VOID
1771 SpiAllocateSrbExtension(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1772 PSCSI_REQUEST_BLOCK Srb)
1773 {
1774 ULONG index;
1775
1776 DPRINT("SpiAllocateSrbExtension\n");
1777
1778 DPRINT("DeviceExtension->VirtualAddress %x, DeviceExtension->SrbExtensionSize %x\n",
1779 DeviceExtension->VirtualAddress, DeviceExtension->SrbExtensionSize);
1780
1781 Srb->SrbExtension = NULL;
1782 if (DeviceExtension->VirtualAddress != NULL &&
1783 DeviceExtension->SrbExtensionSize > 0)
1784 {
1785 index = RtlFindClearBitsAndSet(&DeviceExtension->SrbExtensionAllocMap, 1, 0);
1786 if (index != 0xffffffff)
1787 {
1788 DeviceExtension->CurrentSrbExtensions++;
1789 Srb->SrbExtension = DeviceExtension->VirtualAddress + index * DeviceExtension->SrbExtensionSize;
1790 }
1791 }
1792 DPRINT("%x\n", Srb->SrbExtension);
1793 }
1794
1795 static VOID
1796 SpiFreeSrbExtension(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1797 PSCSI_REQUEST_BLOCK Srb)
1798 {
1799 ULONG index;
1800
1801 if (DeviceExtension->VirtualAddress != NULL &&
1802 DeviceExtension->SrbExtensionSize > 0 &&
1803 Srb->SrbExtension != NULL)
1804 {
1805 index = ((ULONG_PTR)Srb->SrbExtension - (ULONG_PTR)DeviceExtension->VirtualAddress) / DeviceExtension->SrbExtensionSize;
1806 RtlClearBits(&DeviceExtension->SrbExtensionAllocMap, index, 1);
1807 DeviceExtension->CurrentSrbExtensions--;
1808 }
1809 Srb->SrbExtension = NULL;
1810 }
1811
1812
1813 static BOOLEAN STDCALL
1814 ScsiPortStartPacket(IN OUT PVOID Context)
1815 {
1816 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1817 PSCSI_REQUEST_BLOCK Srb;
1818 PIRP Irp;
1819 PIO_STACK_LOCATION IrpStack;
1820
1821 DPRINT("ScsiPortStartPacket(Context %x) called\n", Context);
1822
1823 Srb = (PSCSI_REQUEST_BLOCK)Context;
1824 Irp = (PIRP)Srb->OriginalRequest;
1825 IrpStack = IoGetCurrentIrpStackLocation(Irp);
1826 DeviceExtension = IrpStack->DeviceObject->DeviceExtension;
1827
1828 return(DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
1829 Srb));
1830 }
1831
1832
1833 static PSCSI_PORT_LUN_EXTENSION
1834 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1835 IN UCHAR PathId,
1836 IN UCHAR TargetId,
1837 IN UCHAR Lun)
1838 {
1839 PSCSI_PORT_LUN_EXTENSION LunExtension;
1840 ULONG LunExtensionSize;
1841
1842 DPRINT("SpiAllocateLunExtension (%p %u %u %u)\n",
1843 DeviceExtension, PathId, TargetId, Lun);
1844
1845 LunExtensionSize =
1846 sizeof(SCSI_PORT_LUN_EXTENSION) + DeviceExtension->LunExtensionSize;
1847 DPRINT("LunExtensionSize %lu\n", LunExtensionSize);
1848
1849 LunExtension = ExAllocatePool(NonPagedPool,
1850 LunExtensionSize);
1851 if (LunExtension == NULL)
1852 {
1853 return NULL;
1854 }
1855
1856 RtlZeroMemory(LunExtension,
1857 LunExtensionSize);
1858
1859 InsertTailList(&DeviceExtension->LunExtensionListHead,
1860 &LunExtension->List);
1861
1862 LunExtension->PathId = PathId;
1863 LunExtension->TargetId = TargetId;
1864 LunExtension->Lun = Lun;
1865
1866 LunExtension->PendingIrpCount = 0;
1867 LunExtension->ActiveIrpCount = 0;
1868
1869 LunExtension->NextIrp = NULL;
1870
1871 return LunExtension;
1872 }
1873
1874
1875 static VOID
1876 SpiRemoveLunExtension (IN PSCSI_PORT_LUN_EXTENSION LunExtension)
1877 {
1878 DPRINT("SpiRemoveLunExtension(%p) called\n",
1879 LunExtension);
1880
1881 if (LunExtension == NULL)
1882 return;
1883
1884 RemoveEntryList (&LunExtension->List);
1885
1886
1887 /* Release LUN extersion data */
1888
1889
1890 ExFreePool (LunExtension);
1891
1892 return;
1893 }
1894
1895
1896 static PSCSI_PORT_LUN_EXTENSION
1897 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1898 IN UCHAR PathId,
1899 IN UCHAR TargetId,
1900 IN UCHAR Lun)
1901 {
1902 PSCSI_PORT_LUN_EXTENSION LunExtension;
1903 PLIST_ENTRY Entry;
1904
1905 DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
1906 DeviceExtension, PathId, TargetId, Lun);
1907
1908 if (IsListEmpty(&DeviceExtension->LunExtensionListHead))
1909 return NULL;
1910
1911 Entry = DeviceExtension->LunExtensionListHead.Flink;
1912 while (Entry != &DeviceExtension->LunExtensionListHead)
1913 {
1914 LunExtension = CONTAINING_RECORD(Entry,
1915 SCSI_PORT_LUN_EXTENSION,
1916 List);
1917 if (LunExtension->PathId == PathId &&
1918 LunExtension->TargetId == TargetId &&
1919 LunExtension->Lun == Lun)
1920 {
1921 return LunExtension;
1922 }
1923
1924 Entry = Entry->Flink;
1925 }
1926
1927 return NULL;
1928 }
1929
1930
1931 static NTSTATUS
1932 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject,
1933 IN OUT PSCSI_REQUEST_BLOCK Srb,
1934 IN OUT PIO_STATUS_BLOCK IoStatusBlock,
1935 IN OUT PKEVENT Event)
1936 {
1937 PIO_STACK_LOCATION IrpStack;
1938 PIRP Irp;
1939 NTSTATUS Status;
1940
1941 DPRINT ("SpiSendInquiry() called\n");
1942
1943
1944 KeInitializeEvent (Event,
1945 NotificationEvent,
1946 FALSE);
1947
1948 Irp = IoBuildDeviceIoControlRequest (IOCTL_SCSI_EXECUTE_OUT,
1949 DeviceObject,
1950 NULL,
1951 0,
1952 Srb->DataBuffer,
1953 Srb->DataTransferLength,
1954 TRUE,
1955 Event,
1956 IoStatusBlock);
1957 if (Irp == NULL)
1958 {
1959 DPRINT("IoBuildDeviceIoControlRequest() failed\n");
1960 return STATUS_INSUFFICIENT_RESOURCES;
1961 }
1962
1963 /* Attach Srb to the Irp */
1964 IrpStack = IoGetNextIrpStackLocation (Irp);
1965 IrpStack->Parameters.Scsi.Srb = Srb;
1966 Srb->OriginalRequest = Irp;
1967
1968 /* Call the driver */
1969 Status = IoCallDriver (DeviceObject,
1970 Irp);
1971
1972 return Status;
1973 }
1974
1975 static VOID
1976 SpiScanAdapter (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
1977 {
1978 PSCSI_REQUEST_BLOCK Srb;
1979 PCDB Cdb;
1980 ULONG Bus;
1981 ULONG Target;
1982 PSCSI_PORT_SCAN_ADAPTER ScanDataArray;
1983 PSCSI_PORT_SCAN_ADAPTER ScanData;
1984 ULONG i;
1985 ULONG MaxCount;
1986 ULONG WaitCount;
1987 ULONG ActiveCount;
1988 PVOID* EventArray;
1989 PKWAIT_BLOCK WaitBlockArray;
1990
1991 DPRINT ("SpiScanAdapter() called\n");
1992
1993 MaxCount = DeviceExtension->PortConfig->NumberOfBuses *
1994 DeviceExtension->PortConfig->MaximumNumberOfTargets;
1995
1996 ScanDataArray = ExAllocatePool(NonPagedPool, MaxCount * (sizeof(SCSI_PORT_SCAN_ADAPTER) + sizeof(PVOID) + sizeof(KWAIT_BLOCK)));
1997 if (ScanDataArray == NULL)
1998 {
1999 return;
2000 }
2001 EventArray = (PVOID*)((PUCHAR)ScanDataArray + MaxCount * sizeof(SCSI_PORT_SCAN_ADAPTER));
2002 WaitBlockArray = (PKWAIT_BLOCK)((PUCHAR)EventArray + MaxCount * sizeof(PVOID));
2003
2004 for (Bus = 0; Bus < DeviceExtension->PortConfig->NumberOfBuses; Bus++)
2005 {
2006 for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
2007 {
2008 ScanData = &ScanDataArray[Bus * DeviceExtension->PortConfig->MaximumNumberOfTargets + Target];
2009 ScanData->Bus = Bus;
2010 ScanData->Target = Target;
2011 ScanData->Lun = 0;
2012 ScanData->Active = FALSE;
2013 }
2014 }
2015 do
2016 {
2017 ActiveCount = 0;
2018 WaitCount = 0;
2019 for (i = 0; i < MaxCount; i++)
2020 {
2021 ScanData = &ScanDataArray[i];
2022 Srb = &ScanData->Srb;
2023 if (ScanData->Active)
2024 {
2025 if (ScanData->Status == STATUS_PENDING &&
2026 0 == KeReadStateEvent(&ScanData->Event))
2027 {
2028 ActiveCount++;
2029 continue;
2030 }
2031 else
2032 {
2033 ScanData->Status = ScanData->IoStatusBlock.Status;
2034 }
2035 ScanData->Active = FALSE;
2036 DPRINT ("Target %lu Lun %lu\n", ScanData->Target, ScanData->Lun);
2037 DPRINT ("Status %lx Srb.SrbStatus %x\n", ScanData->Status, Srb->SrbStatus);
2038 DPRINT ("DeviceTypeQualifier %x\n", ((PINQUIRYDATA)Srb->DataBuffer)->DeviceTypeQualifier);
2039
2040 if (NT_SUCCESS(ScanData->Status) &&
2041 (Srb->SrbStatus == SRB_STATUS_SUCCESS ||
2042 (Srb->SrbStatus == SRB_STATUS_DATA_OVERRUN &&
2043 /*
2044 * FIXME:
2045 * The NT 4.0 driver from an inic950 based scsi controller
2046 * returns only 4 byte of inquiry data, but the device name
2047 * is visible on NT 4.0. We must implement an other way
2048 * to get the complete inquiry data.
2049 */
2050 Srb->DataTransferLength >= /*INQUIRYDATABUFFERSIZE*/4)) &&
2051 ((PINQUIRYDATA)Srb->DataBuffer)->DeviceTypeQualifier == 0)
2052 {
2053 /* Copy inquiry data */
2054 RtlCopyMemory (&ScanData->LunExtension->InquiryData,
2055 Srb->DataBuffer,
2056 min(sizeof(INQUIRYDATA), Srb->DataTransferLength));
2057 ScanData->Lun++;
2058 }
2059 else
2060 {
2061 SpiRemoveLunExtension (ScanData->LunExtension);
2062 ScanData->Lun = SCSI_MAXIMUM_LOGICAL_UNITS;
2063 }
2064 }
2065 if (ScanData->Lun >= SCSI_MAXIMUM_LOGICAL_UNITS)
2066 {
2067 continue;
2068 }
2069 RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
2070 Srb->SrbFlags = SRB_FLAGS_DATA_IN;
2071 Srb->DataBuffer = ScanData->DataBuffer;
2072 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
2073 Srb->DataTransferLength = 255; //256;
2074 Srb->CdbLength = 6;
2075 Srb->Lun = ScanData->Lun;
2076 Srb->PathId = ScanData->Bus;
2077 Srb->TargetId = ScanData->Target;
2078 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2079 Srb->TimeOutValue = 2;
2080 Cdb = (PCDB) &Srb->Cdb;
2081
2082 Cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
2083 Cdb->CDB6INQUIRY.AllocationLength = 255;
2084 Cdb->CDB6INQUIRY.LogicalUnitNumber = ScanData->Lun;
2085
2086 RtlZeroMemory(Srb->DataBuffer, 256);
2087
2088 ScanData->LunExtension = SpiAllocateLunExtension (DeviceExtension,
2089 ScanData->Bus,
2090 ScanData->Target,
2091 ScanData->Lun);
2092 if (ScanData->LunExtension == NULL)
2093 {
2094 DPRINT1("Failed to allocate the LUN extension!\n");
2095 ScanData->Lun = SCSI_MAXIMUM_LOGICAL_UNITS;
2096 continue;
2097 }
2098 ScanData->Status = SpiSendInquiry (DeviceExtension->DeviceObject,
2099 Srb,
2100 &ScanData->IoStatusBlock,
2101 &ScanData->Event);
2102 ScanData->Active = TRUE;
2103 ActiveCount++;
2104 if (ScanData->Status == STATUS_PENDING)
2105 {
2106 EventArray[WaitCount] = &ScanData->Event;
2107 WaitCount++;
2108 }
2109 }
2110 if (WaitCount > 0 && WaitCount == ActiveCount)
2111 {
2112 KeWaitForMultipleObjects(WaitCount,
2113 EventArray,
2114 WaitAny,
2115 Executive,
2116 KernelMode,
2117 FALSE,
2118 NULL,
2119 WaitBlockArray);
2120 }
2121 }
2122 while (ActiveCount > 0);
2123
2124 ExFreePool(ScanDataArray);
2125
2126 DPRINT ("SpiScanAdapter() done\n");
2127 }
2128
2129
2130 static ULONG
2131 SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
2132 OUT PSCSI_ADAPTER_BUS_INFO AdapterBusInfo)
2133 {
2134 PSCSI_PORT_LUN_EXTENSION LunExtension;
2135 PSCSI_INQUIRY_DATA UnitInfo, PrevUnit;
2136 ULONG Bus;
2137 ULONG Target;
2138 ULONG Lun;
2139 ULONG UnitCount;
2140
2141 DPRINT("SpiGetInquiryData() called\n");
2142
2143 /* Copy inquiry data to the port device extension */
2144 AdapterBusInfo->NumberOfBuses = DeviceExtension->PortConfig->NumberOfBuses;
2145
2146 UnitInfo = (PSCSI_INQUIRY_DATA)
2147 ((PUCHAR)AdapterBusInfo + sizeof(SCSI_ADAPTER_BUS_INFO) +
2148 (sizeof(SCSI_BUS_DATA) * (AdapterBusInfo->NumberOfBuses - 1)));
2149
2150 for (Bus = 0; Bus < AdapterBusInfo->NumberOfBuses; Bus++)
2151 {
2152 AdapterBusInfo->BusData[Bus].InitiatorBusId =
2153 DeviceExtension->PortConfig->InitiatorBusId[Bus];
2154 AdapterBusInfo->BusData[Bus].InquiryDataOffset =
2155 (ULONG)((PUCHAR)UnitInfo - (PUCHAR)AdapterBusInfo);
2156
2157 PrevUnit = NULL;
2158 UnitCount = 0;
2159
2160 for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
2161 {
2162 for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
2163 {
2164 LunExtension = SpiGetLunExtension(DeviceExtension,
2165 Bus,
2166 Target,
2167 Lun);
2168 if (LunExtension != NULL)
2169 {
2170 DPRINT("(Bus %lu Target %lu Lun %lu)\n",
2171 Bus, Target, Lun);
2172
2173 UnitInfo->PathId = Bus;
2174 UnitInfo->TargetId = Target;
2175 UnitInfo->Lun = Lun;
2176 UnitInfo->InquiryDataLength = INQUIRYDATABUFFERSIZE;
2177 RtlCopyMemory (&UnitInfo->InquiryData,
2178 &LunExtension->InquiryData,
2179 INQUIRYDATABUFFERSIZE);
2180 if (PrevUnit != NULL)
2181 {
2182 PrevUnit->NextInquiryDataOffset =
2183 (ULONG)((ULONG_PTR)UnitInfo-(ULONG_PTR)AdapterBusInfo);
2184 }
2185 PrevUnit = UnitInfo;
2186 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)UnitInfo + sizeof(SCSI_INQUIRY_DATA)+INQUIRYDATABUFFERSIZE-1);
2187 UnitCount++;
2188 }
2189 }
2190 }
2191 DPRINT("UnitCount: %lu\n", UnitCount);
2192 AdapterBusInfo->BusData[Bus].NumberOfLogicalUnits = UnitCount;
2193 if (UnitCount == 0)
2194 {
2195 AdapterBusInfo->BusData[Bus].InquiryDataOffset = 0;
2196 }
2197 }
2198
2199 DPRINT("Data size: %lu\n", (ULONG)UnitInfo - (ULONG)AdapterBusInfo);
2200
2201 return (ULONG)((PUCHAR)UnitInfo-(PUCHAR)AdapterBusInfo);
2202 }
2203
2204
2205 static BOOLEAN STDCALL
2206 ScsiPortIsr(IN PKINTERRUPT Interrupt,
2207 IN PVOID ServiceContext)
2208 {
2209 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2210
2211 DPRINT("ScsiPortIsr() called!\n");
2212
2213 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext;
2214
2215 return DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension);
2216 }
2217
2218
2219 // ScsiPortDpc
2220 // DESCRIPTION:
2221 //
2222 // RUN LEVEL:
2223 //
2224 // ARGUMENTS:
2225 // IN PKDPC Dpc
2226 // IN PDEVICE_OBJECT DpcDeviceObject
2227 // IN PIRP DpcIrp
2228 // IN PVOID DpcContext
2229 //
2230 static VOID STDCALL
2231 ScsiPortDpc(IN PKDPC Dpc,
2232 IN PDEVICE_OBJECT DpcDeviceObject,
2233 IN PIRP DpcIrp,
2234 IN PVOID DpcContext)
2235 {
2236 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2237
2238 DPRINT("ScsiPortDpc(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
2239 Dpc, DpcDeviceObject, DpcIrp, DpcContext);
2240
2241 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DpcContext;
2242
2243 SpiProcessRequests(DeviceExtension, NULL);
2244
2245 DPRINT("ScsiPortDpc() done\n");
2246 }
2247
2248
2249 // ScsiPortIoTimer
2250 // DESCRIPTION:
2251 // This function handles timeouts and other time delayed processing
2252 //
2253 // RUN LEVEL:
2254 //
2255 // ARGUMENTS:
2256 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
2257 // IN PVOID Context the Controller extension for the
2258 // controller the device is on
2259 //
2260 static VOID STDCALL
2261 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
2262 PVOID Context)
2263 {
2264 DPRINT1("ScsiPortIoTimer()\n");
2265 }
2266
2267
2268 static PSCSI_REQUEST_BLOCK
2269 ScsiPortInitSenseRequestSrb(PSCSI_REQUEST_BLOCK OriginalSrb)
2270 {
2271 PSCSI_REQUEST_BLOCK Srb;
2272 ULONG Length;
2273 PCDB Cdb;
2274
2275 Length = sizeof(SCSI_REQUEST_BLOCK) + sizeof(SENSE_DATA) + 32;
2276 Srb = ExAllocatePoolWithTag(NonPagedPool,
2277 Length,
2278 TAG('S', 'S', 'r', 'b'));
2279 if (Srb == NULL)
2280 {
2281 return NULL;
2282 }
2283
2284 RtlZeroMemory(Srb, Length);
2285
2286 Srb->PathId = OriginalSrb->PathId;
2287 Srb->TargetId = OriginalSrb->TargetId;
2288 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
2289 Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
2290 Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
2291 Srb->OriginalRequest = OriginalSrb->OriginalRequest;
2292
2293 Srb->TimeOutValue = 4;
2294
2295 Srb->CdbLength = 6;
2296 /* The DataBuffer must be located in contiguous physical memory if
2297 * the miniport driver uses dma for the sense info. The size of
2298 * the sense data is 18 byte. If the buffer starts at a 32 byte
2299 * boundary than is the buffer always in one memory page.
2300 */
2301 Srb->DataBuffer = (PVOID)ROUND_UP((ULONG_PTR)(Srb + 1), 32);
2302 Srb->DataTransferLength = sizeof(SENSE_DATA);
2303
2304 Cdb = (PCDB)Srb->Cdb;
2305 Cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE;
2306 Cdb->CDB6INQUIRY.AllocationLength = sizeof(SENSE_DATA);
2307
2308 return(Srb);
2309 }
2310
2311 /**********************************************************************
2312 * NAME INTERNAL
2313 * SpiBuildDeviceMap
2314 *
2315 * DESCRIPTION
2316 * Builds the registry device map of all device which are attached
2317 * to the given SCSI HBA port. The device map is located at:
2318 * \Registry\Machine\DeviceMap\Scsi
2319 *
2320 * RUN LEVEL
2321 * PASSIVE_LEVEL
2322 *
2323 * ARGUMENTS
2324 * DeviceExtension
2325 * ...
2326 *
2327 * RegistryPath
2328 * Name of registry driver service key.
2329 *
2330 * RETURNS
2331 * NTSTATUS
2332 */
2333
2334 static NTSTATUS
2335 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
2336 PUNICODE_STRING RegistryPath)
2337 {
2338 PSCSI_PORT_LUN_EXTENSION LunExtension;
2339 OBJECT_ATTRIBUTES ObjectAttributes;
2340 UNICODE_STRING KeyName;
2341 UNICODE_STRING ValueName;
2342 WCHAR NameBuffer[64];
2343 ULONG Disposition;
2344 HANDLE ScsiKey;
2345 HANDLE ScsiPortKey = NULL;
2346 HANDLE ScsiBusKey = NULL;
2347 HANDLE ScsiInitiatorKey = NULL;
2348 HANDLE ScsiTargetKey = NULL;
2349 HANDLE ScsiLunKey = NULL;
2350 ULONG BusNumber;
2351 ULONG Target;
2352 ULONG CurrentTarget;
2353 ULONG Lun;
2354 PWCHAR DriverName;
2355 ULONG UlongData;
2356 PWCHAR TypeName;
2357 NTSTATUS Status;
2358
2359 DPRINT("SpiBuildDeviceMap() called\n");
2360
2361 if (DeviceExtension == NULL || RegistryPath == NULL)
2362 {
2363 DPRINT1("Invalid parameter\n");
2364 return(STATUS_INVALID_PARAMETER);
2365 }
2366
2367 /* Open or create the 'Scsi' subkey */
2368 RtlRosInitUnicodeStringFromLiteral(&KeyName,
2369 L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
2370 InitializeObjectAttributes(&ObjectAttributes,
2371 &KeyName,
2372 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
2373 0,
2374 NULL);
2375 Status = ZwCreateKey(&ScsiKey,
2376 KEY_ALL_ACCESS,
2377 &ObjectAttributes,
2378 0,
2379 NULL,
2380 REG_OPTION_VOLATILE,
2381 &Disposition);
2382 if (!NT_SUCCESS(Status))
2383 {
2384 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
2385 return(Status);
2386 }
2387
2388 /* Create new 'Scsi Port X' subkey */
2389 DPRINT("Scsi Port %lu\n",
2390 DeviceExtension->PortNumber);
2391
2392 swprintf(NameBuffer,
2393 L"Scsi Port %lu",
2394 DeviceExtension->PortNumber);
2395 RtlInitUnicodeString(&KeyName,
2396 NameBuffer);
2397 InitializeObjectAttributes(&ObjectAttributes,
2398 &KeyName,
2399 0,
2400 ScsiKey,
2401 NULL);
2402 Status = ZwCreateKey(&ScsiPortKey,
2403 KEY_ALL_ACCESS,
2404 &ObjectAttributes,
2405 0,
2406 NULL,
2407 REG_OPTION_VOLATILE,
2408 &Disposition);
2409 ZwClose(ScsiKey);
2410 if (!NT_SUCCESS(Status))
2411 {
2412 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
2413 return(Status);
2414 }
2415
2416 /*
2417 * Create port-specific values
2418 */
2419
2420 /* Set 'DMA Enabled' (REG_DWORD) value */
2421 UlongData = (ULONG)!DeviceExtension->PortCapabilities->AdapterUsesPio;
2422 DPRINT(" DMA Enabled = %s\n", (UlongData) ? "TRUE" : "FALSE");
2423 RtlInitUnicodeString(&ValueName,
2424 L"DMA Enabled");
2425 Status = ZwSetValueKey(ScsiPortKey,
2426 &ValueName,
2427 0,
2428 REG_DWORD,
2429 &UlongData,
2430 sizeof(ULONG));
2431 if (!NT_SUCCESS(Status))
2432 {
2433 DPRINT("ZwSetValueKey('DMA Enabled') failed (Status %lx)\n", Status);
2434 ZwClose(ScsiPortKey);
2435 return(Status);
2436 }
2437
2438 /* Set 'Driver' (REG_SZ) value */
2439 DriverName = wcsrchr(RegistryPath->Buffer, L'\\') + 1;
2440 RtlInitUnicodeString(&ValueName,
2441 L"Driver");
2442 Status = ZwSetValueKey(ScsiPortKey,
2443 &ValueName,
2444 0,
2445 REG_SZ,
2446 DriverName,
2447 (wcslen(DriverName) + 1) * sizeof(WCHAR));
2448 if (!NT_SUCCESS(Status))
2449 {
2450 DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status);
2451 ZwClose(ScsiPortKey);
2452 return(Status);
2453 }
2454
2455 /* Set 'Interrupt' (REG_DWORD) value (NT4 only) */
2456 UlongData = (ULONG)DeviceExtension->PortConfig->BusInterruptLevel;
2457 DPRINT(" Interrupt = %lu\n", UlongData);
2458 RtlInitUnicodeString(&ValueName,
2459 L"Interrupt");
2460 Status = ZwSetValueKey(ScsiPortKey,
2461 &ValueName,
2462 0,
2463 REG_DWORD,
2464 &UlongData,
2465 sizeof(ULONG));
2466 if (!NT_SUCCESS(Status))
2467 {
2468 DPRINT("ZwSetValueKey('Interrupt') failed (Status %lx)\n", Status);
2469 ZwClose(ScsiPortKey);
2470 return(Status);
2471 }
2472
2473 /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
2474 UlongData = ScsiPortConvertPhysicalAddressToUlong(DeviceExtension->PortConfig->AccessRanges[0].RangeStart);
2475 DPRINT(" IOAddress = %lx\n", UlongData);
2476 RtlInitUnicodeString(&ValueName,
2477 L"IOAddress");
2478 Status = ZwSetValueKey(ScsiPortKey,
2479 &ValueName,
2480 0,
2481 REG_DWORD,
2482 &UlongData,
2483 sizeof(ULONG));
2484 if (!NT_SUCCESS(Status))
2485 {
2486 DPRINT("ZwSetValueKey('IOAddress') failed (Status %lx)\n", Status);
2487 ZwClose(ScsiPortKey);
2488 return(Status);
2489 }
2490
2491 /* Enumerate buses */
2492 for (BusNumber = 0; BusNumber < DeviceExtension->PortConfig->NumberOfBuses; BusNumber++)
2493 {
2494 /* Create 'Scsi Bus X' key */
2495 DPRINT(" Scsi Bus %lu\n", BusNumber);
2496 swprintf(NameBuffer,
2497 L"Scsi Bus %lu",
2498 BusNumber);
2499 RtlInitUnicodeString(&KeyName,
2500 NameBuffer);
2501 InitializeObjectAttributes(&ObjectAttributes,
2502 &KeyName,
2503 0,
2504 ScsiPortKey,
2505 NULL);
2506 Status = ZwCreateKey(&ScsiBusKey,
2507 KEY_ALL_ACCESS,
2508 &ObjectAttributes,
2509 0,
2510 NULL,
2511 REG_OPTION_VOLATILE,
2512 &Disposition);
2513 if (!NT_SUCCESS(Status))
2514 {
2515 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
2516 goto ByeBye;
2517 }
2518
2519 /* Create 'Initiator Id X' key */
2520 DPRINT(" Initiator Id %u\n",
2521 DeviceExtension->PortConfig->InitiatorBusId[BusNumber]);
2522 swprintf(NameBuffer,
2523 L"Initiator Id %u",
2524 (unsigned int)(UCHAR)DeviceExtension->PortConfig->InitiatorBusId[BusNumber]);
2525 RtlInitUnicodeString(&KeyName,
2526 NameBuffer);
2527 InitializeObjectAttributes(&ObjectAttributes,
2528 &KeyName,
2529 0,
2530 ScsiBusKey,
2531 NULL);
2532 Status = ZwCreateKey(&ScsiInitiatorKey,
2533 KEY_ALL_ACCESS,
2534 &ObjectAttributes,
2535 0,
2536 NULL,
2537 REG_OPTION_VOLATILE,
2538 &Disposition);
2539 if (!NT_SUCCESS(Status))
2540 {
2541 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
2542 goto ByeBye;
2543 }
2544
2545 /* FIXME: Are there any initiator values (??) */
2546
2547 ZwClose(ScsiInitiatorKey);
2548 ScsiInitiatorKey = NULL;
2549
2550
2551 /* Enumerate targets */
2552 CurrentTarget = (ULONG)-1;
2553 ScsiTargetKey = NULL;
2554 for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
2555 {
2556 for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
2557 {
2558 LunExtension = SpiGetLunExtension(DeviceExtension,
2559 BusNumber,
2560 Target,
2561 Lun);
2562 if (LunExtension != NULL)
2563 {
2564 if (Target != CurrentTarget)
2565 {
2566 /* Close old target key */
2567 if (ScsiTargetKey != NULL)
2568 {
2569 ZwClose(ScsiTargetKey);
2570 ScsiTargetKey = NULL;
2571 }
2572
2573 /* Create 'Target Id X' key */
2574 DPRINT(" Target Id %lu\n", Target);
2575 swprintf(NameBuffer,
2576 L"Target Id %lu",
2577 Target);
2578 RtlInitUnicodeString(&KeyName,
2579 NameBuffer);
2580 InitializeObjectAttributes(&ObjectAttributes,
2581 &KeyName,
2582 0,
2583 ScsiBusKey,
2584 NULL);
2585 Status = ZwCreateKey(&ScsiTargetKey,
2586 KEY_ALL_ACCESS,
2587 &ObjectAttributes,
2588 0,
2589 NULL,
2590 REG_OPTION_VOLATILE,
2591 &Disposition);
2592 if (!NT_SUCCESS(Status))
2593 {
2594 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
2595 goto ByeBye;
2596 }
2597
2598 CurrentTarget = Target;
2599 }
2600
2601 /* Create 'Logical Unit Id X' key */
2602 DPRINT(" Logical Unit Id %lu\n", Lun);
2603 swprintf(NameBuffer,
2604 L"Logical Unit Id %lu",
2605 Lun);
2606 RtlInitUnicodeString(&KeyName,
2607 NameBuffer);
2608 InitializeObjectAttributes(&ObjectAttributes,
2609 &KeyName,
2610 0,
2611 ScsiTargetKey,
2612 NULL);
2613 Status = ZwCreateKey(&ScsiLunKey,
2614 KEY_ALL_ACCESS,
2615 &ObjectAttributes,
2616 0,
2617 NULL,
2618 REG_OPTION_VOLATILE,
2619 &Disposition);
2620 if (!NT_SUCCESS(Status))
2621 {
2622 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
2623 goto ByeBye;
2624 }
2625
2626 /* Set 'Identifier' (REG_SZ) value */
2627 swprintf(NameBuffer,
2628 L"%.8S%.16S%.4S",
2629 LunExtension->InquiryData.VendorId,
2630 LunExtension->InquiryData.ProductId,
2631 LunExtension->InquiryData.ProductRevisionLevel);
2632 DPRINT(" Identifier = '%S'\n", NameBuffer);
2633 RtlInitUnicodeString(&ValueName,
2634 L"Identifier");
2635 Status = ZwSetValueKey(ScsiLunKey,
2636 &ValueName,
2637 0,
2638 REG_SZ,
2639 NameBuffer,
2640 (wcslen(NameBuffer) + 1) * sizeof(WCHAR));
2641 if (!NT_SUCCESS(Status))
2642 {
2643 DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", Status);
2644 goto ByeBye;
2645 }
2646
2647 /* Set 'Type' (REG_SZ) value */
2648 switch (LunExtension->InquiryData.DeviceType)
2649 {
2650 case 0:
2651 TypeName = L"DiskPeripheral";
2652 break;
2653 case 1:
2654 TypeName = L"TapePeripheral";
2655 break;
2656 case 2:
2657 TypeName = L"PrinterPeripheral";
2658 break;
2659 case 4:
2660 TypeName = L"WormPeripheral";
2661 break;
2662 case 5:
2663 TypeName = L"CdRomPeripheral";
2664 break;
2665 case 6:
2666 TypeName = L"ScannerPeripheral";
2667 break;
2668 case 7:
2669 TypeName = L"OpticalDiskPeripheral";
2670 break;
2671 case 8:
2672 TypeName = L"MediumChangerPeripheral";
2673 break;
2674 case 9:
2675 TypeName = L"CommunicationPeripheral";
2676 break;
2677 default:
2678 TypeName = L"OtherPeripheral";
2679 break;
2680 }
2681 DPRINT(" Type = '%S'\n", TypeName);
2682 RtlInitUnicodeString(&ValueName,
2683 L"Type");
2684 Status = ZwSetValueKey(ScsiLunKey,
2685 &ValueName,
2686 0,
2687 REG_SZ,
2688 TypeName,
2689 (wcslen(TypeName) + 1) * sizeof(WCHAR));
2690 if (!NT_SUCCESS(Status))
2691 {
2692 DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status);
2693 goto ByeBye;
2694 }
2695
2696 ZwClose(ScsiLunKey);
2697 ScsiLunKey = NULL;
2698 }
2699 }
2700
2701 /* Close old target key */
2702 if (ScsiTargetKey != NULL)
2703 {
2704 ZwClose(ScsiTargetKey);
2705 ScsiTargetKey = NULL;
2706 }
2707 }
2708
2709 ZwClose(ScsiBusKey);
2710 ScsiBusKey = NULL;
2711 }
2712
2713 ByeBye:
2714 if (ScsiLunKey != NULL)
2715 ZwClose (ScsiLunKey);
2716
2717 if (ScsiInitiatorKey != NULL)
2718 ZwClose (ScsiInitiatorKey);
2719
2720 if (ScsiTargetKey != NULL)
2721 ZwClose (ScsiTargetKey);
2722
2723 if (ScsiBusKey != NULL)
2724 ZwClose (ScsiBusKey);
2725
2726 if (ScsiPortKey != NULL)
2727 ZwClose (ScsiPortKey);
2728
2729 DPRINT("SpiBuildDeviceMap() done\n");
2730
2731 return Status;
2732 }
2733
2734 static VOID
2735 SpiRemoveActiveIrp(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
2736 PIRP Irp,
2737 PIRP PrevIrp)
2738 {
2739 PSCSI_PORT_LUN_EXTENSION LunExtension;
2740 PIRP CurrentIrp;
2741 LunExtension = Irp->Tail.Overlay.DriverContext[2];
2742 InterlockedDecrement((PLONG)&LunExtension->ActiveIrpCount);
2743 InterlockedDecrement((PLONG)&DeviceExtension->ActiveIrpCount);
2744 if (PrevIrp)
2745 {
2746 InterlockedExchangePointer(&PrevIrp->Tail.Overlay.DriverContext[0],
2747 Irp->Tail.Overlay.DriverContext[0]);
2748 }
2749 else
2750 {
2751 InterlockedExchangePointer(&DeviceExtension->NextIrp,
2752 Irp->Tail.Overlay.DriverContext[0]);
2753 }
2754 if (LunExtension->NextIrp == Irp)
2755 {
2756 InterlockedExchangePointer(&LunExtension->NextIrp,
2757 Irp->Tail.Overlay.DriverContext[1]);
2758 return;
2759 }
2760 else
2761 {
2762 CurrentIrp = LunExtension->NextIrp;
2763 while (CurrentIrp)
2764 {
2765 if (CurrentIrp->Tail.Overlay.DriverContext[1] == Irp)
2766 {
2767 InterlockedExchangePointer(&CurrentIrp->Tail.Overlay.DriverContext[1],
2768 Irp->Tail.Overlay.DriverContext[1]);
2769 return;
2770 }
2771 CurrentIrp = CurrentIrp->Tail.Overlay.DriverContext[1];
2772 }
2773 KEBUGCHECK(0);
2774 }
2775 }
2776
2777 static VOID
2778 SpiAddActiveIrp(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
2779 PIRP Irp)
2780 {
2781 PSCSI_PORT_LUN_EXTENSION LunExtension;
2782 PSCSI_REQUEST_BLOCK Srb;
2783 LunExtension = Irp->Tail.Overlay.DriverContext[2];
2784 Srb = Irp->Tail.Overlay.DriverContext[3];
2785 Irp->Tail.Overlay.DriverContext[0] = (PVOID)DeviceExtension->NextIrp;
2786 InterlockedExchangePointer(&DeviceExtension->NextIrp, Irp);
2787 Irp->Tail.Overlay.DriverContext[1] = (PVOID)LunExtension->NextIrp;
2788 InterlockedExchangePointer(&LunExtension->NextIrp, Irp);
2789 }
2790
2791 static VOID
2792 SpiProcessRequests(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
2793 IN PIRP NextIrp)
2794 {
2795 /*
2796 * Using of some fields from Srb and Irp while processing requests:
2797 *
2798 * NextIrp on entry:
2799 * Srb->OriginalRequest -> LunExtension
2800 * Irp->Tail.Overlay.DriverContext[3] -> original Srb
2801 * IoStack->Parameters.Scsi.Srb -> original Srb
2802 *
2803 * Irp is within the pending irp list:
2804 * Srb->OriginalRequest -> LunExtension
2805 * Irp->Tail.Overlay.DriverContext[0] and DriverContext[1] -> ListEntry for queue
2806 * Irp->Tail.Overlay.DriverContext[2] -> sort key (from Srb->QueueSortKey)
2807 * Irp->Tail.Overlay.DriverContext[3] -> current Srb (original or sense request)
2808 * IoStack->Parameters.Scsi.Srb -> original Srb
2809 *
2810 * Irp is within the active irp list or while other processing:
2811 * Srb->OriginalRequest -> Irp
2812 * Irp->Tail.Overlay.DriverContext[0] -> next irp, DeviceExtension->NextIrp is head.
2813 * Irp->Tail.Overlay.DriverContext[1] -> next irp, LunExtension->NextIrp is head.
2814 * Irp->Tail.Overlay.DriverContext[2] -> LunExtension
2815 * Irp->Tail.Overlay.DriverContext[3] -> current Srb (original or sense request)
2816 * IoStack->Parameters.Scsi.Srb -> original Srb
2817 */
2818 PIO_STACK_LOCATION IrpStack;
2819 PSCSI_PORT_LUN_EXTENSION LunExtension;
2820 PLIST_ENTRY ListEntry;
2821 KIRQL oldIrql;
2822 PIRP Irp;
2823 LIST_ENTRY NextIrpListHead;
2824 LIST_ENTRY CompleteIrpListHead;
2825 PSCSI_REQUEST_BLOCK Srb;
2826 PSCSI_REQUEST_BLOCK OriginalSrb;
2827 PIRP PrevIrp;
2828
2829 DPRINT("SpiProcessRequests() called\n");
2830
2831 InitializeListHead(&NextIrpListHead);
2832 InitializeListHead(&CompleteIrpListHead);
2833
2834 KeAcquireSpinLock(&DeviceExtension->Lock, &oldIrql);
2835
2836 if (NextIrp)
2837 {
2838 Srb = NextIrp->Tail.Overlay.DriverContext[3];
2839 /*
2840 * FIXME:
2841 * Is this the right place to set this flag ?
2842 */
2843 NextIrp->Tail.Overlay.DriverContext[2] = (PVOID)Srb->QueueSortKey;
2844 LunExtension = Srb->OriginalRequest;
2845
2846 ListEntry = DeviceExtension->PendingIrpListHead.Flink;
2847 while (ListEntry != &DeviceExtension->PendingIrpListHead)
2848 {
2849 Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.DriverContext[0]);
2850 if ((ULONG)Irp->Tail.Overlay.DriverContext[2] > Srb->QueueSortKey)
2851 {
2852 break;
2853 }
2854 ListEntry = ListEntry->Flink;
2855 }
2856 InsertTailList(ListEntry, (PLIST_ENTRY)&NextIrp->Tail.Overlay.DriverContext[0]);
2857 DeviceExtension->PendingIrpCount++;
2858 LunExtension->PendingIrpCount++;
2859 }
2860
2861 while (DeviceExtension->Flags & IRP_FLAG_COMPLETE ||
2862 (((DeviceExtension->SrbExtensionSize == 0 || DeviceExtension->CurrentSrbExtensions < DeviceExtension->MaxSrbExtensions) &&
2863 DeviceExtension->PendingIrpCount > 0 &&
2864 (DeviceExtension->Flags & (IRP_FLAG_NEXT|IRP_FLAG_NEXT_LU) || DeviceExtension->NextIrp == NULL))))
2865 {
2866 DPRINT ("RequestComplete %d, NextRequest %d, NextLuRequest %d, PendingIrpCount %d, ActiveIrpCount %d\n",
2867 DeviceExtension->Flags & IRP_FLAG_COMPLETE ? 1 : 0,
2868 DeviceExtension->Flags & IRP_FLAG_NEXT ? 1 : 0,
2869 DeviceExtension->Flags & IRP_FLAG_NEXT_LU ? 1 : 0,
2870 DeviceExtension->PendingIrpCount,
2871 DeviceExtension->ActiveIrpCount);
2872
2873
2874 if (DeviceExtension->Flags & IRP_FLAG_COMPLETE)
2875 {
2876 DeviceExtension->Flags &= ~IRP_FLAG_COMPLETE;
2877 PrevIrp = NULL;
2878 Irp = DeviceExtension->NextIrp;
2879 while (Irp)
2880 {
2881 NextIrp = (PIRP)Irp->Tail.Overlay.DriverContext[0];
2882 Srb = Irp->Tail.Overlay.DriverContext[3];
2883 if (!(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE))
2884 {
2885 BOOLEAN CompleteThisRequest;
2886 LunExtension = Irp->Tail.Overlay.DriverContext[2];
2887 IrpStack = IoGetCurrentIrpStackLocation(Irp);
2888 OriginalSrb = IrpStack->Parameters.Scsi.Srb;
2889
2890 if (Srb->SrbStatus == SRB_STATUS_BUSY)
2891 {
2892 SpiRemoveActiveIrp(DeviceExtension, Irp, PrevIrp);
2893 SpiFreeSrbExtension(DeviceExtension, OriginalSrb);
2894 InsertHeadList(&DeviceExtension->PendingIrpListHead, (PLIST_ENTRY)&Irp->Tail.Overlay.DriverContext[0]);
2895 DeviceExtension->PendingIrpCount++;
2896 LunExtension->PendingIrpCount++;
2897 Irp = NextIrp;
2898 continue;
2899 }
2900
2901 if (OriginalSrb != Srb)
2902 {
2903 SENSE_DATA* SenseInfoBuffer;
2904
2905 SenseInfoBuffer = Srb->DataBuffer;
2906
2907 DPRINT("Got sense data!\n");
2908
2909 DPRINT("Valid: %x\n", SenseInfoBuffer->Valid);
2910 DPRINT("ErrorCode: %x\n", SenseInfoBuffer->ErrorCode);
2911 DPRINT("SenseKey: %x\n", SenseInfoBuffer->SenseKey);
2912 DPRINT("SenseCode: %x\n", SenseInfoBuffer->AdditionalSenseCode);
2913
2914 /* Copy sense data */
2915 RtlCopyMemory(OriginalSrb->SenseInfoBuffer,
2916 SenseInfoBuffer,
2917 sizeof(SENSE_DATA));
2918 OriginalSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
2919 ExFreePool(Srb);
2920 CompleteThisRequest = TRUE;
2921 }
2922 else if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS &&
2923 Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION &&
2924 Srb->SenseInfoBuffer != NULL &&
2925 Srb->SenseInfoBufferLength >= sizeof(SENSE_DATA) &&
2926 !(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID))
2927 {
2928 DPRINT("SCSIOP_REQUEST_SENSE required!\n");
2929
2930 Srb = ScsiPortInitSenseRequestSrb(OriginalSrb);
2931
2932 if (Srb)
2933 {
2934 CompleteThisRequest = FALSE;
2935 Irp->Tail.Overlay.DriverContext[3] = Srb;
2936 SpiRemoveActiveIrp(DeviceExtension, Irp, PrevIrp);
2937 SpiFreeSrbExtension(DeviceExtension, Srb);
2938
2939 Srb->OriginalRequest = LunExtension;
2940 Irp->Tail.Overlay.DriverContext[2] = 0;
2941
2942 InsertHeadList(&DeviceExtension->PendingIrpListHead, (PLIST_ENTRY)&Irp->Tail.Overlay.DriverContext[0]);
2943 DeviceExtension->PendingIrpCount++;
2944 LunExtension->PendingIrpCount++;
2945 Irp = NextIrp;
2946 continue;
2947 }
2948 else
2949 {
2950 CompleteThisRequest = TRUE;
2951 }
2952 }
2953 else
2954 {
2955 DPRINT("Complete Request\n");
2956 CompleteThisRequest = TRUE;
2957 }
2958 if (CompleteThisRequest)
2959 {
2960 SpiRemoveActiveIrp(DeviceExtension, Irp, PrevIrp);
2961 InsertHeadList(&CompleteIrpListHead, (PLIST_ENTRY)&Irp->Tail.Overlay.DriverContext[0]);
2962 SpiFreeSrbExtension(DeviceExtension, OriginalSrb);
2963 }
2964 else
2965 {
2966 PrevIrp = Irp;
2967 }
2968 Irp = NextIrp;
2969 continue;
2970 }
2971 PrevIrp = Irp;
2972 Irp = NextIrp;
2973 }
2974 }
2975 if (!IsListEmpty(&CompleteIrpListHead))
2976 {
2977 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->Lock);
2978 while (!IsListEmpty(&CompleteIrpListHead))
2979 {
2980 ListEntry = RemoveTailList(&CompleteIrpListHead);
2981 Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.DriverContext[0]);
2982 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2983 }
2984 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->Lock);
2985 }
2986 if (DeviceExtension->Flags & (IRP_FLAG_NEXT|IRP_FLAG_NEXT_LU) &&
2987 (DeviceExtension->SrbExtensionSize == 0 || DeviceExtension->CurrentSrbExtensions < DeviceExtension->MaxSrbExtensions))
2988 {
2989 BOOLEAN StartThisRequest;
2990 ListEntry = DeviceExtension->PendingIrpListHead.Flink;
2991 while (ListEntry != &DeviceExtension->PendingIrpListHead)
2992 {
2993 Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.DriverContext[0]);
2994 ListEntry = ListEntry->Flink;
2995 Srb = Irp->Tail.Overlay.DriverContext[3];
2996 LunExtension = Srb->OriginalRequest;
2997 if (DeviceExtension->SrbExtensionSize > 0 &&
2998 DeviceExtension->CurrentSrbExtensions >= DeviceExtension->MaxSrbExtensions)
2999 {
3000 break;
3001 }
3002 if (LunExtension->Flags & IRP_FLAG_NEXT_LU)
3003 {
3004 StartThisRequest = TRUE;
3005 LunExtension->Flags &= ~IRP_FLAG_NEXT_LU;
3006 DeviceExtension->Flags &= ~IRP_FLAG_NEXT_LU;
3007 }
3008 else if (DeviceExtension->Flags & IRP_FLAG_NEXT &&
3009 LunExtension->ActiveIrpCount == 0)
3010 {
3011 StartThisRequest = TRUE;
3012 DeviceExtension->Flags &= ~IRP_FLAG_NEXT;
3013 }
3014 else
3015 {
3016 StartThisRequest = FALSE;
3017 }
3018 if (StartThisRequest)
3019 {
3020 LunExtension->PendingIrpCount--;
3021 DeviceExtension->PendingIrpCount--;
3022 Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
3023 LunExtension->ActiveIrpCount++;
3024 DeviceExtension->ActiveIrpCount++;
3025
3026 RemoveEntryList((PLIST_ENTRY)&Irp->Tail.Overlay.DriverContext[0]);
3027 Irp->Tail.Overlay.DriverContext[2] = LunExtension;
3028 Srb->OriginalRequest = Irp;
3029 SpiAllocateSrbExtension(DeviceExtension, Srb);
3030
3031 InsertHeadList(&NextIrpListHead, (PLIST_ENTRY)&Irp->Tail.Overlay.DriverContext[0]);
3032 }
3033 }
3034 }
3035
3036 if (!IsListEmpty(&NextIrpListHead))
3037 {
3038 while (!IsListEmpty(&NextIrpListHead))
3039 {
3040 ListEntry = RemoveTailList(&NextIrpListHead);
3041 Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.DriverContext[0]);
3042 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->Lock);
3043
3044 // Start this Irp
3045 SpiStartIo(DeviceExtension, Irp);
3046 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->Lock);
3047 }
3048 }
3049
3050 if (!IsListEmpty(&DeviceExtension->PendingIrpListHead) &&
3051 DeviceExtension->NextIrp == NULL &&
3052 (DeviceExtension->SrbExtensionSize == 0 || DeviceExtension->CurrentSrbExtensions < DeviceExtension->MaxSrbExtensions))
3053 {
3054 ListEntry = RemoveHeadList(&DeviceExtension->PendingIrpListHead);
3055 Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.DriverContext[0]);
3056 Srb = Irp->Tail.Overlay.DriverContext[3];
3057 LunExtension = Srb->OriginalRequest;
3058 Irp->Tail.Overlay.DriverContext[2] = LunExtension;
3059 Srb->OriginalRequest = Irp;
3060
3061 LunExtension->PendingIrpCount--;
3062 DeviceExtension->PendingIrpCount--;
3063 Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
3064 LunExtension->ActiveIrpCount++;
3065 DeviceExtension->ActiveIrpCount++;
3066
3067 SpiAllocateSrbExtension(DeviceExtension, Srb);
3068 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->Lock);
3069
3070 /* Start this irp */
3071 SpiStartIo(DeviceExtension, Irp);
3072 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->Lock);
3073 }
3074 }
3075 KeReleaseSpinLock(&DeviceExtension->Lock, oldIrql);
3076
3077 DPRINT("SpiProcessRequests() done\n");
3078 }
3079
3080 static VOID
3081 SpiStartIo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
3082 IN PIRP Irp)
3083 {
3084 PSCSI_PORT_LUN_EXTENSION LunExtension;
3085 PSCSI_REQUEST_BLOCK Srb;
3086
3087 DPRINT("SpiStartIo() called!\n");
3088
3089 assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
3090
3091 Srb = Irp->Tail.Overlay.DriverContext[3];
3092 LunExtension = Irp->Tail.Overlay.DriverContext[2];
3093
3094 Irp->IoStatus.Status = STATUS_SUCCESS;
3095 Irp->IoStatus.Information = Srb->DataTransferLength;
3096
3097 SpiAddActiveIrp(DeviceExtension, Irp);
3098
3099 if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
3100 ScsiPortStartPacket,
3101 Srb))
3102 {
3103 DPRINT1("Synchronization failed!\n");
3104 DPRINT1("Irp %x, Srb->Function %02x, Srb->Cdb[0] %02x, Srb->SrbStatus %02x\n", Irp, Srb->Function, Srb->Cdb[0], Srb->SrbStatus);
3105 ScsiPortNotification(RequestComplete,
3106 &DeviceExtension->MiniPortDeviceExtension,
3107 Srb);
3108 }
3109
3110 DPRINT("SpiStartIo() done\n");
3111 }
3112
3113
3114
3115 /* EOF */