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