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