0db7e81bf31754505071343e71638e65e0388927
[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 DPRINT1("PathId: 0x%02x TargetId: 0x%02x Lun: 0x%02x ErrorCode: 0x%08lx UniqueId: 0x%08lx\n",
1844 PathId, TargetId, Lun, ErrorCode, UniqueId);
1845
1846 //DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, SCSI_PORT_DEVICE_EXTENSION, MiniPortDeviceExtension);
1847
1848
1849 DPRINT("ScsiPortLogError() done\n");
1850 }
1851
1852 /*
1853 * @implemented
1854 */
1855 VOID NTAPI
1856 ScsiPortMoveMemory(OUT PVOID Destination,
1857 IN PVOID Source,
1858 IN ULONG Length)
1859 {
1860 RtlMoveMemory(Destination,
1861 Source,
1862 Length);
1863 }
1864
1865
1866 /*
1867 * @implemented
1868 */
1869 VOID
1870 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType,
1871 IN PVOID HwDeviceExtension,
1872 ...)
1873 {
1874 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1875 va_list ap;
1876
1877 DPRINT("ScsiPortNotification() called\n");
1878
1879 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
1880 SCSI_PORT_DEVICE_EXTENSION,
1881 MiniPortDeviceExtension);
1882
1883 DPRINT("DeviceExtension %p\n", DeviceExtension);
1884
1885 va_start(ap, HwDeviceExtension);
1886
1887 switch (NotificationType)
1888 {
1889 case RequestComplete:
1890 {
1891 PSCSI_REQUEST_BLOCK Srb;
1892 PSCSI_REQUEST_BLOCK_INFO SrbData;
1893
1894 Srb = (PSCSI_REQUEST_BLOCK) va_arg (ap, PSCSI_REQUEST_BLOCK);
1895
1896 DPRINT("Notify: RequestComplete (Srb %p)\n", Srb);
1897
1898 /* Make sure Srb is allright */
1899 ASSERT(Srb->SrbStatus != SRB_STATUS_PENDING);
1900 ASSERT(Srb->Function != SRB_FUNCTION_EXECUTE_SCSI || Srb->SrbStatus != SRB_STATUS_SUCCESS || Srb->ScsiStatus == SCSISTAT_GOOD);
1901
1902 if (!(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE))
1903 {
1904 /* It's been already completed */
1905 va_end(ap);
1906 return;
1907 }
1908
1909 /* It's not active anymore */
1910 Srb->SrbFlags &= ~SRB_FLAGS_IS_ACTIVE;
1911
1912 if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
1913 {
1914 /* TODO: Treat it specially */
1915 ASSERT(FALSE);
1916 }
1917 else
1918 {
1919 /* Get the SRB data */
1920 SrbData = SpiGetSrbData(DeviceExtension,
1921 Srb->PathId,
1922 Srb->TargetId,
1923 Srb->Lun,
1924 Srb->QueueTag);
1925
1926 /* Make sure there are no CompletedRequests and there is a Srb */
1927 ASSERT(SrbData->CompletedRequests == NULL && SrbData->Srb != NULL);
1928
1929 /* If it's a read/write request, make sure it has data inside it */
1930 if ((Srb->SrbStatus == SRB_STATUS_SUCCESS) &&
1931 ((Srb->Cdb[0] == SCSIOP_READ) || (Srb->Cdb[0] == SCSIOP_WRITE)))
1932 {
1933 ASSERT(Srb->DataTransferLength);
1934 }
1935
1936 SrbData->CompletedRequests = DeviceExtension->InterruptData.CompletedRequests;
1937 DeviceExtension->InterruptData.CompletedRequests = SrbData;
1938 }
1939 }
1940 break;
1941
1942 case NextRequest:
1943 DPRINT("Notify: NextRequest\n");
1944 DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY;
1945 break;
1946
1947 case NextLuRequest:
1948 {
1949 UCHAR PathId;
1950 UCHAR TargetId;
1951 UCHAR Lun;
1952 PSCSI_PORT_LUN_EXTENSION LunExtension;
1953
1954 PathId = (UCHAR) va_arg (ap, int);
1955 TargetId = (UCHAR) va_arg (ap, int);
1956 Lun = (UCHAR) va_arg (ap, int);
1957
1958 DPRINT("Notify: NextLuRequest(PathId %u TargetId %u Lun %u)\n",
1959 PathId, TargetId, Lun);
1960
1961 /* Mark it in the flags field */
1962 DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY;
1963
1964 /* Get the LUN extension */
1965 LunExtension = SpiGetLunExtension(DeviceExtension,
1966 PathId,
1967 TargetId,
1968 Lun);
1969
1970 /* If returned LunExtension is NULL, break out */
1971 if (!LunExtension) break;
1972
1973 /* This request should not be processed if */
1974 if ((LunExtension->ReadyLun) ||
1975 (LunExtension->SrbInfo.Srb))
1976 {
1977 /* Nothing to do here */
1978 break;
1979 }
1980
1981 /* Add this LUN to the list */
1982 LunExtension->ReadyLun = DeviceExtension->InterruptData.ReadyLun;
1983 DeviceExtension->InterruptData.ReadyLun = LunExtension;
1984 }
1985 break;
1986
1987 case ResetDetected:
1988 DPRINT("Notify: ResetDetected\n");
1989 /* Add RESET flags */
1990 DeviceExtension->InterruptData.Flags |=
1991 SCSI_PORT_RESET | SCSI_PORT_RESET_REPORTED;
1992 break;
1993
1994 case CallDisableInterrupts:
1995 DPRINT1("UNIMPLEMENTED SCSI Notification called: CallDisableInterrupts!\n");
1996 break;
1997
1998 case CallEnableInterrupts:
1999 DPRINT1("UNIMPLEMENTED SCSI Notification called: CallEnableInterrupts!\n");
2000 break;
2001
2002 case RequestTimerCall:
2003 DPRINT("Notify: RequestTimerCall\n");
2004 DeviceExtension->InterruptData.Flags |= SCSI_PORT_TIMER_NEEDED;
2005 DeviceExtension->InterruptData.HwScsiTimer = (PHW_TIMER)va_arg(ap, PHW_TIMER);
2006 DeviceExtension->InterruptData.MiniportTimerValue = (ULONG)va_arg(ap, ULONG);
2007 break;
2008
2009 case BusChangeDetected:
2010 DPRINT1("UNIMPLEMENTED SCSI Notification called: BusChangeDetected!\n");
2011 break;
2012
2013 default:
2014 DPRINT1 ("Unsupported notification from WMI: %lu\n", NotificationType);
2015 break;
2016 }
2017
2018 va_end(ap);
2019
2020 /* Request a DPC after we're done with the interrupt */
2021 DeviceExtension->InterruptData.Flags |= SCSI_PORT_NOTIFICATION_NEEDED;
2022 }
2023
2024 /*
2025 * @implemented
2026 */
2027 BOOLEAN NTAPI
2028 ScsiPortValidateRange(IN PVOID HwDeviceExtension,
2029 IN INTERFACE_TYPE BusType,
2030 IN ULONG SystemIoBusNumber,
2031 IN SCSI_PHYSICAL_ADDRESS IoAddress,
2032 IN ULONG NumberOfBytes,
2033 IN BOOLEAN InIoSpace)
2034 {
2035 DPRINT("ScsiPortValidateRange()\n");
2036 return(TRUE);
2037 }
2038
2039
2040 /* INTERNAL FUNCTIONS ********************************************************/
2041
2042 static VOID
2043 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData,
2044 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor,
2045 IN PPORT_CONFIGURATION_INFORMATION PortConfig)
2046 {
2047 PACCESS_RANGE AccessRange;
2048 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialData;
2049 ULONG RangeNumber;
2050 ULONG Index;
2051 ULONG Interrupt = 0;
2052 ULONG Dma = 0;
2053
2054 RangeNumber = 0;
2055
2056 /* Loop through all entries */
2057 for (Index = 0; Index < ResourceDescriptor->PartialResourceList.Count; Index++)
2058 {
2059 PartialData = &ResourceDescriptor->PartialResourceList.PartialDescriptors[Index];
2060
2061 switch (PartialData->Type)
2062 {
2063 case CmResourceTypePort:
2064 /* Copy access ranges */
2065 if (RangeNumber < HwInitializationData->NumberOfAccessRanges)
2066 {
2067 AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]);
2068
2069 AccessRange->RangeStart = PartialData->u.Port.Start;
2070 AccessRange->RangeLength = PartialData->u.Port.Length;
2071
2072 AccessRange->RangeInMemory = FALSE;
2073 RangeNumber++;
2074 }
2075 break;
2076
2077 case CmResourceTypeMemory:
2078 /* Copy access ranges */
2079 if (RangeNumber < HwInitializationData->NumberOfAccessRanges)
2080 {
2081 AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]);
2082
2083 AccessRange->RangeStart = PartialData->u.Memory.Start;
2084 AccessRange->RangeLength = PartialData->u.Memory.Length;
2085
2086 AccessRange->RangeInMemory = TRUE;
2087 RangeNumber++;
2088 }
2089 break;
2090
2091 case CmResourceTypeInterrupt:
2092
2093 if (Interrupt == 0)
2094 {
2095 /* Copy interrupt data */
2096 PortConfig->BusInterruptLevel = PartialData->u.Interrupt.Level;
2097 PortConfig->BusInterruptVector = PartialData->u.Interrupt.Vector;
2098
2099 /* Set interrupt mode accordingly to the resource */
2100 if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
2101 {
2102 PortConfig->InterruptMode = Latched;
2103 }
2104 else if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
2105 {
2106 PortConfig->InterruptMode = LevelSensitive;
2107 }
2108 }
2109 else if (Interrupt == 1)
2110 {
2111 /* Copy interrupt data */
2112 PortConfig->BusInterruptLevel2 = PartialData->u.Interrupt.Level;
2113 PortConfig->BusInterruptVector2 = PartialData->u.Interrupt.Vector;
2114
2115 /* Set interrupt mode accordingly to the resource */
2116 if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
2117 {
2118 PortConfig->InterruptMode2 = Latched;
2119 }
2120 else if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
2121 {
2122 PortConfig->InterruptMode2 = LevelSensitive;
2123 }
2124 }
2125
2126 Interrupt++;
2127 break;
2128
2129 case CmResourceTypeDma:
2130
2131 if (Dma == 0)
2132 {
2133 PortConfig->DmaChannel = PartialData->u.Dma.Channel;
2134 PortConfig->DmaPort = PartialData->u.Dma.Port;
2135
2136 if (PartialData->Flags & CM_RESOURCE_DMA_8)
2137 PortConfig->DmaWidth = Width8Bits;
2138 else if ((PartialData->Flags & CM_RESOURCE_DMA_16) ||
2139 (PartialData->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
2140 PortConfig->DmaWidth = Width16Bits;
2141 else if (PartialData->Flags & CM_RESOURCE_DMA_32)
2142 PortConfig->DmaWidth = Width32Bits;
2143 }
2144 else if (Dma == 1)
2145 {
2146 PortConfig->DmaChannel2 = PartialData->u.Dma.Channel;
2147 PortConfig->DmaPort2 = PartialData->u.Dma.Port;
2148
2149 if (PartialData->Flags & CM_RESOURCE_DMA_8)
2150 PortConfig->DmaWidth2 = Width8Bits;
2151 else if ((PartialData->Flags & CM_RESOURCE_DMA_16) ||
2152 (PartialData->Flags & CM_RESOURCE_DMA_8_AND_16)) //???
2153 PortConfig->DmaWidth2 = Width16Bits;
2154 else if (PartialData->Flags & CM_RESOURCE_DMA_32)
2155 PortConfig->DmaWidth2 = Width32Bits;
2156 }
2157 break;
2158 }
2159 }
2160 }
2161
2162 static PCM_RESOURCE_LIST
2163 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
2164 PPORT_CONFIGURATION_INFORMATION PortConfig)
2165 {
2166 PCONFIGURATION_INFORMATION ConfigInfo;
2167 PCM_RESOURCE_LIST ResourceList;
2168 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor;
2169 PACCESS_RANGE AccessRange;
2170 ULONG ListLength = 0, i, FullSize;
2171 ULONG Interrupt, Dma;
2172
2173 /* Get current Atdisk usage from the system */
2174 ConfigInfo = IoGetConfigurationInformation();
2175
2176 if (PortConfig->AtdiskPrimaryClaimed)
2177 ConfigInfo->AtDiskPrimaryAddressClaimed = TRUE;
2178
2179 if (PortConfig->AtdiskSecondaryClaimed)
2180 ConfigInfo->AtDiskSecondaryAddressClaimed = TRUE;
2181
2182 /* Do we use DMA? */
2183 if (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE ||
2184 PortConfig->DmaPort != SP_UNINITIALIZED_VALUE)
2185 {
2186 Dma = 1;
2187
2188 if (PortConfig->DmaChannel2 != SP_UNINITIALIZED_VALUE ||
2189 PortConfig->DmaPort2 != SP_UNINITIALIZED_VALUE)
2190 Dma++;
2191 }
2192 else
2193 {
2194 Dma = 0;
2195 }
2196 ListLength += Dma;
2197
2198 /* How many interrupts to we have? */
2199 Interrupt = DeviceExtension->InterruptCount;
2200 ListLength += Interrupt;
2201
2202 /* How many access ranges do we use? */
2203 AccessRange = &((*(PortConfig->AccessRanges))[0]);
2204 for (i = 0; i < PortConfig->NumberOfAccessRanges; i++)
2205 {
2206 if (AccessRange->RangeLength != 0)
2207 ListLength++;
2208
2209 AccessRange++;
2210 }
2211
2212 /* Allocate the resource list, since we know its size now */
2213 FullSize = sizeof(CM_RESOURCE_LIST) + (ListLength - 1) *
2214 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
2215
2216 ResourceList = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(PagedPool, FullSize, TAG_SCSIPORT);
2217
2218 if (!ResourceList)
2219 return NULL;
2220
2221 /* Zero it */
2222 RtlZeroMemory(ResourceList, FullSize);
2223
2224 /* Initialize it */
2225 ResourceList->Count = 1;
2226 ResourceList->List[0].InterfaceType = PortConfig->AdapterInterfaceType;
2227 ResourceList->List[0].BusNumber = PortConfig->SystemIoBusNumber;
2228 ResourceList->List[0].PartialResourceList.Count = ListLength;
2229 ResourceDescriptor = ResourceList->List[0].PartialResourceList.PartialDescriptors;
2230
2231 /* Copy access ranges array over */
2232 for (i = 0; i < PortConfig->NumberOfAccessRanges; i++)
2233 {
2234 AccessRange = &((*(PortConfig->AccessRanges))[i]);
2235
2236 /* If the range is empty - skip it */
2237 if (AccessRange->RangeLength == 0)
2238 continue;
2239
2240 if (AccessRange->RangeInMemory)
2241 {
2242 ResourceDescriptor->Type = CmResourceTypeMemory;
2243 ResourceDescriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
2244 }
2245 else
2246 {
2247 ResourceDescriptor->Type = CmResourceTypePort;
2248 ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
2249 }
2250
2251 ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
2252
2253 ResourceDescriptor->u.Memory.Start = AccessRange->RangeStart;
2254 ResourceDescriptor->u.Memory.Length = AccessRange->RangeLength;
2255
2256 ResourceDescriptor++;
2257 }
2258
2259 /* If we use interrupt(s), copy them */
2260 while (Interrupt)
2261 {
2262 ResourceDescriptor->Type = CmResourceTypeInterrupt;
2263
2264 if (PortConfig->AdapterInterfaceType == MicroChannel ||
2265 ((Interrupt == 2) ? PortConfig->InterruptMode2 : PortConfig->InterruptMode) == LevelSensitive)
2266 {
2267 ResourceDescriptor->ShareDisposition = CmResourceShareShared;
2268 ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
2269 }
2270 else
2271 {
2272 ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
2273 ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
2274 }
2275
2276 ResourceDescriptor->u.Interrupt.Level = (Interrupt == 2) ? PortConfig->BusInterruptLevel2 : PortConfig->BusInterruptLevel;
2277 ResourceDescriptor->u.Interrupt.Vector = (Interrupt == 2) ? PortConfig->BusInterruptVector2 : PortConfig->BusInterruptVector;
2278 ResourceDescriptor->u.Interrupt.Affinity = 0;
2279
2280 ResourceDescriptor++;
2281 Interrupt--;
2282 }
2283
2284 /* Copy DMA data */
2285 while (Dma)
2286 {
2287 ResourceDescriptor->Type = CmResourceTypeDma;
2288 ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
2289 ResourceDescriptor->u.Dma.Channel = (Dma == 2) ? PortConfig->DmaChannel2 : PortConfig->DmaChannel;
2290 ResourceDescriptor->u.Dma.Port = (Dma == 2) ? PortConfig->DmaPort2 : PortConfig->DmaPort;
2291 ResourceDescriptor->Flags = 0;
2292
2293 if (((Dma == 2) ? PortConfig->DmaWidth2 : PortConfig->DmaWidth) == Width8Bits)
2294 ResourceDescriptor->Flags |= CM_RESOURCE_DMA_8;
2295 else if (((Dma == 2) ? PortConfig->DmaWidth2 : PortConfig->DmaWidth) == Width16Bits)
2296 ResourceDescriptor->Flags |= CM_RESOURCE_DMA_16;
2297 else
2298 ResourceDescriptor->Flags |= CM_RESOURCE_DMA_32;
2299
2300 if (((Dma == 2) ? PortConfig->DmaChannel2 : PortConfig->DmaChannel) == SP_UNINITIALIZED_VALUE)
2301 ResourceDescriptor->u.Dma.Channel = 0;
2302
2303 if (((Dma == 2) ? PortConfig->DmaPort2 : PortConfig->DmaPort) == SP_UNINITIALIZED_VALUE)
2304 ResourceDescriptor->u.Dma.Port = 0;
2305
2306 ResourceDescriptor++;
2307 Dma--;
2308 }
2309
2310 return ResourceList;
2311 }
2312
2313
2314 static BOOLEAN
2315 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject,
2316 IN PDEVICE_OBJECT DeviceObject,
2317 IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
2318 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,
2319 IN PUNICODE_STRING RegistryPath,
2320 IN ULONG BusNumber,
2321 IN OUT PPCI_SLOT_NUMBER NextSlotNumber)
2322 {
2323 PCI_COMMON_CONFIG PciConfig;
2324 PCI_SLOT_NUMBER SlotNumber;
2325 ULONG DataSize;
2326 ULONG DeviceNumber;
2327 ULONG FunctionNumber;
2328 CHAR VendorIdString[8];
2329 CHAR DeviceIdString[8];
2330 UNICODE_STRING UnicodeStr;
2331 PCM_RESOURCE_LIST ResourceList = NULL;
2332 NTSTATUS Status;
2333
2334 DPRINT ("SpiGetPciConfiguration() called\n");
2335
2336 SlotNumber.u.AsULONG = 0;
2337
2338 /* Loop through all devices */
2339 for (DeviceNumber = NextSlotNumber->u.bits.DeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
2340 {
2341 SlotNumber.u.bits.DeviceNumber = DeviceNumber;
2342
2343 /* Loop through all functions */
2344 for (FunctionNumber = NextSlotNumber->u.bits.FunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
2345 {
2346 SlotNumber.u.bits.FunctionNumber = FunctionNumber;
2347
2348 /* Get PCI config bytes */
2349 DataSize = HalGetBusData(PCIConfiguration,
2350 BusNumber,
2351 SlotNumber.u.AsULONG,
2352 &PciConfig,
2353 sizeof(ULONG));
2354
2355 /* If result of HalGetBusData is 0, then the bus is wrong */
2356 if (DataSize == 0)
2357 return FALSE;
2358
2359 /* Check if result is PCI_INVALID_VENDORID or too small */
2360 if ((DataSize < sizeof(ULONG)) ||
2361 (PciConfig.VendorID == PCI_INVALID_VENDORID))
2362 {
2363 /* Continue to try the next function */
2364 continue;
2365 }
2366
2367 sprintf (VendorIdString, "%04hx", PciConfig.VendorID);
2368 sprintf (DeviceIdString, "%04hx", PciConfig.DeviceID);
2369
2370 if (_strnicmp(VendorIdString, HwInitializationData->VendorId, HwInitializationData->VendorIdLength) ||
2371 _strnicmp(DeviceIdString, HwInitializationData->DeviceId, HwInitializationData->DeviceIdLength))
2372 {
2373 /* It is not our device */
2374 continue;
2375 }
2376
2377 DPRINT("Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n",
2378 PciConfig.VendorID,
2379 PciConfig.DeviceID,
2380 BusNumber,
2381 SlotNumber.u.bits.DeviceNumber,
2382 SlotNumber.u.bits.FunctionNumber);
2383
2384
2385 RtlInitUnicodeString(&UnicodeStr, L"ScsiAdapter");
2386 Status = HalAssignSlotResources(RegistryPath,
2387 &UnicodeStr,
2388 DriverObject,
2389 DeviceObject,
2390 PCIBus,
2391 BusNumber,
2392 SlotNumber.u.AsULONG,
2393 &ResourceList);
2394
2395 if (!NT_SUCCESS(Status))
2396 break;
2397
2398 /* Create configuration information */
2399 SpiResourceToConfig(HwInitializationData,
2400 ResourceList->List,
2401 PortConfig);
2402
2403 /* Free the resource list */
2404 ExFreePool(ResourceList);
2405
2406 /* Set dev & fn numbers */
2407 NextSlotNumber->u.bits.DeviceNumber = DeviceNumber;
2408 NextSlotNumber->u.bits.FunctionNumber = FunctionNumber + 1;
2409
2410 /* Save the slot number */
2411 PortConfig->SlotNumber = SlotNumber.u.AsULONG;
2412
2413 return TRUE;
2414 }
2415 NextSlotNumber->u.bits.FunctionNumber = 0;
2416 }
2417
2418 NextSlotNumber->u.bits.DeviceNumber = 0;
2419 DPRINT ("No device found\n");
2420
2421 return FALSE;
2422 }
2423
2424
2425
2426 /**********************************************************************
2427 * NAME INTERNAL
2428 * ScsiPortCreateClose
2429 *
2430 * DESCRIPTION
2431 * Answer requests for Create/Close calls: a null operation.
2432 *
2433 * RUN LEVEL
2434 * PASSIVE_LEVEL
2435 *
2436 * ARGUMENTS
2437 * DeviceObject
2438 * Pointer to a device object.
2439 *
2440 * Irp
2441 * Pointer to an IRP.
2442 *
2443 * RETURN VALUE
2444 * Status.
2445 */
2446
2447 static NTSTATUS NTAPI
2448 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
2449 IN PIRP Irp)
2450 {
2451 DPRINT("ScsiPortCreateClose()\n");
2452
2453 Irp->IoStatus.Status = STATUS_SUCCESS;
2454 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2455
2456 return STATUS_SUCCESS;
2457 }
2458
2459 static NTSTATUS
2460 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
2461 PIRP Irp)
2462 {
2463 PSCSI_LUN_INFO LunInfo;
2464 PIO_STACK_LOCATION IrpStack;
2465 PDEVICE_OBJECT DeviceObject;
2466 PSCSI_REQUEST_BLOCK Srb;
2467 KIRQL Irql;
2468
2469 /* Get pointer to the SRB */
2470 IrpStack = IoGetCurrentIrpStackLocation(Irp);
2471 Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
2472
2473 /* Check if PathId matches number of buses */
2474 if (DeviceExtension->BusesConfig == NULL ||
2475 DeviceExtension->BusesConfig->NumberOfBuses <= Srb->PathId)
2476 {
2477 Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
2478 return STATUS_DEVICE_DOES_NOT_EXIST;
2479 }
2480
2481 /* Get pointer to LunInfo */
2482 LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Srb->PathId]->LunInfo;
2483
2484 /* Find matching LunInfo */
2485 while (LunInfo)
2486 {
2487 if (LunInfo->PathId == Srb->PathId &&
2488 LunInfo->TargetId == Srb->TargetId &&
2489 LunInfo->Lun == Srb->Lun)
2490 {
2491 break;
2492 }
2493
2494 LunInfo = LunInfo->Next;
2495 }
2496
2497 /* If we couldn't find it - exit */
2498 if (LunInfo == NULL)
2499 return STATUS_DEVICE_DOES_NOT_EXIST;
2500
2501
2502 /* Get spinlock */
2503 KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
2504
2505 /* Release, if asked */
2506 if (Srb->Function == SRB_FUNCTION_RELEASE_DEVICE)
2507 {
2508 LunInfo->DeviceClaimed = FALSE;
2509 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2510 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2511
2512 return STATUS_SUCCESS;
2513 }
2514
2515 /* Attach, if not already claimed */
2516 if (LunInfo->DeviceClaimed)
2517 {
2518 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2519 Srb->SrbStatus = SRB_STATUS_BUSY;
2520
2521 return STATUS_DEVICE_BUSY;
2522 }
2523
2524 /* Save the device object */
2525 DeviceObject = LunInfo->DeviceObject;
2526
2527 if (Srb->Function == SRB_FUNCTION_CLAIM_DEVICE)
2528 LunInfo->DeviceClaimed = TRUE;
2529
2530 if (Srb->Function == SRB_FUNCTION_ATTACH_DEVICE)
2531 LunInfo->DeviceObject = Srb->DataBuffer;
2532
2533 Srb->DataBuffer = DeviceObject;
2534
2535 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2536 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2537
2538 return STATUS_SUCCESS;
2539 }
2540
2541
2542 /**********************************************************************
2543 * NAME INTERNAL
2544 * ScsiPortDispatchScsi
2545 *
2546 * DESCRIPTION
2547 * Answer requests for SCSI calls
2548 *
2549 * RUN LEVEL
2550 * PASSIVE_LEVEL
2551 *
2552 * ARGUMENTS
2553 * Standard dispatch arguments
2554 *
2555 * RETURNS
2556 * NTSTATUS
2557 */
2558
2559 static NTSTATUS NTAPI
2560 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
2561 IN PIRP Irp)
2562 {
2563 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2564 PSCSI_PORT_LUN_EXTENSION LunExtension;
2565 PIO_STACK_LOCATION Stack;
2566 PSCSI_REQUEST_BLOCK Srb;
2567 KIRQL Irql;
2568 NTSTATUS Status = STATUS_SUCCESS;
2569 PIRP NextIrp, IrpList;
2570 PKDEVICE_QUEUE_ENTRY Entry;
2571
2572 DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n",
2573 DeviceObject, Irp);
2574
2575 DeviceExtension = DeviceObject->DeviceExtension;
2576 Stack = IoGetCurrentIrpStackLocation(Irp);
2577
2578 Srb = Stack->Parameters.Scsi.Srb;
2579 if (Srb == NULL)
2580 {
2581 DPRINT1("ScsiPortDispatchScsi() called with Srb = NULL!\n");
2582 Status = STATUS_UNSUCCESSFUL;
2583
2584 Irp->IoStatus.Status = Status;
2585 Irp->IoStatus.Information = 0;
2586
2587 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2588
2589 return(Status);
2590 }
2591
2592 DPRINT("Srb: %p\n", Srb);
2593 DPRINT("Srb->Function: %lu\n", Srb->Function);
2594 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
2595
2596 LunExtension = SpiGetLunExtension(DeviceExtension,
2597 Srb->PathId,
2598 Srb->TargetId,
2599 Srb->Lun);
2600 if (LunExtension == NULL)
2601 {
2602 DPRINT("ScsiPortDispatchScsi() called with an invalid LUN\n");
2603 Status = STATUS_NO_SUCH_DEVICE;
2604
2605 Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
2606 Irp->IoStatus.Status = Status;
2607 Irp->IoStatus.Information = 0;
2608
2609 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2610
2611 return(Status);
2612 }
2613
2614 switch (Srb->Function)
2615 {
2616 case SRB_FUNCTION_SHUTDOWN:
2617 case SRB_FUNCTION_FLUSH:
2618 DPRINT (" SRB_FUNCTION_SHUTDOWN or FLUSH\n");
2619 if (DeviceExtension->CachesData == FALSE)
2620 {
2621 /* All success here */
2622 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2623 Irp->IoStatus.Status = STATUS_SUCCESS;
2624 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2625 return STATUS_SUCCESS;
2626 }
2627 /* Fall through to a usual execute operation */
2628
2629 case SRB_FUNCTION_EXECUTE_SCSI:
2630 case SRB_FUNCTION_IO_CONTROL:
2631 DPRINT(" SRB_FUNCTION_EXECUTE_SCSI or SRB_FUNCTION_IO_CONTROL\n");
2632 /* Mark IRP as pending in all cases */
2633 IoMarkIrpPending(Irp);
2634
2635 if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
2636 {
2637 /* Start IO directly */
2638 IoStartPacket(DeviceObject, Irp, NULL, NULL);
2639 }
2640 else
2641 {
2642 KIRQL oldIrql;
2643
2644 /* We need to be at DISPATCH_LEVEL */
2645 KeRaiseIrql (DISPATCH_LEVEL, &oldIrql);
2646
2647 /* Insert IRP into the queue */
2648 if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue,
2649 &Irp->Tail.Overlay.DeviceQueueEntry,
2650 Srb->QueueSortKey))
2651 {
2652 /* It means the queue is empty, and we just start this request */
2653 IoStartPacket(DeviceObject, Irp, NULL, NULL);
2654 }
2655
2656 /* Back to the old IRQL */
2657 KeLowerIrql (oldIrql);
2658 }
2659 return STATUS_PENDING;
2660
2661 case SRB_FUNCTION_CLAIM_DEVICE:
2662 case SRB_FUNCTION_ATTACH_DEVICE:
2663 DPRINT (" SRB_FUNCTION_CLAIM_DEVICE or ATTACH\n");
2664
2665 /* Reference device object and keep the device object */
2666 Status = SpiHandleAttachRelease(DeviceExtension, Irp);
2667 break;
2668
2669 case SRB_FUNCTION_RELEASE_DEVICE:
2670 DPRINT (" SRB_FUNCTION_RELEASE_DEVICE\n");
2671
2672 /* Dereference device object and clear the device object */
2673 Status = SpiHandleAttachRelease(DeviceExtension, Irp);
2674 break;
2675
2676 case SRB_FUNCTION_RELEASE_QUEUE:
2677 DPRINT(" SRB_FUNCTION_RELEASE_QUEUE\n");
2678
2679 /* Guard with the spinlock */
2680 KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
2681
2682 if (!(LunExtension->Flags & LUNEX_FROZEN_QUEUE))
2683 {
2684 DPRINT("Queue is not frozen really\n");
2685
2686 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2687 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2688 Status = STATUS_SUCCESS;
2689 break;
2690
2691 }
2692
2693 /* Unfreeze the queue */
2694 LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
2695
2696 if (LunExtension->SrbInfo.Srb == NULL)
2697 {
2698 /* Get next logical unit request */
2699 SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
2700
2701 /* SpiGetNextRequestFromLun() releases the spinlock */
2702 KeLowerIrql(Irql);
2703 }
2704 else
2705 {
2706 DPRINT("The queue has active request\n");
2707 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2708 }
2709
2710
2711 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2712 Status = STATUS_SUCCESS;
2713 break;
2714
2715 case SRB_FUNCTION_FLUSH_QUEUE:
2716 DPRINT(" SRB_FUNCTION_FLUSH_QUEUE\n");
2717
2718 /* Guard with the spinlock */
2719 KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
2720
2721 if (!(LunExtension->Flags & LUNEX_FROZEN_QUEUE))
2722 {
2723 DPRINT("Queue is not frozen really\n");
2724
2725 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2726 Status = STATUS_INVALID_DEVICE_REQUEST;
2727 break;
2728 }
2729
2730 /* Make sure there is no active request */
2731 ASSERT(LunExtension->SrbInfo.Srb == NULL);
2732
2733 /* Compile a list from the device queue */
2734 IrpList = NULL;
2735 while ((Entry = KeRemoveDeviceQueue(&LunExtension->DeviceQueue)) != NULL)
2736 {
2737 NextIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
2738
2739 /* Get the Srb */
2740 Stack = IoGetCurrentIrpStackLocation(NextIrp);
2741 Srb = Stack->Parameters.Scsi.Srb;
2742
2743 /* Set statuse */
2744 Srb->SrbStatus = SRB_STATUS_REQUEST_FLUSHED;
2745 NextIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
2746
2747 /* Add then to the list */
2748 NextIrp->Tail.Overlay.ListEntry.Flink = (PLIST_ENTRY)IrpList;
2749 IrpList = NextIrp;
2750 }
2751
2752 /* Unfreeze the queue */
2753 LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
2754
2755 /* Release the spinlock */
2756 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2757
2758 /* Complete those requests */
2759 while (IrpList)
2760 {
2761 NextIrp = IrpList;
2762 IrpList = (PIRP)NextIrp->Tail.Overlay.ListEntry.Flink;
2763
2764 IoCompleteRequest(NextIrp, 0);
2765 }
2766
2767 Status = STATUS_SUCCESS;
2768 break;
2769
2770 default:
2771 DPRINT1("SRB function not implemented (Function %lu)\n", Srb->Function);
2772 Status = STATUS_NOT_IMPLEMENTED;
2773 break;
2774 }
2775
2776 Irp->IoStatus.Status = Status;
2777
2778 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2779
2780 return(Status);
2781 }
2782
2783
2784 /**********************************************************************
2785 * NAME INTERNAL
2786 * ScsiPortDeviceControl
2787 *
2788 * DESCRIPTION
2789 * Answer requests for device control calls
2790 *
2791 * RUN LEVEL
2792 * PASSIVE_LEVEL
2793 *
2794 * ARGUMENTS
2795 * Standard dispatch arguments
2796 *
2797 * RETURNS
2798 * NTSTATUS
2799 */
2800
2801 static NTSTATUS NTAPI
2802 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
2803 IN PIRP Irp)
2804 {
2805 PIO_STACK_LOCATION Stack;
2806 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2807 PDUMP_POINTERS DumpPointers;
2808 NTSTATUS Status;
2809
2810 DPRINT("ScsiPortDeviceControl()\n");
2811
2812 Irp->IoStatus.Information = 0;
2813
2814 Stack = IoGetCurrentIrpStackLocation(Irp);
2815 DeviceExtension = DeviceObject->DeviceExtension;
2816
2817 switch (Stack->Parameters.DeviceIoControl.IoControlCode)
2818 {
2819 case IOCTL_SCSI_GET_DUMP_POINTERS:
2820 DPRINT(" IOCTL_SCSI_GET_DUMP_POINTERS\n");
2821
2822 if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DUMP_POINTERS))
2823 {
2824 Status = STATUS_BUFFER_OVERFLOW;
2825 Irp->IoStatus.Information = sizeof(DUMP_POINTERS);
2826 break;
2827 }
2828
2829 DumpPointers = Irp->AssociatedIrp.SystemBuffer;
2830 DumpPointers->DeviceObject = DeviceObject;
2831 /* More data.. ? */
2832
2833 Status = STATUS_SUCCESS;
2834 Irp->IoStatus.Information = sizeof(DUMP_POINTERS);
2835 break;
2836
2837 case IOCTL_SCSI_GET_CAPABILITIES:
2838 DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
2839 if (Stack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(PVOID))
2840 {
2841 *((PVOID *)Irp->AssociatedIrp.SystemBuffer) = &DeviceExtension->PortCapabilities;
2842
2843 Irp->IoStatus.Information = sizeof(PVOID);
2844 Status = STATUS_SUCCESS;
2845 break;
2846 }
2847
2848 if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(IO_SCSI_CAPABILITIES))
2849 {
2850 Status = STATUS_BUFFER_TOO_SMALL;
2851 break;
2852 }
2853
2854 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
2855 &DeviceExtension->PortCapabilities,
2856 sizeof(IO_SCSI_CAPABILITIES));
2857
2858 Irp->IoStatus.Information = sizeof(IO_SCSI_CAPABILITIES);
2859 Status = STATUS_SUCCESS;
2860 break;
2861
2862 case IOCTL_SCSI_GET_INQUIRY_DATA:
2863 DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
2864
2865 /* Copy inquiry data to the port device extension */
2866 Status = SpiGetInquiryData(DeviceExtension, Irp);
2867 break;
2868
2869 case IOCTL_SCSI_MINIPORT:
2870 DPRINT1("IOCTL_SCSI_MINIPORT unimplemented!\n");
2871 Status = STATUS_NOT_IMPLEMENTED;
2872 break;
2873
2874 case IOCTL_SCSI_PASS_THROUGH:
2875 DPRINT1("IOCTL_SCSI_PASS_THROUGH unimplemented!\n");
2876 Status = STATUS_NOT_IMPLEMENTED;
2877 break;
2878
2879 default:
2880 if ('M' == (Stack->Parameters.DeviceIoControl.IoControlCode >> 16)) {
2881 DPRINT1(" got ioctl intended for the mount manager: 0x%lX\n", Stack->Parameters.DeviceIoControl.IoControlCode);
2882 } else {
2883 DPRINT1(" unknown ioctl code: 0x%lX\n", Stack->Parameters.DeviceIoControl.IoControlCode);
2884 }
2885 Status = STATUS_NOT_IMPLEMENTED;
2886 break;
2887 }
2888
2889 /* Complete the request with the given status */
2890 Irp->IoStatus.Status = Status;
2891 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2892
2893 return Status;
2894 }
2895
2896
2897 static VOID NTAPI
2898 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
2899 IN PIRP Irp)
2900 {
2901 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2902 PSCSI_PORT_LUN_EXTENSION LunExtension;
2903 PIO_STACK_LOCATION IrpStack;
2904 PSCSI_REQUEST_BLOCK Srb;
2905 PSCSI_REQUEST_BLOCK_INFO SrbInfo;
2906 LONG CounterResult;
2907 NTSTATUS Status;
2908
2909 DPRINT("ScsiPortStartIo() called!\n");
2910
2911 DeviceExtension = DeviceObject->DeviceExtension;
2912 IrpStack = IoGetCurrentIrpStackLocation(Irp);
2913
2914 DPRINT("DeviceExtension %p\n", DeviceExtension);
2915
2916 Srb = IrpStack->Parameters.Scsi.Srb;
2917
2918 /* Apply "default" flags */
2919 Srb->SrbFlags |= DeviceExtension->SrbFlags;
2920
2921 /* Get LUN extension */
2922 LunExtension = SpiGetLunExtension(DeviceExtension,
2923 Srb->PathId,
2924 Srb->TargetId,
2925 Srb->Lun);
2926
2927 if (DeviceExtension->NeedSrbDataAlloc ||
2928 DeviceExtension->NeedSrbExtensionAlloc)
2929 {
2930 /* Allocate them */
2931 SrbInfo = SpiAllocateSrbStructures(DeviceExtension,
2932 LunExtension,
2933 Srb);
2934
2935 /* Couldn't alloc one or both data structures, return */
2936 if (SrbInfo == NULL)
2937 {
2938 /* We have to call IoStartNextPacket, because this request
2939 was not started */
2940 if (LunExtension->Flags & LUNEX_REQUEST_PENDING)
2941 IoStartNextPacket(DeviceObject, FALSE);
2942
2943 return;
2944 }
2945 }
2946 else
2947 {
2948 /* No allocations are needed */
2949 SrbInfo = &LunExtension->SrbInfo;
2950 Srb->SrbExtension = NULL;
2951 Srb->QueueTag = SP_UNTAGGED;
2952 }
2953
2954 /* Increase sequence number of SRB */
2955 if (!SrbInfo->SequenceNumber)
2956 {
2957 /* Increase global sequence number */
2958 DeviceExtension->SequenceNumber++;
2959
2960 /* Assign it */
2961 SrbInfo->SequenceNumber = DeviceExtension->SequenceNumber;
2962 }
2963
2964 /* Check some special SRBs */
2965 if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
2966 {
2967 /* Some special handling */
2968 DPRINT1("Abort command! Unimplemented now\n");
2969 }
2970 else
2971 {
2972 SrbInfo->Srb = Srb;
2973 }
2974
2975 if (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION)
2976 {
2977 // Store the MDL virtual address in SrbInfo structure
2978 SrbInfo->DataOffset = MmGetMdlVirtualAddress(Irp->MdlAddress);
2979
2980 if (DeviceExtension->MapBuffers)
2981 {
2982 /* Calculate offset within DataBuffer */
2983 SrbInfo->DataOffset = MmGetSystemAddressForMdl(Irp->MdlAddress);
2984 Srb->DataBuffer = SrbInfo->DataOffset +
2985 (ULONG)((PUCHAR)Srb->DataBuffer -
2986 (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress));
2987 }
2988
2989 if (DeviceExtension->AdapterObject)
2990 {
2991 /* Flush buffers */
2992 KeFlushIoBuffers(Irp->MdlAddress,
2993 Srb->SrbFlags & SRB_FLAGS_DATA_IN ? TRUE : FALSE,
2994 TRUE);
2995 }
2996
2997 if (DeviceExtension->MapRegisters)
2998 {
2999 /* Calculate number of needed map registers */
3000 SrbInfo->NumberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
3001 Srb->DataBuffer,
3002 Srb->DataTransferLength);
3003
3004 /* Allocate adapter channel */
3005 Status = IoAllocateAdapterChannel(DeviceExtension->AdapterObject,
3006 DeviceExtension->DeviceObject,
3007 SrbInfo->NumberOfMapRegisters,
3008 SpiAdapterControl,
3009 SrbInfo);
3010
3011 if (!NT_SUCCESS(Status))
3012 {
3013 DPRINT1("IoAllocateAdapterChannel() failed!\n");
3014
3015 Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
3016 ScsiPortNotification(RequestComplete,
3017 DeviceExtension + 1,
3018 Srb);
3019
3020 ScsiPortNotification(NextRequest,
3021 DeviceExtension + 1);
3022
3023 /* Request DPC for that work */
3024 IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
3025 }
3026
3027 /* Control goes to SpiAdapterControl */
3028 return;
3029 }
3030 }
3031
3032 /* Increase active request counter */
3033 CounterResult = InterlockedIncrement(&DeviceExtension->ActiveRequestCounter);
3034
3035 if (CounterResult == 0 &&
3036 DeviceExtension->AdapterObject != NULL &&
3037 !DeviceExtension->MapRegisters)
3038 {
3039 IoAllocateAdapterChannel(
3040 DeviceExtension->AdapterObject,
3041 DeviceObject,
3042 DeviceExtension->PortCapabilities.MaximumPhysicalPages,
3043 ScsiPortAllocateAdapterChannel,
3044 LunExtension
3045 );
3046
3047 return;
3048 }
3049
3050 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
3051
3052 if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0],
3053 ScsiPortStartPacket,
3054 DeviceObject))
3055 {
3056 DPRINT("Synchronization failed!\n");
3057
3058 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
3059 Irp->IoStatus.Information = 0;
3060 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3061
3062 IoCompleteRequest(Irp, IO_NO_INCREMENT);
3063 }
3064 else
3065 {
3066 /* Release the spinlock only */
3067 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3068 }
3069
3070
3071 DPRINT("ScsiPortStartIo() done\n");
3072 }
3073
3074
3075 static BOOLEAN NTAPI
3076 ScsiPortStartPacket(IN OUT PVOID Context)
3077 {
3078 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
3079 PIO_STACK_LOCATION IrpStack;
3080 PSCSI_REQUEST_BLOCK Srb;
3081 PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)Context;
3082 PSCSI_PORT_LUN_EXTENSION LunExtension;
3083 PSCSI_REQUEST_BLOCK_INFO SrbInfo;
3084 BOOLEAN Result;
3085 BOOLEAN StartTimer;
3086
3087 DPRINT("ScsiPortStartPacket() called\n");
3088
3089 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
3090
3091 IrpStack = IoGetCurrentIrpStackLocation(DeviceObject->CurrentIrp);
3092 Srb = IrpStack->Parameters.Scsi.Srb;
3093
3094 /* Get LUN extension */
3095 LunExtension = SpiGetLunExtension(DeviceExtension,
3096 Srb->PathId,
3097 Srb->TargetId,
3098 Srb->Lun);
3099
3100 /* Check if we are in a reset state */
3101 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET)
3102 {
3103 /* Mark the we've got requests while being in the reset state */
3104 DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET_REQUEST;
3105 return TRUE;
3106 }
3107
3108 /* Set the time out value */
3109 DeviceExtension->TimerCount = Srb->TimeOutValue;
3110
3111 /* We are busy */
3112 DeviceExtension->Flags |= SCSI_PORT_DEVICE_BUSY;
3113
3114 if (LunExtension->RequestTimeout != -1)
3115 {
3116 /* Timer already active */
3117 StartTimer = FALSE;
3118 }
3119 else
3120 {
3121 /* It hasn't been initialized yet */
3122 LunExtension->RequestTimeout = Srb->TimeOutValue;
3123 StartTimer = TRUE;
3124 }
3125
3126 if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
3127 {
3128 /* Handle bypass-requests */
3129
3130 /* Is this an abort request? */
3131 if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
3132 {
3133 /* Get pointer to SRB info structure */
3134 SrbInfo = SpiGetSrbData(DeviceExtension,
3135 Srb->PathId,
3136 Srb->TargetId,
3137 Srb->Lun,
3138 Srb->QueueTag);
3139
3140 /* Check if the request is still "active" */
3141 if (SrbInfo == NULL ||
3142 SrbInfo->Srb == NULL ||
3143 !(SrbInfo->Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE))
3144 {
3145 /* It's not, mark it as active then */
3146 Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
3147
3148 if (StartTimer)
3149 LunExtension->RequestTimeout = -1;
3150
3151 DPRINT("Request has been already completed, but abort request came\n");
3152 Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
3153
3154 /* Notify about request complete */
3155 ScsiPortNotification(RequestComplete,
3156 DeviceExtension->MiniPortDeviceExtension,
3157 Srb);
3158
3159 /* and about readiness for the next request */
3160 ScsiPortNotification(NextRequest,
3161 DeviceExtension->MiniPortDeviceExtension);
3162
3163 /* They might ask for some work, so queue the DPC for them */
3164 IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
3165
3166 /* We're done in this branch */
3167 return TRUE;
3168 }
3169 }
3170 else
3171 {
3172 /* Add number of queued requests */
3173 LunExtension->QueueCount++;
3174 }
3175
3176 /* Bypass requests don't need request sense */
3177 LunExtension->Flags &= ~LUNEX_NEED_REQUEST_SENSE;
3178
3179 /* Is disconnect disabled for this request? */
3180 if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
3181 {
3182 /* Set the corresponding flag */
3183 DeviceExtension->Flags &= ~SCSI_PORT_DISCONNECT_ALLOWED;
3184 }
3185
3186 /* Transfer timeout value from Srb to Lun */
3187 LunExtension->RequestTimeout = Srb->TimeOutValue;
3188 }
3189 else
3190 {
3191 if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
3192 {
3193 /* It's a disconnect, so no more requests can go */
3194 DeviceExtension->Flags &= ~SCSI_PORT_DISCONNECT_ALLOWED;
3195 }
3196
3197 LunExtension->Flags |= SCSI_PORT_LU_ACTIVE;
3198
3199 /* Increment queue count */
3200 LunExtension->QueueCount++;
3201
3202 /* If it's tagged - special thing */
3203 if (Srb->QueueTag != SP_UNTAGGED)
3204 {
3205 SrbInfo = &DeviceExtension->SrbInfo[Srb->QueueTag - 1];
3206
3207 /* Chek for consistency */
3208 ASSERT(SrbInfo->Requests.Blink == NULL);
3209
3210 /* Insert it into the list of requests */
3211 InsertTailList(&LunExtension->SrbInfo.Requests, &SrbInfo->Requests);
3212 }
3213 }
3214
3215 /* Mark this Srb active */
3216 Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
3217
3218 /* Call HwStartIo routine */
3219 Result = DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
3220 Srb);
3221
3222 /* If notification is needed, then request a DPC */
3223 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
3224 IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
3225
3226 return Result;
3227 }
3228
3229 IO_ALLOCATION_ACTION
3230 NTAPI
3231 SpiAdapterControl(PDEVICE_OBJECT DeviceObject,
3232 PIRP Irp,
3233 PVOID MapRegisterBase,
3234 PVOID Context)
3235 {
3236 PSCSI_REQUEST_BLOCK Srb;
3237 PSCSI_SG_ADDRESS ScatterGatherList;
3238 KIRQL CurrentIrql;
3239 PIO_STACK_LOCATION IrpStack;
3240 ULONG TotalLength = 0;
3241 PSCSI_REQUEST_BLOCK_INFO SrbInfo;
3242 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
3243 PUCHAR DataVA;
3244 BOOLEAN WriteToDevice;
3245
3246 /* Get pointers to SrbInfo and DeviceExtension */
3247 SrbInfo = (PSCSI_REQUEST_BLOCK_INFO)Context;
3248 DeviceExtension = DeviceObject->DeviceExtension;
3249
3250 /* Get pointer to SRB */
3251 IrpStack = IoGetCurrentIrpStackLocation(Irp);
3252 Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
3253
3254 /* Depending on the map registers number, we allocate
3255 either from NonPagedPool, or from our static list */
3256 if (SrbInfo->NumberOfMapRegisters > MAX_SG_LIST)
3257 {
3258 SrbInfo->ScatterGather = ExAllocatePoolWithTag(
3259 NonPagedPool, SrbInfo->NumberOfMapRegisters * sizeof(SCSI_SG_ADDRESS), TAG_SCSIPORT);
3260
3261 if (SrbInfo->ScatterGather == NULL)
3262 ASSERT(FALSE);
3263
3264 Srb->SrbFlags |= SRB_FLAGS_SGLIST_FROM_POOL;
3265 }
3266 else
3267 {
3268 SrbInfo->ScatterGather = SrbInfo->ScatterGatherList;
3269 }
3270
3271 /* Use chosen SG list source */
3272 ScatterGatherList = SrbInfo->ScatterGather;
3273
3274 /* Save map registers base */
3275 SrbInfo->BaseOfMapRegister = MapRegisterBase;
3276
3277 /* Determine WriteToDevice flag */
3278 WriteToDevice = Srb->SrbFlags & SRB_FLAGS_DATA_OUT ? TRUE : FALSE;
3279
3280 /* Get virtual address of the data buffer */
3281 DataVA = (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress) +
3282 ((PCHAR)Srb->DataBuffer - SrbInfo->DataOffset);
3283
3284 /* Build the actual SG list */
3285 while (TotalLength < Srb->DataTransferLength)
3286 {
3287 if (!ScatterGatherList)
3288 break;
3289
3290 ScatterGatherList->Length = Srb->DataTransferLength - TotalLength;
3291 ScatterGatherList->PhysicalAddress = IoMapTransfer(DeviceExtension->AdapterObject,
3292 Irp->MdlAddress,
3293 MapRegisterBase,
3294 DataVA + TotalLength,
3295 &ScatterGatherList->Length,
3296 WriteToDevice);
3297
3298 TotalLength += ScatterGatherList->Length;
3299 ScatterGatherList++;
3300 }
3301
3302 /* Schedule an active request */
3303 InterlockedIncrement(&DeviceExtension->ActiveRequestCounter );
3304 KeAcquireSpinLock(&DeviceExtension->SpinLock, &CurrentIrql);
3305 KeSynchronizeExecution(DeviceExtension->Interrupt[0],
3306 ScsiPortStartPacket,
3307 DeviceObject);
3308 KeReleaseSpinLock(&DeviceExtension->SpinLock, CurrentIrql);
3309
3310 return DeallocateObjectKeepRegisters;
3311 }
3312
3313 static PSCSI_PORT_LUN_EXTENSION
3314 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
3315 {
3316 PSCSI_PORT_LUN_EXTENSION LunExtension;
3317 ULONG LunExtensionSize;
3318
3319 DPRINT("SpiAllocateLunExtension (%p)\n",
3320 DeviceExtension);
3321
3322 /* Round LunExtensionSize first to the sizeof LONGLONG */
3323 LunExtensionSize = (DeviceExtension->LunExtensionSize +
3324 sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1);
3325
3326 LunExtensionSize += sizeof(SCSI_PORT_LUN_EXTENSION);
3327 DPRINT("LunExtensionSize %lu\n", LunExtensionSize);
3328
3329 LunExtension = ExAllocatePoolWithTag(NonPagedPool, LunExtensionSize, TAG_SCSIPORT);
3330 if (LunExtension == NULL)
3331 {
3332 DPRINT1("Out of resources!\n");
3333 return NULL;
3334 }
3335
3336 /* Zero everything */
3337 RtlZeroMemory(LunExtension, LunExtensionSize);
3338
3339 /* Initialize a list of requests */
3340 InitializeListHead(&LunExtension->SrbInfo.Requests);
3341
3342 /* Initialize timeout counter */
3343 LunExtension->RequestTimeout = -1;
3344
3345 /* Set maximum queue size */
3346 LunExtension->MaxQueueCount = 256;
3347
3348 /* Initialize request queue */
3349 KeInitializeDeviceQueue (&LunExtension->DeviceQueue);
3350
3351 return LunExtension;
3352 }
3353
3354 static PSCSI_PORT_LUN_EXTENSION
3355 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
3356 IN UCHAR PathId,
3357 IN UCHAR TargetId,
3358 IN UCHAR Lun)
3359 {
3360 PSCSI_PORT_LUN_EXTENSION LunExtension;
3361
3362 DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
3363 DeviceExtension, PathId, TargetId, Lun);
3364
3365 /* Get appropriate list */
3366 LunExtension = DeviceExtension->LunExtensionList[(TargetId + Lun) % LUS_NUMBER];
3367
3368 /* Iterate it until we find what we need */
3369 while (LunExtension)
3370 {
3371 if (LunExtension->TargetId == TargetId &&
3372 LunExtension->Lun == Lun &&
3373 LunExtension->PathId == PathId)
3374 {
3375 /* All matches, return */
3376 return LunExtension;
3377 }
3378
3379 /* Advance to the next item */
3380 LunExtension = LunExtension->Next;
3381 }
3382
3383 /* We did not find anything */
3384 DPRINT("Nothing found\n");
3385 return NULL;
3386 }
3387
3388 static PSCSI_REQUEST_BLOCK_INFO
3389 SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
3390 PSCSI_PORT_LUN_EXTENSION LunExtension,
3391 PSCSI_REQUEST_BLOCK Srb)
3392 {
3393 PCHAR SrbExtension;
3394 PSCSI_REQUEST_BLOCK_INFO SrbInfo;
3395
3396 /* Spinlock must be held while this function executes */
3397 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
3398
3399 /* Allocate SRB data structure */
3400 if (DeviceExtension->NeedSrbDataAlloc)
3401 {
3402 /* Treat the abort request in a special way */
3403 if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
3404 {
3405 SrbInfo = SpiGetSrbData(DeviceExtension,
3406 Srb->PathId,
3407 Srb->TargetId,
3408 Srb->Lun,
3409 Srb->QueueTag);
3410 }
3411 else if (Srb->SrbFlags &
3412 (SRB_FLAGS_QUEUE_ACTION_ENABLE | SRB_FLAGS_NO_QUEUE_FREEZE) &&
3413 !(Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
3414 )
3415 {
3416 /* Do not process tagged commands if need request sense is set */
3417 if (LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE)
3418 {
3419 ASSERT(!(LunExtension->Flags & LUNEX_REQUEST_PENDING));
3420
3421 LunExtension->PendingRequest = Srb->OriginalRequest;
3422 LunExtension->Flags |= LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE;
3423
3424 /* Relese the spinlock and return */
3425 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3426 return NULL;
3427 }
3428
3429 ASSERT(LunExtension->SrbInfo.Srb == NULL);
3430 SrbInfo = DeviceExtension->FreeSrbInfo;
3431
3432 if (SrbInfo == NULL)
3433 {
3434 /* No SRB structures left in the list. We have to leave
3435 and wait while we are called again */
3436
3437 DeviceExtension->Flags |= SCSI_PORT_REQUEST_PENDING;
3438 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3439 return NULL;
3440 }
3441
3442 DeviceExtension->FreeSrbInfo = (PSCSI_REQUEST_BLOCK_INFO)SrbInfo->Requests.Flink;
3443
3444 /* QueueTag must never be 0, so +1 to it */
3445 Srb->QueueTag = (UCHAR)(SrbInfo - DeviceExtension->SrbInfo) + 1;
3446 }
3447 else
3448 {
3449 /* Usual untagged command */
3450 if (
3451 (!IsListEmpty(&LunExtension->SrbInfo.Requests) ||
3452 LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE) &&
3453 !(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
3454 )
3455 {
3456 /* Mark it as pending and leave */
3457 ASSERT(!(LunExtension->Flags & LUNEX_REQUEST_PENDING));
3458 LunExtension->Flags |= LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE;
3459 LunExtension->PendingRequest = Srb->OriginalRequest;
3460
3461 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3462 return(NULL);
3463 }
3464
3465 Srb->QueueTag = SP_UNTAGGED;
3466 SrbInfo = &LunExtension->SrbInfo;
3467 }
3468 }
3469 else
3470 {
3471 Srb->QueueTag = SP_UNTAGGED;
3472 SrbInfo = &LunExtension->SrbInfo;
3473 }
3474
3475 /* Allocate SRB extension structure */
3476 if (DeviceExtension->NeedSrbExtensionAlloc)
3477 {
3478 /* Check the list of free extensions */
3479 SrbExtension = DeviceExtension->FreeSrbExtensions;
3480
3481 /* If no free extensions... */
3482 if (SrbExtension == NULL)
3483 {
3484 /* Free SRB data */
3485 if (Srb->Function != SRB_FUNCTION_ABORT_COMMAND &&
3486 Srb->QueueTag != SP_UNTAGGED)
3487 {
3488 SrbInfo->Requests.Blink = NULL;
3489 SrbInfo->Requests.Flink = (PLIST_ENTRY)DeviceExtension->FreeSrbInfo;
3490 DeviceExtension->FreeSrbInfo = SrbInfo;
3491 }
3492
3493 /* Return, in order to be called again later */
3494 DeviceExtension->Flags |= SCSI_PORT_REQUEST_PENDING;
3495 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3496 return NULL;
3497 }
3498
3499 /* Remove that free SRB extension from the list (since
3500 we're going to use it) */
3501 DeviceExtension->FreeSrbExtensions = *((PVOID *)SrbExtension);
3502
3503 /* Spinlock can be released now */
3504 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3505
3506 Srb->SrbExtension = SrbExtension;
3507
3508 if (Srb->SenseInfoBuffer != NULL &&
3509 DeviceExtension->SupportsAutoSense)
3510 {
3511 /* Store pointer to the SenseInfo buffer */
3512 SrbInfo->SaveSenseRequest = Srb->SenseInfoBuffer;
3513
3514 /* Does data fit the buffer? */
3515 if (Srb->SenseInfoBufferLength > sizeof(SENSE_DATA))
3516 {
3517 /* No, disabling autosense at all */
3518 Srb->SrbFlags |= SRB_FLAGS_DISABLE_AUTOSENSE;
3519 }
3520 else
3521 {
3522 /* Yes, update the buffer pointer */
3523 Srb->SenseInfoBuffer = SrbExtension + DeviceExtension->SrbExtensionSize;
3524 }
3525 }
3526 }
3527 else
3528 {
3529 /* Cleanup... */
3530 Srb->SrbExtension = NULL;
3531 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3532 }
3533
3534 return SrbInfo;
3535 }
3536
3537
3538 static NTSTATUS
3539 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject,
3540 IN PSCSI_LUN_INFO LunInfo)
3541 {
3542 IO_STATUS_BLOCK IoStatusBlock;
3543 PIO_STACK_LOCATION IrpStack;
3544 KEVENT Event;
3545 KIRQL Irql;
3546 PIRP Irp;
3547 NTSTATUS Status;
3548 PINQUIRYDATA InquiryBuffer;
3549 PSENSE_DATA SenseBuffer;
3550 BOOLEAN KeepTrying = TRUE;
3551 ULONG RetryCount = 0;
3552 SCSI_REQUEST_BLOCK Srb;
3553 PCDB Cdb;
3554 PSCSI_PORT_LUN_EXTENSION LunExtension;
3555 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
3556
3557 DPRINT ("SpiSendInquiry() called\n");
3558
3559 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
3560
3561 InquiryBuffer = ExAllocatePoolWithTag (NonPagedPool, INQUIRYDATABUFFERSIZE, TAG_SCSIPORT);
3562 if (InquiryBuffer == NULL)
3563 return STATUS_INSUFFICIENT_RESOURCES;
3564
3565 SenseBuffer = ExAllocatePoolWithTag (NonPagedPool, SENSE_BUFFER_SIZE, TAG_SCSIPORT);
3566 if (SenseBuffer == NULL)
3567 {
3568 ExFreePool(InquiryBuffer);
3569 return STATUS_INSUFFICIENT_RESOURCES;
3570 }
3571
3572 while (KeepTrying)
3573 {
3574 /* Initialize event for waiting */
3575 KeInitializeEvent(&Event,
3576 NotificationEvent,
3577 FALSE);
3578
3579 /* Create an IRP */
3580 Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_IN,
3581 DeviceObject,
3582 NULL,
3583 0,
3584 InquiryBuffer,
3585 INQUIRYDATABUFFERSIZE,
3586 TRUE,
3587 &Event,
3588 &IoStatusBlock);
3589 if (Irp == NULL)
3590 {
3591 DPRINT("IoBuildDeviceIoControlRequest() failed\n");
3592 return STATUS_INSUFFICIENT_RESOURCES;
3593 }
3594
3595 /* Prepare SRB */
3596 RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
3597
3598 Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
3599 Srb.OriginalRequest = Irp;
3600 Srb.PathId = LunInfo->PathId;
3601 Srb.TargetId = LunInfo->TargetId;
3602 Srb.Lun = LunInfo->Lun;
3603 Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
3604 Srb.SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
3605 Srb.TimeOutValue = 4;
3606 Srb.CdbLength = 6;
3607
3608 Srb.SenseInfoBuffer = SenseBuffer;
3609 Srb.SenseInfoBufferLength = SENSE_BUFFER_SIZE;
3610
3611 Srb.DataBuffer = InquiryBuffer;
3612 Srb.DataTransferLength = INQUIRYDATABUFFERSIZE;
3613
3614 /* Attach Srb to the Irp */
3615 IrpStack = IoGetNextIrpStackLocation (Irp);
3616 IrpStack->Parameters.Scsi.Srb = &Srb;
3617
3618 /* Fill in CDB */
3619 Cdb = (PCDB)Srb.Cdb;
3620 Cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
3621 Cdb->CDB6INQUIRY.LogicalUnitNumber = LunInfo->Lun;
3622 Cdb->CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE;
3623
3624 /* Call the driver */
3625 Status = IoCallDriver(DeviceObject, Irp);
3626
3627 /* Wait for it to complete */
3628 if (Status == STATUS_PENDING)
3629 {
3630 DPRINT("SpiSendInquiry(): Waiting for the driver to process request...\n");
3631 KeWaitForSingleObject(&Event,
3632 Executive,
3633 KernelMode,
3634 FALSE,
3635 NULL);
3636 Status = IoStatusBlock.Status;
3637 }
3638
3639 DPRINT("SpiSendInquiry(): Request processed by driver, status = 0x%08X\n", Status);
3640
3641 if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_SUCCESS)
3642 {
3643 /* All fine, copy data over */
3644 RtlCopyMemory(LunInfo->InquiryData,
3645 InquiryBuffer,
3646 INQUIRYDATABUFFERSIZE);
3647
3648 Status = STATUS_SUCCESS;
3649 KeepTrying = FALSE;
3650 }
3651 else
3652 {
3653 DPRINT("Inquiry SRB failed with SrbStatus 0x%08X\n", Srb.SrbStatus);
3654 /* Check if the queue is frozen */
3655 if (Srb.SrbStatus & SRB_STATUS_QUEUE_FROZEN)
3656 {
3657 /* Something weird happened, deal with it (unfreeze the queue) */
3658 KeepTrying = FALSE;
3659
3660 DPRINT("SpiSendInquiry(): the queue is frozen at TargetId %d\n", Srb.TargetId);
3661
3662 LunExtension = SpiGetLunExtension(DeviceExtension,
3663 LunInfo->PathId,
3664 LunInfo->TargetId,
3665 LunInfo->Lun);
3666
3667 /* Clear frozen flag */
3668 LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
3669
3670 /* Acquire the spinlock */
3671 KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
3672
3673 /* Process the request */
3674 SpiGetNextRequestFromLun(DeviceObject->DeviceExtension, LunExtension);
3675
3676 /* SpiGetNextRequestFromLun() releases the spinlock,
3677 so we just lower irql back to what it was before */
3678 KeLowerIrql(Irql);
3679 }
3680
3681 /* Check if data overrun happened */
3682 if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN)
3683 {
3684 DPRINT("Data overrun at TargetId %d\n", LunInfo->TargetId);
3685 /* Nothing dramatic, just copy data, but limiting the size */
3686 RtlCopyMemory(LunInfo->InquiryData,
3687 InquiryBuffer,
3688 (Srb.DataTransferLength > INQUIRYDATABUFFERSIZE) ?
3689 INQUIRYDATABUFFERSIZE : Srb.DataTransferLength);
3690
3691 Status = STATUS_SUCCESS;
3692 KeepTrying = FALSE;
3693 }
3694 else if ((Srb.SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
3695 SenseBuffer->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST)
3696 {
3697 /* LUN is not valid, but some device responds there.
3698 Mark it as invalid anyway */
3699
3700 Status = STATUS_INVALID_DEVICE_REQUEST;
3701 KeepTrying = FALSE;
3702 }
3703 else
3704 {
3705 /* Retry a couple of times if no timeout happened */
3706 if ((RetryCount < 2) &&
3707 (SRB_STATUS(Srb.SrbStatus) != SRB_STATUS_NO_DEVICE) &&
3708 (SRB_STATUS(Srb.SrbStatus) != SRB_STATUS_SELECTION_TIMEOUT))
3709 {
3710 RetryCount++;
3711 KeepTrying = TRUE;
3712 }
3713 else
3714 {
3715 /* That's all, go to exit */
3716 KeepTrying = FALSE;
3717
3718 /* Set status according to SRB status */
3719 if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_BAD_FUNCTION ||
3720 SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_BAD_SRB_BLOCK_LENGTH)
3721 {
3722 Status = STATUS_INVALID_DEVICE_REQUEST;
3723 }
3724 else
3725 {
3726 Status = STATUS_IO_DEVICE_ERROR;
3727 }
3728 }
3729 }
3730 }
3731 }
3732
3733 /* Free buffers */
3734 ExFreePool(InquiryBuffer);
3735 ExFreePool(SenseBuffer);
3736
3737 DPRINT("SpiSendInquiry() done with Status 0x%08X\n", Status);
3738
3739 return Status;
3740 }
3741
3742
3743 /* Scans all SCSI buses */
3744 static VOID
3745 SpiScanAdapter(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
3746 {
3747 PSCSI_PORT_LUN_EXTENSION LunExtension;
3748 ULONG Bus;
3749 ULONG Target;
3750 ULONG Lun;
3751 PSCSI_BUS_SCAN_INFO BusScanInfo;
3752 PSCSI_LUN_INFO LastLunInfo, LunInfo, LunInfoExists;
3753 BOOLEAN DeviceExists;
3754 ULONG Hint;
3755 NTSTATUS Status;
3756 ULONG DevicesFound;
3757
3758 DPRINT("SpiScanAdapter() called\n");
3759
3760 /* Scan all buses */
3761 for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
3762 {
3763 DPRINT(" Scanning bus %d\n", Bus);
3764 DevicesFound = 0;
3765
3766 /* Get pointer to the scan information */
3767 BusScanInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus];
3768
3769 if (BusScanInfo)
3770 {
3771 /* Find the last LUN info in the list */
3772 LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
3773 LastLunInfo = LunInfo;
3774
3775 while (LunInfo != NULL)
3776 {
3777 LastLunInfo = LunInfo;
3778 LunInfo = LunInfo->Next;
3779 }
3780 }
3781 else
3782 {
3783 /* We need to allocate this buffer */
3784 BusScanInfo = ExAllocatePoolWithTag(NonPagedPool, sizeof(SCSI_BUS_SCAN_INFO), TAG_SCSIPORT);
3785
3786 if (!BusScanInfo)
3787 {
3788