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