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