sync with trunk r46493
[reactos.git] / 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 along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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
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 case CallDisableInterrupts:
1985 DPRINT1("UNIMPLEMENTED SCSI Notification called: CallDisableInterrupts!\n");
1986 break;
1987
1988 case CallEnableInterrupts:
1989 DPRINT1("UNIMPLEMENTED SCSI Notification called: CallEnableInterrupts!\n");
1990 break;
1991
1992 case RequestTimerCall:
1993 DPRINT1("UNIMPLEMENTED SCSI Notification called: RequestTimerCall!\n");
1994 break;
1995
1996 case BusChangeDetected:
1997 DPRINT1("UNIMPLEMENTED SCSI Notification called: BusChangeDetected!\n");
1998 break;
1999
2000 default:
2001 DPRINT1 ("Unsupported notification from WMI: %lu\n", NotificationType);
2002 break;
2003 }
2004
2005 va_end(ap);
2006
2007 /* Request a DPC after we're done with the interrupt */
2008 DeviceExtension->InterruptData.Flags |= SCSI_PORT_NOTIFICATION_NEEDED;
2009 }
2010
2011 /*
2012 * @implemented
2013 */
2014 BOOLEAN NTAPI
2015 ScsiPortValidateRange(IN PVOID HwDeviceExtension,
2016 IN INTERFACE_TYPE BusType,
2017 IN ULONG SystemIoBusNumber,
2018 IN SCSI_PHYSICAL_ADDRESS IoAddress,
2019 IN ULONG NumberOfBytes,
2020 IN BOOLEAN InIoSpace)
2021 {
2022 DPRINT("ScsiPortValidateRange()\n");
2023 return(TRUE);
2024 }
2025
2026
2027 /* INTERNAL FUNCTIONS ********************************************************/
2028
2029 static VOID
2030 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData,
2031 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor,
2032 IN PPORT_CONFIGURATION_INFORMATION PortConfig)
2033 {
2034 PACCESS_RANGE AccessRange;
2035 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialData;
2036 ULONG RangeNumber;
2037 ULONG Index;
2038
2039 RangeNumber = 0;
2040
2041 /* Loop through all entries */
2042 for (Index = 0; Index < ResourceDescriptor->PartialResourceList.Count; Index++)
2043 {
2044 PartialData = &ResourceDescriptor->PartialResourceList.PartialDescriptors[Index];
2045
2046 switch (PartialData->Type)
2047 {
2048 case CmResourceTypePort:
2049 /* Copy access ranges */
2050 if (RangeNumber < HwInitializationData->NumberOfAccessRanges)
2051 {
2052 AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]);
2053
2054 AccessRange->RangeStart = PartialData->u.Port.Start;
2055 AccessRange->RangeLength = PartialData->u.Port.Length;
2056
2057 AccessRange->RangeInMemory = FALSE;
2058 RangeNumber++;
2059 }
2060 break;
2061
2062 case CmResourceTypeMemory:
2063 /* Copy access ranges */
2064 if (RangeNumber < HwInitializationData->NumberOfAccessRanges)
2065 {
2066 AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]);
2067
2068 AccessRange->RangeStart = PartialData->u.Memory.Start;
2069 AccessRange->RangeLength = PartialData->u.Memory.Length;
2070
2071 AccessRange->RangeInMemory = TRUE;
2072 RangeNumber++;
2073 }
2074 break;
2075
2076 case CmResourceTypeInterrupt:
2077 /* Copy interrupt data */
2078 PortConfig->BusInterruptLevel = PartialData->u.Interrupt.Level;
2079 PortConfig->BusInterruptVector = PartialData->u.Interrupt.Vector;
2080
2081 /* Set interrupt mode accordingly to the resource */
2082 if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
2083 {
2084 PortConfig->InterruptMode = Latched;
2085 }
2086 else if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
2087 {
2088 PortConfig->InterruptMode = LevelSensitive;
2089 }
2090 break;
2091
2092 case CmResourceTypeDma:
2093 PortConfig->DmaChannel = PartialData->u.Dma.Channel;
2094 PortConfig->DmaPort = PartialData->u.Dma.Port;
2095 break;
2096 }
2097 }
2098 }
2099
2100 static PCM_RESOURCE_LIST
2101 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
2102 PPORT_CONFIGURATION_INFORMATION PortConfig)
2103 {
2104 PCONFIGURATION_INFORMATION ConfigInfo;
2105 PCM_RESOURCE_LIST ResourceList;
2106 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor;
2107 PACCESS_RANGE AccessRange;
2108 BOOLEAN Dma;
2109 ULONG ListLength = 0, i, FullSize;
2110 ULONG Interrupt;
2111
2112 /* Get current Atdisk usage from the system */
2113 ConfigInfo = IoGetConfigurationInformation();
2114
2115 if (PortConfig->AtdiskPrimaryClaimed)
2116 ConfigInfo->AtDiskPrimaryAddressClaimed = TRUE;
2117
2118 if (PortConfig->AtdiskSecondaryClaimed)
2119 ConfigInfo->AtDiskSecondaryAddressClaimed = TRUE;
2120
2121 /* Do we use DMA? */
2122 if (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE ||
2123 PortConfig->DmaPort != SP_UNINITIALIZED_VALUE)
2124 {
2125 Dma = TRUE;
2126 ListLength++;
2127 }
2128 else
2129 {
2130 Dma = FALSE;
2131 }
2132
2133 /* How many interrupts to we have? */
2134 if (DeviceExtension->HwInterrupt == NULL ||
2135 (PortConfig->BusInterruptLevel == 0 &&
2136 PortConfig->BusInterruptVector == 0))
2137 {
2138 Interrupt = 0;
2139 }
2140 else
2141 {
2142 Interrupt = 1;
2143 ListLength++;
2144 }
2145
2146 if (DeviceExtension->HwInterrupt != NULL &&
2147 (PortConfig->BusInterruptLevel2 != 0 ||
2148 PortConfig->BusInterruptVector2 != 0))
2149 {
2150 Interrupt++;
2151 ListLength++;
2152 }
2153
2154 /* How many access ranges do we use? */
2155 AccessRange = &((*(PortConfig->AccessRanges))[0]);
2156 for (i = 0; i < PortConfig->NumberOfAccessRanges; i++)
2157 {
2158 if (AccessRange->RangeLength != 0)
2159 ListLength++;
2160
2161 AccessRange++;
2162 }
2163
2164 /* Allocate the resource list, since we know its size now */
2165 FullSize = sizeof(CM_RESOURCE_LIST) + (ListLength - 1) *
2166 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
2167
2168 ResourceList = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(PagedPool, FullSize, TAG_SCSIPORT);
2169
2170 if (!ResourceList)
2171 return NULL;
2172
2173 /* Zero it */
2174 RtlZeroMemory(ResourceList, FullSize);
2175
2176 /* Initialize it */
2177 ResourceList->Count = 1;
2178 ResourceList->List[0].InterfaceType = PortConfig->AdapterInterfaceType;
2179 ResourceList->List[0].BusNumber = PortConfig->SystemIoBusNumber;
2180 ResourceList->List[0].PartialResourceList.Count = ListLength;
2181 ResourceDescriptor = ResourceList->List[0].PartialResourceList.PartialDescriptors;
2182
2183 /* Copy access ranges array over */
2184 for (i = 0; i < PortConfig->NumberOfAccessRanges; i++)
2185 {
2186 AccessRange = &((*(PortConfig->AccessRanges))[i]);
2187
2188 /* If the range is empty - skip it */
2189 if (AccessRange->RangeLength == 0)
2190 continue;
2191
2192 if (AccessRange->RangeInMemory)
2193 {
2194 ResourceDescriptor->Type = CmResourceTypeMemory;
2195 ResourceDescriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
2196 }
2197 else
2198 {
2199 ResourceDescriptor->Type = CmResourceTypePort;
2200 ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
2201 }
2202
2203 ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
2204
2205 ResourceDescriptor->u.Memory.Start = AccessRange->RangeStart;
2206 ResourceDescriptor->u.Memory.Length = AccessRange->RangeLength;
2207
2208 ResourceDescriptor++;
2209 }
2210
2211 /* If we use interrupt(s), copy them */
2212 if (Interrupt)
2213 {
2214 ResourceDescriptor->Type = CmResourceTypeInterrupt;
2215
2216 if (PortConfig->AdapterInterfaceType == MicroChannel ||
2217 PortConfig->InterruptMode == LevelSensitive)
2218 {
2219 ResourceDescriptor->ShareDisposition = CmResourceShareShared;
2220 ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
2221 }
2222 else
2223 {
2224 ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
2225 ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
2226 }
2227
2228 ResourceDescriptor->u.Interrupt.Level = PortConfig->BusInterruptLevel;
2229 ResourceDescriptor->u.Interrupt.Vector = PortConfig->BusInterruptVector;
2230 ResourceDescriptor->u.Interrupt.Affinity = 0;
2231
2232 ResourceDescriptor++;
2233 Interrupt--;
2234 }
2235
2236 /* Copy 2nd interrupt
2237 FIXME: Stupid code duplication, remove */
2238 if (Interrupt)
2239 {
2240 ResourceDescriptor->Type = CmResourceTypeInterrupt;
2241
2242 if (PortConfig->AdapterInterfaceType == MicroChannel ||
2243 PortConfig->InterruptMode == LevelSensitive)
2244 {
2245 ResourceDescriptor->ShareDisposition = CmResourceShareShared;
2246 ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
2247 }
2248 else
2249 {
2250 ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
2251 ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
2252 }
2253
2254 ResourceDescriptor->u.Interrupt.Level = PortConfig->BusInterruptLevel;
2255 ResourceDescriptor->u.Interrupt.Vector = PortConfig->BusInterruptVector;
2256 ResourceDescriptor->u.Interrupt.Affinity = 0;
2257
2258 ResourceDescriptor++;
2259 }
2260
2261 /* Copy DMA data */
2262 if (Dma)
2263 {
2264 ResourceDescriptor->Type = CmResourceTypeDma;
2265 ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
2266 ResourceDescriptor->u.Dma.Channel = PortConfig->DmaChannel;
2267 ResourceDescriptor->u.Dma.Port = PortConfig->DmaPort;
2268 ResourceDescriptor->Flags = 0;
2269
2270 if (PortConfig->DmaChannel == SP_UNINITIALIZED_VALUE)
2271 ResourceDescriptor->u.Dma.Channel = 0;
2272
2273 if (PortConfig->DmaPort == SP_UNINITIALIZED_VALUE)
2274 ResourceDescriptor->u.Dma.Port = 0;
2275 }
2276
2277 return ResourceList;
2278 }
2279
2280
2281 static BOOLEAN
2282 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject,
2283 IN PDEVICE_OBJECT DeviceObject,
2284 IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
2285 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,
2286 IN PUNICODE_STRING RegistryPath,
2287 IN ULONG BusNumber,
2288 IN OUT PPCI_SLOT_NUMBER NextSlotNumber)
2289 {
2290 PCI_COMMON_CONFIG PciConfig;
2291 PCI_SLOT_NUMBER SlotNumber;
2292 ULONG DataSize;
2293 ULONG DeviceNumber;
2294 ULONG FunctionNumber;
2295 CHAR VendorIdString[8];
2296 CHAR DeviceIdString[8];
2297 UNICODE_STRING UnicodeStr;
2298 PCM_RESOURCE_LIST ResourceList;
2299 NTSTATUS Status;
2300
2301 DPRINT ("SpiGetPciConfiguration() called\n");
2302
2303 RtlZeroMemory(&ResourceList, sizeof(PCM_RESOURCE_LIST));
2304 SlotNumber.u.AsULONG = 0;
2305
2306 /* Loop through all devices */
2307 for (DeviceNumber = NextSlotNumber->u.bits.DeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
2308 {
2309 SlotNumber.u.bits.DeviceNumber = DeviceNumber;
2310
2311 /* Loop through all functions */
2312 for (FunctionNumber = NextSlotNumber->u.bits.FunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
2313 {
2314 SlotNumber.u.bits.FunctionNumber = FunctionNumber;
2315
2316 /* Get PCI config bytes */
2317 DataSize = HalGetBusData(PCIConfiguration,
2318 BusNumber,
2319 SlotNumber.u.AsULONG,
2320 &PciConfig,
2321 sizeof(ULONG));
2322
2323 /* If result of HalGetBusData is 0, then the bus is wrong */
2324 if (DataSize == 0)
2325 return FALSE;
2326
2327 /* If result is PCI_INVALID_VENDORID, then this device has no more
2328 "Functions" */
2329 if (PciConfig.VendorID == PCI_INVALID_VENDORID)
2330 break;
2331
2332 sprintf (VendorIdString, "%04hx", PciConfig.VendorID);
2333 sprintf (DeviceIdString, "%04hx", PciConfig.DeviceID);
2334
2335 if (_strnicmp(VendorIdString, HwInitializationData->VendorId, HwInitializationData->VendorIdLength) ||
2336 _strnicmp(DeviceIdString, HwInitializationData->DeviceId, HwInitializationData->DeviceIdLength))
2337 {
2338 /* It is not our device */
2339 continue;
2340 }
2341
2342 DPRINT("Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n",
2343 PciConfig.VendorID,
2344 PciConfig.DeviceID,
2345 BusNumber,
2346 SlotNumber.u.bits.DeviceNumber,
2347 SlotNumber.u.bits.FunctionNumber);
2348
2349
2350 RtlInitUnicodeString(&UnicodeStr, L"ScsiAdapter");
2351 Status = HalAssignSlotResources(RegistryPath,
2352 &UnicodeStr,
2353 DriverObject,
2354 DeviceObject,
2355 PCIBus,
2356 BusNumber,
2357 SlotNumber.u.AsULONG,
2358 &ResourceList);
2359
2360 if (!NT_SUCCESS(Status))
2361 break;
2362
2363 /* Create configuration information */
2364 SpiResourceToConfig(HwInitializationData,
2365 ResourceList->List,
2366 PortConfig);
2367
2368 /* Free the resource list */
2369 ExFreePool(ResourceList);
2370
2371 /* Set dev & fn numbers */
2372 NextSlotNumber->u.bits.DeviceNumber = DeviceNumber;
2373 NextSlotNumber->u.bits.FunctionNumber = FunctionNumber + 1;
2374
2375 /* Save the slot number */
2376 PortConfig->SlotNumber = SlotNumber.u.AsULONG;
2377
2378 return TRUE;
2379 }
2380 NextSlotNumber->u.bits.FunctionNumber = 0;
2381 }
2382
2383 NextSlotNumber->u.bits.DeviceNumber = 0;
2384 DPRINT ("No device found\n");
2385
2386 return FALSE;
2387 }
2388
2389
2390
2391 /**********************************************************************
2392 * NAME INTERNAL
2393 * ScsiPortCreateClose
2394 *
2395 * DESCRIPTION
2396 * Answer requests for Create/Close calls: a null operation.
2397 *
2398 * RUN LEVEL
2399 * PASSIVE_LEVEL
2400 *
2401 * ARGUMENTS
2402 * DeviceObject
2403 * Pointer to a device object.
2404 *
2405 * Irp
2406 * Pointer to an IRP.
2407 *
2408 * RETURN VALUE
2409 * Status.
2410 */
2411
2412 static NTSTATUS NTAPI
2413 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
2414 IN PIRP Irp)
2415 {
2416 DPRINT("ScsiPortCreateClose()\n");
2417
2418 Irp->IoStatus.Status = STATUS_SUCCESS;
2419 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2420
2421 return STATUS_SUCCESS;
2422 }
2423
2424 static NTSTATUS
2425 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
2426 PIRP Irp)
2427 {
2428 PSCSI_LUN_INFO LunInfo;
2429 PIO_STACK_LOCATION IrpStack;
2430 PDEVICE_OBJECT DeviceObject;
2431 PSCSI_REQUEST_BLOCK Srb;
2432 KIRQL Irql;
2433
2434 /* Get pointer to the SRB */
2435 IrpStack = IoGetCurrentIrpStackLocation(Irp);
2436 Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
2437
2438 /* Check if PathId matches number of buses */
2439 if (DeviceExtension->BusesConfig == NULL ||
2440 DeviceExtension->BusesConfig->NumberOfBuses <= Srb->PathId)
2441 {
2442 Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
2443 return STATUS_DEVICE_DOES_NOT_EXIST;
2444 }
2445
2446 /* Get pointer to LunInfo */
2447 LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Srb->PathId]->LunInfo;
2448
2449 /* Find matching LunInfo */
2450 while (LunInfo)
2451 {
2452 if (LunInfo->PathId == Srb->PathId &&
2453 LunInfo->TargetId == Srb->TargetId &&
2454 LunInfo->Lun == Srb->Lun)
2455 {
2456 break;
2457 }
2458
2459 LunInfo = LunInfo->Next;
2460 }
2461
2462 /* If we couldn't find it - exit */
2463 if (LunInfo == NULL)
2464 return STATUS_DEVICE_DOES_NOT_EXIST;
2465
2466
2467 /* Get spinlock */
2468 KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
2469
2470 /* Release, if asked */
2471 if (Srb->Function == SRB_FUNCTION_RELEASE_DEVICE)
2472 {
2473 LunInfo->DeviceClaimed = FALSE;
2474 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2475 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2476
2477 return STATUS_SUCCESS;
2478 }
2479
2480 /* Attach, if not already claimed */
2481 if (LunInfo->DeviceClaimed)
2482 {
2483 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2484 Srb->SrbStatus = SRB_STATUS_BUSY;
2485
2486 return STATUS_DEVICE_BUSY;
2487 }
2488
2489 /* Save the device object */
2490 DeviceObject = LunInfo->DeviceObject;
2491
2492 if (Srb->Function == SRB_FUNCTION_CLAIM_DEVICE)
2493 LunInfo->DeviceClaimed = TRUE;
2494
2495 if (Srb->Function == SRB_FUNCTION_ATTACH_DEVICE)
2496 LunInfo->DeviceObject = Srb->DataBuffer;
2497
2498 Srb->DataBuffer = DeviceObject;
2499
2500 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2501 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2502
2503 return STATUS_SUCCESS;
2504 }
2505
2506
2507 /**********************************************************************
2508 * NAME INTERNAL
2509 * ScsiPortDispatchScsi
2510 *
2511 * DESCRIPTION
2512 * Answer requests for SCSI calls
2513 *
2514 * RUN LEVEL
2515 * PASSIVE_LEVEL
2516 *
2517 * ARGUMENTS
2518 * Standard dispatch arguments
2519 *
2520 * RETURNS
2521 * NTSTATUS
2522 */
2523
2524 static NTSTATUS NTAPI
2525 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
2526 IN PIRP Irp)
2527 {
2528 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2529 PSCSI_PORT_LUN_EXTENSION LunExtension;
2530 PIO_STACK_LOCATION Stack;
2531 PSCSI_REQUEST_BLOCK Srb;
2532 KIRQL Irql;
2533 NTSTATUS Status = STATUS_SUCCESS;
2534 PIRP NextIrp, IrpList;
2535 PKDEVICE_QUEUE_ENTRY Entry;
2536
2537 DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n",
2538 DeviceObject, Irp);
2539
2540 DeviceExtension = DeviceObject->DeviceExtension;
2541 Stack = IoGetCurrentIrpStackLocation(Irp);
2542
2543 Srb = Stack->Parameters.Scsi.Srb;
2544 if (Srb == NULL)
2545 {
2546 DPRINT1("ScsiPortDispatchScsi() called with Srb = NULL!\n");
2547 Status = STATUS_UNSUCCESSFUL;
2548
2549 Irp->IoStatus.Status = Status;
2550 Irp->IoStatus.Information = 0;
2551
2552 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2553
2554 return(Status);
2555 }
2556
2557 DPRINT("Srb: %p\n", Srb);
2558 DPRINT("Srb->Function: %lu\n", Srb->Function);
2559 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
2560
2561 LunExtension = SpiGetLunExtension(DeviceExtension,
2562 Srb->PathId,
2563 Srb->TargetId,
2564 Srb->Lun);
2565 if (LunExtension == NULL)
2566 {
2567 DPRINT("ScsiPortDispatchScsi() called with an invalid LUN\n");
2568 Status = STATUS_NO_SUCH_DEVICE;
2569
2570 Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
2571 Irp->IoStatus.Status = Status;
2572 Irp->IoStatus.Information = 0;
2573
2574 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2575
2576 return(Status);
2577 }
2578
2579 switch (Srb->Function)
2580 {
2581 case SRB_FUNCTION_SHUTDOWN:
2582 case SRB_FUNCTION_FLUSH:
2583 DPRINT (" SRB_FUNCTION_SHUTDOWN or FLUSH\n");
2584 if (DeviceExtension->CachesData == FALSE)
2585 {
2586 /* All success here */
2587 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2588 Irp->IoStatus.Status = STATUS_SUCCESS;
2589 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2590 return STATUS_SUCCESS;
2591 }
2592 /* Fall through to a usual execute operation */
2593
2594 case SRB_FUNCTION_EXECUTE_SCSI:
2595 case SRB_FUNCTION_IO_CONTROL:
2596 /* Mark IRP as pending in all cases */
2597 IoMarkIrpPending(Irp);
2598
2599 if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
2600 {
2601 /* Start IO directly */
2602 IoStartPacket(DeviceObject, Irp, NULL, NULL);
2603 }
2604 else
2605 {
2606 KIRQL oldIrql;
2607
2608 /* We need to be at DISPATCH_LEVEL */
2609 KeRaiseIrql (DISPATCH_LEVEL, &oldIrql);
2610
2611 /* Insert IRP into the queue */
2612 if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue,
2613 &Irp->Tail.Overlay.DeviceQueueEntry,
2614 Srb->QueueSortKey))
2615 {
2616 /* It means the queue is empty, and we just start this request */
2617 IoStartPacket(DeviceObject, Irp, NULL, NULL);
2618 }
2619
2620 /* Back to the old IRQL */
2621 KeLowerIrql (oldIrql);
2622 }
2623 return STATUS_PENDING;
2624
2625 case SRB_FUNCTION_CLAIM_DEVICE:
2626 case SRB_FUNCTION_ATTACH_DEVICE:
2627 DPRINT (" SRB_FUNCTION_CLAIM_DEVICE or ATTACH\n");
2628
2629 /* Reference device object and keep the device object */
2630 Status = SpiHandleAttachRelease(DeviceExtension, Irp);
2631 break;
2632
2633 case SRB_FUNCTION_RELEASE_DEVICE:
2634 DPRINT (" SRB_FUNCTION_RELEASE_DEVICE\n");
2635
2636 /* Dereference device object and clear the device object */
2637 Status = SpiHandleAttachRelease(DeviceExtension, Irp);
2638 break;
2639
2640 case SRB_FUNCTION_RELEASE_QUEUE:
2641 DPRINT(" SRB_FUNCTION_RELEASE_QUEUE\n");
2642
2643 /* Guard with the spinlock */
2644 KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
2645
2646 if (!(LunExtension->Flags & LUNEX_FROZEN_QUEUE))
2647 {
2648 DPRINT("Queue is not frozen really\n");
2649
2650 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2651 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2652 Status = STATUS_SUCCESS;
2653 break;
2654
2655 }
2656
2657 /* Unfreeze the queue */
2658 LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
2659
2660 if (LunExtension->SrbInfo.Srb == NULL)
2661 {
2662 /* Get next logical unit request */
2663 SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
2664
2665 /* SpiGetNextRequestFromLun() releases the spinlock */
2666 KeLowerIrql(Irql);
2667 }
2668 else
2669 {
2670 DPRINT("The queue has active request\n");
2671 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2672 }
2673
2674
2675 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2676 Status = STATUS_SUCCESS;
2677 break;
2678
2679 case SRB_FUNCTION_FLUSH_QUEUE:
2680 DPRINT(" SRB_FUNCTION_FLUSH_QUEUE\n");
2681
2682 /* Guard with the spinlock */
2683 KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
2684
2685 if (!(LunExtension->Flags & LUNEX_FROZEN_QUEUE))
2686 {
2687 DPRINT("Queue is not frozen really\n");
2688
2689 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2690 Status = STATUS_INVALID_DEVICE_REQUEST;
2691 break;
2692 }
2693
2694 /* Make sure there is no active request */
2695 ASSERT(LunExtension->SrbInfo.Srb == NULL);
2696
2697 /* Compile a list from the device queue */
2698 IrpList = NULL;
2699 while ((Entry = KeRemoveDeviceQueue(&LunExtension->DeviceQueue)) != NULL)
2700 {
2701 NextIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
2702
2703 /* Get the Srb */
2704 Stack = IoGetCurrentIrpStackLocation(NextIrp);
2705 Srb = Stack->Parameters.Scsi.Srb;
2706
2707 /* Set statuse */
2708 Srb->SrbStatus = SRB_STATUS_REQUEST_FLUSHED;
2709 NextIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
2710
2711 /* Add then to the list */
2712 NextIrp->Tail.Overlay.ListEntry.Flink = (PLIST_ENTRY)IrpList;
2713 IrpList = NextIrp;
2714 }
2715
2716 /* Unfreeze the queue */
2717 LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
2718
2719 /* Release the spinlock */
2720 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2721
2722 /* Complete those requests */
2723 while (IrpList)
2724 {
2725 NextIrp = IrpList;
2726 IrpList = (PIRP)NextIrp->Tail.Overlay.ListEntry.Flink;
2727
2728 IoCompleteRequest(NextIrp, 0);
2729 }
2730
2731 Status = STATUS_SUCCESS;
2732 break;
2733
2734 default:
2735 DPRINT1("SRB function not implemented (Function %lu)\n", Srb->Function);
2736 Status = STATUS_NOT_IMPLEMENTED;
2737 break;
2738 }
2739
2740 Irp->IoStatus.Status = Status;
2741
2742 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2743
2744 return(Status);
2745 }
2746
2747
2748 /**********************************************************************
2749 * NAME INTERNAL
2750 * ScsiPortDeviceControl
2751 *
2752 * DESCRIPTION
2753 * Answer requests for device control calls
2754 *
2755 * RUN LEVEL
2756 * PASSIVE_LEVEL
2757 *
2758 * ARGUMENTS
2759 * Standard dispatch arguments
2760 *
2761 * RETURNS
2762 * NTSTATUS
2763 */
2764
2765 static NTSTATUS NTAPI
2766 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
2767 IN PIRP Irp)
2768 {
2769 PIO_STACK_LOCATION Stack;
2770 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2771 NTSTATUS Status = STATUS_SUCCESS;
2772
2773 DPRINT("ScsiPortDeviceControl()\n");
2774
2775 Irp->IoStatus.Information = 0;
2776
2777 Stack = IoGetCurrentIrpStackLocation(Irp);
2778 DeviceExtension = DeviceObject->DeviceExtension;
2779
2780 switch (Stack->Parameters.DeviceIoControl.IoControlCode)
2781 {
2782 case IOCTL_SCSI_GET_DUMP_POINTERS:
2783 {
2784 PDUMP_POINTERS DumpPointers;
2785 DPRINT(" IOCTL_SCSI_GET_DUMP_POINTERS\n");
2786 DumpPointers = (PDUMP_POINTERS)Irp->AssociatedIrp.SystemBuffer;
2787 DumpPointers->DeviceObject = DeviceObject;
2788
2789 Irp->IoStatus.Information = sizeof(DUMP_POINTERS);
2790 }
2791 break;
2792
2793 case IOCTL_SCSI_GET_CAPABILITIES:
2794 DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
2795 if (Stack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(PVOID))
2796 {
2797 *((PVOID *)Irp->AssociatedIrp.SystemBuffer) = &DeviceExtension->PortCapabilities;
2798
2799 Irp->IoStatus.Information = sizeof(PVOID);
2800 Status = STATUS_SUCCESS;
2801 break;
2802 }
2803
2804 if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(IO_SCSI_CAPABILITIES))
2805 {
2806 Status = STATUS_BUFFER_TOO_SMALL;
2807 break;
2808 }
2809
2810 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
2811 &DeviceExtension->PortCapabilities,
2812 sizeof(IO_SCSI_CAPABILITIES));
2813
2814 Irp->IoStatus.Information = sizeof(IO_SCSI_CAPABILITIES);
2815 Status = STATUS_SUCCESS;
2816 break;
2817
2818 case IOCTL_SCSI_GET_INQUIRY_DATA:
2819 DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
2820
2821 /* Copy inquiry data to the port device extension */
2822 Status = SpiGetInquiryData(DeviceExtension, Irp);
2823 break;
2824
2825 case IOCTL_SCSI_MINIPORT:
2826 DPRINT1("IOCTL_SCSI_MINIPORT unimplemented!\n");
2827 break;
2828
2829 case IOCTL_SCSI_PASS_THROUGH:
2830 DPRINT1("IOCTL_SCSI_PASS_THROUGH unimplemented!\n");
2831 break;
2832
2833 default:
2834 DPRINT1(" unknown ioctl code: 0x%lX\n",
2835 Stack->Parameters.DeviceIoControl.IoControlCode);
2836 break;
2837 }
2838
2839 /* Complete the request with the given status */
2840 Irp->IoStatus.Status = Status;
2841 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2842
2843 return Status;
2844 }
2845
2846
2847 static VOID NTAPI
2848 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
2849 IN PIRP Irp)
2850 {
2851 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2852 PSCSI_PORT_LUN_EXTENSION LunExtension;
2853 PIO_STACK_LOCATION IrpStack;
2854 PSCSI_REQUEST_BLOCK Srb;
2855 PSCSI_REQUEST_BLOCK_INFO SrbInfo;
2856 LONG CounterResult;
2857 NTSTATUS Status;
2858
2859 DPRINT("ScsiPortStartIo() called!\n");
2860
2861 DeviceExtension = DeviceObject->DeviceExtension;
2862 IrpStack = IoGetCurrentIrpStackLocation(Irp);
2863
2864 DPRINT("DeviceExtension %p\n", DeviceExtension);
2865
2866 Srb = IrpStack->Parameters.Scsi.Srb;
2867
2868 /* Apply "default" flags */
2869 Srb->SrbFlags |= DeviceExtension->SrbFlags;
2870
2871 /* Get LUN extension */
2872 LunExtension = SpiGetLunExtension(DeviceExtension,
2873 Srb->PathId,
2874 Srb->TargetId,
2875 Srb->Lun);
2876
2877 if (DeviceExtension->NeedSrbDataAlloc ||
2878 DeviceExtension->NeedSrbExtensionAlloc)
2879 {
2880 /* Allocate them */
2881 SrbInfo = SpiAllocateSrbStructures(DeviceExtension,
2882 LunExtension,
2883 Srb);
2884
2885 /* Couldn't alloc one or both data structures, return */
2886 if (SrbInfo == NULL)
2887 {
2888 /* We have to call IoStartNextPacket, because this request
2889 was not started */
2890 if (LunExtension->Flags & LUNEX_REQUEST_PENDING)
2891 IoStartNextPacket(DeviceObject, FALSE);
2892
2893 return;
2894 }
2895 }
2896 else
2897 {
2898 /* No allocations are needed */
2899 SrbInfo = &LunExtension->SrbInfo;
2900 Srb->SrbExtension = NULL;
2901 Srb->QueueTag = SP_UNTAGGED;
2902 }
2903
2904 /* Increase sequence number of SRB */
2905 if (!SrbInfo->SequenceNumber)
2906 {
2907 /* Increase global sequence number */
2908 DeviceExtension->SequenceNumber++;
2909
2910 /* Assign it */
2911 SrbInfo->SequenceNumber = DeviceExtension->SequenceNumber;
2912 }
2913
2914 /* Check some special SRBs */
2915 if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
2916 {
2917 /* Some special handling */
2918 DPRINT1("Abort command! Unimplemented now\n");
2919 }
2920 else
2921 {
2922 SrbInfo->Srb = Srb;
2923 }
2924
2925 if (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION)
2926 {
2927 // Store the MDL virtual address in SrbInfo structure
2928 SrbInfo->DataOffset = MmGetMdlVirtualAddress(Irp->MdlAddress);
2929
2930 if (DeviceExtension->MapBuffers)
2931 {
2932 /* Calculate offset within DataBuffer */
2933 SrbInfo->DataOffset = MmGetSystemAddressForMdl(Irp->MdlAddress);
2934 Srb->DataBuffer = SrbInfo->DataOffset +
2935 (ULONG)((PUCHAR)Srb->DataBuffer -
2936 (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress));
2937 }
2938
2939 if (DeviceExtension->AdapterObject)
2940 {
2941 /* Flush buffers */
2942 KeFlushIoBuffers(Irp->MdlAddress,
2943 Srb->SrbFlags & SRB_FLAGS_DATA_IN ? TRUE : FALSE,
2944 TRUE);
2945 }
2946
2947 if (DeviceExtension->MapRegisters)
2948 {
2949 /* Calculate number of needed map registers */
2950 SrbInfo->NumberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
2951 Srb->DataBuffer,
2952 Srb->DataTransferLength);
2953
2954 /* Allocate adapter channel */
2955 Status = IoAllocateAdapterChannel(DeviceExtension->AdapterObject,
2956 DeviceExtension->DeviceObject,
2957 SrbInfo->NumberOfMapRegisters,
2958 SpiAdapterControl,
2959 SrbInfo);
2960
2961 if (!NT_SUCCESS(Status))
2962 {
2963 DPRINT1("IoAllocateAdapterChannel() failed!\n");
2964
2965 Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
2966 ScsiPortNotification(RequestComplete,
2967 DeviceExtension + 1,
2968 Srb);
2969
2970 ScsiPortNotification(NextRequest,
2971 DeviceExtension + 1);
2972
2973 /* Request DPC for that work */
2974 IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
2975 }
2976
2977 /* Control goes to SpiAdapterControl */
2978 return;
2979 }
2980 }
2981
2982 /* Increase active request counter */
2983 CounterResult = InterlockedIncrement(&DeviceExtension->ActiveRequestCounter);
2984
2985 if (CounterResult == 0 &&
2986 DeviceExtension->AdapterObject != NULL &&
2987 !DeviceExtension->MapRegisters)
2988 {
2989 IoAllocateAdapterChannel(
2990 DeviceExtension->AdapterObject,
2991 DeviceObject,
2992 DeviceExtension->PortCapabilities.MaximumPhysicalPages,
2993 ScsiPortAllocateAdapterChannel,
2994 LunExtension
2995 );
2996
2997 return;
2998 }
2999
3000 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
3001
3002 if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
3003 ScsiPortStartPacket,
3004 DeviceObject))
3005 {
3006 DPRINT("Synchronization failed!\n");
3007
3008 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
3009 Irp->IoStatus.Information = 0;
3010 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3011
3012 IoCompleteRequest(Irp, IO_NO_INCREMENT);
3013 }
3014 else
3015 {
3016 /* Release the spinlock only */
3017 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3018 }
3019
3020
3021 DPRINT("ScsiPortStartIo() done\n");
3022 }
3023
3024
3025 static BOOLEAN NTAPI
3026 ScsiPortStartPacket(IN OUT PVOID Context)
3027 {
3028 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
3029 PIO_STACK_LOCATION IrpStack;
3030 PSCSI_REQUEST_BLOCK Srb;
3031 PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)Context;
3032 PSCSI_PORT_LUN_EXTENSION LunExtension;
3033 PSCSI_REQUEST_BLOCK_INFO SrbInfo;
3034 BOOLEAN Result;
3035 BOOLEAN StartTimer;
3036
3037 DPRINT("ScsiPortStartPacket() called\n");
3038
3039 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
3040
3041 IrpStack = IoGetCurrentIrpStackLocation(DeviceObject->CurrentIrp);
3042 Srb = IrpStack->Parameters.Scsi.Srb;
3043
3044 /* Get LUN extension */
3045 LunExtension = SpiGetLunExtension(DeviceExtension,
3046 Srb->PathId,
3047 Srb->TargetId,
3048 Srb->Lun);
3049
3050 /* Check if we are in a reset state */
3051 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET)
3052 {
3053 /* Mark the we've got requests while being in the reset state */
3054 DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET_REQUEST;
3055 return TRUE;
3056 }
3057
3058 /* Set the time out value */
3059 DeviceExtension->TimerCount = Srb->TimeOutValue;
3060
3061 /* We are busy */
3062 DeviceExtension->Flags |= SCSI_PORT_DEVICE_BUSY;
3063
3064 if (LunExtension->RequestTimeout != -1)
3065 {
3066 /* Timer already active */
3067 StartTimer = FALSE;
3068 }
3069 else
3070 {
3071 /* It hasn't been initialized yet */
3072 LunExtension->RequestTimeout = Srb->TimeOutValue;
3073 StartTimer = TRUE;
3074 }
3075
3076 if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
3077 {
3078 /* Handle bypass-requests */
3079
3080 /* Is this an abort request? */
3081 if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
3082 {
3083 /* Get pointer to SRB info structure */
3084 SrbInfo = SpiGetSrbData(DeviceExtension,
3085 Srb->PathId,
3086 Srb->TargetId,
3087 Srb->Lun,
3088 Srb->QueueTag);
3089
3090 /* Check if the request is still "active" */
3091 if (SrbInfo == NULL ||
3092 SrbInfo->Srb == NULL ||
3093 !(SrbInfo->Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE))
3094 {
3095 /* It's not, mark it as active then */
3096 Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
3097
3098 if (StartTimer)
3099 LunExtension->RequestTimeout = -1;
3100
3101 DPRINT("Request has been already completed, but abort request came\n");
3102 Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
3103
3104 /* Notify about request complete */
3105 ScsiPortNotification(RequestComplete,
3106 DeviceExtension->MiniPortDeviceExtension,
3107 Srb);
3108
3109 /* and about readiness for the next request */
3110 ScsiPortNotification(NextRequest,
3111 DeviceExtension->MiniPortDeviceExtension);
3112
3113 /* They might ask for some work, so queue the DPC for them */
3114 IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
3115
3116 /* We're done in this branch */
3117 return TRUE;
3118 }
3119 }
3120 else
3121 {
3122 /* Add number of queued requests */
3123 LunExtension->QueueCount++;
3124 }
3125
3126 /* Bypass requests don't need request sense */
3127 LunExtension->Flags &= ~LUNEX_NEED_REQUEST_SENSE;
3128
3129 /* Is disconnect disabled for this request? */
3130 if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
3131 {
3132 /* Set the corresponding flag */
3133 DeviceExtension->Flags &= ~SCSI_PORT_DISCONNECT_ALLOWED;
3134 }
3135
3136 /* Transfer timeout value from Srb to Lun */
3137 LunExtension->RequestTimeout = Srb->TimeOutValue;
3138 }
3139 else
3140 {
3141 if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
3142 {
3143 /* It's a disconnect, so no more requests can go */
3144 DeviceExtension->Flags &= ~SCSI_PORT_DISCONNECT_ALLOWED;
3145 }
3146
3147 LunExtension->Flags |= SCSI_PORT_LU_ACTIVE;
3148
3149 /* Increment queue count */
3150 LunExtension->QueueCount++;
3151
3152 /* If it's tagged - special thing */
3153 if (Srb->QueueTag != SP_UNTAGGED)
3154 {
3155 SrbInfo = &DeviceExtension->SrbInfo[Srb->QueueTag - 1];
3156
3157 /* Chek for consistency */
3158 ASSERT(SrbInfo->Requests.Blink == NULL);
3159
3160 /* Insert it into the list of requests */
3161 InsertTailList(&LunExtension->SrbInfo.Requests, &SrbInfo->Requests);
3162 }
3163 }
3164
3165 /* Mark this Srb active */
3166 Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
3167
3168 /* Call HwStartIo routine */
3169 Result = DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
3170 Srb);
3171
3172 /* If notification is needed, then request a DPC */
3173 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
3174 IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
3175
3176 return Result;
3177 }
3178
3179 IO_ALLOCATION_ACTION
3180 NTAPI
3181 SpiAdapterControl(PDEVICE_OBJECT DeviceObject,
3182 PIRP Irp,
3183 PVOID MapRegisterBase,
3184 PVOID Context)
3185 {
3186 PSCSI_REQUEST_BLOCK Srb;
3187 PSCSI_SG_ADDRESS ScatterGatherList;
3188 KIRQL CurrentIrql;
3189 PIO_STACK_LOCATION IrpStack;
3190 ULONG TotalLength = 0;
3191 PSCSI_REQUEST_BLOCK_INFO SrbInfo;
3192 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
3193 PUCHAR DataVA;
3194 BOOLEAN WriteToDevice;
3195
3196 /* Get pointers to SrbInfo and DeviceExtension */
3197 SrbInfo = (PSCSI_REQUEST_BLOCK_INFO)Context;
3198 DeviceExtension = DeviceObject->DeviceExtension;
3199
3200 /* Get pointer to SRB */
3201 IrpStack = IoGetCurrentIrpStackLocation(Irp);
3202 Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
3203
3204 /* Depending on the map registers number, we allocate
3205 either from NonPagedPool, or from our static list */
3206 if (SrbInfo->NumberOfMapRegisters > MAX_SG_LIST)
3207 {
3208 SrbInfo->ScatterGather = ExAllocatePoolWithTag(
3209 NonPagedPool, SrbInfo->NumberOfMapRegisters * sizeof(SCSI_SG_ADDRESS), TAG_SCSIPORT);
3210
3211 if (SrbInfo->ScatterGather == NULL)
3212 ASSERT(FALSE);
3213
3214 Srb->SrbFlags |= SRB_FLAGS_SGLIST_FROM_POOL;
3215 }
3216 else
3217 {
3218 SrbInfo->ScatterGather = SrbInfo->ScatterGatherList;
3219 }
3220
3221 /* Use chosen SG list source */
3222 ScatterGatherList = SrbInfo->ScatterGather;
3223
3224 /* Save map registers base */
3225 SrbInfo->BaseOfMapRegister = MapRegisterBase;
3226
3227 /* Determine WriteToDevice flag */
3228 WriteToDevice = Srb->SrbFlags & SRB_FLAGS_DATA_OUT ? TRUE : FALSE;
3229
3230 /* Get virtual address of the data buffer */
3231 DataVA = (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress) +
3232 ((PCHAR)Srb->DataBuffer - SrbInfo->DataOffset);
3233
3234 /* Build the actual SG list */
3235 while (TotalLength < Srb->DataTransferLength)
3236 {
3237 if (!ScatterGatherList)
3238 break;
3239
3240 ScatterGatherList->Length = Srb->DataTransferLength - TotalLength;
3241 ScatterGatherList->PhysicalAddress = IoMapTransfer(NULL,
3242 Irp->MdlAddress,
3243 MapRegisterBase,
3244 DataVA + TotalLength,
3245 &ScatterGatherList->Length,
3246 WriteToDevice);
3247
3248 TotalLength += ScatterGatherList->Length;
3249 ScatterGatherList++;
3250 }
3251
3252 /* Schedule an active request */
3253 InterlockedIncrement(&DeviceExtension->ActiveRequestCounter );
3254 KeAcquireSpinLock(&DeviceExtension->SpinLock, &CurrentIrql);
3255 KeSynchronizeExecution(DeviceExtension->Interrupt,
3256 ScsiPortStartPacket,
3257 DeviceObject);
3258 KeReleaseSpinLock(&DeviceExtension->SpinLock, CurrentIrql);
3259
3260 return DeallocateObjectKeepRegisters;
3261 }
3262
3263 static PSCSI_PORT_LUN_EXTENSION
3264 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
3265 {
3266 PSCSI_PORT_LUN_EXTENSION LunExtension;
3267 ULONG LunExtensionSize;
3268
3269 DPRINT("SpiAllocateLunExtension (%p)\n",
3270 DeviceExtension);
3271
3272 /* Round LunExtensionSize first to the sizeof LONGLONG */
3273 LunExtensionSize = (DeviceExtension->LunExtensionSize +
3274 sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1);
3275
3276 LunExtensionSize += sizeof(SCSI_PORT_LUN_EXTENSION);
3277 DPRINT("LunExtensionSize %lu\n", LunExtensionSize);
3278
3279 LunExtension = ExAllocatePoolWithTag(NonPagedPool, LunExtensionSize, TAG_SCSIPORT);
3280 if (LunExtension == NULL)
3281 {
3282 DPRINT1("Out of resources!\n");
3283 return NULL;
3284 }
3285
3286 /* Zero everything */
3287 RtlZeroMemory(LunExtension, LunExtensionSize);
3288
3289 /* Initialize a list of requests */
3290 InitializeListHead(&LunExtension->SrbInfo.Requests);
3291
3292 /* Initialize timeout counter */
3293 LunExtension->RequestTimeout = -1;
3294
3295 /* Set maximum queue size */
3296 LunExtension->MaxQueueCount = 256;
3297
3298 /* Initialize request queue */
3299 KeInitializeDeviceQueue (&LunExtension->DeviceQueue);
3300
3301 return LunExtension;
3302 }
3303
3304 static PSCSI_PORT_LUN_EXTENSION
3305 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
3306 IN UCHAR PathId,
3307 IN UCHAR TargetId,
3308 IN UCHAR Lun)
3309 {
3310 PSCSI_PORT_LUN_EXTENSION LunExtension;
3311
3312 DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
3313 DeviceExtension, PathId, TargetId, Lun);
3314
3315 /* Get appropriate list */
3316 LunExtension = DeviceExtension->LunExtensionList[(TargetId + Lun) % LUS_NUMBER];
3317
3318 /* Iterate it until we find what we need */
3319 while (LunExtension)
3320 {
3321 if (LunExtension->TargetId == TargetId &&
3322 LunExtension->Lun == Lun &&
3323 LunExtension->PathId == PathId)
3324 {
3325 /* All matches, return */
3326 return LunExtension;
3327 }
3328
3329 /* Advance to the next item */
3330 LunExtension = LunExtension->Next;
3331 }
3332
3333 /* We did not find anything */
3334 DPRINT("Nothing found\n");
3335 return NULL;
3336 }
3337
3338 static PSCSI_REQUEST_BLOCK_INFO
3339 SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
3340 PSCSI_PORT_LUN_EXTENSION LunExtension,
3341 PSCSI_REQUEST_BLOCK Srb)
3342 {
3343 PCHAR SrbExtension;
3344 PSCSI_REQUEST_BLOCK_INFO SrbInfo;
3345
3346 /* Spinlock must be held while this function executes */
3347 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
3348
3349 /* Allocate SRB data structure */
3350 if (DeviceExtension->NeedSrbDataAlloc)
3351 {
3352 /* Treat the abort request in a special way */
3353 if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
3354 {
3355 SrbInfo = SpiGetSrbData(DeviceExtension,
3356 Srb->PathId,
3357 Srb->TargetId,
3358 Srb->Lun,
3359 Srb->QueueTag);
3360 }
3361 else if (Srb->SrbFlags &
3362 (SRB_FLAGS_QUEUE_ACTION_ENABLE | SRB_FLAGS_NO_QUEUE_FREEZE) &&
3363 !(Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
3364 )
3365 {
3366 /* Do not process tagged commands if need request sense is set */
3367 if (LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE)
3368 {
3369 ASSERT(!(LunExtension->Flags & LUNEX_REQUEST_PENDING));
3370
3371 LunExtension->PendingRequest = Srb->OriginalRequest;
3372 LunExtension->Flags