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