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