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