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