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