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