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