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