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