-avoid dereferencing of NULL pointers
[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
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS Storage Stack
23 * FILE: drivers/storage/scsiport/scsiport.c
24 * PURPOSE: SCSI port driver
25 * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
26 * Aleksey Bragin (aleksey reactos org)
27 */
28
29 /* INCLUDES *****************************************************************/
30
31 #include <ntddk.h>
32 #include <srb.h>
33 #include <scsi.h>
34 #include <ntddscsi.h>
35 #include <ntddstor.h>
36 #include <ntdddisk.h>
37 #include <stdio.h>
38 #include <stdarg.h>
39
40 #ifndef NDEBUG
41 #define NDEBUG
42 #endif
43 #include <debug.h>
44
45 #include "scsiport_int.h"
46
47 #ifdef _MSC_VER
48 #define STDCALL
49 #define DDKAPI
50 #endif
51
52 ULONG InternalDebugLevel = 0x00;
53
54 /* TYPES *********************************************************************/
55
56 /* GLOBALS *******************************************************************/
57
58 static BOOLEAN
59 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject,
60 IN PDEVICE_OBJECT DeviceObject,
61 IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
62 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,
63 IN PUNICODE_STRING RegistryPath,
64 IN ULONG BusNumber,
65 IN OUT PPCI_SLOT_NUMBER NextSlotNumber);
66
67 static NTSTATUS STDCALL
68 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
69 IN PIRP Irp);
70
71 static DRIVER_DISPATCH ScsiPortDispatchScsi;
72 static NTSTATUS STDCALL
73 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
74 IN PIRP Irp);
75
76 static NTSTATUS STDCALL
77 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
78 IN PIRP Irp);
79
80 static DRIVER_STARTIO ScsiPortStartIo;
81 static VOID STDCALL
82 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
83 IN PIRP Irp);
84
85 static BOOLEAN STDCALL
86 ScsiPortStartPacket(IN OUT PVOID Context);
87
88 IO_ALLOCATION_ACTION
89 STDCALL
90 SpiAdapterControl(PDEVICE_OBJECT DeviceObject, PIRP Irp,
91 PVOID MapRegisterBase, PVOID Context);
92
93 static PSCSI_PORT_LUN_EXTENSION
94 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
95
96 static PSCSI_PORT_LUN_EXTENSION
97 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
98 IN UCHAR PathId,
99 IN UCHAR TargetId,
100 IN UCHAR Lun);
101
102 static PSCSI_REQUEST_BLOCK_INFO
103 SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
104 PSCSI_PORT_LUN_EXTENSION LunExtension,
105 PSCSI_REQUEST_BLOCK Srb);
106
107 static NTSTATUS
108 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject,
109 IN PSCSI_LUN_INFO LunInfo);
110
111 static VOID
112 SpiScanAdapter (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
113
114 static NTSTATUS
115 SpiGetInquiryData (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
116 IN PIRP Irp);
117
118 static PSCSI_REQUEST_BLOCK_INFO
119 SpiGetSrbData(IN PVOID DeviceExtension,
120 IN UCHAR PathId,
121 IN UCHAR TargetId,
122 IN UCHAR Lun,
123 IN UCHAR QueueTag);
124
125 static KSERVICE_ROUTINE ScsiPortIsr;
126 static BOOLEAN STDCALL
127 ScsiPortIsr(IN PKINTERRUPT Interrupt,
128 IN PVOID ServiceContext);
129
130 static VOID STDCALL
131 ScsiPortDpcForIsr(IN PKDPC Dpc,
132 IN PDEVICE_OBJECT DpcDeviceObject,
133 IN PIRP DpcIrp,
134 IN PVOID DpcContext);
135
136 static VOID STDCALL
137 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
138 PVOID Context);
139
140 static NTSTATUS
141 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
142 PUNICODE_STRING RegistryPath);
143
144 static NTSTATUS
145 SpiStatusSrbToNt(UCHAR SrbStatus);
146
147 static VOID
148 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
149 IN PSCSI_REQUEST_BLOCK Srb);
150
151 static IO_COMPLETION_ROUTINE SpiCompletionRoutine;
152 NTSTATUS STDCALL
153 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject,
154 PIRP Irp,
155 PVOID Context);
156
157 static VOID
158 STDCALL
159 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
160 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo,
161 OUT PBOOLEAN NeedToCallStartIo);
162
163 VOID STDCALL
164 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
165 IN PSCSI_PORT_LUN_EXTENSION LunExtension);
166
167 VOID STDCALL
168 SpiMiniportTimerDpc(IN struct _KDPC *Dpc,
169 IN PVOID DeviceObject,
170 IN PVOID SystemArgument1,
171 IN PVOID SystemArgument2);
172
173 static NTSTATUS
174 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
175 PHW_INITIALIZATION_DATA HwInitData,
176 PCONFIGURATION_INFO InternalConfigInfo,
177 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
178 BOOLEAN FirstCall);
179
180 NTSTATUS STDCALL
181 SpQueryDeviceCallout(IN PVOID Context,
182 IN PUNICODE_STRING PathName,
183 IN INTERFACE_TYPE BusType,
184 IN ULONG BusNumber,
185 IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
186 IN CONFIGURATION_TYPE ControllerType,
187 IN ULONG ControllerNumber,
188 IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
189 IN CONFIGURATION_TYPE PeripheralType,
190 IN ULONG PeripheralNumber,
191 IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation);
192
193 static VOID
194 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
195 IN HANDLE Key,
196 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
197 IN PCONFIGURATION_INFO InternalConfigInfo,
198 IN PUCHAR Buffer);
199
200 static VOID
201 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData,
202 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor,
203 IN PPORT_CONFIGURATION_INFORMATION PortConfig);
204
205 static PCM_RESOURCE_LIST
206 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
207 PPORT_CONFIGURATION_INFORMATION PortConfig);
208
209 static VOID
210 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
211
212 static NTSTATUS
213 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
214 PIRP Irp);
215
216 static NTSTATUS
217 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, ULONG NonCachedSize);
218
219
220
221 /* FUNCTIONS *****************************************************************/
222
223 /**********************************************************************
224 * NAME EXPORTED
225 * DriverEntry
226 *
227 * DESCRIPTION
228 * This function initializes the driver.
229 *
230 * RUN LEVEL
231 * PASSIVE_LEVEL
232 *
233 * ARGUMENTS
234 * DriverObject
235 * System allocated Driver Object for this driver.
236 *
237 * RegistryPath
238 * Name of registry driver service key.
239 *
240 * RETURN VALUE
241 * Status.
242 */
243
244 NTSTATUS STDCALL
245 DriverEntry(IN PDRIVER_OBJECT DriverObject,
246 IN PUNICODE_STRING RegistryPath)
247 {
248 DPRINT("ScsiPort Driver %s\n", VERSION);
249 return(STATUS_SUCCESS);
250 }
251
252
253 /**********************************************************************
254 * NAME EXPORTED
255 * ScsiDebugPrint
256 *
257 * DESCRIPTION
258 * Prints debugging messages.
259 *
260 * RUN LEVEL
261 * PASSIVE_LEVEL
262 *
263 * ARGUMENTS
264 * DebugPrintLevel
265 * Debug level of the given message.
266 *
267 * DebugMessage
268 * Pointer to printf()-compatible format string.
269 *
270 * ...
271 Additional output data (see printf()).
272 *
273 * RETURN VALUE
274 * None.
275 *
276 * @implemented
277 */
278
279 VOID
280 ScsiDebugPrint(IN ULONG DebugPrintLevel,
281 IN PCHAR DebugMessage,
282 ...)
283 {
284 char Buffer[256];
285 va_list ap;
286
287 if (DebugPrintLevel > InternalDebugLevel)
288 return;
289
290 va_start(ap, DebugMessage);
291 vsprintf(Buffer, DebugMessage, ap);
292 va_end(ap);
293
294 DbgPrint(Buffer);
295 }
296
297
298 /*
299 * @unimplemented
300 */
301 VOID STDCALL
302 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension,
303 IN UCHAR PathId,
304 IN UCHAR TargetId,
305 IN UCHAR Lun,
306 IN UCHAR SrbStatus)
307 {
308 DPRINT("ScsiPortCompleteRequest()\n");
309 UNIMPLEMENTED;
310 }
311
312 /*
313 * @unimplemented
314 */
315 VOID STDCALL
316 ScsiPortFlushDma(IN PVOID HwDeviceExtension)
317 {
318 DPRINT("ScsiPortFlushDma()\n");
319 UNIMPLEMENTED;
320 }
321
322
323 /*
324 * @implemented
325 */
326 VOID STDCALL
327 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension,
328 IN PVOID MappedAddress)
329 {
330 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
331 PMAPPED_ADDRESS NextMa, LastMa;
332
333 //DPRINT("ScsiPortFreeDeviceBase() called\n");
334
335 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
336 SCSI_PORT_DEVICE_EXTENSION,
337 MiniPortDeviceExtension);
338
339
340 /* Initialize our pointers */
341 NextMa = DeviceExtension->MappedAddressList;
342 LastMa = NextMa;
343
344 while (NextMa)
345 {
346 if (NextMa->MappedAddress == MappedAddress)
347 {
348 /* Unmap it first */
349 MmUnmapIoSpace(MappedAddress, NextMa->NumberOfBytes);
350
351 /* Remove it from the list */
352 if (NextMa == DeviceExtension->MappedAddressList)
353 {
354 /* Remove the first entry */
355 DeviceExtension->MappedAddressList = NextMa->NextMappedAddress;
356 }
357 else
358 {
359 LastMa->NextMappedAddress = NextMa->NextMappedAddress;
360 }
361
362 /* Free the resources and quit */
363 ExFreePool(NextMa);
364
365 return;
366 }
367 else
368 {
369 LastMa = NextMa;
370 NextMa = NextMa->NextMappedAddress;
371 }
372 }
373 }
374
375
376 /*
377 * @implemented
378 */
379 ULONG STDCALL
380 ScsiPortGetBusData(IN PVOID DeviceExtension,
381 IN ULONG BusDataType,
382 IN ULONG SystemIoBusNumber,
383 IN ULONG SlotNumber,
384 IN PVOID Buffer,
385 IN ULONG Length)
386 {
387 return(HalGetBusData(BusDataType,
388 SystemIoBusNumber,
389 SlotNumber,
390 Buffer,
391 Length));
392 }
393
394
395 /*
396 * @implemented
397 */
398 PVOID STDCALL
399 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension,
400 IN INTERFACE_TYPE BusType,
401 IN ULONG SystemIoBusNumber,
402 IN SCSI_PHYSICAL_ADDRESS IoAddress,
403 IN ULONG NumberOfBytes,
404 IN BOOLEAN InIoSpace)
405 {
406 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
407 PHYSICAL_ADDRESS TranslatedAddress;
408 PMAPPED_ADDRESS DeviceBase;
409 ULONG AddressSpace;
410 PVOID MappedAddress;
411
412 //DPRINT ("ScsiPortGetDeviceBase() called\n");
413
414 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
415 SCSI_PORT_DEVICE_EXTENSION,
416 MiniPortDeviceExtension);
417
418 AddressSpace = (ULONG)InIoSpace;
419 if (HalTranslateBusAddress(BusType,
420 SystemIoBusNumber,
421 IoAddress,
422 &AddressSpace,
423 &TranslatedAddress) == FALSE)
424 {
425 return NULL;
426 }
427
428 /* i/o space */
429 if (AddressSpace != 0)
430 return((PVOID)TranslatedAddress.u.LowPart);
431
432 MappedAddress = MmMapIoSpace(TranslatedAddress,
433 NumberOfBytes,
434 FALSE);
435
436 DeviceBase = ExAllocatePoolWithTag(NonPagedPool,
437 sizeof(MAPPED_ADDRESS), TAG_SCSIPORT);
438
439 if (DeviceBase == NULL)
440 return MappedAddress;
441
442 DeviceBase->MappedAddress = MappedAddress;
443 DeviceBase->NumberOfBytes = NumberOfBytes;
444 DeviceBase->IoAddress = IoAddress;
445 DeviceBase->BusNumber = SystemIoBusNumber;
446
447 /* Link it to the Device Extension list */
448 DeviceBase->NextMappedAddress = DeviceExtension->MappedAddressList;
449 DeviceExtension->MappedAddressList = DeviceBase;
450
451 return MappedAddress;
452 }
453
454 /*
455 * @implemented
456 */
457 PVOID STDCALL
458 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension,
459 IN UCHAR PathId,
460 IN UCHAR TargetId,
461 IN UCHAR Lun)
462 {
463 UNIMPLEMENTED;
464 #if 0
465 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
466 PSCSI_PORT_LUN_EXTENSION LunExtension;
467 PLIST_ENTRY Entry;
468
469 DPRINT("ScsiPortGetLogicalUnit() called\n");
470
471 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
472 SCSI_PORT_DEVICE_EXTENSION,
473 MiniPortDeviceExtension);
474 if (IsListEmpty(&DeviceExtension->LunExtensionListHead))
475 return NULL;
476
477 Entry = DeviceExtension->LunExtensionListHead.Flink;
478 while (Entry != &DeviceExtension->LunExtensionListHead)
479 {
480 LunExtension = CONTAINING_RECORD(Entry,
481 SCSI_PORT_LUN_EXTENSION,
482 List);
483 if (LunExtension->PathId == PathId &&
484 LunExtension->TargetId == TargetId &&
485 LunExtension->Lun == Lun)
486 {
487 return (PVOID)&LunExtension->MiniportLunExtension;
488 }
489
490 Entry = Entry->Flink;
491 }
492 #endif
493 return NULL;
494 }
495
496
497 /*
498 * @unimplemented
499 */
500 SCSI_PHYSICAL_ADDRESS STDCALL
501 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension,
502 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
503 IN PVOID VirtualAddress,
504 OUT ULONG *Length)
505 {
506 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
507 SCSI_PHYSICAL_ADDRESS PhysicalAddress;
508 ULONG BufferLength = 0;
509 ULONG Offset;
510 PSCSI_SG_ADDRESS SGList;
511 PSCSI_REQUEST_BLOCK_INFO SrbInfo;
512
513 DPRINT("ScsiPortGetPhysicalAddress(%p %p %p %p)\n",
514 HwDeviceExtension, Srb, VirtualAddress, Length);
515
516 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
517 SCSI_PORT_DEVICE_EXTENSION,
518 MiniPortDeviceExtension);
519
520 if (Srb == NULL || Srb->SenseInfoBuffer == VirtualAddress)
521 {
522 /* Simply look it up in the allocated common buffer */
523 Offset = (PUCHAR)VirtualAddress - (PUCHAR)DeviceExtension->SrbExtensionBuffer;
524
525 BufferLength = DeviceExtension->CommonBufferLength - Offset;
526 PhysicalAddress.QuadPart = DeviceExtension->PhysicalAddress.QuadPart + Offset;
527 }
528 else if (DeviceExtension->MapRegisters)
529 {
530 /* Scatter-gather list must be used */
531 SrbInfo = SpiGetSrbData(DeviceExtension,
532 Srb->PathId,
533 Srb->TargetId,
534 Srb->Lun,
535 Srb->QueueTag);
536
537 SGList = SrbInfo->ScatterGather;
538
539 /* Find needed item in the SG list */
540 Offset = (PCHAR)VirtualAddress - (PCHAR)Srb->DataBuffer;
541 while (Offset >= SGList->Length)
542 {
543 Offset -= SGList->Length;
544 SGList++;
545 }
546
547 /* We're done, store length and physical address */
548 BufferLength = SGList->Length - Offset;
549 PhysicalAddress.QuadPart = SGList->PhysicalAddress.QuadPart + Offset;
550 }
551 else
552 {
553 /* Nothing */
554 *Length = 0;
555 PhysicalAddress.QuadPart = (LONGLONG)(SP_UNINITIALIZED_VALUE);
556 }
557
558 *Length = BufferLength;
559 return PhysicalAddress;
560 }
561
562
563 /*
564 * @unimplemented
565 */
566 PSCSI_REQUEST_BLOCK STDCALL
567 ScsiPortGetSrb(IN PVOID DeviceExtension,
568 IN UCHAR PathId,
569 IN UCHAR TargetId,
570 IN UCHAR Lun,
571 IN LONG QueueTag)
572 {
573 DPRINT1("ScsiPortGetSrb() unimplemented\n");
574 UNIMPLEMENTED;
575 return NULL;
576 }
577
578
579 /*
580 * @implemented
581 */
582 PVOID STDCALL
583 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension,
584 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
585 IN ULONG NumberOfBytes)
586 {
587 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
588 DEVICE_DESCRIPTION DeviceDescription;
589 ULONG MapRegistersCount;
590 NTSTATUS Status;
591
592 DPRINT("ScsiPortGetUncachedExtension(%p %p %lu)\n",
593 HwDeviceExtension, ConfigInfo, NumberOfBytes);
594
595 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
596 SCSI_PORT_DEVICE_EXTENSION,
597 MiniPortDeviceExtension);
598
599 /* Check for allocated common DMA buffer */
600 if (DeviceExtension->SrbExtensionBuffer != NULL)
601 {
602 DPRINT1("The HBA has already got a common DMA buffer!\n");
603 return NULL;
604 }
605
606 /* Check for DMA adapter object */
607 if (DeviceExtension->AdapterObject == NULL)
608 {
609 /* Initialize DMA adapter description */
610 RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
611
612 DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
613 DeviceDescription.Master = ConfigInfo->Master;
614 DeviceDescription.ScatterGather = ConfigInfo->ScatterGather;
615 DeviceDescription.DemandMode = ConfigInfo->DemandMode;
616 DeviceDescription.Dma32BitAddresses = ConfigInfo->Dma32BitAddresses;
617 DeviceDescription.BusNumber = ConfigInfo->SystemIoBusNumber;
618 DeviceDescription.DmaChannel = ConfigInfo->DmaChannel;
619 DeviceDescription.InterfaceType = ConfigInfo->AdapterInterfaceType;
620 DeviceDescription.DmaWidth = ConfigInfo->DmaWidth;
621 DeviceDescription.DmaSpeed = ConfigInfo->DmaSpeed;
622 DeviceDescription.MaximumLength = ConfigInfo->MaximumTransferLength;
623 DeviceDescription.DmaPort = ConfigInfo->DmaPort;
624
625 /* Get a DMA adapter object */
626 DeviceExtension->AdapterObject =
627 HalGetAdapter(&DeviceDescription, &MapRegistersCount);
628
629 /* Fail in case of error */
630 if (DeviceExtension->AdapterObject == NULL)
631 {
632 DPRINT1("HalGetAdapter() failed\n");
633 return NULL;
634 }
635
636 /* Set number of physical breaks */
637 if (ConfigInfo->NumberOfPhysicalBreaks != 0 &&
638 MapRegistersCount > ConfigInfo->NumberOfPhysicalBreaks)
639 {
640 DeviceExtension->PortCapabilities.MaximumPhysicalPages =
641 ConfigInfo->NumberOfPhysicalBreaks;
642 }
643 else
644 {
645 DeviceExtension->PortCapabilities.MaximumPhysicalPages = MapRegistersCount;
646 }
647 }
648
649 /* Update auto request sense feature */
650 DeviceExtension->SupportsAutoSense = ConfigInfo->AutoRequestSense;
651
652 /* Update Srb extension size */
653 if (DeviceExtension->SrbExtensionSize != ConfigInfo->SrbExtensionSize)
654 DeviceExtension->SrbExtensionSize = ConfigInfo->SrbExtensionSize;
655
656 /* Update Srb extension alloc flag */
657 if (ConfigInfo->AutoRequestSense || DeviceExtension->SrbExtensionSize)
658 DeviceExtension->NeedSrbExtensionAlloc = TRUE;
659
660 /* Allocate a common DMA buffer */
661 Status = SpiAllocateCommonBuffer(DeviceExtension, NumberOfBytes);
662
663 if (!NT_SUCCESS(Status))
664 {
665 DPRINT1("SpiAllocateCommonBuffer() failed with Status = 0x%08X!\n", Status);
666 return NULL;
667 }
668
669 return DeviceExtension->NonCachedExtension;
670 }
671
672 static NTSTATUS
673 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, ULONG NonCachedSize)
674 {
675 PVOID *SrbExtension, CommonBuffer;
676 ULONG CommonBufferLength, BufSize;
677
678 /* If size is 0, set it to 16 */
679 if (!DeviceExtension->SrbExtensionSize)
680 DeviceExtension->SrbExtensionSize = 16;
681
682 /* Calculate size */
683 BufSize = DeviceExtension->SrbExtensionSize;
684
685 /* Add autosense data size if needed */
686 if (DeviceExtension->SupportsAutoSense)
687 BufSize += sizeof(SENSE_DATA);
688
689
690 /* Round it */
691 BufSize = (BufSize + sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1);
692
693 /* Sum up into the total common buffer length, and round it to page size */
694 CommonBufferLength =
695 ROUND_TO_PAGES(NonCachedSize + BufSize * DeviceExtension->RequestsNumber);
696
697 /* Allocate it */
698 if (!DeviceExtension->AdapterObject)
699 {
700 /* From nonpaged pool if there is no DMA */
701 CommonBuffer = ExAllocatePoolWithTag(NonPagedPool, CommonBufferLength, TAG_SCSIPORT);
702 }
703 else
704 {
705 /* Perform a full request since we have a DMA adapter*/
706 CommonBuffer = HalAllocateCommonBuffer(DeviceExtension->AdapterObject,
707 CommonBufferLength,
708 &DeviceExtension->PhysicalAddress,
709 FALSE );
710 }
711
712 /* Fail in case of error */
713 if (!CommonBuffer)
714 return STATUS_INSUFFICIENT_RESOURCES;
715
716 /* Zero it */
717 RtlZeroMemory(CommonBuffer, CommonBufferLength);
718
719 /* Store its size in Device Extension */
720 DeviceExtension->CommonBufferLength = CommonBufferLength;
721
722 /* SrbExtension buffer is located at the beginning of the buffer */
723 DeviceExtension->SrbExtensionBuffer = CommonBuffer;
724
725 /* Non-cached extension buffer is located at the end of
726 the common buffer */
727 if (NonCachedSize)
728 {
729 CommonBufferLength -= NonCachedSize;
730 DeviceExtension->NonCachedExtension = (PUCHAR)CommonBuffer + CommonBufferLength;
731 }
732 else
733 {
734 DeviceExtension->NonCachedExtension = NULL;
735 }
736
737 if (DeviceExtension->NeedSrbExtensionAlloc)
738 {
739 /* Look up how many SRB data structures we need */
740 DeviceExtension->SrbDataCount = CommonBufferLength / BufSize;
741
742 /* Initialize the free SRB extensions list */
743 SrbExtension = (PVOID *)CommonBuffer;
744 DeviceExtension->FreeSrbExtensions = SrbExtension;
745
746 /* Fill the remainding pointers (if we have more than 1 SRB) */
747 while (CommonBufferLength >= 2 * BufSize)
748 {
749 *SrbExtension = (PVOID*)((PCHAR)SrbExtension + BufSize);
750 SrbExtension = *SrbExtension;
751
752 CommonBufferLength -= BufSize;
753 }
754 }
755
756 return STATUS_SUCCESS;
757 }
758
759
760
761 /*
762 * @implemented
763 */
764 PVOID STDCALL
765 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension,
766 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress)
767 {
768 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
769 ULONG Offset;
770
771 DPRINT("ScsiPortGetVirtualAddress(%p %I64x)\n",
772 HwDeviceExtension, PhysicalAddress.QuadPart);
773
774 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
775 SCSI_PORT_DEVICE_EXTENSION,
776 MiniPortDeviceExtension);
777
778 if (DeviceExtension->PhysicalAddress.QuadPart > PhysicalAddress.QuadPart)
779 return NULL;
780
781 Offset = (ULONG)(PhysicalAddress.QuadPart - DeviceExtension->PhysicalAddress.QuadPart);
782
783 if (Offset >= DeviceExtension->CommonBufferLength)
784 return NULL;
785
786 return (PVOID)((ULONG_PTR)DeviceExtension->SrbExtensionBuffer + Offset);
787 }
788
789 static VOID
790 SpiInitOpenKeys(PCONFIGURATION_INFO ConfigInfo, PUNICODE_STRING RegistryPath)
791 {
792 OBJECT_ATTRIBUTES ObjectAttributes;
793 UNICODE_STRING KeyName;
794 NTSTATUS Status;
795
796 /* Open the service key */
797 InitializeObjectAttributes(&ObjectAttributes,
798 RegistryPath,
799 OBJ_CASE_INSENSITIVE,
800 NULL,
801 NULL);
802
803 Status = ZwOpenKey(&ConfigInfo->ServiceKey,
804 KEY_READ,
805 &ObjectAttributes);
806
807 if (!NT_SUCCESS(Status))
808 {
809 DPRINT1("Unable to open driver's registry key %wZ, status 0x%08x\n", RegistryPath, Status);
810 ConfigInfo->ServiceKey = NULL;
811 }
812
813 /* If we could open driver's service key, then proceed to the Parameters key */
814 if (ConfigInfo->ServiceKey != NULL)
815 {
816 RtlInitUnicodeString(&KeyName, L"Parameters");
817 InitializeObjectAttributes(&ObjectAttributes,
818 &KeyName,
819 OBJ_CASE_INSENSITIVE,
820 ConfigInfo->ServiceKey,
821 (PSECURITY_DESCRIPTOR) NULL);
822
823 /* Try to open it */
824 Status = ZwOpenKey(&ConfigInfo->DeviceKey,
825 KEY_READ,
826 &ObjectAttributes);
827
828 if (NT_SUCCESS(Status))
829 {
830 /* Yes, Parameters key exist, and it must be used instead of
831 the Service key */
832 ZwClose(ConfigInfo->ServiceKey);
833 ConfigInfo->ServiceKey = ConfigInfo->DeviceKey;
834 ConfigInfo->DeviceKey = NULL;
835 }
836 }
837
838 /* Open the Device key */
839 RtlInitUnicodeString(&KeyName, L"Device");
840 InitializeObjectAttributes(&ObjectAttributes,
841 &KeyName,
842 OBJ_CASE_INSENSITIVE,
843 ConfigInfo->ServiceKey,
844 NULL);
845
846 /* We don't check for failure here - not needed */
847 ZwOpenKey(&ConfigInfo->DeviceKey,
848 KEY_READ,
849 &ObjectAttributes);
850 }
851
852
853 /**********************************************************************
854 * NAME EXPORTED
855 * ScsiPortInitialize
856 *
857 * DESCRIPTION
858 * Initializes SCSI port driver specific data.
859 *
860 * RUN LEVEL
861 * PASSIVE_LEVEL
862 *
863 * ARGUMENTS
864 * Argument1
865 * Pointer to the miniport driver's driver object.
866 *
867 * Argument2
868 * Pointer to the miniport driver's registry path.
869 *
870 * HwInitializationData
871 * Pointer to port driver specific configuration data.
872 *
873 * HwContext
874 Miniport driver specific context.
875 *
876 * RETURN VALUE
877 * Status.
878 *
879 * @implemented
880 */
881
882 ULONG STDCALL
883 ScsiPortInitialize(IN PVOID Argument1,
884 IN PVOID Argument2,
885 IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
886 IN PVOID HwContext)
887 {
888 PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Argument1;
889 PUNICODE_STRING RegistryPath = (PUNICODE_STRING)Argument2;
890 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = NULL;
891 PCONFIGURATION_INFORMATION SystemConfig;
892 PPORT_CONFIGURATION_INFORMATION PortConfig;
893 PORT_CONFIGURATION_INFORMATION InitialPortConfig;
894 CONFIGURATION_INFO ConfigInfo;
895 ULONG DeviceExtensionSize;
896 ULONG PortConfigSize;
897 BOOLEAN Again;
898 BOOLEAN DeviceFound = FALSE;
899 BOOLEAN FirstConfigCall = TRUE;
900 ULONG Result;
901 NTSTATUS Status;
902 ULONG MaxBus;
903 ULONG BusNumber = 0;
904 PCI_SLOT_NUMBER SlotNumber;
905
906 PDEVICE_OBJECT PortDeviceObject;
907 WCHAR NameBuffer[80];
908 UNICODE_STRING DeviceName;
909 WCHAR DosNameBuffer[80];
910 UNICODE_STRING DosDeviceName;
911 PIO_SCSI_CAPABILITIES PortCapabilities;
912 ULONG MappedIrq;
913 KIRQL Dirql;
914 KAFFINITY Affinity;
915
916 PCM_RESOURCE_LIST ResourceList;
917 BOOLEAN Conflict;
918
919
920 DPRINT ("ScsiPortInitialize() called!\n");
921
922 /* Check params for validity */
923 if ((HwInitializationData->HwInitialize == NULL) ||
924 (HwInitializationData->HwStartIo == NULL) ||
925 (HwInitializationData->HwInterrupt == NULL) ||
926 (HwInitializationData->HwFindAdapter == NULL) ||
927 (HwInitializationData->HwResetBus == NULL))
928 {
929 return STATUS_INVALID_PARAMETER;
930 }
931
932 /* Set handlers */
933 DriverObject->DriverStartIo = ScsiPortStartIo;
934 DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiPortCreateClose;
935 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiPortCreateClose;
936 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiPortDeviceControl;
937 DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = ScsiPortDeviceControl;
938 DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiPortDispatchScsi;
939
940 /* Obtain configuration information */
941 SystemConfig = IoGetConfigurationInformation();
942
943 /* Zero the internal configuration info structure */
944 RtlZeroMemory(&ConfigInfo, sizeof(CONFIGURATION_INFO));
945
946 /* Zero starting slot number */
947 SlotNumber.u.AsULONG = 0;
948
949 /* Allocate space for access ranges */
950 if (HwInitializationData->NumberOfAccessRanges)
951 {
952 ConfigInfo.AccessRanges =
953 ExAllocatePoolWithTag(PagedPool,
954 HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE), TAG_SCSIPORT);
955
956 /* Fail if failed */
957 if (ConfigInfo.AccessRanges == NULL)
958 return STATUS_INSUFFICIENT_RESOURCES;
959 }
960
961 /* Open registry keys */
962 SpiInitOpenKeys(&ConfigInfo, (PUNICODE_STRING)Argument2);
963
964 /* Last adapter number = not known */
965 ConfigInfo.LastAdapterNumber = SP_UNINITIALIZED_VALUE;
966
967 /* Calculate sizes of DeviceExtension and PortConfig */
968 DeviceExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) +
969 HwInitializationData->DeviceExtensionSize;
970
971 MaxBus = (HwInitializationData->AdapterInterfaceType == PCIBus) ? 8 : 1;
972 DPRINT("MaxBus: %lu\n", MaxBus);
973
974 while (TRUE)
975 {
976 /* Create a unicode device name */
977 swprintf(NameBuffer,
978 L"\\Device\\ScsiPort%lu",
979 SystemConfig->ScsiPortCount);
980 RtlInitUnicodeString(&DeviceName, NameBuffer);
981
982 DPRINT("Creating device: %wZ\n", &DeviceName);
983
984 /* Create the port device */
985 Status = IoCreateDevice(DriverObject,
986 DeviceExtensionSize,
987 &DeviceName,
988 FILE_DEVICE_CONTROLLER,
989 0,
990 FALSE,
991 &PortDeviceObject);
992
993 if (!NT_SUCCESS(Status))
994 {
995 DPRINT1("IoCreateDevice call failed! (Status 0x%lX)\n", Status);
996 PortDeviceObject = NULL;
997 break;
998 }
999
1000 DPRINT ("Created device: %wZ (%p)\n", &DeviceName, PortDeviceObject);
1001
1002 /* Set the buffering strategy here... */
1003 PortDeviceObject->Flags |= DO_DIRECT_IO;
1004 PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT; /* FIXME: Is this really needed? */
1005
1006 /* Fill Device Extension */
1007 DeviceExtension = PortDeviceObject->DeviceExtension;
1008 DeviceExtension->Length = DeviceExtensionSize;
1009 DeviceExtension->DeviceObject = PortDeviceObject;
1010 DeviceExtension->PortNumber = SystemConfig->ScsiPortCount;
1011
1012 /* Driver's routines... */
1013 DeviceExtension->HwInitialize = HwInitializationData->HwInitialize;
1014 DeviceExtension->HwStartIo = HwInitializationData->HwStartIo;
1015 DeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
1016 DeviceExtension->HwResetBus = HwInitializationData->HwResetBus;
1017 DeviceExtension->HwDmaStarted = HwInitializationData->HwDmaStarted;
1018
1019 /* Extensions sizes */
1020 DeviceExtension->MiniPortExtensionSize = HwInitializationData->DeviceExtensionSize;
1021 DeviceExtension->LunExtensionSize = HwInitializationData->SpecificLuExtensionSize;
1022 DeviceExtension->SrbExtensionSize = HwInitializationData->SrbExtensionSize;
1023
1024 /* Round Srb extension size to the quadword */
1025 DeviceExtension->SrbExtensionSize =
1026 ~(sizeof(LONGLONG) - 1) & (DeviceExtension->SrbExtensionSize +
1027 sizeof(LONGLONG) - 1);
1028
1029 /* Fill some numbers (bus count, lun count, etc) */
1030 DeviceExtension->MaxLunCount = SCSI_MAXIMUM_LOGICAL_UNITS;
1031 DeviceExtension->RequestsNumber = 16;
1032
1033 /* Initialize the spin lock in the controller extension */
1034 KeInitializeSpinLock(&DeviceExtension->IrqLock);
1035 KeInitializeSpinLock(&DeviceExtension->SpinLock);
1036
1037 /* Initialize the DPC object */
1038 IoInitializeDpcRequest(PortDeviceObject,
1039 ScsiPortDpcForIsr);
1040
1041 /* Initialize the device timer */
1042 DeviceExtension->TimerCount = -1;
1043 IoInitializeTimer(PortDeviceObject,
1044 ScsiPortIoTimer,
1045 DeviceExtension);
1046
1047 /* Initialize miniport timer */
1048 KeInitializeTimer(&DeviceExtension->MiniportTimer);
1049 KeInitializeDpc(&DeviceExtension->MiniportTimerDpc,
1050 SpiMiniportTimerDpc,
1051 PortDeviceObject);
1052
1053 CreatePortConfig:
1054
1055 Status = SpiCreatePortConfig(DeviceExtension,
1056 HwInitializationData,
1057 &ConfigInfo,
1058 &InitialPortConfig,
1059 FirstConfigCall);
1060
1061 if (!NT_SUCCESS(Status))
1062 break;
1063
1064 /* Allocate and initialize port configuration info */
1065 PortConfigSize = (sizeof(PORT_CONFIGURATION_INFORMATION) +
1066 HwInitializationData->NumberOfAccessRanges *
1067 sizeof(ACCESS_RANGE) + 7) & ~7;
1068 DeviceExtension->PortConfig = ExAllocatePoolWithTag(NonPagedPool, PortConfigSize, TAG_SCSIPORT);
1069
1070 /* Fail if failed */
1071 if (DeviceExtension->PortConfig == NULL)
1072 {
1073 Status = STATUS_INSUFFICIENT_RESOURCES;
1074 break;
1075 }
1076
1077 PortConfig = DeviceExtension->PortConfig;
1078
1079 /* Copy information here */
1080 RtlCopyMemory(PortConfig,
1081 &InitialPortConfig,
1082 sizeof(PORT_CONFIGURATION_INFORMATION));
1083
1084
1085 /* Copy extension sizes into the PortConfig */
1086 PortConfig->SpecificLuExtensionSize = DeviceExtension->LunExtensionSize;
1087 PortConfig->SrbExtensionSize = DeviceExtension->SrbExtensionSize;
1088
1089 /* Initialize Access ranges */
1090 if (HwInitializationData->NumberOfAccessRanges != 0)
1091 {
1092 PortConfig->AccessRanges = (PVOID)(PortConfig+1);
1093
1094 /* Align to LONGLONG */
1095 PortConfig->AccessRanges = (PVOID)((ULONG)(PortConfig->AccessRanges) + 7);
1096 PortConfig->AccessRanges = (PVOID)((ULONG)(PortConfig->AccessRanges) & ~7);
1097
1098 /* Copy the data */
1099 RtlCopyMemory(PortConfig->AccessRanges,
1100 ConfigInfo.AccessRanges,
1101 HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE));
1102 }
1103
1104 /* Search for matching PCI device */
1105 if ((HwInitializationData->AdapterInterfaceType == PCIBus) &&
1106 (HwInitializationData->VendorIdLength > 0) &&
1107 (HwInitializationData->VendorId != NULL) &&
1108 (HwInitializationData->DeviceIdLength > 0) &&
1109 (HwInitializationData->DeviceId != NULL))
1110 {
1111 PortConfig->BusInterruptLevel = 0;
1112
1113 /* Get PCI device data */
1114 DPRINT("VendorId '%.*s' DeviceId '%.*s'\n",
1115 HwInitializationData->VendorIdLength,
1116 HwInitializationData->VendorId,
1117 HwInitializationData->DeviceIdLength,
1118 HwInitializationData->DeviceId);
1119
1120 if (!SpiGetPciConfigData(DriverObject,
1121 PortDeviceObject,
1122 HwInitializationData,
1123 PortConfig,
1124 RegistryPath,
1125 ConfigInfo.BusNumber,
1126 &SlotNumber))
1127 {
1128 /* Continue to the next bus, nothing here */
1129 ConfigInfo.BusNumber++;
1130 DeviceExtension->PortConfig = NULL;
1131 ExFreePool(PortConfig);
1132 Again = FALSE;
1133 goto CreatePortConfig;
1134 }
1135
1136 if (!PortConfig->BusInterruptLevel)
1137 {
1138 /* Bypass this slot, because no interrupt was assigned */
1139 DeviceExtension->PortConfig = NULL;
1140 ExFreePool(PortConfig);
1141 goto CreatePortConfig;
1142 }
1143 }
1144 else
1145 {
1146 DPRINT("Non-pci bus\n");
1147 }
1148
1149 /* Note: HwFindAdapter is called once for each bus */
1150 Again = FALSE;
1151 DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber);
1152 Result = (HwInitializationData->HwFindAdapter)(&DeviceExtension->MiniPortDeviceExtension,
1153 HwContext,
1154 0, /* BusInformation */
1155 ConfigInfo.Parameter, /* ArgumentString */
1156 PortConfig,
1157 &Again);
1158
1159 DPRINT("HwFindAdapter() Result: %lu Again: %s\n",
1160 Result, (Again) ? "True" : "False");
1161
1162 /* Free MapRegisterBase, it's not needed anymore */
1163 if (DeviceExtension->MapRegisterBase != NULL)
1164 {
1165 ExFreePool(DeviceExtension->MapRegisterBase);
1166 DeviceExtension->MapRegisterBase = NULL;
1167 }
1168
1169 /* If result is nothing good... */
1170 if (Result != SP_RETURN_FOUND)
1171 {
1172 DPRINT("HwFindAdapter() Result: %lu\n", Result);
1173
1174 if (Result == SP_RETURN_NOT_FOUND)
1175 {
1176 /* We can continue on the next bus */
1177 ConfigInfo.BusNumber++;
1178 Again = FALSE;
1179
1180 DeviceExtension->PortConfig = NULL;
1181 ExFreePool(PortConfig);
1182 goto CreatePortConfig;
1183 }
1184
1185 /* Otherwise, break */
1186 Status = STATUS_INTERNAL_ERROR;
1187 break;
1188 }
1189
1190 DPRINT("ScsiPortInitialize(): Found HBA! (%x), adapter Id %d\n",
1191 PortConfig->BusInterruptVector, PortConfig->InitiatorBusId[0]);
1192
1193 /* If the SRB extension size was updated */
1194 if (!DeviceExtension->NonCachedExtension &&
1195 (PortConfig->SrbExtensionSize != DeviceExtension->SrbExtensionSize))
1196 {
1197 /* Set it (rounding to LONGLONG again) */
1198 DeviceExtension->SrbExtensionSize =
1199 (PortConfig->SrbExtensionSize +
1200 sizeof(LONGLONG)) & ~(sizeof(LONGLONG) - 1);
1201 }
1202
1203 /* The same with LUN extension size */
1204 if (PortConfig->SpecificLuExtensionSize != DeviceExtension->LunExtensionSize)
1205 DeviceExtension->LunExtensionSize = PortConfig->SpecificLuExtensionSize;
1206
1207
1208 if (!((HwInitializationData->AdapterInterfaceType == PCIBus) &&
1209 (HwInitializationData->VendorIdLength > 0) &&
1210 (HwInitializationData->VendorId != NULL) &&
1211 (HwInitializationData->DeviceIdLength > 0) &&
1212 (HwInitializationData->DeviceId != NULL)))
1213 {
1214 /* Construct a resource list */
1215 ResourceList = SpiConfigToResource(DeviceExtension,
1216 PortConfig);
1217
1218 if (ResourceList)
1219 {
1220 UNICODE_STRING UnicodeString;
1221 RtlInitUnicodeString(&UnicodeString, L"ScsiAdapter");
1222 DPRINT("Reporting resources\n");
1223 Status = IoReportResourceUsage(&UnicodeString,
1224 DriverObject,
1225 NULL,
1226 0,
1227 PortDeviceObject,
1228 ResourceList,
1229 FIELD_OFFSET(CM_RESOURCE_LIST,
1230 List[0].PartialResourceList.PartialDescriptors) +
1231 ResourceList->List[0].PartialResourceList.Count
1232 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
1233 FALSE,
1234 &Conflict);
1235 ExFreePool(ResourceList);
1236
1237 /* In case of a failure or a conflict, break */
1238 if (Conflict || (!NT_SUCCESS(Status)))
1239 {
1240 if (Conflict)
1241 Status = STATUS_CONFLICTING_ADDRESSES;
1242 break;
1243 }
1244 }
1245 }
1246
1247 /* Reset the Conflict var */
1248 Conflict = FALSE;
1249
1250 /* Copy all stuff which we ever need from PortConfig to the DeviceExtension */
1251 if (PortConfig->MaximumNumberOfTargets > SCSI_MAXIMUM_TARGETS_PER_BUS)
1252 DeviceExtension->MaxTargedIds = SCSI_MAXIMUM_TARGETS_PER_BUS;
1253 else
1254 DeviceExtension->MaxTargedIds = PortConfig->MaximumNumberOfTargets;
1255
1256 DeviceExtension->BusNum = PortConfig->NumberOfBuses;
1257 DeviceExtension->CachesData = PortConfig->CachesData;
1258 DeviceExtension->ReceiveEvent = PortConfig->ReceiveEvent;
1259 DeviceExtension->SupportsTaggedQueuing = PortConfig->TaggedQueuing;
1260 DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu;
1261
1262 /* If something was disabled via registry - apply it */
1263 if (ConfigInfo.DisableMultipleLun)
1264 DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu = FALSE;
1265
1266 if (ConfigInfo.DisableTaggedQueueing)
1267 DeviceExtension->SupportsTaggedQueuing = PortConfig->MultipleRequestPerLu = FALSE;
1268
1269 /* Check if we need to alloc SRB data */
1270 if (DeviceExtension->SupportsTaggedQueuing ||
1271 DeviceExtension->MultipleReqsPerLun)
1272 {
1273 DeviceExtension->NeedSrbDataAlloc = TRUE;
1274 }
1275 else
1276 {
1277 DeviceExtension->NeedSrbDataAlloc = FALSE;
1278 }
1279
1280 /* Get a pointer to the port capabilities */
1281 PortCapabilities = &DeviceExtension->PortCapabilities;
1282
1283 /* Copy one field there */
1284 DeviceExtension->MapBuffers = PortConfig->MapBuffers;
1285 PortCapabilities->AdapterUsesPio = PortConfig->MapBuffers;
1286
1287 if (DeviceExtension->AdapterObject == NULL &&
1288 (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE || PortConfig->Master))
1289 {
1290 DPRINT1("DMA is not supported yet\n");
1291 ASSERT(FALSE);
1292 }
1293
1294 if (DeviceExtension->SrbExtensionBuffer == NULL &&
1295 (DeviceExtension->SrbExtensionSize != 0 ||
1296 PortConfig->AutoRequestSense))
1297 {
1298 DeviceExtension->SupportsAutoSense = PortConfig->AutoRequestSense;
1299 DeviceExtension->NeedSrbExtensionAlloc = TRUE;
1300
1301 /* Allocate common buffer */
1302 Status = SpiAllocateCommonBuffer(DeviceExtension, 0);
1303
1304 /* Check for failure */
1305 if (!NT_SUCCESS(Status))
1306 break;
1307 }
1308
1309 /* Allocate SrbData, if needed */
1310 if (DeviceExtension->NeedSrbDataAlloc)
1311 {
1312 ULONG Count;
1313 PSCSI_REQUEST_BLOCK_INFO SrbData;
1314
1315 if (DeviceExtension->SrbDataCount != 0)
1316 Count = DeviceExtension->SrbDataCount;
1317 else
1318 Count = DeviceExtension->RequestsNumber * 2;
1319
1320 /* Allocate the data */
1321 SrbData = ExAllocatePoolWithTag(NonPagedPool, Count * sizeof(SCSI_REQUEST_BLOCK_INFO), TAG_SCSIPORT);
1322 if (SrbData == NULL)
1323 return STATUS_INSUFFICIENT_RESOURCES;
1324
1325 RtlZeroMemory(SrbData, Count * sizeof(SCSI_REQUEST_BLOCK_INFO));
1326
1327 DeviceExtension->SrbInfo = SrbData;
1328 DeviceExtension->FreeSrbInfo = SrbData;
1329 DeviceExtension->SrbDataCount = Count;
1330
1331 /* Link it to the list */
1332 while (Count > 0)
1333 {
1334 SrbData->Requests.Flink = (PLIST_ENTRY)(SrbData + 1);
1335 SrbData++;
1336 Count--;
1337 }
1338
1339 /* Mark the last entry of the list */
1340 SrbData--;
1341 SrbData->Requests.Flink = NULL;
1342 }
1343
1344 /* Initialize port capabilities */
1345 PortCapabilities = &DeviceExtension->PortCapabilities;
1346 PortCapabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
1347 PortCapabilities->MaximumTransferLength = PortConfig->MaximumTransferLength;
1348
1349 if (PortConfig->ReceiveEvent)
1350 PortCapabilities->SupportedAsynchronousEvents |= SRBEV_SCSI_ASYNC_NOTIFICATION;
1351
1352 PortCapabilities->TaggedQueuing = DeviceExtension->SupportsTaggedQueuing;
1353 PortCapabilities->AdapterScansDown = PortConfig->AdapterScansDown;
1354
1355 if (PortConfig->AlignmentMask > PortDeviceObject->AlignmentRequirement)
1356 PortDeviceObject->AlignmentRequirement = PortConfig->AlignmentMask;
1357
1358 PortCapabilities->AlignmentMask = PortDeviceObject->AlignmentRequirement;
1359
1360 if (PortCapabilities->MaximumPhysicalPages == 0)
1361 {
1362 PortCapabilities->MaximumPhysicalPages =
1363 BYTES_TO_PAGES(PortCapabilities->MaximumTransferLength);
1364
1365 /* Apply miniport's limits */
1366 if (PortConfig->NumberOfPhysicalBreaks < PortCapabilities->MaximumPhysicalPages)
1367 {
1368 PortCapabilities->MaximumPhysicalPages = PortConfig->NumberOfPhysicalBreaks;
1369 }
1370 }
1371
1372 /* Deal with interrupts */
1373 if (DeviceExtension->HwInterrupt == NULL ||
1374 (PortConfig->BusInterruptLevel == 0 && PortConfig->BusInterruptVector == 0))
1375 {
1376 /* No interrupts */
1377 KeInitializeSpinLock(&DeviceExtension->IrqLock);
1378
1379 /* FIXME: Use synchronization routine */
1380 ASSERT("No interrupts branch requires changes in synchronization\n");
1381
1382 DeviceExtension->Interrupt = (PVOID)DeviceExtension;
1383 DPRINT("No interrupts\n");
1384
1385 }
1386 else
1387 {
1388 /* Are 2 interrupts needed? */
1389 if (DeviceExtension->HwInterrupt != NULL &&
1390 (PortConfig->BusInterruptLevel != 0 || PortConfig->BusInterruptVector != 0) &&
1391 (PortConfig->BusInterruptLevel2 != 0 || PortConfig->BusInterruptVector2 != 0))
1392 {
1393 DPRINT1("2 interrupts requested! Not yet supported\n");
1394 ASSERT(FALSE);
1395 }
1396 else
1397 {
1398 BOOLEAN InterruptShareable;
1399
1400 /* No, only 1 interrupt */
1401 DPRINT("1 interrupt, IRQ is %d\n", PortConfig->BusInterruptLevel);
1402
1403 DeviceExtension->InterruptLevel = PortConfig->BusInterruptLevel;
1404
1405 /* Register an interrupt handler for this device */
1406 MappedIrq = HalGetInterruptVector(PortConfig->AdapterInterfaceType,
1407 PortConfig->SystemIoBusNumber,
1408 PortConfig->BusInterruptLevel,
1409 PortConfig->BusInterruptVector,
1410 &Dirql,
1411 &Affinity);
1412
1413 /* Determing IRQ sharability as usual */
1414 if (PortConfig->AdapterInterfaceType == MicroChannel ||
1415 PortConfig->InterruptMode == LevelSensitive)
1416 {
1417 InterruptShareable = TRUE;
1418 }
1419 else
1420 {
1421 InterruptShareable = FALSE;
1422 }
1423
1424 Status = IoConnectInterrupt(&DeviceExtension->Interrupt,
1425 (PKSERVICE_ROUTINE)ScsiPortIsr,
1426 DeviceExtension,
1427 NULL,
1428 MappedIrq,
1429 Dirql,
1430 Dirql,
1431 PortConfig->InterruptMode,
1432 InterruptShareable,
1433 Affinity,
1434 FALSE);
1435
1436 if (!(NT_SUCCESS(Status)))
1437 {
1438 DPRINT1("Could not connect interrupt %d\n",
1439 PortConfig->BusInterruptVector);
1440 DeviceExtension->Interrupt = NULL;
1441 break;
1442 }
1443
1444 }
1445 }
1446
1447 /* Save IoAddress (from access ranges) */
1448 if (HwInitializationData->NumberOfAccessRanges != 0)
1449 {
1450 DeviceExtension->IoAddress =
1451 ((*(PortConfig->AccessRanges))[0]).RangeStart.LowPart;
1452
1453 DPRINT("Io Address %x\n", DeviceExtension->IoAddress);
1454 }
1455
1456 /* Set flag that it's allowed to disconnect during this command */
1457 DeviceExtension->Flags |= SCSI_PORT_DISCONNECT_ALLOWED;
1458
1459 /* Initialize counter of active requests (-1 means there are none) */
1460 DeviceExtension->ActiveRequestCounter = -1;
1461
1462 /* Analyze what we have about DMA */
1463 if (DeviceExtension->AdapterObject != NULL &&
1464 PortConfig->Master &&
1465 PortConfig->NeedPhysicalAddresses)
1466 {
1467 DeviceExtension->MapRegisters = TRUE;
1468 }
1469 else
1470 {
1471 DeviceExtension->MapRegisters = FALSE;
1472 }
1473
1474 /* Call HwInitialize at DISPATCH_LEVEL */
1475 KeRaiseIrql(DISPATCH_LEVEL, &Dirql);
1476
1477 if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
1478 DeviceExtension->HwInitialize,
1479 DeviceExtension->MiniPortDeviceExtension))
1480 {
1481 DPRINT1("HwInitialize() failed!\n");
1482 KeLowerIrql(Dirql);
1483 Status = STATUS_ADAPTER_HARDWARE_ERROR;
1484 break;
1485 }
1486
1487 /* Check if a notification is needed */
1488 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
1489 {
1490 /* Call DPC right away, because we're already at DISPATCH_LEVEL */
1491 ScsiPortDpcForIsr(NULL,
1492 DeviceExtension->DeviceObject,
1493 NULL,
1494 NULL);
1495 }
1496
1497 /* Lower irql back to what it was */
1498 KeLowerIrql(Dirql);
1499
1500 /* Start our timer */
1501 IoStartTimer(PortDeviceObject);
1502
1503 /* Initialize bus scanning information */
1504 DeviceExtension->BusesConfig = ExAllocatePoolWithTag(PagedPool,
1505 sizeof(PSCSI_BUS_SCAN_INFO) * DeviceExtension->PortConfig->NumberOfBuses
1506 + sizeof(ULONG), TAG_SCSIPORT);
1507
1508 if (!DeviceExtension->BusesConfig)
1509 {
1510 DPRINT1("Out of resources!\n");
1511 Status = STATUS_INSUFFICIENT_RESOURCES;
1512 break;
1513 }
1514
1515 /* Zero it */
1516 RtlZeroMemory(DeviceExtension->BusesConfig,
1517 sizeof(PSCSI_BUS_SCAN_INFO) * DeviceExtension->PortConfig->NumberOfBuses
1518 + sizeof(ULONG));
1519
1520 /* Store number of buses there */
1521 DeviceExtension->BusesConfig->NumberOfBuses = (UCHAR)DeviceExtension->BusNum;
1522
1523 /* Scan the adapter for devices */
1524 SpiScanAdapter(DeviceExtension);
1525
1526 /* Build the registry device map */
1527 SpiBuildDeviceMap(DeviceExtension,
1528 (PUNICODE_STRING)Argument2);
1529
1530 /* Create the dos device link */
1531 swprintf(DosNameBuffer,
1532 L"\\??\\Scsi%lu:",
1533 SystemConfig->ScsiPortCount);
1534 RtlInitUnicodeString(&DosDeviceName, DosNameBuffer);
1535 IoCreateSymbolicLink(&DosDeviceName, &DeviceName);
1536
1537 /* Increase the port count */
1538 SystemConfig->ScsiPortCount++;
1539 FirstConfigCall = FALSE;
1540
1541 /* Increase adapter number and bus number respectively */
1542 ConfigInfo.AdapterNumber++;
1543
1544 if (!Again)
1545 ConfigInfo.BusNumber++;
1546
1547 DPRINT("Bus: %lu MaxBus: %lu\n", BusNumber, MaxBus);
1548
1549 DeviceFound = TRUE;
1550 }
1551
1552 /* Clean up the mess */
1553 SpiCleanupAfterInit(DeviceExtension);
1554
1555 /* Close registry keys */
1556 if (ConfigInfo.ServiceKey != NULL)
1557 ZwClose(ConfigInfo.ServiceKey);
1558
1559 if (ConfigInfo.DeviceKey != NULL)
1560 ZwClose(ConfigInfo.DeviceKey);
1561
1562 if (ConfigInfo.BusKey != NULL)
1563 ZwClose(ConfigInfo.BusKey);
1564
1565 if (ConfigInfo.AccessRanges != NULL)
1566 ExFreePool(ConfigInfo.AccessRanges);
1567
1568 if (ConfigInfo.Parameter != NULL)
1569 ExFreePool(ConfigInfo.Parameter);
1570
1571 DPRINT("ScsiPortInitialize() done, Status = 0x%08X, DeviceFound = %b!\n",
1572 Status, DeviceFound);
1573
1574 return (DeviceFound == FALSE) ? Status : STATUS_SUCCESS;
1575 }
1576
1577 static VOID
1578 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
1579 {
1580 PSCSI_LUN_INFO LunInfo;
1581 PVOID Ptr;
1582 ULONG Bus, Lun;
1583
1584 /* Check if we have something to clean up */
1585 if (DeviceExtension == NULL)
1586 return;
1587
1588 /* Stop the timer and disconnect the interrupt */
1589 if (DeviceExtension->Interrupt)
1590 {
1591 IoStopTimer(DeviceExtension->DeviceObject);
1592 IoDisconnectInterrupt(DeviceExtension->Interrupt);
1593 }
1594
1595 /* Delete ConfigInfo */
1596 if (DeviceExtension->BusesConfig)
1597 {
1598 for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
1599 {
1600 if (!DeviceExtension->BusesConfig->BusScanInfo[Bus])
1601 continue;
1602
1603 LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
1604
1605 while (!LunInfo)
1606 {
1607 /* Free current, but save pointer to the next one */
1608 Ptr = LunInfo->Next;
1609 ExFreePool(LunInfo);
1610 LunInfo = Ptr;
1611 }
1612
1613 ExFreePool(DeviceExtension->BusesConfig->BusScanInfo[Bus]);
1614 }
1615
1616 ExFreePool(DeviceExtension->BusesConfig);
1617 }
1618
1619 /* Free PortConfig */
1620 if (DeviceExtension->PortConfig)
1621 ExFreePool(DeviceExtension->PortConfig);
1622
1623 /* Free LUNs*/
1624 for(Lun = 0; Lun < LUS_NUMBER; Lun++)
1625 {
1626 while (DeviceExtension->LunExtensionList[Lun])
1627 {
1628 Ptr = DeviceExtension->LunExtensionList[Lun];
1629 DeviceExtension->LunExtensionList[Lun] = DeviceExtension->LunExtensionList[Lun]->Next;
1630
1631 ExFreePool(Ptr);
1632 }
1633 }
1634
1635 /* Free common buffer (if it exists) */
1636 if (DeviceExtension->SrbExtensionBuffer != NULL &&
1637 DeviceExtension->CommonBufferLength != 0)
1638 {
1639 if (!DeviceExtension->AdapterObject)
1640 {
1641 ExFreePool(DeviceExtension->SrbExtensionBuffer);
1642 }
1643 else
1644 {
1645 #if 0
1646 HalFreeCommonBuffer(DeviceExtension->AdapterObject,
1647 DeviceExtension->CommonBufferLength,
1648 DeviceExtension->PhysicalCommonBuffer,
1649 DeviceExtension->SrbExtensionBuffer,
1650 FALSE);
1651 #endif
1652 }
1653 }
1654
1655 /* Free SRB info */
1656 if (DeviceExtension->SrbInfo != NULL)
1657 ExFreePool(DeviceExtension->SrbInfo);
1658
1659 /* Unmap mapped addresses */
1660 while (DeviceExtension->MappedAddressList != NULL)
1661 {
1662 MmUnmapIoSpace(DeviceExtension->MappedAddressList->MappedAddress,
1663 DeviceExtension->MappedAddressList->NumberOfBytes);
1664
1665 Ptr = DeviceExtension->MappedAddressList;
1666 DeviceExtension->MappedAddressList = DeviceExtension->MappedAddressList->NextMappedAddress;
1667
1668 ExFreePool(Ptr);
1669 }
1670
1671 /* Finally delete the device object */
1672 DPRINT("Deleting device %p\n", DeviceExtension->DeviceObject);
1673 IoDeleteDevice(DeviceExtension->DeviceObject);
1674 }
1675
1676
1677
1678 /*
1679 * @unimplemented
1680 */
1681 VOID STDCALL
1682 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension,
1683 IN PSCSI_REQUEST_BLOCK Srb,
1684 IN PVOID LogicalAddress,
1685 IN ULONG Length)
1686 {
1687 DPRINT1("ScsiPortIoMapTransfer()\n");
1688 UNIMPLEMENTED;
1689 }
1690
1691
1692 /*
1693 * @unimplemented
1694 */
1695 VOID STDCALL
1696 ScsiPortLogError(IN PVOID HwDeviceExtension,
1697 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
1698 IN UCHAR PathId,
1699 IN UCHAR TargetId,
1700 IN UCHAR Lun,
1701 IN ULONG ErrorCode,
1702 IN ULONG UniqueId)
1703 {
1704 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1705
1706 DPRINT1("ScsiPortLogError() called\n");
1707
1708 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
1709 SCSI_PORT_DEVICE_EXTENSION,
1710 MiniPortDeviceExtension);
1711
1712
1713 DPRINT("ScsiPortLogError() done\n");
1714 }
1715
1716
1717 /*
1718 * @implemented
1719 */
1720 VOID STDCALL
1721 ScsiPortMoveMemory(OUT PVOID Destination,
1722 IN PVOID Source,
1723 IN ULONG Length)
1724 {
1725 RtlMoveMemory(Destination,
1726 Source,
1727 Length);
1728 }
1729
1730
1731 /*
1732 * @implemented
1733 */
1734 VOID
1735 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType,
1736 IN PVOID HwDeviceExtension,
1737 ...)
1738 {
1739 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1740 va_list ap;
1741
1742 DPRINT("ScsiPortNotification() called\n");
1743
1744 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
1745 SCSI_PORT_DEVICE_EXTENSION,
1746 MiniPortDeviceExtension);
1747
1748 DPRINT("DeviceExtension %p\n", DeviceExtension);
1749
1750 va_start(ap, HwDeviceExtension);
1751
1752 switch (NotificationType)
1753 {
1754 case RequestComplete:
1755 {
1756 PSCSI_REQUEST_BLOCK Srb;
1757 PSCSI_REQUEST_BLOCK_INFO SrbData;
1758
1759 Srb = (PSCSI_REQUEST_BLOCK) va_arg (ap, PSCSI_REQUEST_BLOCK);
1760
1761 DPRINT("Notify: RequestComplete (Srb %p)\n", Srb);
1762
1763 /* Make sure Srb is allright */
1764 ASSERT(Srb->SrbStatus != SRB_STATUS_PENDING);
1765 ASSERT(Srb->Function != SRB_FUNCTION_EXECUTE_SCSI || Srb->SrbStatus != SRB_STATUS_SUCCESS || Srb->ScsiStatus == SCSISTAT_GOOD);
1766
1767 if (!(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE))
1768 {
1769 /* It's been already completed */
1770 va_end(ap);
1771 return;
1772 }
1773
1774 /* It's not active anymore */
1775 Srb->SrbFlags &= ~SRB_FLAGS_IS_ACTIVE;
1776
1777 if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
1778 {
1779 /* TODO: Treat it specially */
1780 ASSERT(FALSE);
1781 }
1782 else
1783 {
1784 /* Get the SRB data */
1785 SrbData = SpiGetSrbData(DeviceExtension,
1786 Srb->PathId,
1787 Srb->TargetId,
1788 Srb->Lun,
1789 Srb->QueueTag);
1790
1791 /* Make sure there are no CompletedRequests and there is a Srb */
1792 ASSERT(SrbData->CompletedRequests == NULL && SrbData->Srb != NULL);
1793
1794 /* If it's a read/write request, make sure it has data inside it */
1795 if ((Srb->SrbStatus == SRB_STATUS_SUCCESS) &&
1796 ((Srb->Cdb[0] == SCSIOP_READ) || (Srb->Cdb[0] == SCSIOP_WRITE)))
1797 {
1798 ASSERT(Srb->DataTransferLength);
1799 }
1800
1801 SrbData->CompletedRequests = DeviceExtension->InterruptData.CompletedRequests;
1802 DeviceExtension->InterruptData.CompletedRequests = SrbData;
1803 }
1804 }
1805 break;
1806
1807 case NextRequest:
1808 DPRINT("Notify: NextRequest\n");
1809 DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY;
1810 break;
1811
1812 case NextLuRequest:
1813 {
1814 UCHAR PathId;
1815 UCHAR TargetId;
1816 UCHAR Lun;
1817
1818 PathId = (UCHAR) va_arg (ap, int);
1819 TargetId = (UCHAR) va_arg (ap, int);
1820 Lun = (UCHAR) va_arg (ap, int);
1821
1822 DPRINT1 ("Notify: NextLuRequest(PathId %u TargetId %u Lun %u)\n",
1823 PathId, TargetId, Lun);
1824 /* FIXME: Implement it! */
1825 ASSERT(FALSE);
1826
1827 // DeviceExtension->IrpFlags |= IRP_FLAG_NEXT;
1828 // DeviceExtension->IrpFlags |= IRP_FLAG_NEXT_LU;
1829
1830 /* Hack! */
1831 // DeviceExtension->IrpFlags |= IRP_FLAG_NEXT;
1832 }
1833 break;
1834
1835 case ResetDetected:
1836 DPRINT1("Notify: ResetDetected\n");
1837 /* FIXME: ??? */
1838 break;
1839
1840 default:
1841 DPRINT1 ("Unsupported notification %lu\n", NotificationType);
1842 break;
1843 }
1844
1845 va_end(ap);
1846
1847 /* Request a DPC after we're done with the interrupt */
1848 DeviceExtension->InterruptData.Flags |= SCSI_PORT_NOTIFICATION_NEEDED;
1849 }
1850
1851
1852 /*
1853 * @implemented
1854 */
1855 ULONG STDCALL
1856 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension,
1857 IN ULONG BusDataType,
1858 IN ULONG SystemIoBusNumber,
1859 IN ULONG SlotNumber,
1860 IN PVOID Buffer,
1861 IN ULONG Offset,
1862 IN ULONG Length)
1863 {
1864 DPRINT("ScsiPortSetBusDataByOffset()\n");
1865 return(HalSetBusDataByOffset(BusDataType,
1866 SystemIoBusNumber,
1867 SlotNumber,
1868 Buffer,
1869 Offset,
1870 Length));
1871 }
1872
1873
1874 /*
1875 * @implemented
1876 */
1877 BOOLEAN STDCALL
1878 ScsiPortValidateRange(IN PVOID HwDeviceExtension,
1879 IN INTERFACE_TYPE BusType,
1880 IN ULONG SystemIoBusNumber,
1881 IN SCSI_PHYSICAL_ADDRESS IoAddress,
1882 IN ULONG NumberOfBytes,
1883 IN BOOLEAN InIoSpace)
1884 {
1885 DPRINT("ScsiPortValidateRange()\n");
1886 return(TRUE);
1887 }
1888
1889
1890 /* INTERNAL FUNCTIONS ********************************************************/
1891
1892 static VOID
1893 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData,
1894 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor,
1895 IN PPORT_CONFIGURATION_INFORMATION PortConfig)
1896 {
1897 PACCESS_RANGE AccessRange;
1898 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialData;
1899 ULONG RangeNumber;
1900 ULONG Index;
1901
1902 RangeNumber = 0;
1903
1904 /* Loop through all entries */
1905 for (Index = 0; Index < ResourceDescriptor->PartialResourceList.Count; Index++)
1906 {
1907 PartialData = &ResourceDescriptor->PartialResourceList.PartialDescriptors[Index];
1908
1909 switch (PartialData->Type)
1910 {
1911 case CmResourceTypePort:
1912 /* Copy access ranges */
1913 if (RangeNumber < HwInitializationData->NumberOfAccessRanges)
1914 {
1915 AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]);
1916
1917 AccessRange->RangeStart = PartialData->u.Port.Start;
1918 AccessRange->RangeLength = PartialData->u.Port.Length;
1919
1920 AccessRange->RangeInMemory = FALSE;
1921 RangeNumber++;
1922 }
1923 break;
1924
1925 case CmResourceTypeMemory:
1926 /* Copy access ranges */
1927 if (RangeNumber < HwInitializationData->NumberOfAccessRanges)
1928 {
1929 AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]);
1930
1931 AccessRange->RangeStart = PartialData->u.Memory.Start;
1932 AccessRange->RangeLength = PartialData->u.Memory.Length;
1933
1934 AccessRange->RangeInMemory = TRUE;
1935 RangeNumber++;
1936 }
1937 break;
1938
1939 case CmResourceTypeInterrupt:
1940 /* Copy interrupt data */
1941 PortConfig->BusInterruptLevel = PartialData->u.Interrupt.Level;
1942 PortConfig->BusInterruptVector = PartialData->u.Interrupt.Vector;
1943
1944 /* Set interrupt mode accordingly to the resource */
1945 if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
1946 {
1947 PortConfig->InterruptMode = Latched;
1948 }
1949 else if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
1950 {
1951 PortConfig->InterruptMode = LevelSensitive;
1952 }
1953 break;
1954
1955 case CmResourceTypeDma:
1956 PortConfig->DmaChannel = PartialData->u.Dma.Channel;
1957 PortConfig->DmaPort = PartialData->u.Dma.Port;
1958 break;
1959 }
1960 }
1961 }
1962
1963 static PCM_RESOURCE_LIST
1964 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1965 PPORT_CONFIGURATION_INFORMATION PortConfig)
1966 {
1967 PCONFIGURATION_INFORMATION ConfigInfo;
1968 PCM_RESOURCE_LIST ResourceList;
1969 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor;
1970 PACCESS_RANGE AccessRange;
1971 BOOLEAN Dma;
1972 ULONG ListLength = 0, i, FullSize;
1973 ULONG Interrupt;
1974
1975 /* Get current Atdisk usage from the system */
1976 ConfigInfo = IoGetConfigurationInformation();
1977
1978 if (PortConfig->AtdiskPrimaryClaimed)
1979 ConfigInfo->AtDiskPrimaryAddressClaimed = TRUE;
1980
1981 if (PortConfig->AtdiskSecondaryClaimed)
1982 ConfigInfo->AtDiskSecondaryAddressClaimed = TRUE;
1983
1984 /* Do we use DMA? */
1985 if (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE ||
1986 PortConfig->DmaPort != SP_UNINITIALIZED_VALUE)
1987 {
1988 Dma = TRUE;
1989 ListLength++;
1990 }
1991 else
1992 {
1993 Dma = FALSE;
1994 }
1995
1996 /* How many interrupts to we have? */
1997 if (DeviceExtension->HwInterrupt == NULL ||
1998 (PortConfig->BusInterruptLevel == 0 &&
1999 PortConfig->BusInterruptVector == 0))
2000 {
2001 Interrupt = 0;
2002 }
2003 else
2004 {
2005 Interrupt = 1;
2006 ListLength++;
2007 }
2008
2009 if (DeviceExtension->HwInterrupt != NULL &&
2010 (PortConfig->BusInterruptLevel2 != 0 ||
2011 PortConfig->BusInterruptVector2 != 0))
2012 {
2013 Interrupt++;
2014 ListLength++;
2015 }
2016
2017 /* How many access ranges do we use? */
2018 AccessRange = &((*(PortConfig->AccessRanges))[0]);
2019 for (i = 0; i < PortConfig->NumberOfAccessRanges; i++)
2020 {
2021 if (AccessRange->RangeLength != 0)
2022 ListLength++;
2023
2024 AccessRange++;
2025 }
2026
2027 /* Allocate the resource list, since we know its size now */
2028 FullSize = sizeof(CM_RESOURCE_LIST) + (ListLength - 1) *
2029 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
2030
2031 ResourceList = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(PagedPool, FullSize, TAG_SCSIPORT);
2032
2033 if (!ResourceList)
2034 return NULL;
2035
2036 /* Zero it */
2037 RtlZeroMemory(ResourceList, FullSize);
2038
2039 /* Initialize it */
2040 ResourceList->Count = 1;
2041 ResourceList->List[0].InterfaceType = PortConfig->AdapterInterfaceType;
2042 ResourceList->List[0].BusNumber = PortConfig->SystemIoBusNumber;
2043 ResourceList->List[0].PartialResourceList.Count = ListLength;
2044 ResourceDescriptor = ResourceList->List[0].PartialResourceList.PartialDescriptors;
2045
2046 /* Copy access ranges array over */
2047 for (i = 0; i < PortConfig->NumberOfAccessRanges; i++)
2048 {
2049 AccessRange = &((*(PortConfig->AccessRanges))[i]);
2050
2051 /* If the range is empty - skip it */
2052 if (AccessRange->RangeLength == 0)
2053 continue;
2054
2055 if (AccessRange->RangeInMemory)
2056 {
2057 ResourceDescriptor->Type = CmResourceTypeMemory;
2058 ResourceDescriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
2059 }
2060 else
2061 {
2062 ResourceDescriptor->Type = CmResourceTypePort;
2063 ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
2064 }
2065
2066 ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
2067
2068 ResourceDescriptor->u.Memory.Start = AccessRange->RangeStart;
2069 ResourceDescriptor->u.Memory.Length = AccessRange->RangeLength;
2070
2071 ResourceDescriptor++;
2072 }
2073
2074 /* If we use interrupt(s), copy them */
2075 if (Interrupt)
2076 {
2077 ResourceDescriptor->Type = CmResourceTypeInterrupt;
2078
2079 if (PortConfig->AdapterInterfaceType == MicroChannel ||
2080 PortConfig->InterruptMode == LevelSensitive)
2081 {
2082 ResourceDescriptor->ShareDisposition = CmResourceShareShared;
2083 ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
2084 }
2085 else
2086 {
2087 ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
2088 ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
2089 }
2090
2091 ResourceDescriptor->u.Interrupt.Level = PortConfig->BusInterruptLevel;
2092 ResourceDescriptor->u.Interrupt.Vector = PortConfig->BusInterruptVector;
2093 ResourceDescriptor->u.Interrupt.Affinity = 0;
2094
2095 ResourceDescriptor++;
2096 Interrupt--;
2097 }
2098
2099 /* Copy 2nd interrupt
2100 FIXME: Stupid code duplication, remove */
2101 if (Interrupt)
2102 {
2103 ResourceDescriptor->Type = CmResourceTypeInterrupt;
2104
2105 if (PortConfig->AdapterInterfaceType == MicroChannel ||
2106 PortConfig->InterruptMode == LevelSensitive)
2107 {
2108 ResourceDescriptor->ShareDisposition = CmResourceShareShared;
2109 ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
2110 }
2111 else
2112 {
2113 ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
2114 ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
2115 }
2116
2117 ResourceDescriptor->u.Interrupt.Level = PortConfig->BusInterruptLevel;
2118 ResourceDescriptor->u.Interrupt.Vector = PortConfig->BusInterruptVector;
2119 ResourceDescriptor->u.Interrupt.Affinity = 0;
2120
2121 ResourceDescriptor++;
2122 }
2123
2124 /* Copy DMA data */
2125 if (Dma)
2126 {
2127 ResourceDescriptor->Type = CmResourceTypeDma;
2128 ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
2129 ResourceDescriptor->u.Dma.Channel = PortConfig->DmaChannel;
2130 ResourceDescriptor->u.Dma.Port = PortConfig->DmaPort;
2131 ResourceDescriptor->Flags = 0;
2132
2133 if (PortConfig->DmaChannel == SP_UNINITIALIZED_VALUE)
2134 ResourceDescriptor->u.Dma.Channel = 0;
2135
2136 if (PortConfig->DmaPort == SP_UNINITIALIZED_VALUE)
2137 ResourceDescriptor->u.Dma.Port = 0;
2138 }
2139
2140 return ResourceList;
2141 }
2142
2143
2144 static BOOLEAN
2145 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject,
2146 IN PDEVICE_OBJECT DeviceObject,
2147 IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
2148 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig,
2149 IN PUNICODE_STRING RegistryPath,
2150 IN ULONG BusNumber,
2151 IN OUT PPCI_SLOT_NUMBER NextSlotNumber)
2152 {
2153 PCI_COMMON_CONFIG PciConfig;
2154 PCI_SLOT_NUMBER SlotNumber;
2155 ULONG DataSize;
2156 ULONG DeviceNumber;
2157 ULONG FunctionNumber;
2158 CHAR VendorIdString[8];
2159 CHAR DeviceIdString[8];
2160 UNICODE_STRING UnicodeStr;
2161 PCM_RESOURCE_LIST ResourceList;
2162 NTSTATUS Status;
2163
2164 DPRINT ("SpiGetPciConfiguration() called\n");
2165
2166 RtlZeroMemory(&ResourceList, sizeof(PCM_RESOURCE_LIST));
2167 SlotNumber.u.AsULONG = 0;
2168
2169 /* Loop through all devices */
2170 for (DeviceNumber = NextSlotNumber->u.bits.DeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
2171 {
2172 SlotNumber.u.bits.DeviceNumber = DeviceNumber;
2173
2174 /* Loop through all functions */
2175 for (FunctionNumber = NextSlotNumber->u.bits.FunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
2176 {
2177 SlotNumber.u.bits.FunctionNumber = FunctionNumber;
2178
2179 /* Get PCI config bytes */
2180 DataSize = HalGetBusData(PCIConfiguration,
2181 BusNumber,
2182 SlotNumber.u.AsULONG,
2183 &PciConfig,
2184 sizeof(ULONG));
2185
2186 /* If result of HalGetBusData is 0, then the bus is wrong */
2187 if (DataSize == 0)
2188 return FALSE;
2189
2190 /* If result is PCI_INVALID_VENDORID, then this device has no more
2191 "Functions" */
2192 if (PciConfig.VendorID == PCI_INVALID_VENDORID)
2193 break;
2194
2195 sprintf (VendorIdString, "%04hx", PciConfig.VendorID);
2196 sprintf (DeviceIdString, "%04hx", PciConfig.DeviceID);
2197
2198 if (_strnicmp(VendorIdString, HwInitializationData->VendorId, HwInitializationData->VendorIdLength) ||
2199 _strnicmp(DeviceIdString, HwInitializationData->DeviceId, HwInitializationData->DeviceIdLength))
2200 {
2201 /* It is not our device */
2202 continue;
2203 }
2204
2205 DPRINT("Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n",
2206 PciConfig.VendorID,
2207 PciConfig.DeviceID,
2208 BusNumber,
2209 SlotNumber.u.bits.DeviceNumber,
2210 SlotNumber.u.bits.FunctionNumber);
2211
2212
2213 RtlInitUnicodeString(&UnicodeStr, L"ScsiAdapter");
2214 Status = HalAssignSlotResources(RegistryPath,
2215 &UnicodeStr,
2216 DriverObject,
2217 DeviceObject,
2218 PCIBus,
2219 BusNumber,
2220 SlotNumber.u.AsULONG,
2221 &ResourceList);
2222
2223 if (!NT_SUCCESS(Status))
2224 break;
2225
2226 /* Create configuration information */
2227 SpiResourceToConfig(HwInitializationData,
2228 ResourceList->List,
2229 PortConfig);
2230
2231 /* Free the resource list */
2232 ExFreePool(ResourceList);
2233
2234 /* Set dev & fn numbers */
2235 NextSlotNumber->u.bits.DeviceNumber = DeviceNumber;
2236 NextSlotNumber->u.bits.FunctionNumber = FunctionNumber + 1;
2237
2238 /* Save the slot number */
2239 PortConfig->SlotNumber = SlotNumber.u.AsULONG;
2240
2241 return TRUE;
2242 }
2243 NextSlotNumber->u.bits.FunctionNumber = 0;
2244 }
2245
2246 NextSlotNumber->u.bits.DeviceNumber = 0;
2247 DPRINT ("No device found\n");
2248
2249 return FALSE;
2250 }
2251
2252
2253
2254 /**********************************************************************
2255 * NAME INTERNAL
2256 * ScsiPortCreateClose
2257 *
2258 * DESCRIPTION
2259 * Answer requests for Create/Close calls: a null operation.
2260 *
2261 * RUN LEVEL
2262 * PASSIVE_LEVEL
2263 *
2264 * ARGUMENTS
2265 * DeviceObject
2266 * Pointer to a device object.
2267 *
2268 * Irp
2269 * Pointer to an IRP.
2270 *
2271 * RETURN VALUE
2272 * Status.
2273 */
2274
2275 static NTSTATUS STDCALL
2276 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
2277 IN PIRP Irp)
2278 {
2279 DPRINT("ScsiPortCreateClose()\n");
2280
2281 Irp->IoStatus.Status = STATUS_SUCCESS;
2282 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2283
2284 return STATUS_SUCCESS;
2285 }
2286
2287 static NTSTATUS
2288 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
2289 PIRP Irp)
2290 {
2291 PSCSI_LUN_INFO LunInfo;
2292 PIO_STACK_LOCATION IrpStack;
2293 PDEVICE_OBJECT DeviceObject;
2294 PSCSI_REQUEST_BLOCK Srb;
2295 KIRQL Irql;
2296
2297 /* Get pointer to the SRB */
2298 IrpStack = IoGetCurrentIrpStackLocation(Irp);
2299 Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
2300
2301 /* Check if PathId matches number of buses */
2302 if (DeviceExtension->BusesConfig == NULL ||
2303 DeviceExtension->BusesConfig->NumberOfBuses <= Srb->PathId)
2304 {
2305 Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
2306 return STATUS_DEVICE_DOES_NOT_EXIST;
2307 }
2308
2309 /* Get pointer to LunInfo */
2310 LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Srb->PathId]->LunInfo;
2311
2312 /* Find matching LunInfo */
2313 while (LunInfo)
2314 {
2315 if (LunInfo->PathId == Srb->PathId &&
2316 LunInfo->TargetId == Srb->TargetId &&
2317 LunInfo->Lun == Srb->Lun)
2318 {
2319 break;
2320 }
2321
2322 LunInfo = LunInfo->Next;
2323 }
2324
2325 /* If we couldn't find it - exit */
2326 if (LunInfo == NULL)
2327 return STATUS_DEVICE_DOES_NOT_EXIST;
2328
2329
2330 /* Get spinlock */
2331 KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
2332
2333 /* Release, if asked */
2334 if (Srb->Function == SRB_FUNCTION_RELEASE_DEVICE)
2335 {
2336 LunInfo->DeviceClaimed = FALSE;
2337 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2338 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2339
2340 return STATUS_SUCCESS;
2341 }
2342
2343 /* Attach, if not already claimed */
2344 if (LunInfo->DeviceClaimed)
2345 {
2346 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2347 Srb->SrbStatus = SRB_STATUS_BUSY;
2348
2349 return STATUS_DEVICE_BUSY;
2350 }
2351
2352 /* Save the device object */
2353 DeviceObject = LunInfo->DeviceObject;
2354
2355 if (Srb->Function == SRB_FUNCTION_CLAIM_DEVICE)
2356 LunInfo->DeviceClaimed = TRUE;
2357
2358 if (Srb->Function == SRB_FUNCTION_ATTACH_DEVICE)
2359 LunInfo->DeviceObject = Srb->DataBuffer;
2360
2361 Srb->DataBuffer = DeviceObject;
2362
2363 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2364 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2365
2366 return STATUS_SUCCESS;
2367 }
2368
2369
2370 /**********************************************************************
2371 * NAME INTERNAL
2372 * ScsiPortDispatchScsi
2373 *
2374 * DESCRIPTION
2375 * Answer requests for SCSI calls
2376 *
2377 * RUN LEVEL
2378 * PASSIVE_LEVEL
2379 *
2380 * ARGUMENTS
2381 * Standard dispatch arguments
2382 *
2383 * RETURNS
2384 * NTSTATUS
2385 */
2386
2387 static NTSTATUS STDCALL
2388 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
2389 IN PIRP Irp)
2390 {
2391 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2392 PSCSI_PORT_LUN_EXTENSION LunExtension;
2393 PIO_STACK_LOCATION Stack;
2394 PSCSI_REQUEST_BLOCK Srb;
2395 KIRQL Irql;
2396 NTSTATUS Status = STATUS_SUCCESS;
2397 PIRP NextIrp, IrpList;
2398 PKDEVICE_QUEUE_ENTRY Entry;
2399
2400 DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n",
2401 DeviceObject, Irp);
2402
2403 DeviceExtension = DeviceObject->DeviceExtension;
2404 Stack = IoGetCurrentIrpStackLocation(Irp);
2405
2406 Srb = Stack->Parameters.Scsi.Srb;
2407 if (Srb == NULL)
2408 {
2409 DPRINT1("ScsiPortDispatchScsi() called with Srb = NULL!\n");
2410 Status = STATUS_UNSUCCESSFUL;
2411
2412 Irp->IoStatus.Status = Status;
2413 Irp->IoStatus.Information = 0;
2414
2415 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2416
2417 return(Status);
2418 }
2419
2420 DPRINT("Srb: %p\n", Srb);
2421 DPRINT("Srb->Function: %lu\n", Srb->Function);
2422 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
2423
2424 LunExtension = SpiGetLunExtension(DeviceExtension,
2425 Srb->PathId,
2426 Srb->TargetId,
2427 Srb->Lun);
2428 if (LunExtension == NULL)
2429 {
2430 DPRINT("ScsiPortDispatchScsi() called with an invalid LUN\n");
2431 Status = STATUS_NO_SUCH_DEVICE;
2432
2433 Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
2434 Irp->IoStatus.Status = Status;
2435 Irp->IoStatus.Information = 0;
2436
2437 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2438
2439 return(Status);
2440 }
2441
2442 switch (Srb->Function)
2443 {
2444 case SRB_FUNCTION_SHUTDOWN:
2445 case SRB_FUNCTION_FLUSH:
2446 DPRINT (" SRB_FUNCTION_SHUTDOWN or FLUSH\n");
2447 if (DeviceExtension->CachesData == FALSE)
2448 {
2449 /* All success here */
2450 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2451 Irp->IoStatus.Status = STATUS_SUCCESS;
2452 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2453 return STATUS_SUCCESS;
2454 }
2455 /* Fall through to a usual execute operation */
2456
2457 case SRB_FUNCTION_EXECUTE_SCSI:
2458 case SRB_FUNCTION_IO_CONTROL:
2459 /* Mark IRP as pending in all cases */
2460 IoMarkIrpPending(Irp);
2461
2462 if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
2463 {
2464 /* Start IO directly */
2465 IoStartPacket(DeviceObject, Irp, NULL, NULL);
2466 }
2467 else
2468 {
2469 KIRQL oldIrql;
2470
2471 /* We need to be at DISPATCH_LEVEL */
2472 KeRaiseIrql (DISPATCH_LEVEL, &oldIrql);
2473
2474 /* Insert IRP into the queue */
2475 if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue,
2476 &Irp->Tail.Overlay.DeviceQueueEntry,
2477 Srb->QueueSortKey))
2478 {
2479 /* It means the queue is empty, and we just start this request */
2480 IoStartPacket(DeviceObject, Irp, NULL, NULL);
2481 }
2482
2483 /* Back to the old IRQL */
2484 KeLowerIrql (oldIrql);
2485 }
2486 return STATUS_PENDING;
2487
2488 case SRB_FUNCTION_CLAIM_DEVICE:
2489 case SRB_FUNCTION_ATTACH_DEVICE:
2490 DPRINT (" SRB_FUNCTION_CLAIM_DEVICE or ATTACH\n");
2491
2492 /* Reference device object and keep the device object */
2493 Status = SpiHandleAttachRelease(DeviceExtension, Irp);
2494 break;
2495
2496 case SRB_FUNCTION_RELEASE_DEVICE:
2497 DPRINT (" SRB_FUNCTION_RELEASE_DEVICE\n");
2498
2499 /* Dereference device object and clear the device object */
2500 Status = SpiHandleAttachRelease(DeviceExtension, Irp);
2501 break;
2502
2503 case SRB_FUNCTION_RELEASE_QUEUE:
2504 DPRINT(" SRB_FUNCTION_RELEASE_QUEUE\n");
2505
2506 /* Guard with the spinlock */
2507 KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
2508
2509 if (!(LunExtension->Flags & LUNEX_FROZEN_QUEUE))
2510 {
2511 DPRINT("Queue is not frozen really\n");
2512
2513 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2514 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2515 Status = STATUS_SUCCESS;
2516 break;
2517
2518 }
2519
2520 /* Unfreeze the queue */
2521 LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
2522
2523 if (LunExtension->SrbInfo.Srb == NULL)
2524 {
2525 /* Get next logical unit request */
2526 SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
2527
2528 /* SpiGetNextRequestFromLun() releases the spinlock */
2529 KeLowerIrql(Irql);
2530 }
2531 else
2532 {
2533 DPRINT("The queue has active request\n");
2534 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2535 }
2536
2537
2538 Srb->SrbStatus = SRB_STATUS_SUCCESS;
2539 Status = STATUS_SUCCESS;
2540 break;
2541
2542 case SRB_FUNCTION_FLUSH_QUEUE:
2543 DPRINT(" SRB_FUNCTION_FLUSH_QUEUE\n");
2544
2545 /* Guard with the spinlock */
2546 KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
2547
2548 if (!(LunExtension->Flags & LUNEX_FROZEN_QUEUE))
2549 {
2550 DPRINT("Queue is not frozen really\n");
2551
2552 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2553 Status = STATUS_INVALID_DEVICE_REQUEST;
2554 break;
2555 }
2556
2557 /* Make sure there is no active request */
2558 ASSERT(LunExtension->SrbInfo.Srb == NULL);
2559
2560 /* Compile a list from the device queue */
2561 IrpList = NULL;
2562 while ((Entry = KeRemoveDeviceQueue(&LunExtension->DeviceQueue)) != NULL)
2563 {
2564 NextIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
2565
2566 /* Get the Srb */
2567 Stack = IoGetCurrentIrpStackLocation(NextIrp);
2568 Srb = Stack->Parameters.Scsi.Srb;
2569
2570 /* Set statuse */
2571 Srb->SrbStatus = SRB_STATUS_REQUEST_FLUSHED;
2572 NextIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
2573
2574 /* Add then to the list */
2575 NextIrp->Tail.Overlay.ListEntry.Flink = (PLIST_ENTRY)IrpList;
2576 IrpList = NextIrp;
2577 }
2578
2579 /* Unfreeze the queue */
2580 LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
2581
2582 /* Release the spinlock */
2583 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql);
2584
2585 /* Complete those requests */
2586 while (IrpList)
2587 {
2588 NextIrp = IrpList;
2589 IrpList = (PIRP)NextIrp->Tail.Overlay.ListEntry.Flink;
2590
2591 IoCompleteRequest(NextIrp, 0);
2592 }
2593
2594 Status = STATUS_SUCCESS;
2595 break;
2596
2597 default:
2598 DPRINT1("SRB function not implemented (Function %lu)\n", Srb->Function);
2599 Status = STATUS_NOT_IMPLEMENTED;
2600 break;
2601 }
2602
2603 Irp->IoStatus.Status = Status;
2604
2605 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2606
2607 return(Status);
2608 }
2609
2610
2611 /**********************************************************************
2612 * NAME INTERNAL
2613 * ScsiPortDeviceControl
2614 *
2615 * DESCRIPTION
2616 * Answer requests for device control calls
2617 *
2618 * RUN LEVEL
2619 * PASSIVE_LEVEL
2620 *
2621 * ARGUMENTS
2622 * Standard dispatch arguments
2623 *
2624 * RETURNS
2625 * NTSTATUS
2626 */
2627
2628 static NTSTATUS STDCALL
2629 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
2630 IN PIRP Irp)
2631 {
2632 PIO_STACK_LOCATION Stack;
2633 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2634 NTSTATUS Status = STATUS_SUCCESS;;
2635
2636 DPRINT("ScsiPortDeviceControl()\n");
2637
2638 Irp->IoStatus.Information = 0;
2639
2640 Stack = IoGetCurrentIrpStackLocation(Irp);
2641 DeviceExtension = DeviceObject->DeviceExtension;
2642
2643 switch (Stack->Parameters.DeviceIoControl.IoControlCode)
2644 {
2645 case IOCTL_SCSI_GET_DUMP_POINTERS:
2646 {
2647 PDUMP_POINTERS DumpPointers;
2648 DPRINT(" IOCTL_SCSI_GET_DUMP_POINTERS\n");
2649 DumpPointers = (PDUMP_POINTERS)Irp->AssociatedIrp.SystemBuffer;
2650 DumpPointers->DeviceObject = DeviceObject;
2651
2652 Irp->IoStatus.Information = sizeof(DUMP_POINTERS);
2653 }
2654 break;
2655
2656 case IOCTL_SCSI_GET_CAPABILITIES:
2657 DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
2658 if (Stack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(PVOID))
2659 {
2660 *((PVOID *)Irp->AssociatedIrp.SystemBuffer) = &DeviceExtension->PortCapabilities;
2661
2662 Irp->IoStatus.Information = sizeof(PVOID);
2663 Status = STATUS_SUCCESS;
2664 break;
2665 }
2666
2667 if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(IO_SCSI_CAPABILITIES))
2668 {
2669 Status = STATUS_BUFFER_TOO_SMALL;
2670 break;
2671 }
2672
2673 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
2674 &DeviceExtension->PortCapabilities,
2675 sizeof(IO_SCSI_CAPABILITIES));
2676
2677 Irp->IoStatus.Information = sizeof(IO_SCSI_CAPABILITIES);
2678 Status = STATUS_SUCCESS;
2679 break;
2680
2681 case IOCTL_SCSI_GET_INQUIRY_DATA:
2682 DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
2683
2684 /* Copy inquiry data to the port device extension */
2685 Status = SpiGetInquiryData(DeviceExtension, Irp);
2686 break;
2687
2688 default:
2689 DPRINT1(" unknown ioctl code: 0x%lX\n",
2690 Stack->Parameters.DeviceIoControl.IoControlCode);
2691 break;
2692 }
2693
2694 /* Complete the request with the given status */
2695 Irp->IoStatus.Status = Status;
2696 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2697
2698 return Status;
2699 }
2700
2701
2702 static VOID STDCALL
2703 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
2704 IN PIRP Irp)
2705 {
2706 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2707 PSCSI_PORT_LUN_EXTENSION LunExtension;
2708 PIO_STACK_LOCATION IrpStack;
2709 PSCSI_REQUEST_BLOCK Srb;
2710 PSCSI_REQUEST_BLOCK_INFO SrbInfo;
2711 LONG CounterResult;
2712 NTSTATUS Status;
2713
2714 DPRINT("ScsiPortStartIo() called!\n");
2715
2716 DeviceExtension = DeviceObject->DeviceExtension;
2717 IrpStack = IoGetCurrentIrpStackLocation(Irp);
2718
2719 DPRINT("DeviceExtension %p\n", DeviceExtension);
2720
2721 Srb = IrpStack->Parameters.Scsi.Srb;
2722
2723 /* Apply "default" flags */
2724 Srb->SrbFlags |= DeviceExtension->SrbFlags;
2725
2726 /* Get LUN extension */
2727 LunExtension = SpiGetLunExtension(DeviceExtension,
2728 Srb->PathId,
2729 Srb->TargetId,
2730 Srb->Lun);
2731
2732 if (DeviceExtension->NeedSrbDataAlloc ||
2733 DeviceExtension->NeedSrbExtensionAlloc)
2734 {
2735 /* Allocate them */
2736 SrbInfo = SpiAllocateSrbStructures(DeviceExtension,
2737 LunExtension,
2738 Srb);
2739
2740 /* Couldn't alloc one or both data structures, return */
2741 if (SrbInfo == NULL)
2742 {
2743 /* We have to call IoStartNextPacket, because this request
2744 was not started */
2745 if (LunExtension->Flags & LUNEX_REQUEST_PENDING)
2746 IoStartNextPacket(DeviceObject, FALSE);
2747
2748 return;
2749 }
2750 }
2751 else
2752 {
2753 /* No allocations are needed */
2754 SrbInfo = &LunExtension->SrbInfo;
2755 Srb->SrbExtension = NULL;
2756 Srb->QueueTag = SP_UNTAGGED;
2757 }
2758
2759 /* Increase sequence number of SRB */
2760 if (!SrbInfo->SequenceNumber)
2761 {
2762 /* Increase global sequence number */
2763 DeviceExtension->SequenceNumber++;
2764
2765 /* Assign it */
2766 SrbInfo->SequenceNumber = DeviceExtension->SequenceNumber;
2767 }
2768
2769 /* Check some special SRBs */
2770 if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
2771 {
2772 /* Some special handling */
2773 DPRINT1("Abort command! Unimplemented now\n");
2774 }
2775 else
2776 {
2777 SrbInfo->Srb = Srb;
2778 }
2779
2780 if (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION)
2781 {
2782 // Store the MDL virtual address in SrbInfo structure
2783 SrbInfo->DataOffset = MmGetMdlVirtualAddress(Irp->MdlAddress);
2784
2785 if (DeviceExtension->MapBuffers && Irp->MdlAddress)
2786 {
2787 /* Calculate offset within DataBuffer */
2788 SrbInfo->DataOffset = MmGetSystemAddressForMdl(Irp->MdlAddress);
2789 Srb->DataBuffer = SrbInfo->DataOffset +
2790 (ULONG)((PUCHAR)Srb->DataBuffer -
2791 (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress));
2792 }
2793
2794 if (DeviceExtension->AdapterObject)
2795 {
2796 /* Flush buffers */
2797 KeFlushIoBuffers(Irp->MdlAddress,
2798 Srb->SrbFlags & SRB_FLAGS_DATA_IN ? TRUE : FALSE,
2799 TRUE);
2800 }
2801
2802 if (DeviceExtension->MapRegisters)
2803 {
2804 /* Calculate number of needed map registers */
2805 SrbInfo->NumberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
2806 Srb->DataBuffer,
2807 Srb->DataTransferLength);
2808
2809 /* Allocate adapter channel */
2810 Status = IoAllocateAdapterChannel(DeviceExtension->AdapterObject,
2811 DeviceExtension->DeviceObject,
2812 SrbInfo->NumberOfMapRegisters,
2813 SpiAdapterControl,
2814 SrbInfo);
2815
2816 if (!NT_SUCCESS(Status))
2817 {
2818 DPRINT1("IoAllocateAdapterChannel() failed!\n");
2819
2820 Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
2821 ScsiPortNotification(RequestComplete,
2822 DeviceExtension + 1,
2823 Srb);
2824
2825 ScsiPortNotification(NextRequest,
2826 DeviceExtension + 1);
2827
2828 /* Request DPC for that work */
2829 IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
2830 }
2831
2832 /* Control goes to SpiAdapterControl */
2833 return;
2834 }
2835 }
2836
2837 /* Increase active request counter */
2838 CounterResult = InterlockedIncrement(&DeviceExtension->ActiveRequestCounter);
2839
2840 if (CounterResult == 0 &&
2841 DeviceExtension->AdapterObject != NULL &&
2842 !DeviceExtension->MapRegisters)
2843 {
2844 #if 0
2845 IoAllocateAdapterChannel(
2846 DeviceExtension->AdapterObject,
2847 DeviceObject,
2848 DeviceExtension->PortCapabilities.MaximumPhysicalPages,
2849 ScsiPortAllocationRoutine,
2850 LunExtension
2851 );
2852
2853 return;
2854 #else
2855 /* TODO: DMA is not implemented yet */
2856 ASSERT(FALSE);
2857 #endif
2858 }
2859
2860
2861 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
2862
2863 if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
2864 ScsiPortStartPacket,
2865 DeviceObject))
2866 {
2867 DPRINT("Synchronization failed!\n");
2868
2869 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
2870 Irp->IoStatus.Information = 0;
2871 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
2872
2873 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2874 }
2875
2876 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
2877
2878 DPRINT("ScsiPortStartIo() done\n");
2879 }
2880
2881
2882 static BOOLEAN STDCALL
2883 ScsiPortStartPacket(IN OUT PVOID Context)
2884 {
2885 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
2886 PIO_STACK_LOCATION IrpStack;
2887 PSCSI_REQUEST_BLOCK Srb;
2888 PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)Context;
2889 PSCSI_PORT_LUN_EXTENSION LunExtension;
2890 BOOLEAN Result;
2891 BOOLEAN StartTimer;
2892
2893 DPRINT("ScsiPortStartPacket() called\n");
2894
2895 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
2896
2897 IrpStack = IoGetCurrentIrpStackLocation(DeviceObject->CurrentIrp);
2898 Srb = IrpStack->Parameters.Scsi.Srb;
2899
2900 /* Get LUN extension */
2901 LunExtension = SpiGetLunExtension(DeviceExtension,
2902 Srb->PathId,
2903 Srb->TargetId,
2904 Srb->Lun);
2905
2906 /* Check if we are in a reset state */
2907 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET)
2908 {
2909 /* Mark the we've got requests while being in the reset state */
2910 DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET_REQUEST;
2911 return TRUE;
2912 }
2913
2914 /* Set the time out value */
2915 DeviceExtension->TimerCount = Srb->TimeOutValue;
2916
2917 /* We are busy */
2918 DeviceExtension->Flags |= SCSI_PORT_DEVICE_BUSY;
2919
2920 if (LunExtension->RequestTimeout != -1)
2921 {
2922 /* Timer already active */
2923 StartTimer = FALSE;
2924 }
2925 else
2926 {
2927 /* It hasn't been initialized yet */
2928 LunExtension->RequestTimeout = Srb->TimeOutValue;
2929 StartTimer = TRUE;
2930 }
2931
2932 if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
2933 {
2934 /* Handle bypass-requests */
2935
2936 /* Is this an abort request? */
2937 if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
2938 {
2939 PSCSI_REQUEST_BLOCK_INFO SrbInfo;
2940
2941 /* Get pointer to SRB info structure */
2942 SrbInfo = SpiGetSrbData(DeviceExtension,
2943 Srb->PathId,
2944 Srb->TargetId,
2945 Srb->Lun,
2946 Srb->QueueTag);
2947
2948 /* Check if the request is still "active" */
2949 if (SrbInfo == NULL ||
2950 SrbInfo->Srb == NULL ||
2951 !(SrbInfo->Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE))
2952 {
2953 /* It's not, mark it as active then */
2954 Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
2955
2956 if (StartTimer)
2957 LunExtension->RequestTimeout = -1;
2958
2959 DPRINT("Request has been already completed, but abort request came\n");
2960 Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
2961
2962 /* Notify about request complete */
2963 ScsiPortNotification(RequestComplete,
2964 DeviceExtension->MiniPortDeviceExtension,
2965 Srb);
2966
2967 /* and about readiness for the next request */
2968 ScsiPortNotification(NextRequest,
2969 DeviceExtension->MiniPortDeviceExtension);
2970
2971 /* They might ask for some work, so queue the DPC for them */
2972 IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
2973
2974 /* We're done in this branch */
2975 return TRUE;
2976 }
2977 }
2978 else
2979 {
2980 /* Add number of queued requests */
2981 LunExtension->QueueCount++;
2982 }
2983
2984 /* Bypass requests don't need request sense */
2985 LunExtension->Flags &= ~LUNEX_NEED_REQUEST_SENSE;
2986
2987 /* Is disconnect disabled for this request? */
2988 if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
2989 {
2990 /* Set the corresponding flag */
2991 DeviceExtension->Flags &= ~SCSI_PORT_DISCONNECT_ALLOWED;
2992 }
2993
2994 /* Transfer timeout value from Srb to Lun */
2995 LunExtension->RequestTimeout = Srb->TimeOutValue;
2996 }
2997 else
2998 {
2999 if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
3000 {
3001 /* It's a disconnect, so no more requests can go */
3002 DeviceExtension->Flags &= ~SCSI_PORT_DISCONNECT_ALLOWED;
3003 }
3004
3005 LunExtension->Flags |= SCSI_PORT_LU_ACTIVE;
3006
3007 /* Increment queue count */
3008 LunExtension->QueueCount++;
3009
3010 /* If it's tagged - special thing */
3011 if (Srb->QueueTag != SP_UNTAGGED)
3012 {
3013 /* TODO: Support tagged requests */
3014 ASSERT(FALSE);
3015 }
3016 }
3017
3018 /* Mark this Srb active */
3019 Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
3020
3021 /* Call HwStartIo routine */
3022 Result = DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
3023 Srb);
3024
3025 /* If notification is needed, then request a DPC */
3026 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
3027 IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
3028
3029 return Result;
3030 }
3031
3032 IO_ALLOCATION_ACTION
3033 STDCALL
3034 SpiAdapterControl(PDEVICE_OBJECT DeviceObject,
3035 PIRP Irp,
3036 PVOID MapRegisterBase,
3037 PVOID Context)
3038 {
3039 PSCSI_REQUEST_BLOCK Srb;
3040 PSCSI_SG_ADDRESS ScatterGatherList;
3041 KIRQL CurrentIrql;
3042 PIO_STACK_LOCATION IrpStack;
3043 ULONG TotalLength = 0;
3044 PSCSI_REQUEST_BLOCK_INFO SrbInfo;
3045 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
3046 PUCHAR DataVA;
3047 BOOLEAN WriteToDevice;
3048
3049 /* Get pointers to SrbInfo and DeviceExtension */
3050 SrbInfo = (PSCSI_REQUEST_BLOCK_INFO)Context;
3051 DeviceExtension = DeviceObject->DeviceExtension;
3052
3053 /* Get pointer to SRB */
3054 IrpStack = IoGetCurrentIrpStackLocation(Irp);
3055 Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
3056
3057 /* Depending on the map registers number, we allocate
3058 either from NonPagedPool, or from our static list */
3059 if (SrbInfo->NumberOfMapRegisters > MAX_SG_LIST)
3060 {
3061 SrbInfo->ScatterGather = ExAllocatePoolWithTag(
3062 NonPagedPool, SrbInfo->NumberOfMapRegisters * sizeof(SCSI_SG_ADDRESS), TAG_SCSIPORT);
3063
3064 if (SrbInfo->ScatterGather == NULL)
3065 ASSERT(FALSE);
3066
3067 Srb->SrbFlags |= SRB_FLAGS_SGLIST_FROM_POOL;
3068 }
3069 else
3070 {
3071 SrbInfo->ScatterGather = SrbInfo->ScatterGatherList;
3072 }
3073
3074 /* Use chosen SG list source */
3075 ScatterGatherList = SrbInfo->ScatterGather;
3076
3077 /* Save map registers base */
3078 SrbInfo->BaseOfMapRegister = MapRegisterBase;
3079
3080 /* Determine WriteToDevice flag */
3081 WriteToDevice = Srb->SrbFlags & SRB_FLAGS_DATA_OUT ? TRUE : FALSE;
3082
3083 /* Get virtual address of the data buffer */
3084 DataVA = (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress) +
3085 ((PCHAR)Srb->DataBuffer - SrbInfo->DataOffset);
3086
3087 /* Build the actual SG list */
3088 while (TotalLength < Srb->DataTransferLength)
3089 {
3090 if (!ScatterGatherList)
3091 break;
3092
3093 ScatterGatherList->Length = Srb->DataTransferLength - TotalLength;
3094 ScatterGatherList->PhysicalAddress = IoMapTransfer(DeviceExtension->AdapterObject,
3095 Irp->MdlAddress,
3096 MapRegisterBase,
3097 DataVA + TotalLength,
3098 &ScatterGatherList->Length,
3099 WriteToDevice);
3100
3101 TotalLength += ScatterGatherList->Length;
3102 ScatterGatherList++;
3103 }
3104
3105 /* Schedule an active request */
3106 InterlockedIncrement(&DeviceExtension->ActiveRequestCounter );
3107 KeAcquireSpinLock(&DeviceExtension->SpinLock, &CurrentIrql);
3108 KeSynchronizeExecution(DeviceExtension->Interrupt,
3109 ScsiPortStartPacket,
3110 DeviceObject);
3111 KeReleaseSpinLock(&DeviceExtension->SpinLock, CurrentIrql);
3112
3113 return DeallocateObjectKeepRegisters;
3114 }
3115
3116 static PSCSI_PORT_LUN_EXTENSION
3117 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
3118 {
3119 PSCSI_PORT_LUN_EXTENSION LunExtension;
3120 ULONG LunExtensionSize;
3121
3122 DPRINT("SpiAllocateLunExtension (%p)\n",
3123 DeviceExtension);
3124
3125 /* Round LunExtensionSize first to the sizeof LONGLONG */
3126 LunExtensionSize = (DeviceExtension->LunExtensionSize +
3127 sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1);
3128
3129 LunExtensionSize += sizeof(SCSI_PORT_LUN_EXTENSION);
3130 DPRINT("LunExtensionSize %lu\n", LunExtensionSize);
3131
3132 LunExtension = ExAllocatePoolWithTag(NonPagedPool, LunExtensionSize, TAG_SCSIPORT);
3133 if (LunExtension == NULL)
3134 {
3135 DPRINT1("Out of resources!\n");
3136 return NULL;
3137 }
3138
3139 /* Zero everything */
3140 RtlZeroMemory(LunExtension, LunExtensionSize);
3141
3142 /* Initialize a list of requests */
3143 InitializeListHead(&LunExtension->SrbInfo.Requests);
3144
3145 /* Initialize timeout counter */
3146 LunExtension->RequestTimeout = -1;
3147
3148 /* Set maximum queue size */
3149 LunExtension->MaxQueueCount = 256;
3150
3151 /* Initialize request queue */
3152 KeInitializeDeviceQueue (&LunExtension->DeviceQueue);
3153
3154 return LunExtension;
3155 }
3156
3157 static PSCSI_PORT_LUN_EXTENSION
3158 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
3159 IN UCHAR PathId,
3160 IN UCHAR TargetId,
3161 IN UCHAR Lun)
3162 {
3163 PSCSI_PORT_LUN_EXTENSION LunExtension;
3164
3165 DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
3166 DeviceExtension, PathId, TargetId, Lun);
3167
3168 /* Get appropriate list */
3169 LunExtension = DeviceExtension->LunExtensionList[(TargetId + Lun) % LUS_NUMBER];
3170
3171 /* Iterate it until we find what we need */
3172 while (LunExtension)
3173 {
3174 if (LunExtension->TargetId == TargetId &&
3175 LunExtension->Lun == Lun &&
3176 LunExtension->PathId == PathId)
3177 {
3178 /* All matches, return */
3179 return LunExtension;
3180 }
3181
3182 /* Advance to the next item */
3183 LunExtension = LunExtension->Next;
3184 }
3185
3186 /* We did not find anything */
3187 DPRINT("Nothing found\n");
3188 return NULL;
3189 }
3190
3191 static PSCSI_REQUEST_BLOCK_INFO
3192 SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
3193 PSCSI_PORT_LUN_EXTENSION LunExtension,
3194 PSCSI_REQUEST_BLOCK Srb)
3195 {
3196 PCHAR SrbExtension;
3197 PSCSI_REQUEST_BLOCK_INFO SrbInfo;
3198
3199 /* Spinlock must be held while this function executes */
3200 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
3201
3202 /* Allocate SRB data structure */
3203 if (DeviceExtension->NeedSrbDataAlloc)
3204 {
3205 /* Treat the abort request in a special way */
3206 if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
3207 {
3208 SrbInfo = SpiGetSrbData(DeviceExtension,
3209 Srb->PathId,
3210 Srb->TargetId,
3211 Srb->Lun,
3212 Srb->QueueTag);
3213 }
3214 else if (Srb->SrbFlags &
3215 (SRB_FLAGS_QUEUE_ACTION_ENABLE | SRB_FLAGS_NO_QUEUE_FREEZE) &&
3216 !(Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
3217 )
3218 {
3219 /* Do not process tagged commands if need request sense is set */
3220 if (LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE)
3221 {
3222 ASSERT(!(LunExtension->Flags & LUNEX_REQUEST_PENDING));
3223
3224 LunExtension->PendingRequest = Srb->OriginalRequest;
3225 LunExtension->Flags |= LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE;
3226
3227 /* Relese the spinlock and return */
3228 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3229 return NULL;
3230 }
3231
3232 ASSERT(LunExtension->SrbInfo.Srb == NULL);
3233 SrbInfo = DeviceExtension->FreeSrbInfo;
3234
3235 if (SrbInfo == NULL)
3236 {
3237 /* No SRB structures left in the list. We have to leave
3238 and wait while we are called again */
3239
3240 DeviceExtension->Flags |= SCSI_PORT_REQUEST_PENDING;
3241 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3242 return NULL;
3243 }
3244
3245 DeviceExtension->FreeSrbInfo = (PSCSI_REQUEST_BLOCK_INFO)SrbInfo->Requests.Flink;
3246
3247 /* QueueTag must never be 0, so +1 to it */
3248 Srb->QueueTag = (UCHAR)(SrbInfo - DeviceExtension->SrbInfo) + 1;
3249 }
3250 else
3251 {
3252 /* Usual untagged command */
3253 if (
3254 (!IsListEmpty(&LunExtension->SrbInfo.Requests) ||
3255 LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE) &&
3256 !(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
3257 )
3258 {
3259 /* Mark it as pending and leave */
3260 ASSERT(!(LunExtension->Flags & LUNEX_REQUEST_PENDING));
3261 LunExtension->Flags |= LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE;
3262 LunExtension->PendingRequest = Srb->OriginalRequest;
3263
3264 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3265 return(NULL);
3266 }
3267
3268 Srb->QueueTag = SP_UNTAGGED;
3269 SrbInfo = &LunExtension->SrbInfo;
3270 }
3271 }
3272 else
3273 {
3274 Srb->QueueTag = SP_UNTAGGED;
3275 SrbInfo = &LunExtension->SrbInfo;
3276 }
3277
3278 /* Allocate SRB extension structure */
3279 if (DeviceExtension->NeedSrbExtensionAlloc)
3280 {
3281 /* Check the list of free extensions */
3282 SrbExtension = DeviceExtension->FreeSrbExtensions;
3283
3284 /* If no free extensions... */
3285 if (SrbExtension == NULL)
3286 {
3287 /* Free SRB data */
3288 if (Srb->Function != SRB_FUNCTION_ABORT_COMMAND &&
3289 Srb->QueueTag != SP_UNTAGGED)
3290 {
3291 SrbInfo->Requests.Blink = NULL;
3292 SrbInfo->Requests.Flink = (PLIST_ENTRY)DeviceExtension->FreeSrbInfo;
3293 DeviceExtension->FreeSrbInfo = SrbInfo;
3294 }
3295
3296 /* Return, in order to be called again later */
3297 DeviceExtension->Flags |= SCSI_PORT_REQUEST_PENDING;
3298 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3299 return NULL;
3300 }
3301
3302 /* Remove that free SRB extension from the list (since
3303 we're going to use it) */
3304 DeviceExtension->FreeSrbExtensions = *((PVOID *)SrbExtension);
3305
3306 /* Spinlock can be released now */
3307 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3308
3309 Srb->SrbExtension = SrbExtension;
3310
3311 if (Srb->SenseInfoBuffer != NULL &&
3312 DeviceExtension->SupportsAutoSense)
3313 {
3314 /* Store pointer to the SenseInfo buffer */
3315 SrbInfo->SaveSenseRequest = Srb->SenseInfoBuffer;
3316
3317 /* Does data fit the buffer? */
3318 if (Srb->SenseInfoBufferLength > sizeof(SENSE_DATA))
3319 {
3320 /* No, disabling autosense at all */
3321 Srb->SrbFlags |= SRB_FLAGS_DISABLE_AUTOSENSE;
3322 }
3323 else
3324 {
3325 /* Yes, update the buffer pointer */
3326 Srb->SenseInfoBuffer = SrbExtension + DeviceExtension->SrbExtensionSize;
3327 }
3328 }
3329 }
3330 else
3331 {
3332 /* Cleanup... */
3333 Srb->SrbExtension = NULL;
3334 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
3335 }
3336
3337 return SrbInfo;
3338 }
3339
3340
3341 static NTSTATUS
3342 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject,
3343 IN PSCSI_LUN_INFO LunInfo)
3344 {
3345 IO_STATUS_BLOCK IoStatusBlock;
3346 PIO_STACK_LOCATION IrpStack;
3347 KEVENT Event;
3348 KIRQL Irql;
3349 PIRP Irp;
3350 NTSTATUS Status;
3351 PINQUIRYDATA InquiryBuffer;
3352 PSENSE_DATA SenseBuffer;
3353 BOOLEAN KeepTrying = TRUE;
3354 ULONG RetryCount = 0;
3355 SCSI_REQUEST_BLOCK Srb;
3356 PCDB Cdb;
3357 PSCSI_PORT_LUN_EXTENSION LunExtension;
3358 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
3359
3360 DPRINT ("SpiSendInquiry() called\n");
3361
3362 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
3363
3364 InquiryBuffer = ExAllocatePoolWithTag (NonPagedPool, INQUIRYDATABUFFERSIZE, TAG_SCSIPORT);
3365 if (InquiryBuffer == NULL)
3366 return STATUS_INSUFFICIENT_RESOURCES;
3367
3368 SenseBuffer = ExAllocatePoolWithTag (NonPagedPool, SENSE_BUFFER_SIZE, TAG_SCSIPORT);
3369 if (SenseBuffer == NULL)
3370 {
3371 ExFreePool(InquiryBuffer);
3372 return STATUS_INSUFFICIENT_RESOURCES;
3373 }
3374
3375 while (KeepTrying)
3376 {
3377 /* Initialize event for waiting */
3378 KeInitializeEvent(&Event,
3379 NotificationEvent,
3380 FALSE);
3381
3382 /* Create an IRP */
3383 Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_IN,
3384 DeviceObject,
3385 NULL,
3386 0,
3387 InquiryBuffer,
3388 INQUIRYDATABUFFERSIZE,
3389 TRUE,
3390 &Event,
3391 &IoStatusBlock);
3392 if (Irp == NULL)
3393 {
3394 DPRINT("IoBuildDeviceIoControlRequest() failed\n");
3395 return STATUS_INSUFFICIENT_RESOURCES;
3396 }
3397
3398 /* Prepare SRB */
3399 RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
3400
3401 Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
3402 Srb.OriginalRequest = Irp;
3403 Srb.PathId = LunInfo->PathId;
3404 Srb.TargetId = LunInfo->TargetId;
3405 Srb.Lun = LunInfo->Lun;
3406 Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
3407 Srb.SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
3408 Srb.TimeOutValue = 4;
3409 Srb.CdbLength = 6;
3410
3411 Srb.SenseInfoBuffer = SenseBuffer;
3412 Srb.SenseInfoBufferLength = SENSE_BUFFER_SIZE;
3413
3414 Srb.DataBuffer = InquiryBuffer;
3415 Srb.DataTransferLength = INQUIRYDATABUFFERSIZE;
3416
3417 /* Attach Srb to the Irp */
3418 IrpStack = IoGetNextIrpStackLocation (Irp);
3419 IrpStack->Parameters.Scsi.Srb = &Srb;
3420
3421 /* Fill in CDB */
3422 Cdb = (PCDB)Srb.Cdb;
3423 Cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
3424 Cdb->CDB6INQUIRY.LogicalUnitNumber = LunInfo->Lun;
3425 Cdb->CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE;
3426
3427 /* Call the driver */
3428 Status = IoCallDriver(DeviceObject, Irp);
3429
3430 /* Wait for it to complete */
3431 if (Status == STATUS_PENDING)
3432 {
3433 DPRINT("SpiSendInquiry(): Waiting for the driver to process request...\n");
3434 KeWaitForSingleObject(&Event,
3435 Executive,
3436 KernelMode,
3437 FALSE,
3438 NULL);
3439 Status = IoStatusBlock.Status;
3440 }
3441
3442 DPRINT("SpiSendInquiry(): Request processed by driver, status = 0x%08X\n", Status);
3443
3444 if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_SUCCESS)
3445 {
3446 /* All fine, copy data over */
3447 RtlCopyMemory(LunInfo->InquiryData,
3448 InquiryBuffer,
3449 INQUIRYDATABUFFERSIZE);
3450
3451 Status = STATUS_SUCCESS;
3452 KeepTrying = FALSE;
3453 }
3454 else
3455 {
3456 DPRINT("Inquiry SRB failed with SrbStatus 0x%08X\n", Srb.SrbStatus);
3457 /* Check if the queue is frozen */
3458 if (Srb.SrbStatus & SRB_STATUS_QUEUE_FROZEN)
3459 {
3460 /* Something weird happened, deal with it (unfreeze the queue) */
3461 KeepTrying = FALSE;
3462
3463 DPRINT("SpiSendInquiry(): the queue is frozen at TargetId %d\n", Srb.TargetId);
3464
3465 LunExtension = SpiGetLunExtension(DeviceExtension,
3466 LunInfo->PathId,
3467 LunInfo->TargetId,
3468 LunInfo->Lun);
3469
3470 /* Clear frozen flag */
3471 LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE;
3472
3473 /* Acquire the spinlock */
3474 KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql);
3475
3476 /* Process the request */
3477 SpiGetNextRequestFromLun(DeviceObject->DeviceExtension, LunExtension);
3478
3479 /* SpiGetNextRequestFromLun() releases the spinlock,
3480 so we just lower irql back to what it was before */
3481 KeLowerIrql(Irql);
3482 }
3483
3484 /* Check if data overrun happened */
3485 if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN)
3486 {
3487 DPRINT("Data overrun at TargetId %d\n", LunInfo->TargetId);
3488 /* Nothing dramatic, just copy data, but limiting the size */
3489 RtlCopyMemory(LunInfo->InquiryData,
3490 InquiryBuffer,
3491 (Srb.DataTransferLength > INQUIRYDATABUFFERSIZE) ?
3492 INQUIRYDATABUFFERSIZE : Srb.DataTransferLength);
3493
3494 Status = STATUS_SUCCESS;
3495 KeepTrying = FALSE;
3496 }
3497 else if ((Srb.SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
3498 SenseBuffer->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST)
3499 {
3500 /* LUN is not valid, but some device responds there.
3501 Mark it as invalid anyway */
3502
3503 Status = STATUS_INVALID_DEVICE_REQUEST;
3504 KeepTrying = FALSE;
3505 }
3506 else
3507 {
3508 /* Retry a couple of times if no timeout happened */
3509 if ((RetryCount < 2) &&
3510 (SRB_STATUS(Srb.SrbStatus) != SRB_STATUS_NO_DEVICE) &&
3511 (SRB_STATUS(Srb.SrbStatus) != SRB_STATUS_SELECTION_TIMEOUT))
3512 {
3513 RetryCount++;
3514 KeepTrying = TRUE;
3515 }
3516 else
3517 {
3518 /* That's all, go to exit */
3519 KeepTrying = FALSE;
3520
3521 /* Set status according to SRB status */
3522 if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_BAD_FUNCTION ||
3523 SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_BAD_SRB_BLOCK_LENGTH)
3524 {
3525 Status = STATUS_INVALID_DEVICE_REQUEST;
3526 }
3527 else
3528 {
3529 Status = STATUS_IO_DEVICE_ERROR;
3530 }
3531 }
3532 }
3533 }
3534 }
3535
3536 /* Free buffers */
3537 ExFreePool(InquiryBuffer);
3538 ExFreePool(SenseBuffer);
3539
3540 DPRINT("SpiSendInquiry() done with Status 0x%08X\n", Status);
3541
3542 return Status;
3543 }
3544
3545
3546 /* Scans all SCSI buses */
3547 static VOID
3548 SpiScanAdapter(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
3549 {
3550 PSCSI_PORT_LUN_EXTENSION LunExtension;
3551 ULONG Bus;
3552 ULONG Target;
3553 ULONG Lun;
3554 PSCSI_BUS_SCAN_INFO BusScanInfo;
3555 PSCSI_LUN_INFO LastLunInfo, LunInfo, LunInfoExists;
3556 BOOLEAN DeviceExists;
3557 ULONG Hint;
3558 NTSTATUS Status;
3559 ULONG DevicesFound;
3560
3561 DPRINT("SpiScanAdapter() called\n");
3562
3563 /* Scan all buses */
3564 for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
3565 {
3566 DPRINT(" Scanning bus %d\n", Bus);
3567 DevicesFound = 0;
3568
3569 /* Get pointer to the scan information */
3570 BusScanInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus];
3571
3572 if (BusScanInfo)
3573 {
3574 /* Find the last LUN info in the list */
3575 LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
3576 LastLunInfo = LunInfo;
3577
3578 while (LunInfo != NULL)
3579 {
3580 LastLunInfo = LunInfo;
3581 LunInfo = LunInfo->Next;
3582 }
3583 }
3584 else
3585 {
3586 /* We need to allocate this buffer */
3587 BusScanInfo = ExAllocatePoolWithTag(NonPagedPool, sizeof(SCSI_BUS_SCAN_INFO), TAG_SCSIPORT);
3588
3589 if (!BusScanInfo)
3590 {
3591 DPRINT1("Out of resources!\n");
3592 return;
3593 }
3594
3595 /* Store the pointer in the BusScanInfo array */
3596 DeviceExtension->BusesConfig->BusScanInfo[Bus] = BusScanInfo;
3597
3598 /* Fill this struct (length and bus ids for now) */
3599 BusScanInfo->Length = sizeof(SCSI_BUS_SCAN_INFO);
3600 BusScanInfo->LogicalUnitsCount = 0;
3601 BusScanInfo->BusIdentifier = DeviceExtension->PortConfig->InitiatorBusId[Bus];
3602 BusScanInfo->LunInfo = NULL;
3603
3604 /* Set pointer to the last LUN info to NULL */
3605 LastLunInfo = NULL;
3606 }
3607
3608 /* Create LUN information structure */
3609 LunInfo = ExAllocatePoolWithTag(PagedPool, sizeof(SCSI_LUN_INFO), TAG_SCSIPORT);
3610
3611 if (LunInfo == NULL)
3612 {
3613 DPRINT1("Out of resources!\n");
3614 return;
3615 }
3616
3617 RtlZeroMemory(LunInfo, sizeof(SCSI_LUN_INFO));
3618
3619 /* Create LunExtension */
3620 LunExtension = SpiAllocateLunExtension (DeviceExtension);
3621
3622 /* And send INQUIRY to every target */
3623 for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
3624 {
3625 /* TODO: Support scan bottom-up */
3626
3627 /* Skip if it's the same address */
3628 if (Target == BusScanInfo->BusIdentifier)
3629 continue;
3630
3631 /* Try to find an existing device here */
3632 DeviceExists = FALSE;
3633 LunInfoExists = BusScanInfo->LunInfo;
3634
3635 /* Find matching address on this bus */
3636 while (LunInfoExists)
3637 {
3638 if (LunInfoExists->TargetId == Target)
3639 {
3640 DeviceExists = TRUE;
3641 break;
3642 }
3643
3644 /* Advance to the next one */
3645 LunInfoExists = LunInfoExists->Next;
3646 }
3647
3648 /* No need to bother rescanning, since we already did that before */
3649 if (DeviceExists)
3650 continue;
3651
3652 /* Scan all logical units */
3653 for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
3654 {
3655 if ((!LunExtension) || (!LunInfo))
3656 break;
3657
3658 /* Add extension to the list */
3659 Hint = (Target + Lun) % LUS_NUMBER;
3660 LunExtension->Next = DeviceExtension->LunExtensionList[Hint];
3661 DeviceExtension->LunExtensionList[Hint] = LunExtension;
3662
3663 /* Fill Path, Target, Lun fields */
3664 LunExtension->PathId = LunInfo->PathId = (UCHAR)Bus;
3665 LunExtension->TargetId = LunInfo->TargetId = (UCHAR) Target;
3666 LunExtension->Lun = LunInfo->Lun = (UCHAR)Lun;
3667
3668 /* Set flag to prevent race conditions */
3669 LunExtension->Flags |= SCSI_PORT_SCAN_IN_PROGRESS;
3670
3671 /* Zero LU extension contents */
3672 if (DeviceExtension->LunExtensionSize)
3673 {
3674 RtlZeroMemory(LunExtension + 1,
3675 DeviceExtension->LunExtensionSize);
3676 }
3677
3678 /* Finally send the inquiry command */
3679 Status = SpiSendInquiry(DeviceExtension->DeviceObject, LunInfo);
3680
3681 if (NT_SUCCESS(Status))
3682 {
3683 /* Let's see if we really found a device */
3684 PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData;
3685
3686 /* Check if this device is unsupported */
3687 if (InquiryData->DeviceTypeQualifier == DEVICE_QUALIFIER_NOT_SUPPORTED)
3688 {
3689 DeviceExtension->LunExtensionList[Hint] =
3690 DeviceExtension->LunExtensionList[Hint]->Next;
3691
3692 continue;
3693 }
3694
3695 /* Clear the "in scan" flag */
3696 LunExtension->Flags &= ~SCSI_PORT_SCAN_IN_PROGRESS;
3697
3698 DPRINT("SpiScanAdapter(): Found device of type %d at bus %d tid %d lun %d\n",
3699 InquiryData->DeviceType, Bus, Target, Lun);
3700
3701 /* Add this info to the linked list */
3702 LunInfo->Next = NULL;
3703 if (LastLunInfo)
3704 LastLunInfo->Next = LunInfo;
3705 else
3706 BusScanInfo->LunInfo = LunInfo;
3707
3708 /* Store the last LUN info */
3709 LastLunInfo = LunInfo;
3710
3711 /* Store DeviceObject */
3712 LunInfo->DeviceObject = DeviceExtension->DeviceObject;
3713
3714 /* Allocate another buffer */
3715 LunInfo = ExAllocatePoolWithTag(PagedPool, sizeof(SCSI_LUN_INFO), TAG_SCSIPORT);
3716
3717 if (!LunInfo)
3718 {
3719 DPRINT1("Out of resources!\n");
3720 break;
3721 }
3722
3723 RtlZeroMemory(LunInfo, sizeof(SCSI_LUN_INFO));
3724
3725 /* Create a new LU extension */
3726 LunExtension = SpiAllocateLunExtension(DeviceExtension);
3727
3728 DevicesFound++;
3729 }
3730 else
3731 {
3732 /* Remove this LUN from the list */
3733 DeviceExtension->LunExtensionList[Hint] =
3734 DeviceExtension->LunExtensionList[Hint]->Next;
3735
3736 /* Decide whether we are continuing or not */
3737 if (Status == STATUS_INVALID_DEVICE_REQUEST)
3738 continue;
3739 else
3740 break;
3741 }
3742 }
3743 }
3744
3745 /* Free allocated buffers */
3746 if (LunExtension)
3747 ExFreePool(LunExtension);
3748
3749 if (LunInfo)
3750 ExFreePool(LunInfo);
3751
3752 /* Sum what we found */
3753 BusScanInfo->LogicalUnitsCount += (UCHAR) DevicesFound;
3754 DPRINT(" Found %d devices on bus %d\n", DevicesFound, Bus);
3755 }
3756
3757 DPRINT ("SpiScanAdapter() done\n");
3758 }
3759
3760
3761 static NTSTATUS
3762 SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
3763 PIRP Irp)
3764 {
3765 ULONG InquiryDataSize;
3766 PSCSI_LUN_INFO LunInfo;
3767 ULONG BusCount, LunCount, Length;
3768 PIO_STACK_LOCATION IrpStack;
3769 PSCSI_ADAPTER_BUS_INFO AdapterBusInfo;
3770 PSCSI_INQUIRY_DATA InquiryData;
3771 PSCSI_BUS_DATA BusData;
3772 ULONG Bus;
3773 PUCHAR Buffer;
3774
3775 DPRINT("SpiGetInquiryData() called\n");
3776
3777 /* Get pointer to the buffer */
3778 IrpStack = IoGetCurrentIrpStackLocation(Irp);
3779 Buffer = Irp->AssociatedIrp.SystemBuffer;
3780
3781 /* Initialize bus and LUN counters */
3782 BusCount = DeviceExtension->BusesConfig->NumberOfBuses;
3783 LunCount = 0;
3784
3785 /* Calculate total number of LUNs */
3786 for (Bus = 0; Bus < BusCount; Bus++)
3787 LunCount += DeviceExtension->BusesConfig->BusScanInfo[Bus]->LogicalUnitsCount;
3788
3789 /* Calculate size of inquiry data, rounding up to sizeof(ULONG) */
3790 InquiryDataSize =
3791 ((sizeof(SCSI_INQUIRY_DATA) - 1 + INQUIRYDATABUFFERSIZE +
3792 sizeof(ULONG) - 1) & ~(sizeof(ULONG) - 1));
3793
3794 /* Calculate data size */
3795 Length = sizeof(SCSI_ADAPTER_BUS_INFO) + (BusCount - 1) *
3796 sizeof(SCSI_BUS_DATA);
3797
3798 Length += InquiryDataSize * LunCount;
3799
3800 /* Check, if all data is going to fit into provided buffer */
3801 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < Length)
3802 {
3803 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
3804 return STATUS_BUFFER_TOO_SMALL;
3805 }
3806
3807 /* Store data size in the IRP */
3808 Irp->IoStatus.Information = Length;
3809
3810 DPRINT("Data size: %lu\n", Length);
3811
3812 AdapterBusInfo = (PSCSI_ADAPTER_BUS_INFO)Buffer;
3813
3814 AdapterBusInfo->NumberOfBuses = (UCHAR)BusCount;
3815
3816 /* Point InquiryData to the corresponding place inside Buffer */
3817 InquiryData = (PSCSI_INQUIRY_DATA)(Buffer + sizeof(SCSI_ADAPTER_BUS_INFO) +
3818 (BusCount - 1) * sizeof(SCSI_BUS_DATA));
3819
3820 /* Loop each bus */
3821 for (Bus = 0; Bus < BusCount; Bus++)
3822 {
3823 BusData = &AdapterBusInfo->BusData[Bus];
3824
3825 /* Calculate and save an offset of the inquiry data */
3826 BusData->InquiryDataOffset = (PUCHAR)InquiryData - Buffer;
3827
3828 /* Get a pointer to the LUN information structure */
3829 LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;
3830
3831 /* Store Initiator Bus Id */
3832 BusData->InitiatorBusId =
3833 DeviceExtension->BusesConfig->BusScanInfo[Bus]->BusIdentifier;
3834
3835 /* Store LUN count */
3836 BusData->NumberOfLogicalUnits =
3837 DeviceExtension->BusesConfig->BusScanInfo[Bus]->LogicalUnitsCount;
3838
3839 /* Loop all LUNs */
3840 while (LunInfo != NULL)
3841 {
3842 DPRINT("(Bus %lu Target %lu Lun %lu)\n",
3843 Bus, LunInfo->TargetId, LunInfo->Lun);
3844
3845 /* Fill InquiryData with values */
3846 InquiryData->PathId = LunInfo->PathId;
3847 InquiryData->TargetId = LunInfo->TargetId;
3848 InquiryData->Lun = LunInfo->Lun;
3849 InquiryData->InquiryDataLength = INQUIRYDATABUFFERSIZE;
3850 InquiryData->DeviceClaimed = LunInfo->DeviceClaimed;
3851 InquiryData->NextInquiryDataOffset =
3852 (PUCHAR)InquiryData + InquiryDataSize - Buffer;
3853
3854 /* Copy data in it */
3855 RtlCopyMemory(InquiryData->InquiryData,
3856 LunInfo->InquiryData,
3857 INQUIRYDATABUFFERSIZE);
3858
3859 /* Move to the next LUN */
3860 LunInfo = LunInfo->Next;
3861 InquiryData = (PSCSI_INQUIRY_DATA) ((PCHAR)InquiryData + InquiryDataSize);
3862 }
3863
3864 /* Either mark the end, or set offset to 0 */
3865 if (BusData->NumberOfLogicalUnits != 0)
3866 ((PSCSI_INQUIRY_DATA) ((PCHAR) InquiryData - InquiryDataSize))->NextInquiryDataOffset = 0;
3867 else
3868 BusData->InquiryDataOffset = 0;
3869 }
3870
3871 /* Finish with success */
3872 Irp->IoStatus.Status = STATUS_SUCCESS;
3873 return STATUS_SUCCESS;
3874 }
3875
3876 static PSCSI_REQUEST_BLOCK_INFO
3877 SpiGetSrbData(IN PVOID DeviceExtension,
3878 IN UCHAR PathId,
3879 IN UCHAR TargetId,
3880 IN UCHAR Lun,
3881 IN UCHAR QueueTag)
3882 {
3883 PSCSI_PORT_LUN_EXTENSION LunExtension;
3884
3885 if (QueueTag == SP_UNTAGGED)
3886 {
3887 /* Untagged request, get LU and return pointer to SrbInfo */
3888 LunExtension = SpiGetLunExtension(DeviceExtension,
3889 PathId,
3890 TargetId,
3891 Lun);
3892
3893 /* Return NULL in case of error */
3894 if (!LunExtension)
3895 return(NULL);
3896
3897 /* Return the pointer to SrbInfo */
3898 return &LunExtension->SrbInfo;
3899 }
3900 else
3901 {
3902 /* TODO: Implement when we have it */
3903 ASSERT(FALSE);
3904 return NULL;
3905 }
3906 }
3907
3908 static VOID
3909 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
3910 IN PSCSI_REQUEST_BLOCK InitialSrb)
3911 {
3912 PSCSI_REQUEST_BLOCK Srb;
3913 PCDB Cdb;
3914 PIRP Irp;
3915 PIO_STACK_LOCATION IrpStack;
3916 LARGE_INTEGER LargeInt;
3917 PVOID *Ptr;
3918
3919 DPRINT("SpiSendRequestSense() entered, InitialSrb %p\n", InitialSrb);
3920
3921 /* Allocate Srb */
3922 Srb = ExAllocatePoolWithTag(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK) + sizeof(PVOID), TAG_SCSIPORT);
3923 RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
3924
3925 /* Allocate IRP */
3926 LargeInt.QuadPart = (LONGLONG) 1;
3927 Irp = IoBuildAsynchronousFsdRequest(IRP_MJ_READ,
3928 DeviceExtension->DeviceObject,
3929 InitialSrb->SenseInfoBuffer,
3930 InitialSrb->SenseInfoBufferLength,
3931 &LargeInt,
3932 NULL);
3933
3934 IoSetCompletionRoutine(Irp,
3935 (PIO_COMPLETION_ROUTINE)SpiCompletionRoutine,
3936 Srb,
3937 TRUE,
3938 TRUE,
3939 TRUE);
3940
3941 if (!Srb)
3942 {
3943 DPRINT("SpiSendRequestSense() failed, Srb %p\n", Srb);
3944 return;
3945 }
3946
3947 IrpStack = IoGetNextIrpStackLocation(Irp);
3948 IrpStack->MajorFunction = IRP_MJ_SCSI;
3949
3950 /* Put Srb address into Irp... */
3951 IrpStack->Parameters.Others.Argument1 = (PVOID)Srb;
3952
3953 /* ...and vice versa */
3954 Srb->OriginalRequest = Irp;
3955
3956 /* Save Srb */
3957 Ptr = (PVOID *)(Srb+1);
3958 *Ptr = InitialSrb;
3959
3960 /* Build CDB for REQUEST SENSE */
3961 Srb->CdbLength = 6;
3962 Cdb = (PCDB)Srb->Cdb;
3963
3964 Cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE;
3965 Cdb->CDB6INQUIRY.LogicalUnitNumber = 0;
3966 Cdb->CDB6INQUIRY.Reserved1 = 0;
3967 Cdb->CDB6INQUIRY.PageCode = 0;
3968 Cdb->CDB6INQUIRY.IReserved = 0;
3969 Cdb->CDB6INQUIRY.AllocationLength = (UCHAR)InitialSrb->SenseInfoBufferLength;
3970 Cdb->CDB6INQUIRY.Control = 0;
3971
3972 /* Set address */
3973 Srb->TargetId = InitialSrb->TargetId;
3974 Srb->Lun = InitialSrb->Lun;
3975 Srb->PathId = InitialSrb->PathId;
3976
3977 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
3978 Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
3979
3980 /* Timeout will be 2 seconds */
3981 Srb->TimeOutValue = 2;
3982
3983 /* No auto request sense */
3984 Srb->SenseInfoBufferLength = 0;
3985 Srb->SenseInfoBuffer = NULL;
3986
3987 /* Set necessary flags */
3988 Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_BYPASS_FROZEN_QUEUE |
3989 SRB_FLAGS_DISABLE_DISCONNECT;
3990
3991 /* Transfer disable synch transfer flag */
3992 if (InitialSrb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER)
3993 Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
3994
3995 Srb->DataBuffer = InitialSrb->SenseInfoBuffer;
3996
3997 /* Fill the transfer length */
3998 Srb->DataTransferLength = InitialSrb->SenseInfoBufferLength;
3999
4000 /* Clear statuses */
4001 Srb->ScsiStatus = Srb->SrbStatus = 0;
4002 Srb->NextSrb = 0;
4003
4004 /* Call the driver */
4005 (VOID)IoCallDriver(DeviceExtension->DeviceObject, Irp);
4006
4007 DPRINT("SpiSendRequestSense() done\n");
4008 }
4009
4010
4011 static
4012 VOID
4013 STDCALL
4014 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
4015 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo,
4016 OUT PBOOLEAN NeedToCallStartIo)
4017 {
4018 PSCSI_REQUEST_BLOCK Srb;
4019 PSCSI_PORT_LUN_EXTENSION LunExtension;
4020 LONG Result;
4021 PIRP Irp;
4022 ULONG SequenceNumber;
4023
4024 Srb = SrbInfo->Srb;
4025 Irp = Srb->OriginalRequest;
4026
4027 /* Get Lun extension */
4028 LunExtension = SpiGetLunExtension(DeviceExtension,
4029 Srb->PathId,
4030 Srb->TargetId,
4031 Srb->Lun);
4032
4033 if (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION &&
4034 DeviceExtension->MapBuffers &&
4035 Irp->MdlAddress)
4036 {
4037 /* MDL is shared if transfer is broken into smaller parts */
4038 Srb->DataBuffer = (PCCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress) +
4039 ((PCCHAR)Srb->DataBuffer - SrbInfo->DataOffset);
4040
4041 /* In case of data going in, flush the buffers */
4042 if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
4043 {
4044 KeFlushIoBuffers(Irp->MdlAddress,
4045 TRUE,
4046 FALSE);
4047 }
4048 }
4049
4050
4051 /* Flush adapter if needed */
4052 if (SrbInfo->BaseOfMapRegister)
4053 {
4054 /* TODO: Implement */
4055 ASSERT(FALSE);
4056 }
4057
4058 /* Clear the request */
4059 SrbInfo->Srb = NULL;
4060
4061 /* If disconnect is disabled... */
4062 if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
4063 {
4064 /* Acquire the spinlock since we mess with flags */
4065 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
4066
4067 /* Set corresponding flag */
4068 DeviceExtension->Flags |= SCSI_PORT_DISCONNECT_ALLOWED;
4069
4070 /* Clear the timer if needed */
4071 if (!(DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET))
4072 DeviceExtension->TimerCount = -1;
4073
4074 /* Spinlock is not needed anymore */
4075 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4076
4077 if (!(DeviceExtension->Flags & SCSI_PORT_REQUEST_PENDING) &&
4078 !(DeviceExtension->Flags & SCSI_PORT_DEVICE_BUSY) &&
4079 !(*NeedToCallStartIo))
4080 {
4081 /* We're not busy, but we have a request pending */
4082 IoStartNextPacket(DeviceExtension->DeviceObject, FALSE);
4083 }
4084 }
4085
4086 /* Scatter/gather */
4087 if (Srb->SrbFlags & SRB_FLAGS_SGLIST_FROM_POOL)
4088 {
4089 /* TODO: Implement */
4090 ASSERT(FALSE);
4091 }
4092
4093 /* Acquire spinlock (we're freeing SrbExtension) */
4094 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
4095
4096 /* Free it (if needed) */
4097 if (Srb->SrbExtension)
4098 {
4099 if (Srb->SenseInfoBuffer != NULL && DeviceExtension->SupportsAutoSense)
4100 {
4101 ASSERT(Srb->SenseInfoBuffer == NULL || SrbInfo->SaveSenseRequest != NULL);
4102
4103 if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)
4104 {
4105 /* Copy sense data to the buffer */
4106 RtlCopyMemory(SrbInfo->SaveSenseRequest,
4107 Srb->SenseInfoBuffer,
4108 Srb->SenseInfoBufferLength);
4109 }
4110
4111 /* And restore the pointer */
4112 Srb->SenseInfoBuffer = SrbInfo->SaveSenseRequest;
4113 }
4114
4115 /* Put it into the free srb extensions list */
4116 *((PVOID *)Srb->SrbExtension) = DeviceExtension->FreeSrbExtensions;
4117 DeviceExtension->FreeSrbExtensions = Srb->SrbExtension;
4118 }
4119
4120 /* Save transfer length in the IRP */
4121 Irp->IoStatus.Information = Srb->DataTransferLength;
4122
4123 SequenceNumber = SrbInfo->SequenceNumber;
4124 SrbInfo->SequenceNumber = 0;
4125
4126 /* Decrement the queue count */
4127 LunExtension->QueueCount--;
4128
4129 /* Free Srb, if needed*/
4130 if (Srb->QueueTag != SP_UNTAGGED)
4131 {
4132 /* Put it into the free list */
4133 SrbInfo->Requests.Blink = NULL;
4134 SrbInfo->Requests.Flink = (PLIST_ENTRY)DeviceExtension->FreeSrbInfo;
4135 DeviceExtension->FreeSrbInfo = SrbInfo;
4136 }
4137
4138 /* SrbInfo is not used anymore */
4139 SrbInfo = NULL;
4140
4141 if (DeviceExtension->Flags & SCSI_PORT_REQUEST_PENDING)
4142 {
4143 /* Clear the flag */
4144 DeviceExtension->Flags &= ~SCSI_PORT_REQUEST_PENDING;
4145
4146 /* Note the caller about StartIo */
4147 *NeedToCallStartIo = TRUE;
4148 }
4149
4150 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
4151 {
4152 /* Start the packet */
4153 Irp->IoStatus.Status = STATUS_SUCCESS;
4154
4155 if (!(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE) &&
4156 LunExtension->RequestTimeout == -1)
4157 {
4158 /* Start the next packet */
4159 SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
4160 }
4161 else
4162 {
4163 /* Release the spinlock */
4164 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4165 }
4166
4167 DPRINT("IoCompleting request IRP 0x%08X\n", Irp);
4168
4169 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
4170
4171 /* Decrement number of active requests, and analyze the result */
4172 Result = InterlockedDecrement(&DeviceExtension->ActiveRequestCounter);
4173
4174 if (Result < 0 &&
4175 !DeviceExtension->MapRegisters &&
4176 DeviceExtension->AdapterObject != NULL)
4177 {
4178 /* Nullify map registers */
4179 DeviceExtension->MapRegisterBase = NULL;
4180 IoFreeAdapterChannel(DeviceExtension->AdapterObject);
4181 }
4182
4183 /* Exit, we're done */
4184 return;
4185 }
4186
4187 /* Decrement number of active requests, and analyze the result */
4188 Result = InterlockedDecrement(&DeviceExtension->ActiveRequestCounter);
4189
4190 if (Result < 0 &&
4191 !DeviceExtension->MapRegisters &&
4192 DeviceExtension->AdapterObject != NULL)
4193 {
4194 /* Result is negative, so this is a slave, free map registers */
4195 DeviceExtension->MapRegisterBase = NULL;
4196 IoFreeAdapterChannel(DeviceExtension->AdapterObject);
4197 }
4198
4199 /* Convert status */
4200 Irp->IoStatus.Status = SpiStatusSrbToNt(Srb->SrbStatus);
4201
4202 /* It's not a bypass, it's busy or the queue is full? */
4203 if ((Srb->ScsiStatus == SCSISTAT_BUSY ||
4204 Srb->SrbStatus == SRB_STATUS_BUSY ||
4205 Srb->ScsiStatus == SCSISTAT_QUEUE_FULL) &&
4206 !(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE))
4207 {
4208
4209 DPRINT("Busy SRB status %x\n", Srb->SrbStatus);
4210
4211 /* Requeu, if needed */
4212 if (LunExtension->Flags & (LUNEX_FROZEN_QUEUE | LUNEX_BUSY))
4213 {
4214 DPRINT("it's being requeued\n");
4215
4216 Srb->SrbStatus = SRB_STATUS_PENDING;
4217 Srb->ScsiStatus = 0;
4218
4219 if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue,
4220 &Irp->Tail.Overlay.DeviceQueueEntry,
4221 Srb->QueueSortKey))
4222 {
4223 /* It's a big f.ck up if we got here */
4224 Srb->SrbStatus = SRB_STATUS_ERROR;
4225 Srb->ScsiStatus = SCSISTAT_BUSY;
4226
4227 ASSERT(FALSE);
4228 goto Error;
4229 }
4230
4231 /* Release the spinlock */
4232 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4233
4234 }
4235 else if (LunExtension->AttemptCount++ < 20)
4236 {
4237 /* LUN is still busy */
4238 Srb->ScsiStatus = 0;
4239 Srb->SrbStatus = SRB_STATUS_PENDING;
4240
4241 LunExtension->BusyRequest = Irp;
4242 LunExtension->Flags |= LUNEX_BUSY;
4243
4244 /* Release the spinlock */
4245 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4246 }
4247 else
4248 {
4249 Error:
4250 /* Freeze the queue*/
4251 Srb->SrbStatus |= SRB_STATUS_QUEUE_FROZEN;
4252 LunExtension->Flags |= LUNEX_FROZEN_QUEUE;
4253
4254 /* "Unfull" the queue */
4255 LunExtension->Flags &= ~LUNEX_FULL_QUEUE;
4256
4257 /* Release the spinlock */
4258 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4259
4260 /* Return status that the device is not ready */
4261 Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
4262 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
4263 }
4264
4265 return;
4266 }
4267
4268 /* Start the next request, if LUN is idle, and this is sense request */
4269 if (((Srb->ScsiStatus != SCSISTAT_CHECK_CONDITION) ||
4270 (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) ||
4271 !Srb->SenseInfoBuffer || !Srb->SenseInfoBufferLength)
4272 && (Srb->SrbFlags & SRB_FLAGS_NO_QUEUE_FREEZE))
4273 {
4274 if (LunExtension->RequestTimeout == -1)
4275 SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
4276 else
4277 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4278 }
4279 else
4280 {
4281 /* Freeze the queue */
4282 Srb->SrbStatus |= SRB_STATUS_QUEUE_FROZEN;
4283 LunExtension->Flags |= LUNEX_FROZEN_QUEUE;
4284
4285 /* Do we need a request sense? */
4286 if (Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION &&
4287 !(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
4288 Srb->SenseInfoBuffer && Srb->SenseInfoBufferLength)
4289 {
4290 /* If LUN is busy, we have to requeue it in order to allow request sense */
4291 if (LunExtension->Flags & LUNEX_BUSY)
4292 {
4293 DPRINT("Requeueing busy request to allow request sense\n");
4294
4295 if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue,
4296 &LunExtension->BusyRequest->Tail.Overlay.DeviceQueueEntry,
4297 Srb->QueueSortKey))
4298 {
4299 /* We should never get here */
4300 ASSERT(FALSE);
4301
4302 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4303 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
4304 return;
4305
4306 }
4307
4308 /* Clear busy flags */
4309 LunExtension->Flags &= ~(LUNEX_FULL_QUEUE | LUNEX_BUSY);
4310 }
4311
4312 /* Release the spinlock */
4313 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4314
4315 /* Send RequestSense */
4316 SpiSendRequestSense(DeviceExtension, Srb);
4317
4318 /* Exit */
4319 return;
4320 }
4321
4322 /* Release the spinlock */
4323 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4324 }
4325
4326 /* Complete the request */
4327 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
4328 }
4329
4330 NTSTATUS
4331 STDCALL
4332 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject,
4333 PIRP Irp,
4334 PVOID Context)
4335 {
4336 PSCSI_REQUEST_BLOCK Srb = (PSCSI_REQUEST_BLOCK)Context;
4337 PSCSI_REQUEST_BLOCK InitialSrb;
4338 PIRP InitialIrp;
4339
4340 DPRINT("SpiCompletionRoutine() entered, IRP %p \n", Irp);
4341
4342 if ((Srb->Function == SRB_FUNCTION_RESET_BUS) ||
4343 (Srb->Function == SRB_FUNCTION_ABORT_COMMAND))
4344 {
4345 /* Deallocate SRB and IRP and exit */
4346 ExFreePool(Srb);
4347 IoFreeIrp(Irp);
4348
4349 return STATUS_MORE_PROCESSING_REQUIRED;
4350 }
4351
4352 /* Get a pointer to the SRB and IRP which were initially sent */
4353 InitialSrb = *((PVOID *)(Srb+1));
4354 InitialIrp = InitialSrb->OriginalRequest;
4355
4356 if ((SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS) ||
4357 (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN))
4358 {
4359 /* Sense data is OK */
4360 InitialSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
4361
4362 /* Set length to be the same */
4363 InitialSrb->SenseInfoBufferLength = (UCHAR)Srb->DataTransferLength;
4364 }
4365
4366 /* Make sure initial SRB's queue is frozen */
4367 ASSERT(InitialSrb->SrbStatus & SRB_STATUS_QUEUE_FROZEN);
4368
4369 /* Complete this request */
4370 IoCompleteRequest(InitialIrp, IO_DISK_INCREMENT);
4371
4372 /* Deallocate everything (internal) */
4373 ExFreePool(Srb);
4374
4375 if (Irp->MdlAddress != NULL)
4376 {
4377 MmUnlockPages(Irp->MdlAddress);
4378 IoFreeMdl(Irp->MdlAddress);
4379 Irp->MdlAddress = NULL;
4380 }
4381
4382 IoFreeIrp(Irp);
4383 return STATUS_MORE_PROCESSING_REQUIRED;
4384 }
4385
4386
4387
4388 static BOOLEAN STDCALL
4389 ScsiPortIsr(IN PKINTERRUPT Interrupt,
4390 IN PVOID ServiceContext)
4391 {
4392 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
4393 BOOLEAN Result;
4394
4395 DPRINT("ScsiPortIsr() called!\n");
4396
4397 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext;
4398
4399 /* If interrupts are disabled - we don't expect any */
4400 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_DISABLE_INTERRUPTS)
4401 return FALSE;
4402
4403 /* Call miniport's HwInterrupt routine */
4404 Result = DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension);
4405
4406 /* If flag of notification is set - queue a DPC */
4407 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
4408 {
4409 IoRequestDpc(DeviceExtension->DeviceObject,
4410 DeviceExtension->CurrentIrp,
4411 DeviceExtension);
4412 }
4413
4414 return TRUE;
4415 }
4416
4417 BOOLEAN
4418 STDCALL
4419 SpiSaveInterruptData(IN PVOID Context)
4420 {
4421 PSCSI_PORT_SAVE_INTERRUPT InterruptContext = Context;
4422 PSCSI_PORT_LUN_EXTENSION LunExtension;
4423 PSCSI_REQUEST_BLOCK Srb;
4424 PSCSI_REQUEST_BLOCK_INFO SrbInfo, NextSrbInfo;
4425 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
4426 BOOLEAN IsTimed;
4427
4428 /* Get pointer to the device extension */
4429 DeviceExtension = InterruptContext->DeviceExtension;
4430
4431 /* If we don't have anything pending - return */
4432 if (!(DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED))
4433 return FALSE;
4434
4435 /* Actually save the interrupt data */
4436 *InterruptContext->InterruptData = DeviceExtension->InterruptData;
4437
4438 /* Clear the data stored in the device extension */
4439 DeviceExtension->InterruptData.Flags &=
4440 (SCSI_PORT_RESET | SCSI_PORT_RESET_REQUEST | SCSI_PORT_DISABLE_INTERRUPTS);
4441 DeviceExtension->InterruptData.CompletedAbort = NULL;
4442 DeviceExtension->InterruptData.ReadyLun = NULL;
4443 DeviceExtension->InterruptData.CompletedRequests = NULL;
4444
4445 /* Loop through the list of completed requests */
4446 SrbInfo = InterruptContext->InterruptData->CompletedRequests;
4447
4448 while (SrbInfo)
4449 {
4450 /* Make sure we have SRV */
4451 ASSERT(SrbInfo->Srb);
4452
4453 /* Get SRB and LunExtension */
4454 Srb = SrbInfo->Srb;
4455
4456 LunExtension = SpiGetLunExtension(DeviceExtension,
4457 Srb->PathId,
4458 Srb->TargetId,
4459 Srb->Lun);
4460
4461 /* We have to check special cases if request is unsuccessfull*/
4462 if (Srb->SrbStatus != SRB_STATUS_SUCCESS)
4463 {
4464 /* Check if we need request sense by a few conditions */
4465 if (Srb->SenseInfoBuffer && Srb->SenseInfoBufferLength &&
4466 Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION &&
4467 !(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID))
4468 {
4469 if (LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE)
4470 {
4471 /* It means: we tried to send REQUEST SENSE, but failed */
4472
4473 Srb->ScsiStatus = 0;
4474 Srb->SrbStatus = SRB_STATUS_REQUEST_SENSE_FAILED;
4475 }
4476 else
4477 {
4478 /* Set the corresponding flag, so that REQUEST SENSE
4479 will be sent */
4480 LunExtension->Flags |= LUNEX_NEED_REQUEST_SENSE;
4481 }
4482
4483 }
4484
4485 /* Check for a full queue */
4486 if (Srb->ScsiStatus == SCSISTAT_QUEUE_FULL)
4487 {
4488 /* TODO: Implement when it's encountered */
4489 ASSERT(FALSE);
4490 }
4491 }
4492
4493 /* Let's decide if we need to watch timeout or not */
4494 if (Srb->QueueTag == SP_UNTAGGED)
4495 {
4496 IsTimed = TRUE;
4497 }
4498 else
4499 {
4500 if (LunExtension->SrbInfo.Requests.Flink == &SrbInfo->Requests)
4501 IsTimed = TRUE;
4502 else
4503 IsTimed = FALSE;
4504
4505 /* Remove it from the queue */
4506 RemoveEntryList(&SrbInfo->Requests);
4507 }
4508
4509 if (IsTimed)
4510 {
4511 /* We have to maintain timeout counter */
4512 if (IsListEmpty(&LunExtension->SrbInfo.Requests))
4513 {
4514 LunExtension->RequestTimeout = -1;
4515 }
4516 else
4517 {
4518 NextSrbInfo = CONTAINING_RECORD(LunExtension->SrbInfo.Requests.Flink,
4519 SCSI_REQUEST_BLOCK_INFO,
4520 Requests);
4521
4522 Srb = NextSrbInfo->Srb;
4523
4524 /* Update timeout counter */
4525 LunExtension->RequestTimeout = Srb->TimeOutValue;
4526 }
4527 }
4528
4529 SrbInfo = SrbInfo->CompletedRequests;
4530 }
4531
4532 return TRUE;
4533 }
4534
4535 VOID
4536 STDCALL
4537 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
4538 IN PSCSI_PORT_LUN_EXTENSION LunExtension)
4539 {
4540 PIO_STACK_LOCATION IrpStack;
4541 PIRP NextIrp;
4542 PKDEVICE_QUEUE_ENTRY Entry;
4543 PSCSI_REQUEST_BLOCK Srb;
4544
4545
4546 /* If LUN is not active or queue is more than maximum allowed */
4547 if (LunExtension->QueueCount >= LunExtension->MaxQueueCount ||
4548 !(LunExtension->Flags & SCSI_PORT_LU_ACTIVE))
4549 {
4550 /* Release the spinlock and exit */
4551 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4552 return;
4553 }
4554
4555 /* Check if we can get a next request */
4556 if (LunExtension->Flags &
4557 (LUNEX_NEED_REQUEST_SENSE | LUNEX_BUSY |
4558 LUNEX_FULL_QUEUE | LUNEX_FROZEN_QUEUE | LUNEX_REQUEST_PENDING))
4559 {
4560 /* Pending requests can only be started if the queue is empty */
4561 if (IsListEmpty(&LunExtension->SrbInfo.Requests) &&
4562 !(LunExtension->Flags &
4563 (LUNEX_BUSY | LUNEX_FROZEN_QUEUE | LUNEX_FULL_QUEUE | LUNEX_NEED_REQUEST_SENSE)))
4564 {
4565 /* Make sure we have SRB */
4566 ASSERT(LunExtension->SrbInfo.Srb == NULL);
4567
4568 /* Clear active and pending flags */
4569 LunExtension->Flags &= ~(LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE);
4570
4571 /* Get next Irp, and clear pending requests list */
4572 NextIrp = LunExtension->PendingRequest;
4573 LunExtension->PendingRequest = NULL;
4574
4575 /* Set attempt counter to zero */
4576 LunExtension->AttemptCount = 0;
4577
4578 /* Release the spinlock */
4579 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4580
4581 /* Start the next pending request */
4582 IoStartPacket(DeviceExtension->DeviceObject, NextIrp, (PULONG)NULL, NULL);
4583
4584 return;
4585 }
4586 else
4587 {
4588 /* Release the spinlock, without clearing any flags and exit */
4589 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4590
4591 return;
4592 }
4593 }
4594
4595 /* Reset active flag */
4596 LunExtension->Flags &= ~SCSI_PORT_LU_ACTIVE;
4597
4598 /* Set attempt counter to zero */
4599 LunExtension->AttemptCount = 0;
4600
4601 /* Remove packet from the device queue */
4602 Entry = KeRemoveByKeyDeviceQueue(&LunExtension->DeviceQueue, LunExtension->SortKey);
4603
4604 if (Entry != NULL)
4605 {
4606 /* Get pointer to the next irp */
4607 NextIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry);
4608
4609 /* Get point to the SRB */
4610 IrpStack = IoGetCurrentIrpStackLocation(NextIrp);
4611 Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1;
4612
4613 /* Set new key*/
4614 LunExtension->SortKey = Srb->QueueSortKey;
4615 LunExtension->SortKey++;
4616
4617 /* Release the spinlock */
4618 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4619
4620 /* Start the next pending request */
4621 IoStartPacket(DeviceExtension->DeviceObject, NextIrp, (PULONG)NULL, NULL);
4622 }
4623 else
4624 {
4625 /* Release the spinlock */
4626 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4627 }
4628 }
4629
4630
4631
4632 // ScsiPortDpcForIsr
4633 // DESCRIPTION:
4634 //
4635 // RUN LEVEL:
4636 //
4637 // ARGUMENTS:
4638 // IN PKDPC Dpc
4639 // IN PDEVICE_OBJECT DpcDeviceObject
4640 // IN PIRP DpcIrp
4641 // IN PVOID DpcContext
4642 //
4643 static VOID STDCALL
4644 ScsiPortDpcForIsr(IN PKDPC Dpc,
4645 IN PDEVICE_OBJECT DpcDeviceObject,
4646 IN PIRP DpcIrp,
4647 IN PVOID DpcContext)
4648 {
4649 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DpcDeviceObject->DeviceExtension;
4650 SCSI_PORT_INTERRUPT_DATA InterruptData;
4651 SCSI_PORT_SAVE_INTERRUPT Context;
4652 PSCSI_PORT_LUN_EXTENSION LunExtension;
4653 BOOLEAN NeedToStartIo;
4654 PSCSI_REQUEST_BLOCK_INFO SrbInfo;
4655
4656 DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
4657 Dpc, DpcDeviceObject, DpcIrp, DpcContext);
4658
4659 /* We need to acquire spinlock */
4660 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
4661
4662 RtlZeroMemory(&InterruptData, sizeof(SCSI_PORT_INTERRUPT_DATA));
4663
4664 TryAgain:
4665
4666 /* Interrupt structure must be snapshotted, and only then analyzed */
4667 Context.InterruptData = &InterruptData;
4668 Context.DeviceExtension = DeviceExtension;
4669
4670 if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
4671 SpiSaveInterruptData,
4672 &Context))
4673 {
4674 /* Nothing - just return (don't forget to release the spinlock */
4675 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4676 DPRINT("ScsiPortDpcForIsr() done\n");
4677 return;
4678 }
4679
4680 /* If flush of adapters is needed - do it */
4681 if (InterruptData.Flags & SCSI_PORT_FLUSH_ADAPTERS)
4682 {
4683 /* TODO: Implement */
4684 ASSERT(FALSE);
4685 }
4686
4687 /* Check for IoMapTransfer */
4688 if (InterruptData.Flags & SCSI_PORT_MAP_TRANSFER)
4689 {
4690 /* TODO: Implement */
4691 ASSERT(FALSE);
4692 }
4693
4694 /* Check if timer is needed */
4695 if (InterruptData.Flags & SCIS_PORT_TIMER_NEEDED)
4696 {
4697 /* TODO: Implement */
4698 ASSERT(FALSE);
4699 }
4700
4701 /* If it's ready for the next request */
4702 if (InterruptData.Flags & SCSI_PORT_NEXT_REQUEST_READY)
4703 {
4704 /* Check for a duplicate request (NextRequest+NextLuRequest) */
4705 if ((DeviceExtension->Flags &
4706 (SCSI_PORT_DEVICE_BUSY | SCSI_PORT_DISCONNECT_ALLOWED)) ==
4707 (SCSI_PORT_DEVICE_BUSY | SCSI_PORT_DISCONNECT_ALLOWED))
4708 {
4709 /* Clear busy flag set by ScsiPortStartPacket() */
4710 DeviceExtension->Flags &= ~SCSI_PORT_DEVICE_BUSY;
4711
4712 if (!(InterruptData.Flags & SCSI_PORT_RESET))
4713 {
4714 /* Ready for next, and no reset is happening */
4715 DeviceExtension->TimerCount = -1;
4716 }
4717 }
4718 else
4719 {
4720 /* Not busy, but not ready for the next request */
4721 DeviceExtension->Flags &= ~SCSI_PORT_DEVICE_BUSY;
4722 InterruptData.Flags &= ~SCSI_PORT_NEXT_REQUEST_READY;
4723 }
4724 }
4725
4726 /* Any resets? */
4727 if (InterruptData.Flags & SCSI_PORT_RESET_REPORTED)
4728 {
4729 /* Hold for a bit */
4730 DeviceExtension->TimerCount = 4;
4731 }
4732
4733 /* Any ready LUN? */
4734 if (InterruptData.ReadyLun != NULL)
4735 {
4736
4737 /* Process all LUNs from the list*/
4738 while (TRUE)
4739 {
4740 /* Remove it from the list first (as processed) */
4741 LunExtension = InterruptData.ReadyLun;
4742 InterruptData.ReadyLun = LunExtension->ReadyLun;
4743 LunExtension->ReadyLun = NULL;
4744
4745 /* Get next request for this LUN */
4746 SpiGetNextRequestFromLun(DeviceExtension, LunExtension);
4747
4748 /* Still ready requests exist?
4749 If yes - get spinlock, if no - stop here */
4750 if (InterruptData.ReadyLun != NULL)
4751 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
4752 else
4753 break;
4754 }
4755 }
4756 else
4757 {
4758 /* Release the spinlock */
4759 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4760 }
4761
4762 /* If we ready for next packet, start it */
4763 if (InterruptData.Flags & SCSI_PORT_NEXT_REQUEST_READY)
4764 IoStartNextPacket(DeviceExtension->DeviceObject, FALSE);
4765
4766 NeedToStartIo = FALSE;
4767
4768 /* Loop the completed request list */
4769 while (InterruptData.CompletedRequests)
4770 {
4771 /* Remove the request */
4772 SrbInfo = InterruptData.CompletedRequests;
4773 InterruptData.CompletedRequests = SrbInfo->CompletedRequests;
4774 SrbInfo->CompletedRequests = NULL;
4775
4776 /* Process it */
4777 SpiProcessCompletedRequest(DeviceExtension,
4778 SrbInfo,
4779 &NeedToStartIo);
4780 }
4781
4782 /* Loop abort request list */
4783 while (InterruptData.CompletedAbort)
4784 {
4785 LunExtension = InterruptData.CompletedAbort;
4786
4787 /* Remove the request */
4788 InterruptData.CompletedAbort = LunExtension->CompletedAbortRequests;
4789
4790 /* Get spinlock since we're going to change flags */
4791 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
4792
4793 /* TODO: Put SrbExtension to the list of free extensions */
4794 ASSERT(FALSE);
4795 }
4796
4797 /* If we need - call StartIo routine */
4798 if (NeedToStartIo)
4799 {
4800 /* Make sure CurrentIrp is not null! */
4801 ASSERT(DpcDeviceObject->CurrentIrp != NULL);
4802 ScsiPortStartIo(DpcDeviceObject, DpcDeviceObject->CurrentIrp);
4803 }
4804
4805 /* Everything has been done, check */
4806 if (InterruptData.Flags & SCSI_PORT_ENABLE_INT_REQUEST)
4807 {
4808 /* Synchronize using spinlock */
4809 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
4810
4811 /* Request an interrupt */
4812 DeviceExtension->HwInterrupt(DeviceExtension->MiniPortDeviceExtension);
4813
4814 ASSERT(DeviceExtension->Flags & SCSI_PORT_DISABLE_INT_REQUESET);
4815
4816 /* Should interrupts be enabled again? */
4817 if (DeviceExtension->Flags & SCSI_PORT_DISABLE_INT_REQUESET)
4818 {
4819 /* Clear this flag */
4820 DeviceExtension->Flags &= ~SCSI_PORT_DISABLE_INT_REQUESET;
4821
4822 /* Call a special routine to do this */
4823 ASSERT(FALSE);
4824 #if 0
4825 KeSynchronizeExecution(DeviceExtension->Interrupt,
4826 SpiEnableInterrupts,
4827 DeviceExtension);
4828 #endif
4829 }
4830
4831 /* If we need a notification again - loop */
4832 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
4833 goto TryAgain;
4834
4835 /* Release the spinlock */
4836 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4837 }
4838
4839 DPRINT("ScsiPortDpcForIsr() done\n");
4840 }
4841
4842 BOOLEAN
4843 STDCALL
4844 SpiProcessTimeout(PVOID ServiceContext)
4845 {
4846 PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)ServiceContext;
4847 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
4848 ULONG Bus;
4849
4850 DPRINT("SpiProcessTimeout() entered\n");
4851
4852 DeviceExtension->TimerCount = -1;
4853
4854 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET)
4855 {
4856 DeviceExtension->InterruptData.Flags &= ~SCSI_PORT_RESET;
4857
4858 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET_REQUEST)
4859 {
4860 DeviceExtension->InterruptData.Flags &= ~SCSI_PORT_RESET_REQUEST;
4861 ScsiPortStartPacket(ServiceContext);
4862 }
4863
4864 return FALSE;
4865 }
4866 else
4867 {
4868 DPRINT("Resetting the bus\n");
4869
4870 for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
4871 {
4872 DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension, Bus);
4873
4874 /* Reset flags and set reset timeout to 4 seconds */
4875 DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET;
4876 DeviceExtension->TimerCount = 4;
4877 }
4878
4879 /* If miniport requested - request a dpc for it */
4880 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
4881 IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
4882 }
4883
4884 return TRUE;
4885 }
4886
4887
4888 BOOLEAN
4889 STDCALL
4890 SpiResetBus(PVOID ServiceContext)
4891 {
4892 PRESETBUS_PARAMS ResetParams = (PRESETBUS_PARAMS)ServiceContext;
4893 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
4894
4895 /* Perform the bus reset */
4896 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ResetParams->DeviceExtension;
4897 DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension,
4898 ResetParams->PathId);
4899
4900 /* Set flags and start the timer */
4901 DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET;
4902 DeviceExtension->TimerCount = 4;
4903
4904 /* If miniport requested - give him a DPC */
4905 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
4906 IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL);
4907
4908 return TRUE;
4909 }
4910
4911 // ScsiPortIoTimer
4912 // DESCRIPTION:
4913 // This function handles timeouts and other time delayed processing
4914 //
4915 // RUN LEVEL:
4916 //
4917 // ARGUMENTS:
4918 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
4919 // IN PVOID Context the Controller extension for the
4920 // controller the device is on
4921 //
4922 static VOID STDCALL
4923 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
4924 PVOID Context)
4925 {
4926 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
4927 PSCSI_PORT_LUN_EXTENSION LunExtension;
4928 ULONG Lun;
4929 PIRP Irp;
4930
4931 DPRINT("ScsiPortIoTimer()\n");
4932
4933 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
4934
4935 /* Protect with the spinlock */
4936 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
4937
4938 /* Check timeouts */
4939 if (DeviceExtension->TimerCount > 0)
4940 {
4941 /* Decrease the timeout counter */
4942 DeviceExtension->TimerCount--;
4943
4944 if (DeviceExtension->TimerCount == 0)
4945 {
4946 /* Timeout, process it */
4947 if (KeSynchronizeExecution(DeviceExtension->Interrupt,
4948 SpiProcessTimeout,
4949 DeviceExtension->DeviceObject))
4950 {
4951 DPRINT("Error happened during processing timeout, but nothing critical\n");
4952 }
4953 }
4954
4955 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4956
4957 /* We should exit now, since timeout is processed */
4958 return;
4959 }
4960
4961 /* Per-Lun scanning of timeouts is needed... */
4962 for (Lun = 0; Lun < LUS_NUMBER; Lun++)
4963 {
4964 LunExtension = DeviceExtension->LunExtensionList[Lun];
4965
4966 while (LunExtension)
4967 {
4968 if (LunExtension->Flags & LUNEX_BUSY)
4969 {
4970 if (!(LunExtension->Flags &
4971 (LUNEX_NEED_REQUEST_SENSE | LUNEX_FROZEN_QUEUE)))
4972 {
4973 DPRINT("Retrying busy request\n");
4974
4975 /* Clear flags, and retry busy request */
4976 LunExtension->Flags &= ~(LUNEX_BUSY | LUNEX_FULL_QUEUE);
4977 Irp = LunExtension->BusyRequest;
4978
4979 /* Clearing busy request */
4980 LunExtension->BusyRequest = NULL;
4981
4982 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
4983
4984 IoStartPacket(DeviceObject, Irp, (PULONG)NULL, NULL);
4985
4986 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
4987 }
4988 }
4989 else if (LunExtension->RequestTimeout == 0)
4990 {
4991 RESETBUS_PARAMS ResetParams;
4992
4993 LunExtension->RequestTimeout = -1;
4994
4995 DPRINT("Request timed out, resetting bus\n");
4996
4997 /* Pass params to the bus reset routine */
4998 ResetParams.PathId = LunExtension->PathId;
4999 ResetParams.DeviceExtension = DeviceExtension;
5000
5001 if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
5002 SpiResetBus,
5003 &ResetParams))
5004 {
5005 DPRINT1("Reset failed\n");
5006 }
5007 }
5008 else if (LunExtension->RequestTimeout > 0)
5009 {
5010 /* Decrement the timeout counter */
5011 LunExtension->RequestTimeout--;
5012 }
5013
5014 LunExtension = LunExtension->Next;
5015 }
5016 }
5017
5018 /* Release the spinlock */
5019 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
5020 }
5021
5022 /**********************************************************************
5023 * NAME INTERNAL
5024 * SpiBuildDeviceMap
5025 *
5026 * DESCRIPTION
5027 * Builds the registry device map of all device which are attached
5028 * to the given SCSI HBA port. The device map is located at:
5029 * \Registry\Machine\DeviceMap\Scsi
5030 *
5031 * RUN LEVEL
5032 * PASSIVE_LEVEL
5033 *
5034 * ARGUMENTS
5035 * DeviceExtension
5036 * ...
5037 *
5038 * RegistryPath
5039 * Name of registry driver service key.
5040 *
5041 * RETURNS
5042 * NTSTATUS
5043 */
5044
5045 static NTSTATUS
5046 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
5047 PUNICODE_STRING RegistryPath)
5048 {
5049 PSCSI_PORT_LUN_EXTENSION LunExtension;
5050 OBJECT_ATTRIBUTES ObjectAttributes;
5051 UNICODE_STRING KeyName;
5052 UNICODE_STRING ValueName;
5053 WCHAR NameBuffer[64];
5054 ULONG Disposition;
5055 HANDLE ScsiKey;
5056 HANDLE ScsiPortKey = NULL;
5057 HANDLE ScsiBusKey = NULL;
5058 HANDLE ScsiInitiatorKey = NULL;
5059 HANDLE ScsiTargetKey = NULL;
5060 HANDLE ScsiLunKey = NULL;
5061 ULONG BusNumber;
5062 ULONG Target;
5063 ULONG CurrentTarget;
5064 ULONG Lun;
5065 PWCHAR DriverName;
5066 ULONG UlongData;
5067 PWCHAR TypeName;
5068 NTSTATUS Status;
5069
5070 DPRINT("SpiBuildDeviceMap() called\n");
5071
5072 if (DeviceExtension == NULL || RegistryPath == NULL)
5073 {
5074 DPRINT1("Invalid parameter\n");
5075 return(STATUS_INVALID_PARAMETER);
5076 }
5077
5078 /* Open or create the 'Scsi' subkey */
5079 RtlInitUnicodeString(&KeyName,
5080 L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
5081 InitializeObjectAttributes(&ObjectAttributes,
5082 &KeyName,
5083 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
5084 0,
5085 NULL);
5086 Status = ZwCreateKey(&ScsiKey,
5087 KEY_ALL_ACCESS,
5088 &ObjectAttributes,
5089 0,
5090 NULL,
5091 REG_OPTION_VOLATILE,
5092 &Disposition);
5093 if (!NT_SUCCESS(Status))
5094 {
5095 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
5096 return(Status);
5097 }
5098
5099 /* Create new 'Scsi Port X' subkey */
5100 DPRINT("Scsi Port %lu\n",
5101 DeviceExtension->PortNumber);
5102
5103 swprintf(NameBuffer,
5104 L"Scsi Port %lu",
5105 DeviceExtension->PortNumber);
5106 RtlInitUnicodeString(&KeyName,
5107 NameBuffer);
5108 InitializeObjectAttributes(&ObjectAttributes,
5109 &KeyName,
5110 0,
5111 ScsiKey,
5112 NULL);
5113 Status = ZwCreateKey(&ScsiPortKey,
5114 KEY_ALL_ACCESS,
5115 &ObjectAttributes,
5116 0,
5117 NULL,
5118 REG_OPTION_VOLATILE,
5119 &Disposition);
5120 ZwClose(ScsiKey);
5121 if (!NT_SUCCESS(Status))
5122 {
5123 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
5124 return(Status);
5125 }
5126
5127 /*
5128 * Create port-specific values
5129 */
5130
5131 /* Set 'DMA Enabled' (REG_DWORD) value */
5132 UlongData = (ULONG)!DeviceExtension->PortCapabilities.AdapterUsesPio;
5133 DPRINT(" DMA Enabled = %s\n", (UlongData) ? "TRUE" : "FALSE");
5134 RtlInitUnicodeString(&ValueName,
5135 L"DMA Enabled");
5136 Status = ZwSetValueKey(ScsiPortKey,
5137 &ValueName,
5138 0,
5139 REG_DWORD,
5140 &UlongData,
5141 sizeof(ULONG));
5142 if (!NT_SUCCESS(Status))
5143 {
5144 DPRINT("ZwSetValueKey('DMA Enabled') failed (Status %lx)\n", Status);
5145 ZwClose(ScsiPortKey);
5146 return(Status);
5147 }
5148
5149 /* Set 'Driver' (REG_SZ) value */
5150 DriverName = wcsrchr(RegistryPath->Buffer, L'\\') + 1;
5151 RtlInitUnicodeString(&ValueName,
5152 L"Driver");
5153 Status = ZwSetValueKey(ScsiPortKey,
5154 &ValueName,
5155 0,
5156 REG_SZ,
5157 DriverName,
5158 (wcslen(DriverName) + 1) * sizeof(WCHAR));
5159 if (!NT_SUCCESS(Status))
5160 {
5161 DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status);
5162 ZwClose(ScsiPortKey);
5163 return(Status);
5164 }
5165
5166 /* Set 'Interrupt' (REG_DWORD) value (NT4 only) */
5167 UlongData = (ULONG)DeviceExtension->PortConfig->BusInterruptLevel;
5168 DPRINT(" Interrupt = %lu\n", UlongData);
5169 RtlInitUnicodeString(&ValueName,
5170 L"Interrupt");
5171 Status = ZwSetValueKey(ScsiPortKey,
5172 &ValueName,
5173 0,
5174 REG_DWORD,
5175 &UlongData,
5176 sizeof(ULONG));
5177 if (!NT_SUCCESS(Status))
5178 {
5179 DPRINT("ZwSetValueKey('Interrupt') failed (Status %lx)\n", Status);
5180 ZwClose(ScsiPortKey);
5181 return(Status);
5182 }
5183
5184 /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
5185 UlongData = ScsiPortConvertPhysicalAddressToUlong((*DeviceExtension->PortConfig->AccessRanges)[0].RangeStart);
5186 DPRINT(" IOAddress = %lx\n", UlongData);
5187 RtlInitUnicodeString(&ValueName,
5188 L"IOAddress");
5189 Status = ZwSetValueKey(ScsiPortKey,
5190 &ValueName,
5191 0,
5192 REG_DWORD,
5193 &UlongData,
5194 sizeof(ULONG));
5195 if (!NT_SUCCESS(Status))
5196 {
5197 DPRINT("ZwSetValueKey('IOAddress') failed (Status %lx)\n", Status);
5198 ZwClose(ScsiPortKey);
5199 return(Status);
5200 }
5201
5202 /* Enumerate buses */
5203 for (BusNumber = 0; BusNumber < DeviceExtension->PortConfig->NumberOfBuses; BusNumber++)
5204 {
5205 /* Create 'Scsi Bus X' key */
5206 DPRINT(" Scsi Bus %lu\n", BusNumber);
5207 swprintf(NameBuffer,
5208 L"Scsi Bus %lu",
5209 BusNumber);
5210 RtlInitUnicodeString(&KeyName,
5211 NameBuffer);
5212 InitializeObjectAttributes(&ObjectAttributes,
5213 &KeyName,
5214 0,
5215 ScsiPortKey,
5216 NULL);
5217 Status = ZwCreateKey(&ScsiBusKey,
5218 KEY_ALL_ACCESS,
5219 &ObjectAttributes,
5220 0,
5221 NULL,
5222 REG_OPTION_VOLATILE,
5223 &Disposition);
5224 if (!NT_SUCCESS(Status))
5225 {
5226 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
5227 goto ByeBye;
5228 }
5229
5230 /* Create 'Initiator Id X' key */
5231 DPRINT(" Initiator Id %u\n",
5232 DeviceExtension->PortConfig->InitiatorBusId[BusNumber]);
5233 swprintf(NameBuffer,
5234 L"Initiator Id %u",
5235 (unsigned int)(UCHAR)DeviceExtension->PortConfig->InitiatorBusId[BusNumber]);
5236 RtlInitUnicodeString(&KeyName,
5237 NameBuffer);
5238 InitializeObjectAttributes(&ObjectAttributes,
5239 &KeyName,
5240 0,
5241 ScsiBusKey,
5242 NULL);
5243 Status = ZwCreateKey(&ScsiInitiatorKey,
5244 KEY_ALL_ACCESS,
5245 &ObjectAttributes,
5246 0,
5247 NULL,
5248 REG_OPTION_VOLATILE,
5249 &Disposition);
5250 if (!NT_SUCCESS(Status))
5251 {
5252 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
5253 goto ByeBye;
5254 }
5255
5256 /* FIXME: Are there any initiator values (??) */
5257
5258 ZwClose(ScsiInitiatorKey);
5259 ScsiInitiatorKey = NULL;
5260
5261
5262 /* Enumerate targets */
5263 CurrentTarget = (ULONG)-1;
5264 ScsiTargetKey = NULL;
5265 for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
5266 {
5267 for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++)
5268 {
5269 LunExtension = SpiGetLunExtension(DeviceExtension,
5270 (UCHAR)BusNumber,
5271 (UCHAR)Target,
5272 (UCHAR)Lun);
5273 if (LunExtension != NULL)
5274 {
5275 if (Target != CurrentTarget)
5276 {
5277 /* Close old target key */
5278 if (ScsiTargetKey != NULL)
5279 {
5280 ZwClose(ScsiTargetKey);
5281 ScsiTargetKey = NULL;
5282 }
5283
5284 /* Create 'Target Id X' key */
5285 DPRINT(" Target Id %lu\n", Target);
5286 swprintf(NameBuffer,
5287 L"Target Id %lu",
5288 Target);
5289 RtlInitUnicodeString(&KeyName,
5290 NameBuffer);
5291 InitializeObjectAttributes(&ObjectAttributes,
5292 &KeyName,
5293 0,
5294 ScsiBusKey,
5295 NULL);
5296 Status = ZwCreateKey(&ScsiTargetKey,
5297 KEY_ALL_ACCESS,
5298 &ObjectAttributes,
5299 0,
5300 NULL,
5301 REG_OPTION_VOLATILE,
5302 &Disposition);
5303 if (!NT_SUCCESS(Status))
5304 {
5305 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
5306 goto ByeBye;
5307 }
5308
5309 CurrentTarget = Target;
5310 }
5311
5312 /* Create 'Logical Unit Id X' key */
5313 DPRINT(" Logical Unit Id %lu\n", Lun);
5314 swprintf(NameBuffer,
5315 L"Logical Unit Id %lu",
5316 Lun);
5317 RtlInitUnicodeString(&KeyName,
5318 NameBuffer);
5319 InitializeObjectAttributes(&ObjectAttributes,
5320 &KeyName,
5321 0,
5322 ScsiTargetKey,
5323 NULL);
5324 Status = ZwCreateKey(&ScsiLunKey,
5325 KEY_ALL_ACCESS,
5326 &ObjectAttributes,
5327 0,
5328 NULL,
5329 REG_OPTION_VOLATILE,
5330 &Disposition);
5331 if (!NT_SUCCESS(Status))
5332 {
5333 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status);
5334 goto ByeBye;
5335 }
5336
5337 /* Set 'Identifier' (REG_SZ) value */
5338 swprintf(NameBuffer,
5339 L"%.8S%.16S%.4S",
5340 LunExtension->InquiryData.VendorId,
5341 LunExtension->InquiryData.ProductId,
5342 LunExtension->InquiryData.ProductRevisionLevel);
5343 DPRINT(" Identifier = '%S'\n", NameBuffer);
5344 RtlInitUnicodeString(&ValueName,
5345 L"Identifier");
5346 Status = ZwSetValueKey(ScsiLunKey,
5347 &ValueName,
5348 0,
5349 REG_SZ,
5350 NameBuffer,
5351 (wcslen(NameBuffer) + 1) * sizeof(WCHAR));
5352 if (!NT_SUCCESS(Status))
5353 {
5354 DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", Status);
5355 goto ByeBye;
5356 }
5357
5358 /* Set 'Type' (REG_SZ) value */
5359 switch (LunExtension->InquiryData.DeviceType)
5360 {
5361 case 0:
5362 TypeName = L"DiskPeripheral";
5363 break;
5364 case 1:
5365 TypeName = L"TapePeripheral";
5366 break;
5367 case 2:
5368 TypeName = L"PrinterPeripheral";
5369 break;
5370 case 4:
5371 TypeName = L"WormPeripheral";
5372 break;
5373 case 5:
5374 TypeName = L"CdRomPeripheral";
5375 break;
5376 case 6:
5377 TypeName = L"ScannerPeripheral";
5378 break;
5379 case 7:
5380 TypeName = L"OpticalDiskPeripheral";
5381 break;
5382 case 8:
5383 TypeName = L"MediumChangerPeripheral";
5384 break;
5385 case 9:
5386 TypeName = L"CommunicationPeripheral";
5387 break;
5388 default:
5389 TypeName = L"OtherPeripheral";
5390 break;
5391 }
5392 DPRINT(" Type = '%S'\n", TypeName);
5393 RtlInitUnicodeString(&ValueName,
5394 L"Type");
5395 Status = ZwSetValueKey(ScsiLunKey,
5396 &ValueName,
5397 0,
5398 REG_SZ,
5399 TypeName,
5400 (wcslen(TypeName) + 1) * sizeof(WCHAR));
5401 if (!NT_SUCCESS(Status))
5402 {
5403 DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status);
5404 goto ByeBye;
5405 }
5406
5407 ZwClose(ScsiLunKey);
5408 ScsiLunKey = NULL;
5409 }
5410 }
5411
5412 /* Close old target key */
5413 if (ScsiTargetKey != NULL)
5414 {
5415 ZwClose(ScsiTargetKey);
5416 ScsiTargetKey = NULL;
5417 }
5418 }
5419
5420 ZwClose(ScsiBusKey);
5421 ScsiBusKey = NULL;
5422 }
5423
5424 ByeBye:
5425 if (ScsiLunKey != NULL)
5426 ZwClose (ScsiLunKey);
5427
5428 if (ScsiInitiatorKey != NULL)
5429 ZwClose (ScsiInitiatorKey);
5430
5431 if (ScsiTargetKey != NULL)
5432 ZwClose (ScsiTargetKey);
5433
5434 if (ScsiBusKey != NULL)
5435 ZwClose (ScsiBusKey);
5436
5437 if (ScsiPortKey != NULL)
5438 ZwClose (ScsiPortKey);
5439
5440 DPRINT("SpiBuildDeviceMap() done\n");
5441
5442 return Status;
5443 }
5444
5445 VOID
5446 STDCALL
5447 SpiMiniportTimerDpc(IN struct _KDPC *Dpc,
5448 IN PVOID DeviceObject,
5449 IN PVOID SystemArgument1,
5450 IN PVOID SystemArgument2)
5451 {
5452 DPRINT1("Miniport timer DPC\n");
5453 }
5454
5455 static NTSTATUS
5456 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
5457 PHW_INITIALIZATION_DATA HwInitData,
5458 PCONFIGURATION_INFO InternalConfigInfo,
5459 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
5460 BOOLEAN ZeroStruct)
5461 {
5462 UNICODE_STRING UnicodeString;
5463 OBJECT_ATTRIBUTES ObjectAttributes;
5464 PCONFIGURATION_INFORMATION DdkConfigInformation;
5465 HANDLE RootKey, Key;
5466 BOOLEAN Found;
5467 WCHAR DeviceBuffer[16];
5468 WCHAR StrBuffer[512];
5469 ULONG Bus;
5470 NTSTATUS Status;
5471
5472 /* Zero out the struct if told so */
5473 if (ZeroStruct)
5474 {
5475 /* First zero the portconfig */
5476 RtlZeroMemory(ConfigInfo, sizeof(PORT_CONFIGURATION_INFORMATION));
5477
5478 /* Then access ranges */
5479 RtlZeroMemory(InternalConfigInfo->AccessRanges,
5480 HwInitData->NumberOfAccessRanges * sizeof(ACCESS_RANGE));
5481
5482 /* Initialize the struct */
5483 ConfigInfo->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
5484 ConfigInfo->AdapterInterfaceType = HwInitData->AdapterInterfaceType;
5485 ConfigInfo->InterruptMode = Latched;
5486 ConfigInfo->DmaChannel = SP_UNINITIALIZED_VALUE;
5487 ConfigInfo->DmaPort = SP_UNINITIALIZED_VALUE;
5488 ConfigInfo->MaximumTransferLength = SP_UNINITIALIZED_VALUE;
5489 ConfigInfo->NumberOfAccessRanges = HwInitData->NumberOfAccessRanges;
5490 ConfigInfo->MaximumNumberOfTargets = 8;
5491
5492 /* Store parameters */
5493 ConfigInfo->NeedPhysicalAddresses = HwInitData->NeedPhysicalAddresses;
5494 ConfigInfo->MapBuffers = HwInitData->MapBuffers;
5495 ConfigInfo->AutoRequestSense = HwInitData->AutoRequestSense;
5496 ConfigInfo->ReceiveEvent = HwInitData->ReceiveEvent;
5497 ConfigInfo->TaggedQueuing = HwInitData->TaggedQueuing;
5498 ConfigInfo->MultipleRequestPerLu = HwInitData->MultipleRequestPerLu;
5499
5500 /* Get the disk usage */
5501 DdkConfigInformation = IoGetConfigurationInformation();
5502 ConfigInfo->AtdiskPrimaryClaimed = DdkConfigInformation->AtDiskPrimaryAddressClaimed;
5503 ConfigInfo->AtdiskSecondaryClaimed = DdkConfigInformation->AtDiskSecondaryAddressClaimed;
5504
5505 /* Initiator bus id is not set */
5506 for (Bus = 0; Bus < 8; Bus++)
5507 ConfigInfo->InitiatorBusId[Bus] = (CCHAR)SP_UNINITIALIZED_VALUE;
5508 }
5509
5510 ConfigInfo->NumberOfPhysicalBreaks = 17;
5511
5512 /* Clear this information */
5513 InternalConfigInfo->DisableTaggedQueueing = FALSE;
5514 InternalConfigInfo->DisableMultipleLun = FALSE;
5515
5516 /* Store Bus Number */
5517 ConfigInfo->SystemIoBusNumber = InternalConfigInfo->BusNumber;
5518
5519 TryNextAd:
5520
5521 if (ConfigInfo->AdapterInterfaceType == Internal)
5522 {
5523 /* Open registry key for HW database */
5524 InitializeObjectAttributes(&ObjectAttributes,
5525 DeviceExtension->DeviceObject->DriverObject->HardwareDatabase,
5526 OBJ_CASE_INSENSITIVE,
5527 NULL,
5528 NULL);
5529
5530 Status = ZwOpenKey(&RootKey,
5531 KEY_READ,
5532 &ObjectAttributes);
5533
5534 if (NT_SUCCESS(Status))
5535 {
5536 /* Create name for it */
5537 swprintf(StrBuffer, L"ScsiAdapter\\%lu",
5538 InternalConfigInfo->AdapterNumber);
5539
5540 RtlInitUnicodeString(&UnicodeString, StrBuffer);
5541
5542 /* Open device key */
5543 InitializeObjectAttributes(&ObjectAttributes,
5544 &UnicodeString,
5545 OBJ_CASE_INSENSITIVE,
5546 RootKey,
5547 NULL);
5548
5549 Status = ZwOpenKey(&Key,
5550 KEY_READ,
5551 &ObjectAttributes);
5552
5553 ZwClose(RootKey);
5554
5555 if (NT_SUCCESS(Status))
5556 {
5557 if (InternalConfigInfo->LastAdapterNumber != InternalConfigInfo->AdapterNumber)
5558 {
5559 DPRINT("Hardware info found at %S\n", StrBuffer);
5560
5561 /* Parse it */
5562 SpiParseDeviceInfo(DeviceExtension,
5563 Key,
5564 ConfigInfo,
5565 InternalConfigInfo,
5566 (PUCHAR)StrBuffer);
5567
5568 InternalConfigInfo->BusNumber = 0;
5569 }
5570 else
5571 {
5572 /* Try the next adapter */
5573 InternalConfigInfo->AdapterNumber++;
5574 goto TryNextAd;
5575 }
5576 }
5577 else
5578 {
5579 /* Info was not found, exit */
5580 return STATUS_DEVICE_DOES_NOT_EXIST;
5581 }
5582 }
5583 }
5584
5585
5586 /* Look at device params */
5587 Key = NULL;
5588 if (InternalConfigInfo->Parameter)
5589 {
5590 ExFreePool(InternalConfigInfo->Parameter);
5591 InternalConfigInfo->Parameter = NULL;
5592 }
5593
5594 if (InternalConfigInfo->ServiceKey != NULL)
5595 {
5596 swprintf(DeviceBuffer, L"Device%lu", InternalConfigInfo->AdapterNumber);
5597 RtlInitUnicodeString(&UnicodeString, DeviceBuffer);
5598
5599 /* Open the service key */
5600 InitializeObjectAttributes(&ObjectAttributes,
5601 &UnicodeString,
5602 OBJ_CASE_INSENSITIVE,
5603 InternalConfigInfo->ServiceKey,
5604 NULL);
5605
5606 Status = ZwOpenKey(&Key,
5607 KEY_READ,
5608 &ObjectAttributes);
5609 }
5610
5611 /* Parse device key */
5612 if (InternalConfigInfo->DeviceKey != NULL)
5613 {
5614 SpiParseDeviceInfo(DeviceExtension,
5615 InternalConfigInfo->DeviceKey,
5616 ConfigInfo,
5617 InternalConfigInfo,
5618 (PUCHAR)StrBuffer);
5619 }
5620
5621 /* Then parse hw info */
5622 if (Key != NULL)
5623 {
5624 if (InternalConfigInfo->LastAdapterNumber != InternalConfigInfo->AdapterNumber)
5625 {
5626 SpiParseDeviceInfo(DeviceExtension,
5627 Key,
5628 ConfigInfo,
5629 InternalConfigInfo,
5630 (PUCHAR)StrBuffer);
5631
5632 /* Close the key */
5633 ZwClose(Key);
5634 }
5635 else
5636 {
5637 /* Adapter not found, go try the next one */
5638 InternalConfigInfo->AdapterNumber++;
5639
5640 /* Close the key */
5641 ZwClose(Key);
5642
5643 goto TryNextAd;
5644 }
5645 }
5646
5647 /* Update the last adapter number */
5648 InternalConfigInfo->LastAdapterNumber = InternalConfigInfo->AdapterNumber;
5649
5650 /* Do we have this kind of bus at all? */
5651 Found = FALSE;
5652 Status = IoQueryDeviceDescription(&HwInitData->AdapterInterfaceType,
5653 &InternalConfigInfo->BusNumber,
5654 NULL,
5655 NULL,
5656 NULL,
5657 NULL,
5658 SpQueryDeviceCallout,
5659 &Found);
5660
5661 /* This bus was not found */
5662 if (!Found)
5663 {
5664 INTERFACE_TYPE InterfaceType = Eisa;
5665
5666 /* Check for EISA */
5667 if (HwInitData->AdapterInterfaceType == Isa)
5668 {
5669 Status = IoQueryDeviceDescription(&InterfaceType,
5670 &InternalConfigInfo->BusNumber,
5671 NULL,
5672 NULL,
5673 NULL,
5674 NULL,
5675 SpQueryDeviceCallout,
5676 &Found);
5677
5678 /* Return respectively */
5679 if (Found)
5680 return STATUS_SUCCESS;
5681 else
5682 return STATUS_DEVICE_DOES_NOT_EXIST;
5683 }
5684 else
5685 {
5686 return STATUS_DEVICE_DOES_NOT_EXIST;
5687 }
5688 }
5689 else
5690 {
5691 return STATUS_SUCCESS;
5692 }
5693 }
5694
5695 static VOID
5696 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
5697 IN HANDLE Key,
5698 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
5699 IN PCONFIGURATION_INFO InternalConfigInfo,
5700 IN PUCHAR Buffer)
5701 {
5702 PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
5703 PCM_FULL_RESOURCE_DESCRIPTOR FullResource;
5704 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
5705 PCM_SCSI_DEVICE_DATA ScsiDeviceData;
5706 ULONG Length, Count;
5707 ULONG Index = 0, RangeCount = 0;
5708 UNICODE_STRING UnicodeString;
5709 ANSI_STRING AnsiString;
5710 NTSTATUS Status = STATUS_SUCCESS;
5711
5712
5713 KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION) Buffer;
5714
5715 /* Loop through all values in the device node */
5716 while(TRUE)
5717 {
5718 Status = ZwEnumerateValueKey(Key,
5719 Index,
5720 KeyValueFullInformation,
5721 Buffer,
5722 512,
5723 &Length);
5724
5725 if (!NT_SUCCESS(Status))
5726 return;
5727
5728 Index++;
5729
5730 /* Length for DWORD is ok? */
5731 if (KeyValueInformation->Type == REG_DWORD &&
5732 KeyValueInformation->DataLength != sizeof(ULONG))
5733 {
5734 continue;
5735 }
5736
5737 /* Get MaximumLogicalUnit */
5738 if (_wcsnicmp(KeyValueInformation->Name, L"MaximumLogicalUnit",
5739 KeyValueInformation->NameLength/2) == 0)
5740 {
5741
5742 if (KeyValueInformation->Type != REG_DWORD)
5743 {
5744 DPRINT("Bad data type for MaximumLogicalUnit\n");
5745 continue;
5746 }
5747
5748 DeviceExtension->MaxLunCount = *((PUCHAR)
5749 (Buffer + KeyValueInformation->DataOffset));
5750
5751 /* Check / reset if needed */
5752 if (DeviceExtension->MaxLunCount > SCSI_MAXIMUM_LOGICAL_UNITS)
5753 DeviceExtension->MaxLunCount = SCSI_MAXIMUM_LOGICAL_UNITS;
5754
5755 DPRINT("MaximumLogicalUnit = %d\n", DeviceExtension->MaxLunCount);
5756 }
5757
5758 /* Get InitiatorTargetId */
5759 if (_wcsnicmp(KeyValueInformation->Name, L"InitiatorTargetId",
5760 KeyValueInformation->NameLength / 2) == 0)
5761 {
5762
5763 if (KeyValueInformation->Type != REG_DWORD)
5764 {
5765 DPRINT("Bad data type for InitiatorTargetId\n");
5766 continue;
5767 }
5768
5769 ConfigInfo->InitiatorBusId[0] = *((PUCHAR)
5770 (Buffer + KeyValueInformation->DataOffset));
5771
5772 /* Check / reset if needed */
5773 if (ConfigInfo->InitiatorBusId[0] > ConfigInfo->MaximumNumberOfTargets - 1)
5774 ConfigInfo->InitiatorBusId[0] = (CCHAR)-1;
5775
5776 DPRINT("InitiatorTargetId = %d\n", ConfigInfo->InitiatorBusId[0]);
5777 }
5778
5779 /* Get ScsiDebug */
5780 if (_wcsnicmp(KeyValueInformation->Name, L"ScsiDebug",
5781 KeyValueInformation->NameLength/2) == 0)
5782 {
5783 DPRINT("ScsiDebug key not supported\n");
5784 }
5785
5786 /* Check for a breakpoint */
5787 if (_wcsnicmp(KeyValueInformation->Name, L"BreakPointOnEntry",
5788 KeyValueInformation->NameLength/2) == 0)
5789 {
5790 DPRINT1("Breakpoint on entry requested!\n");
5791 DbgBreakPoint();
5792 }
5793
5794 /* Get DisableSynchronousTransfers */
5795 if (_wcsnicmp(KeyValueInformation->Name, L"DisableSynchronousTransfers",
5796 KeyValueInformation->NameLength/2) == 0)
5797 {
5798 DeviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
5799 DPRINT("Synch transfers disabled\n");
5800 }
5801
5802 /* Get DisableDisconnects */
5803 if (_wcsnicmp(KeyValueInformation->Name, L"DisableDisconnects",
5804 KeyValueInformation->NameLength/2) == 0)
5805 {
5806 DeviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT;
5807 DPRINT("Disconnects disabled\n");
5808 }
5809
5810 /* Get DisableTaggedQueuing */
5811 if (_wcsnicmp(KeyValueInformation->Name, L"DisableTaggedQueuing",
5812 KeyValueInformation->NameLength/2) == 0)
5813 {
5814 InternalConfigInfo->DisableTaggedQueueing = TRUE;
5815 DPRINT("Tagged queueing disabled\n");
5816 }
5817
5818 /* Get DisableMultipleRequests */
5819 if (_wcsnicmp(KeyValueInformation->Name, L"DisableMultipleRequests",
5820 KeyValueInformation->NameLength/2) == 0)
5821 {
5822 InternalConfigInfo->DisableMultipleLun = TRUE;
5823 DPRINT("Multiple requests disabled\n");
5824 }
5825
5826 /* Get DriverParameters */
5827 if (_wcsnicmp(KeyValueInformation->Name, L"DriverParameters",
5828 KeyValueInformation->NameLength/2) == 0)
5829 {
5830 /* Skip if nothing */
5831 if (KeyValueInformation->DataLength == 0)
5832 continue;
5833
5834 /* If there was something previously allocated - free it */
5835 if (InternalConfigInfo->Parameter != NULL)
5836 ExFreePool(InternalConfigInfo->Parameter);
5837
5838 /* Allocate it */
5839 InternalConfigInfo->Parameter = ExAllocatePoolWithTag(NonPagedPool,
5840 KeyValueInformation->DataLength, TAG_SCSIPORT);
5841
5842 if (InternalConfigInfo->Parameter != NULL)
5843 {
5844 if (KeyValueInformation->Type != REG_SZ)
5845 {
5846 /* Just copy */
5847 RtlCopyMemory(
5848 InternalConfigInfo->Parameter,
5849 (PCCHAR)KeyValueInformation + KeyValueInformation->DataOffset,
5850 KeyValueInformation->DataLength);
5851 }
5852 else
5853 {
5854 /* If it's a unicode string, convert it to ansi */
5855 UnicodeString.Length = (USHORT)KeyValueInformation->DataLength;
5856 UnicodeString.MaximumLength = (USHORT)KeyValueInformation->DataLength;
5857 UnicodeString.Buffer =
5858 (PWSTR)((PCCHAR)KeyValueInformation + KeyValueInformation->DataOffset);
5859
5860 AnsiString.Length = 0;
5861 AnsiString.MaximumLength = (USHORT)KeyValueInformation->DataLength;
5862 AnsiString.Buffer = (PCHAR)InternalConfigInfo->Parameter;
5863
5864 Status = RtlUnicodeStringToAnsiString(&AnsiString,
5865 &UnicodeString,
5866 FALSE);
5867
5868 /* In case of error, free the allocated space */
5869 if (!NT_SUCCESS(Status))
5870 {
5871 ExFreePool(InternalConfigInfo->Parameter);
5872 InternalConfigInfo->Parameter = NULL;
5873 }
5874
5875 }
5876 }
5877
5878 DPRINT("Found driver parameter\n");
5879 }
5880
5881 /* Get MaximumSGList */
5882 if (_wcsnicmp(KeyValueInformation->Name, L"MaximumSGList",
5883 KeyValueInformation->NameLength/2) == 0)
5884 {
5885 if (KeyValueInformation->Type != REG_DWORD)
5886 {
5887 DPRINT("Bad data type for MaximumSGList\n");
5888 continue;
5889 }
5890
5891 ConfigInfo->NumberOfPhysicalBreaks = *((PUCHAR)(Buffer + KeyValueInformation->DataOffset));
5892
5893 /* Check / fix */
5894 if (ConfigInfo->NumberOfPhysicalBreaks > SCSI_MAXIMUM_PHYSICAL_BREAKS)
5895 {
5896 ConfigInfo->NumberOfPhysicalBreaks = SCSI_MAXIMUM_PHYSICAL_BREAKS;
5897 }
5898 else if (ConfigInfo->NumberOfPhysicalBreaks < SCSI_MINIMUM_PHYSICAL_BREAKS)
5899 {
5900 ConfigInfo->NumberOfPhysicalBreaks = SCSI_MINIMUM_PHYSICAL_BREAKS;
5901 }
5902
5903 DPRINT("MaximumSGList = %d\n", ConfigInfo->NumberOfPhysicalBreaks);
5904 }
5905
5906 /* Get NumberOfRequests */
5907 if (_wcsnicmp(KeyValueInformation->Name, L"NumberOfRequests",
5908 KeyValueInformation->NameLength/2) == 0)
5909 {
5910 if (KeyValueInformation->Type != REG_DWORD)
5911 {
5912 DPRINT("NumberOfRequests has wrong data type\n");
5913 continue;
5914 }
5915
5916 DeviceExtension->RequestsNumber = *((PUCHAR)(Buffer + KeyValueInformation->DataOffset));
5917
5918 /* Check / fix */
5919 if (DeviceExtension->RequestsNumber < 16)
5920 {
5921 DeviceExtension->RequestsNumber = 16;
5922 }
5923 else if (DeviceExtension->RequestsNumber > 512)
5924 {
5925 DeviceExtension->RequestsNumber = 512;
5926 }
5927
5928 DPRINT("Number Of Requests = %d\n", DeviceExtension->RequestsNumber);
5929 }
5930
5931 /* Get resource list */
5932 if (_wcsnicmp(KeyValueInformation->Name, L"ResourceList",
5933 KeyValueInformation->NameLength/2) == 0 ||
5934 _wcsnicmp(KeyValueInformation->Name, L"Configuration Data",
5935 KeyValueInformation->NameLength/2) == 0 )
5936 {
5937 if (KeyValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR ||
5938 KeyValueInformation->DataLength < sizeof(REG_FULL_RESOURCE_DESCRIPTOR))
5939 {
5940 DPRINT("Bad data type for ResourceList\n");
5941 continue;
5942 }
5943 else
5944 {
5945 DPRINT("Found ResourceList\n");
5946 }
5947
5948 FullResource = (PCM_FULL_RESOURCE_DESCRIPTOR)(Buffer + KeyValueInformation->DataOffset);
5949
5950 /* Copy some info from it */
5951 InternalConfigInfo->BusNumber = FullResource->BusNumber;
5952 ConfigInfo->SystemIoBusNumber = FullResource->BusNumber;
5953
5954 /* Loop through it */
5955 for (Count = 0; Count < FullResource->PartialResourceList.Count; Count++)
5956 {
5957 /* Get partial descriptor */
5958 PartialDescriptor =
5959 &FullResource->PartialResourceList.PartialDescriptors[Count];
5960
5961 /* Check datalength */
5962 if ((ULONG)((PCHAR)(PartialDescriptor + 1) -
5963 (PCHAR)FullResource) > KeyValueInformation->DataLength)
5964 {
5965 DPRINT("Resource data is of incorrect size\n");
5966 break;
5967 }
5968
5969 switch (PartialDescriptor->Type)
5970 {
5971 case CmResourceTypePort:
5972 if (RangeCount >= ConfigInfo->NumberOfAccessRanges)
5973 {
5974 DPRINT("Too many access ranges\n");
5975 continue;
5976 }
5977
5978 InternalConfigInfo->AccessRanges[RangeCount].RangeInMemory = FALSE;
5979 InternalConfigInfo->AccessRanges[RangeCount].RangeStart = PartialDescriptor->u.Port.Start;
5980 InternalConfigInfo->AccessRanges[RangeCount].RangeLength = PartialDescriptor->u.Port.Length;
5981 RangeCount++;
5982
5983 break;
5984
5985 case CmResourceTypeMemory:
5986 if (RangeCount >= ConfigInfo->NumberOfAccessRanges)
5987 {
5988 DPRINT("Too many access ranges\n");
5989 continue;
5990 }
5991
5992 InternalConfigInfo->AccessRanges[RangeCount].RangeInMemory = TRUE;
5993 InternalConfigInfo->AccessRanges[RangeCount].RangeStart = PartialDescriptor->u.Memory.Start;
5994 InternalConfigInfo->AccessRanges[RangeCount].RangeLength = PartialDescriptor->u.Memory.Length;
5995 RangeCount++;
5996
5997 break;
5998
5999 case CmResourceTypeInterrupt:
6000 ConfigInfo->BusInterruptLevel =
6001 PartialDescriptor->u.Interrupt.Level;
6002
6003 ConfigInfo->BusInterruptVector =
6004 PartialDescriptor->u.Interrupt.Vector;
6005 break;
6006
6007 case CmResourceTypeDma:
6008 ConfigInfo->DmaChannel = PartialDescriptor->u.Dma.Channel;
6009 ConfigInfo->DmaPort = PartialDescriptor->u.Dma.Port;
6010 break;
6011
6012 case CmResourceTypeDeviceSpecific:
6013 if (PartialDescriptor->u.DeviceSpecificData.DataSize <
6014 sizeof(CM_SCSI_DEVICE_DATA) ||
6015 (PCHAR) (PartialDescriptor + 1) - (PCHAR)FullResource +
6016 PartialDescriptor->u.DeviceSpecificData.DataSize >
6017 KeyValueInformation->DataLength)
6018 {
6019 DPRINT("Resource data length is incorrect");
6020 break;
6021 }
6022
6023 /* Set only one field from it */
6024 ScsiDeviceData = (PCM_SCSI_DEVICE_DATA) (PartialDescriptor+1);
6025 ConfigInfo->InitiatorBusId[0] = ScsiDeviceData->HostIdentifier;
6026 break;
6027 }
6028 }
6029 }
6030 }
6031 }
6032
6033
6034 NTSTATUS
6035 STDCALL
6036 SpQueryDeviceCallout(IN PVOID Context,
6037 IN PUNICODE_STRING PathName,
6038 IN INTERFACE_TYPE BusType,
6039 IN ULONG BusNumber,
6040 IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
6041 IN CONFIGURATION_TYPE ControllerType,
6042 IN ULONG ControllerNumber,
6043 IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
6044 IN CONFIGURATION_TYPE PeripheralType,
6045 IN ULONG PeripheralNumber,
6046 IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation)
6047 {
6048 PBOOLEAN Found = (PBOOLEAN)Context;
6049 /* We just set our Found variable to TRUE */
6050
6051 *Found = TRUE;
6052 return STATUS_SUCCESS;
6053 }
6054
6055
6056
6057 static
6058 NTSTATUS
6059 SpiStatusSrbToNt(UCHAR SrbStatus)
6060 {
6061 switch (SRB_STATUS(SrbStatus))
6062 {
6063 case SRB_STATUS_TIMEOUT:
6064 case SRB_STATUS_COMMAND_TIMEOUT:
6065 return STATUS_IO_TIMEOUT;
6066
6067 case SRB_STATUS_BAD_SRB_BLOCK_LENGTH:
6068 case SRB_STATUS_BAD_FUNCTION:
6069 return STATUS_INVALID_DEVICE_REQUEST;
6070
6071 case SRB_STATUS_NO_DEVICE:
6072 case SRB_STATUS_INVALID_LUN:
6073 case SRB_STATUS_INVALID_TARGET_ID:
6074 case SRB_STATUS_NO_HBA:
6075 return STATUS_DEVICE_DOES_NOT_EXIST;
6076
6077 case SRB_STATUS_DATA_OVERRUN:
6078 return STATUS_BUFFER_OVERFLOW;
6079
6080 case SRB_STATUS_SELECTION_TIMEOUT:
6081 return STATUS_DEVICE_NOT_CONNECTED;
6082
6083 default:
6084 return STATUS_IO_DEVICE_ERROR;
6085 }
6086
6087 return STATUS_IO_DEVICE_ERROR;
6088 }
6089
6090
6091 #undef ScsiPortConvertPhysicalAddressToUlong
6092 /*
6093 * @implemented
6094 */
6095 ULONG STDCALL
6096 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address)
6097 {
6098 DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n");
6099 return(Address.u.LowPart);
6100 }
6101
6102
6103 /* EOF */