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