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