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