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