1 /* 2 * PROJECT: ReactOS Storage Stack / SCSIPORT storage port library 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Main and exported functions 5 * COPYRIGHT: Eric Kohl (eric.kohl@reactos.org) 6 * Aleksey Bragin (aleksey@reactos.org) 7 */ 8 9 /* INCLUDES *****************************************************************/ 10 11 #include "scsiport.h" 12 13 #define NDEBUG 14 #include <debug.h> 15 16 ULONG InternalDebugLevel = 0x00; 17 18 #undef ScsiPortMoveMemory 19 20 /* GLOBALS *******************************************************************/ 21 22 static BOOLEAN 23 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject, 24 IN PDEVICE_OBJECT DeviceObject, 25 IN struct _HW_INITIALIZATION_DATA *HwInitializationData, 26 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig, 27 IN PUNICODE_STRING RegistryPath, 28 IN ULONG BusNumber, 29 IN OUT PPCI_SLOT_NUMBER NextSlotNumber); 30 31 static NTSTATUS NTAPI 32 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject, 33 IN PIRP Irp); 34 35 static VOID NTAPI 36 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject, 37 PVOID Context); 38 39 VOID NTAPI 40 SpiMiniportTimerDpc(IN struct _KDPC *Dpc, 41 IN PVOID DeviceObject, 42 IN PVOID SystemArgument1, 43 IN PVOID SystemArgument2); 44 45 static NTSTATUS 46 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 47 PHW_INITIALIZATION_DATA HwInitData, 48 PCONFIGURATION_INFO InternalConfigInfo, 49 PPORT_CONFIGURATION_INFORMATION ConfigInfo, 50 BOOLEAN FirstCall); 51 52 NTSTATUS NTAPI 53 SpQueryDeviceCallout(IN PVOID Context, 54 IN PUNICODE_STRING PathName, 55 IN INTERFACE_TYPE BusType, 56 IN ULONG BusNumber, 57 IN PKEY_VALUE_FULL_INFORMATION *BusInformation, 58 IN CONFIGURATION_TYPE ControllerType, 59 IN ULONG ControllerNumber, 60 IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation, 61 IN CONFIGURATION_TYPE PeripheralType, 62 IN ULONG PeripheralNumber, 63 IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation); 64 65 static VOID 66 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 67 IN HANDLE Key, 68 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo, 69 IN PCONFIGURATION_INFO InternalConfigInfo, 70 IN PUCHAR Buffer); 71 72 static VOID 73 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData, 74 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor, 75 IN PPORT_CONFIGURATION_INFORMATION PortConfig); 76 77 static PCM_RESOURCE_LIST 78 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 79 PPORT_CONFIGURATION_INFORMATION PortConfig); 80 81 static NTSTATUS 82 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, ULONG NonCachedSize); 83 84 NTHALAPI ULONG NTAPI HalGetBusData(BUS_DATA_TYPE, ULONG, ULONG, PVOID, ULONG); 85 NTHALAPI ULONG NTAPI HalGetInterruptVector(INTERFACE_TYPE, ULONG, ULONG, ULONG, PKIRQL, PKAFFINITY); 86 NTHALAPI NTSTATUS NTAPI HalAssignSlotResources(PUNICODE_STRING, PUNICODE_STRING, PDRIVER_OBJECT, PDEVICE_OBJECT, INTERFACE_TYPE, ULONG, ULONG, PCM_RESOURCE_LIST *); 87 88 /* FUNCTIONS *****************************************************************/ 89 90 /********************************************************************** 91 * NAME EXPORTED 92 * DriverEntry 93 * 94 * DESCRIPTION 95 * This function initializes the driver. 96 * 97 * RUN LEVEL 98 * PASSIVE_LEVEL 99 * 100 * ARGUMENTS 101 * DriverObject 102 * System allocated Driver Object for this driver. 103 * 104 * RegistryPath 105 * Name of registry driver service key. 106 * 107 * RETURN VALUE 108 * Status. 109 */ 110 111 NTSTATUS NTAPI 112 DriverEntry(IN PDRIVER_OBJECT DriverObject, 113 IN PUNICODE_STRING RegistryPath) 114 { 115 DPRINT("ScsiPort Driver %s\n", VERSION); 116 return(STATUS_SUCCESS); 117 } 118 119 120 /********************************************************************** 121 * NAME EXPORTED 122 * ScsiDebugPrint 123 * 124 * DESCRIPTION 125 * Prints debugging messages. 126 * 127 * RUN LEVEL 128 * PASSIVE_LEVEL 129 * 130 * ARGUMENTS 131 * DebugPrintLevel 132 * Debug level of the given message. 133 * 134 * DebugMessage 135 * Pointer to printf()-compatible format string. 136 * 137 * ... 138 Additional output data (see printf()). 139 * 140 * RETURN VALUE 141 * None. 142 * 143 * @implemented 144 */ 145 146 VOID 147 ScsiDebugPrint(IN ULONG DebugPrintLevel, 148 IN PCHAR DebugMessage, 149 ...) 150 { 151 char Buffer[256]; 152 va_list ap; 153 154 if (DebugPrintLevel > InternalDebugLevel) 155 return; 156 157 va_start(ap, DebugMessage); 158 vsprintf(Buffer, DebugMessage, ap); 159 va_end(ap); 160 161 DbgPrint(Buffer); 162 } 163 164 /* An internal helper function for ScsiPortCompleteRequest */ 165 VOID 166 NTAPI 167 SpiCompleteRequest(IN PVOID HwDeviceExtension, 168 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo, 169 IN UCHAR SrbStatus) 170 { 171 PSCSI_REQUEST_BLOCK Srb; 172 173 /* Get current SRB */ 174 Srb = SrbInfo->Srb; 175 176 /* Return if there is no SRB or it is not active */ 177 if (!Srb || !(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE)) return; 178 179 /* Set status */ 180 Srb->SrbStatus = SrbStatus; 181 182 /* Set data transfered to 0 */ 183 Srb->DataTransferLength = 0; 184 185 /* Notify */ 186 ScsiPortNotification(RequestComplete, 187 HwDeviceExtension, 188 Srb); 189 } 190 191 /* 192 * @unimplemented 193 */ 194 VOID NTAPI 195 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension, 196 IN UCHAR PathId, 197 IN UCHAR TargetId, 198 IN UCHAR Lun, 199 IN UCHAR SrbStatus) 200 { 201 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 202 PSCSI_PORT_LUN_EXTENSION LunExtension; 203 PSCSI_REQUEST_BLOCK_INFO SrbInfo; 204 PLIST_ENTRY ListEntry; 205 ULONG BusNumber; 206 ULONG Target; 207 208 DPRINT("ScsiPortCompleteRequest() called\n"); 209 210 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, 211 SCSI_PORT_DEVICE_EXTENSION, 212 MiniPortDeviceExtension); 213 214 /* Go through all buses */ 215 for (BusNumber = 0; BusNumber < 8; BusNumber++) 216 { 217 /* Go through all targets */ 218 for (Target = 0; Target < DeviceExtension->MaxTargedIds; Target++) 219 { 220 /* Get logical unit list head */ 221 LunExtension = DeviceExtension->LunExtensionList[Target % 8]; 222 223 /* Go through all logical units */ 224 while (LunExtension) 225 { 226 /* Now match what caller asked with what we are at now */ 227 if ((PathId == SP_UNTAGGED || PathId == LunExtension->PathId) && 228 (TargetId == SP_UNTAGGED || TargetId == LunExtension->TargetId) && 229 (Lun == SP_UNTAGGED || Lun == LunExtension->Lun)) 230 { 231 /* Yes, that's what caller asked for. Complete abort requests */ 232 if (LunExtension->CompletedAbortRequests) 233 { 234 /* TODO: Save SrbStatus in this request */ 235 DPRINT1("Completing abort request without setting SrbStatus!\n"); 236 237 /* Issue a notification request */ 238 ScsiPortNotification(RequestComplete, 239 HwDeviceExtension, 240 LunExtension->CompletedAbortRequests); 241 } 242 243 /* Complete the request using our helper */ 244 SpiCompleteRequest(HwDeviceExtension, 245 &LunExtension->SrbInfo, 246 SrbStatus); 247 248 /* Go through the queue and complete everything there too */ 249 ListEntry = LunExtension->SrbInfo.Requests.Flink; 250 while (ListEntry != &LunExtension->SrbInfo.Requests) 251 { 252 /* Get the actual SRB info entry */ 253 SrbInfo = CONTAINING_RECORD(ListEntry, 254 SCSI_REQUEST_BLOCK_INFO, 255 Requests); 256 257 /* Complete it */ 258 SpiCompleteRequest(HwDeviceExtension, 259 SrbInfo, 260 SrbStatus); 261 262 /* Advance to the next request in queue */ 263 ListEntry = SrbInfo->Requests.Flink; 264 } 265 } 266 267 /* Advance to the next one */ 268 LunExtension = LunExtension->Next; 269 } 270 } 271 } 272 } 273 274 /* 275 * @unimplemented 276 */ 277 VOID NTAPI 278 ScsiPortFlushDma(IN PVOID HwDeviceExtension) 279 { 280 DPRINT("ScsiPortFlushDma()\n"); 281 UNIMPLEMENTED; 282 } 283 284 285 /* 286 * @implemented 287 */ 288 VOID NTAPI 289 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension, 290 IN PVOID MappedAddress) 291 { 292 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 293 PMAPPED_ADDRESS NextMa, LastMa; 294 295 //DPRINT("ScsiPortFreeDeviceBase() called\n"); 296 297 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, 298 SCSI_PORT_DEVICE_EXTENSION, 299 MiniPortDeviceExtension); 300 301 /* Initialize our pointers */ 302 NextMa = DeviceExtension->MappedAddressList; 303 LastMa = NextMa; 304 305 while (NextMa) 306 { 307 if (NextMa->MappedAddress == MappedAddress) 308 { 309 /* Unmap it first */ 310 MmUnmapIoSpace(MappedAddress, NextMa->NumberOfBytes); 311 312 /* Remove it from the list */ 313 if (NextMa == DeviceExtension->MappedAddressList) 314 { 315 /* Remove the first entry */ 316 DeviceExtension->MappedAddressList = NextMa->NextMappedAddress; 317 } 318 else 319 { 320 LastMa->NextMappedAddress = NextMa->NextMappedAddress; 321 } 322 323 /* Free the resources and quit */ 324 ExFreePool(NextMa); 325 326 return; 327 } 328 else 329 { 330 LastMa = NextMa; 331 NextMa = NextMa->NextMappedAddress; 332 } 333 } 334 } 335 336 337 /* 338 * @implemented 339 */ 340 ULONG NTAPI 341 ScsiPortGetBusData(IN PVOID DeviceExtension, 342 IN ULONG BusDataType, 343 IN ULONG SystemIoBusNumber, 344 IN ULONG SlotNumber, 345 IN PVOID Buffer, 346 IN ULONG Length) 347 { 348 DPRINT("ScsiPortGetBusData()\n"); 349 350 if (Length) 351 { 352 /* If Length is non-zero, just forward the call to 353 HalGetBusData() function */ 354 return HalGetBusData(BusDataType, 355 SystemIoBusNumber, 356 SlotNumber, 357 Buffer, 358 Length); 359 } 360 361 /* We have a more complex case here */ 362 UNIMPLEMENTED; 363 return 0; 364 } 365 366 /* 367 * @implemented 368 */ 369 ULONG NTAPI 370 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension, 371 IN ULONG BusDataType, 372 IN ULONG SystemIoBusNumber, 373 IN ULONG SlotNumber, 374 IN PVOID Buffer, 375 IN ULONG Offset, 376 IN ULONG Length) 377 { 378 DPRINT("ScsiPortSetBusDataByOffset()\n"); 379 return HalSetBusDataByOffset(BusDataType, 380 SystemIoBusNumber, 381 SlotNumber, 382 Buffer, 383 Offset, 384 Length); 385 } 386 387 /* 388 * @implemented 389 */ 390 PVOID NTAPI 391 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension, 392 IN INTERFACE_TYPE BusType, 393 IN ULONG SystemIoBusNumber, 394 IN SCSI_PHYSICAL_ADDRESS IoAddress, 395 IN ULONG NumberOfBytes, 396 IN BOOLEAN InIoSpace) 397 { 398 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 399 PHYSICAL_ADDRESS TranslatedAddress; 400 PMAPPED_ADDRESS DeviceBase; 401 ULONG AddressSpace; 402 PVOID MappedAddress; 403 404 //DPRINT ("ScsiPortGetDeviceBase() called\n"); 405 406 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, 407 SCSI_PORT_DEVICE_EXTENSION, 408 MiniPortDeviceExtension); 409 410 AddressSpace = (ULONG)InIoSpace; 411 if (HalTranslateBusAddress(BusType, 412 SystemIoBusNumber, 413 IoAddress, 414 &AddressSpace, 415 &TranslatedAddress) == FALSE) 416 { 417 return NULL; 418 } 419 420 /* i/o space */ 421 if (AddressSpace != 0) 422 return((PVOID)(ULONG_PTR)TranslatedAddress.QuadPart); 423 424 MappedAddress = MmMapIoSpace(TranslatedAddress, 425 NumberOfBytes, 426 FALSE); 427 428 DeviceBase = ExAllocatePoolWithTag(NonPagedPool, 429 sizeof(MAPPED_ADDRESS), TAG_SCSIPORT); 430 431 if (DeviceBase == NULL) 432 return MappedAddress; 433 434 DeviceBase->MappedAddress = MappedAddress; 435 DeviceBase->NumberOfBytes = NumberOfBytes; 436 DeviceBase->IoAddress = IoAddress; 437 DeviceBase->BusNumber = SystemIoBusNumber; 438 439 /* Link it to the Device Extension list */ 440 DeviceBase->NextMappedAddress = DeviceExtension->MappedAddressList; 441 DeviceExtension->MappedAddressList = DeviceBase; 442 443 return MappedAddress; 444 } 445 446 /* 447 * @unimplemented 448 */ 449 PVOID NTAPI 450 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension, 451 IN UCHAR PathId, 452 IN UCHAR TargetId, 453 IN UCHAR Lun) 454 { 455 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 456 PSCSI_PORT_LUN_EXTENSION LunExtension; 457 458 DPRINT("ScsiPortGetLogicalUnit() called\n"); 459 460 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, 461 SCSI_PORT_DEVICE_EXTENSION, 462 MiniPortDeviceExtension); 463 464 /* Check the extension size */ 465 if (!DeviceExtension->LunExtensionSize) 466 { 467 /* They didn't want one */ 468 return NULL; 469 } 470 471 LunExtension = SpiGetLunExtension(DeviceExtension, 472 PathId, 473 TargetId, 474 Lun); 475 /* Check that the logical unit exists */ 476 if (!LunExtension) 477 { 478 /* Nope, return NULL */ 479 return NULL; 480 } 481 482 /* Return the logical unit miniport extension */ 483 return (LunExtension + 1); 484 } 485 486 487 /* 488 * @implemented 489 */ 490 SCSI_PHYSICAL_ADDRESS NTAPI 491 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension, 492 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL, 493 IN PVOID VirtualAddress, 494 OUT ULONG *Length) 495 { 496 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 497 SCSI_PHYSICAL_ADDRESS PhysicalAddress; 498 SIZE_T BufferLength = 0; 499 ULONG_PTR Offset; 500 PSCSI_SG_ADDRESS SGList; 501 PSCSI_REQUEST_BLOCK_INFO SrbInfo; 502 503 DPRINT("ScsiPortGetPhysicalAddress(%p %p %p %p)\n", 504 HwDeviceExtension, Srb, VirtualAddress, Length); 505 506 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, 507 SCSI_PORT_DEVICE_EXTENSION, 508 MiniPortDeviceExtension); 509 510 if (Srb == NULL || Srb->SenseInfoBuffer == VirtualAddress) 511 { 512 /* Simply look it up in the allocated common buffer */ 513 Offset = (PUCHAR)VirtualAddress - (PUCHAR)DeviceExtension->SrbExtensionBuffer; 514 515 BufferLength = DeviceExtension->CommonBufferLength - Offset; 516 PhysicalAddress.QuadPart = DeviceExtension->PhysicalAddress.QuadPart + Offset; 517 } 518 else if (DeviceExtension->MapRegisters) 519 { 520 /* Scatter-gather list must be used */ 521 SrbInfo = SpiGetSrbData(DeviceExtension, 522 Srb->PathId, 523 Srb->TargetId, 524 Srb->Lun, 525 Srb->QueueTag); 526 527 SGList = SrbInfo->ScatterGather; 528 529 /* Find needed item in the SG list */ 530 Offset = (PCHAR)VirtualAddress - (PCHAR)Srb->DataBuffer; 531 while (Offset >= SGList->Length) 532 { 533 Offset -= SGList->Length; 534 SGList++; 535 } 536 537 /* We're done, store length and physical address */ 538 BufferLength = SGList->Length - Offset; 539 PhysicalAddress.QuadPart = SGList->PhysicalAddress.QuadPart + Offset; 540 } 541 else 542 { 543 /* Nothing */ 544 PhysicalAddress.QuadPart = (LONGLONG)(SP_UNINITIALIZED_VALUE); 545 } 546 547 *Length = (ULONG)BufferLength; 548 return PhysicalAddress; 549 } 550 551 552 /* 553 * @unimplemented 554 */ 555 PSCSI_REQUEST_BLOCK NTAPI 556 ScsiPortGetSrb(IN PVOID DeviceExtension, 557 IN UCHAR PathId, 558 IN UCHAR TargetId, 559 IN UCHAR Lun, 560 IN LONG QueueTag) 561 { 562 DPRINT1("ScsiPortGetSrb() unimplemented\n"); 563 UNIMPLEMENTED; 564 return NULL; 565 } 566 567 568 /* 569 * @implemented 570 */ 571 PVOID NTAPI 572 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension, 573 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo, 574 IN ULONG NumberOfBytes) 575 { 576 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 577 DEVICE_DESCRIPTION DeviceDescription; 578 ULONG MapRegistersCount; 579 NTSTATUS Status; 580 581 DPRINT("ScsiPortGetUncachedExtension(%p %p %lu)\n", 582 HwDeviceExtension, ConfigInfo, NumberOfBytes); 583 584 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, 585 SCSI_PORT_DEVICE_EXTENSION, 586 MiniPortDeviceExtension); 587 588 /* Check for allocated common DMA buffer */ 589 if (DeviceExtension->SrbExtensionBuffer != NULL) 590 { 591 DPRINT1("The HBA has already got a common DMA buffer!\n"); 592 return NULL; 593 } 594 595 /* Check for DMA adapter object */ 596 if (DeviceExtension->AdapterObject == NULL) 597 { 598 /* Initialize DMA adapter description */ 599 RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION)); 600 601 DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION; 602 DeviceDescription.Master = ConfigInfo->Master; 603 DeviceDescription.ScatterGather = ConfigInfo->ScatterGather; 604 DeviceDescription.DemandMode = ConfigInfo->DemandMode; 605 DeviceDescription.Dma32BitAddresses = ConfigInfo->Dma32BitAddresses; 606 DeviceDescription.BusNumber = ConfigInfo->SystemIoBusNumber; 607 DeviceDescription.DmaChannel = ConfigInfo->DmaChannel; 608 DeviceDescription.InterfaceType = ConfigInfo->AdapterInterfaceType; 609 DeviceDescription.DmaWidth = ConfigInfo->DmaWidth; 610 DeviceDescription.DmaSpeed = ConfigInfo->DmaSpeed; 611 DeviceDescription.MaximumLength = ConfigInfo->MaximumTransferLength; 612 DeviceDescription.DmaPort = ConfigInfo->DmaPort; 613 614 /* Get a DMA adapter object */ 615 DeviceExtension->AdapterObject = 616 HalGetAdapter(&DeviceDescription, &MapRegistersCount); 617 618 /* Fail in case of error */ 619 if (DeviceExtension->AdapterObject == NULL) 620 { 621 DPRINT1("HalGetAdapter() failed\n"); 622 return NULL; 623 } 624 625 /* Set number of physical breaks */ 626 if (ConfigInfo->NumberOfPhysicalBreaks != 0 && 627 MapRegistersCount > ConfigInfo->NumberOfPhysicalBreaks) 628 { 629 DeviceExtension->PortCapabilities.MaximumPhysicalPages = 630 ConfigInfo->NumberOfPhysicalBreaks; 631 } 632 else 633 { 634 DeviceExtension->PortCapabilities.MaximumPhysicalPages = MapRegistersCount; 635 } 636 } 637 638 /* Update auto request sense feature */ 639 DeviceExtension->SupportsAutoSense = ConfigInfo->AutoRequestSense; 640 641 /* Update Srb extension size */ 642 if (DeviceExtension->SrbExtensionSize != ConfigInfo->SrbExtensionSize) 643 DeviceExtension->SrbExtensionSize = ConfigInfo->SrbExtensionSize; 644 645 /* Update Srb extension alloc flag */ 646 if (ConfigInfo->AutoRequestSense || DeviceExtension->SrbExtensionSize) 647 DeviceExtension->NeedSrbExtensionAlloc = TRUE; 648 649 /* Allocate a common DMA buffer */ 650 Status = SpiAllocateCommonBuffer(DeviceExtension, NumberOfBytes); 651 652 if (!NT_SUCCESS(Status)) 653 { 654 DPRINT1("SpiAllocateCommonBuffer() failed with Status = 0x%08X!\n", Status); 655 return NULL; 656 } 657 658 return DeviceExtension->NonCachedExtension; 659 } 660 661 static NTSTATUS 662 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, ULONG NonCachedSize) 663 { 664 PVOID *SrbExtension, CommonBuffer; 665 ULONG CommonBufferLength, BufSize; 666 667 /* If size is 0, set it to 16 */ 668 if (!DeviceExtension->SrbExtensionSize) 669 DeviceExtension->SrbExtensionSize = 16; 670 671 /* Calculate size */ 672 BufSize = DeviceExtension->SrbExtensionSize; 673 674 /* Add autosense data size if needed */ 675 if (DeviceExtension->SupportsAutoSense) 676 BufSize += sizeof(SENSE_DATA); 677 678 679 /* Round it */ 680 BufSize = (BufSize + sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1); 681 682 /* Sum up into the total common buffer length, and round it to page size */ 683 CommonBufferLength = 684 ROUND_TO_PAGES(NonCachedSize + BufSize * DeviceExtension->RequestsNumber); 685 686 /* Allocate it */ 687 if (!DeviceExtension->AdapterObject) 688 { 689 /* From nonpaged pool if there is no DMA */ 690 CommonBuffer = ExAllocatePoolWithTag(NonPagedPool, CommonBufferLength, TAG_SCSIPORT); 691 } 692 else 693 { 694 /* Perform a full request since we have a DMA adapter*/ 695 CommonBuffer = HalAllocateCommonBuffer(DeviceExtension->AdapterObject, 696 CommonBufferLength, 697 &DeviceExtension->PhysicalAddress, 698 FALSE ); 699 } 700 701 /* Fail in case of error */ 702 if (!CommonBuffer) 703 return STATUS_INSUFFICIENT_RESOURCES; 704 705 /* Zero it */ 706 RtlZeroMemory(CommonBuffer, CommonBufferLength); 707 708 /* Store its size in Device Extension */ 709 DeviceExtension->CommonBufferLength = CommonBufferLength; 710 711 /* SrbExtension buffer is located at the beginning of the buffer */ 712 DeviceExtension->SrbExtensionBuffer = CommonBuffer; 713 714 /* Non-cached extension buffer is located at the end of 715 the common buffer */ 716 if (NonCachedSize) 717 { 718 CommonBufferLength -= NonCachedSize; 719 DeviceExtension->NonCachedExtension = (PUCHAR)CommonBuffer + CommonBufferLength; 720 } 721 else 722 { 723 DeviceExtension->NonCachedExtension = NULL; 724 } 725 726 if (DeviceExtension->NeedSrbExtensionAlloc) 727 { 728 /* Look up how many SRB data structures we need */ 729 DeviceExtension->SrbDataCount = CommonBufferLength / BufSize; 730 731 /* Initialize the free SRB extensions list */ 732 SrbExtension = (PVOID *)CommonBuffer; 733 DeviceExtension->FreeSrbExtensions = SrbExtension; 734 735 /* Fill the remaining pointers (if we have more than 1 SRB) */ 736 while (CommonBufferLength >= 2 * BufSize) 737 { 738 *SrbExtension = (PVOID*)((PCHAR)SrbExtension + BufSize); 739 SrbExtension = *SrbExtension; 740 741 CommonBufferLength -= BufSize; 742 } 743 } 744 745 return STATUS_SUCCESS; 746 } 747 748 749 750 /* 751 * @implemented 752 */ 753 PVOID NTAPI 754 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension, 755 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress) 756 { 757 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 758 ULONG Offset; 759 760 DPRINT("ScsiPortGetVirtualAddress(%p %I64x)\n", 761 HwDeviceExtension, PhysicalAddress.QuadPart); 762 763 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, 764 SCSI_PORT_DEVICE_EXTENSION, 765 MiniPortDeviceExtension); 766 767 if (DeviceExtension->PhysicalAddress.QuadPart > PhysicalAddress.QuadPart) 768 return NULL; 769 770 Offset = (ULONG)(PhysicalAddress.QuadPart - DeviceExtension->PhysicalAddress.QuadPart); 771 772 if (Offset >= DeviceExtension->CommonBufferLength) 773 return NULL; 774 775 return (PVOID)((ULONG_PTR)DeviceExtension->SrbExtensionBuffer + Offset); 776 } 777 778 /********************************************************************** 779 * NAME EXPORTED 780 * ScsiPortInitialize 781 * 782 * DESCRIPTION 783 * Initializes SCSI port driver specific data. 784 * 785 * RUN LEVEL 786 * PASSIVE_LEVEL 787 * 788 * ARGUMENTS 789 * Argument1 790 * Pointer to the miniport driver's driver object. 791 * 792 * Argument2 793 * Pointer to the miniport driver's registry path. 794 * 795 * HwInitializationData 796 * Pointer to port driver specific configuration data. 797 * 798 * HwContext 799 Miniport driver specific context. 800 * 801 * RETURN VALUE 802 * Status. 803 * 804 * @implemented 805 */ 806 807 ULONG NTAPI 808 ScsiPortInitialize( 809 IN PVOID Argument1, 810 IN PVOID Argument2, 811 IN struct _HW_INITIALIZATION_DATA *HwInitializationData, 812 IN PVOID HwContext) 813 { 814 PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Argument1; 815 PUNICODE_STRING RegistryPath = (PUNICODE_STRING)Argument2; 816 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = NULL; 817 PCONFIGURATION_INFORMATION SystemConfig; 818 PPORT_CONFIGURATION_INFORMATION PortConfig; 819 PORT_CONFIGURATION_INFORMATION InitialPortConfig; 820 CONFIGURATION_INFO ConfigInfo; 821 ULONG DeviceExtensionSize; 822 ULONG PortConfigSize; 823 BOOLEAN Again; 824 BOOLEAN DeviceFound = FALSE; 825 BOOLEAN FirstConfigCall = TRUE; 826 ULONG Result; 827 NTSTATUS Status; 828 ULONG MaxBus; 829 PCI_SLOT_NUMBER SlotNumber; 830 831 PDEVICE_OBJECT PortDeviceObject; 832 WCHAR NameBuffer[80]; 833 UNICODE_STRING DeviceName; 834 WCHAR DosNameBuffer[80]; 835 UNICODE_STRING DosDeviceName; 836 PIO_SCSI_CAPABILITIES PortCapabilities; 837 838 PCM_RESOURCE_LIST ResourceList; 839 BOOLEAN Conflict; 840 SIZE_T BusConfigSize; 841 842 843 DPRINT ("ScsiPortInitialize() called!\n"); 844 845 /* Check params for validity */ 846 if ((HwInitializationData->HwInitialize == NULL) || 847 (HwInitializationData->HwStartIo == NULL) || 848 (HwInitializationData->HwInterrupt == NULL) || 849 (HwInitializationData->HwFindAdapter == NULL) || 850 (HwInitializationData->HwResetBus == NULL)) 851 { 852 return STATUS_INVALID_PARAMETER; 853 } 854 855 /* Set handlers */ 856 DriverObject->DriverStartIo = ScsiPortStartIo; 857 DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiPortCreateClose; 858 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiPortCreateClose; 859 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiPortDeviceControl; 860 DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiPortDispatchScsi; 861 862 /* Obtain configuration information */ 863 SystemConfig = IoGetConfigurationInformation(); 864 865 /* Zero the internal configuration info structure */ 866 RtlZeroMemory(&ConfigInfo, sizeof(CONFIGURATION_INFO)); 867 868 /* Zero starting slot number */ 869 SlotNumber.u.AsULONG = 0; 870 871 /* Allocate space for access ranges */ 872 if (HwInitializationData->NumberOfAccessRanges) 873 { 874 ConfigInfo.AccessRanges = 875 ExAllocatePoolWithTag(PagedPool, 876 HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE), TAG_SCSIPORT); 877 878 /* Fail if failed */ 879 if (ConfigInfo.AccessRanges == NULL) 880 return STATUS_INSUFFICIENT_RESOURCES; 881 } 882 883 /* Open registry keys */ 884 SpiInitOpenKeys(&ConfigInfo, (PUNICODE_STRING)Argument2); 885 886 /* Last adapter number = not known */ 887 ConfigInfo.LastAdapterNumber = SP_UNINITIALIZED_VALUE; 888 889 /* Calculate sizes of DeviceExtension and PortConfig */ 890 DeviceExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) + 891 HwInitializationData->DeviceExtensionSize; 892 893 MaxBus = (HwInitializationData->AdapterInterfaceType == PCIBus) ? 8 : 1; 894 DPRINT("MaxBus: %lu\n", MaxBus); 895 896 while (TRUE) 897 { 898 /* Create a unicode device name */ 899 swprintf(NameBuffer, 900 L"\\Device\\ScsiPort%lu", 901 SystemConfig->ScsiPortCount); 902 RtlInitUnicodeString(&DeviceName, NameBuffer); 903 904 DPRINT("Creating device: %wZ\n", &DeviceName); 905 906 /* Create the port device */ 907 Status = IoCreateDevice(DriverObject, 908 DeviceExtensionSize, 909 &DeviceName, 910 FILE_DEVICE_CONTROLLER, 911 0, 912 FALSE, 913 &PortDeviceObject); 914 915 if (!NT_SUCCESS(Status)) 916 { 917 DPRINT1("IoCreateDevice call failed! (Status 0x%lX)\n", Status); 918 PortDeviceObject = NULL; 919 break; 920 } 921 922 DPRINT ("Created device: %wZ (%p)\n", &DeviceName, PortDeviceObject); 923 924 /* Set the buffering strategy here... */ 925 PortDeviceObject->Flags |= DO_DIRECT_IO; 926 PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT; /* FIXME: Is this really needed? */ 927 928 /* Fill Device Extension */ 929 DeviceExtension = PortDeviceObject->DeviceExtension; 930 RtlZeroMemory(DeviceExtension, DeviceExtensionSize); 931 DeviceExtension->Length = DeviceExtensionSize; 932 DeviceExtension->DeviceObject = PortDeviceObject; 933 DeviceExtension->PortNumber = SystemConfig->ScsiPortCount; 934 935 /* Driver's routines... */ 936 DeviceExtension->HwInitialize = HwInitializationData->HwInitialize; 937 DeviceExtension->HwStartIo = HwInitializationData->HwStartIo; 938 DeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt; 939 DeviceExtension->HwResetBus = HwInitializationData->HwResetBus; 940 DeviceExtension->HwDmaStarted = HwInitializationData->HwDmaStarted; 941 942 /* Extensions sizes */ 943 DeviceExtension->MiniPortExtensionSize = HwInitializationData->DeviceExtensionSize; 944 DeviceExtension->LunExtensionSize = HwInitializationData->SpecificLuExtensionSize; 945 DeviceExtension->SrbExtensionSize = HwInitializationData->SrbExtensionSize; 946 947 /* Round Srb extension size to the quadword */ 948 DeviceExtension->SrbExtensionSize = 949 ~(sizeof(LONGLONG) - 1) & (DeviceExtension->SrbExtensionSize + 950 sizeof(LONGLONG) - 1); 951 952 /* Fill some numbers (bus count, lun count, etc) */ 953 DeviceExtension->MaxLunCount = SCSI_MAXIMUM_LOGICAL_UNITS; 954 DeviceExtension->RequestsNumber = 16; 955 956 /* Initialize the spin lock in the controller extension */ 957 KeInitializeSpinLock(&DeviceExtension->IrqLock); 958 KeInitializeSpinLock(&DeviceExtension->SpinLock); 959 960 /* Initialize the DPC object */ 961 IoInitializeDpcRequest(PortDeviceObject, 962 ScsiPortDpcForIsr); 963 964 /* Initialize the device timer */ 965 DeviceExtension->TimerCount = -1; 966 IoInitializeTimer(PortDeviceObject, 967 ScsiPortIoTimer, 968 DeviceExtension); 969 970 /* Initialize miniport timer */ 971 KeInitializeTimer(&DeviceExtension->MiniportTimer); 972 KeInitializeDpc(&DeviceExtension->MiniportTimerDpc, 973 SpiMiniportTimerDpc, 974 PortDeviceObject); 975 976 CreatePortConfig: 977 978 Status = SpiCreatePortConfig(DeviceExtension, 979 HwInitializationData, 980 &ConfigInfo, 981 &InitialPortConfig, 982 FirstConfigCall); 983 984 if (!NT_SUCCESS(Status)) 985 { 986 DPRINT("SpiCreatePortConfig() failed with Status 0x%08X\n", Status); 987 break; 988 } 989 990 /* Allocate and initialize port configuration info */ 991 PortConfigSize = (sizeof(PORT_CONFIGURATION_INFORMATION) + 992 HwInitializationData->NumberOfAccessRanges * 993 sizeof(ACCESS_RANGE) + 7) & ~7; 994 DeviceExtension->PortConfig = ExAllocatePoolWithTag(NonPagedPool, PortConfigSize, TAG_SCSIPORT); 995 996 /* Fail if failed */ 997 if (DeviceExtension->PortConfig == NULL) 998 { 999 Status = STATUS_INSUFFICIENT_RESOURCES; 1000 break; 1001 } 1002 1003 PortConfig = DeviceExtension->PortConfig; 1004 1005 /* Copy information here */ 1006 RtlCopyMemory(PortConfig, 1007 &InitialPortConfig, 1008 sizeof(PORT_CONFIGURATION_INFORMATION)); 1009 1010 1011 /* Copy extension sizes into the PortConfig */ 1012 PortConfig->SpecificLuExtensionSize = DeviceExtension->LunExtensionSize; 1013 PortConfig->SrbExtensionSize = DeviceExtension->SrbExtensionSize; 1014 1015 /* Initialize Access ranges */ 1016 if (HwInitializationData->NumberOfAccessRanges != 0) 1017 { 1018 PortConfig->AccessRanges = (PVOID)(PortConfig+1); 1019 1020 /* Align to LONGLONG */ 1021 PortConfig->AccessRanges = (PVOID)((ULONG_PTR)(PortConfig->AccessRanges) + 7); 1022 PortConfig->AccessRanges = (PVOID)((ULONG_PTR)(PortConfig->AccessRanges) & ~7); 1023 1024 /* Copy the data */ 1025 RtlCopyMemory(PortConfig->AccessRanges, 1026 ConfigInfo.AccessRanges, 1027 HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE)); 1028 } 1029 1030 /* Search for matching PCI device */ 1031 if ((HwInitializationData->AdapterInterfaceType == PCIBus) && 1032 (HwInitializationData->VendorIdLength > 0) && 1033 (HwInitializationData->VendorId != NULL) && 1034 (HwInitializationData->DeviceIdLength > 0) && (HwInitializationData->DeviceId != NULL)) 1035 { 1036 PortConfig->BusInterruptLevel = 0; 1037 1038 /* Get PCI device data */ 1039 DPRINT( 1040 "VendorId '%.*s' DeviceId '%.*s'\n", HwInitializationData->VendorIdLength, 1041 HwInitializationData->VendorId, HwInitializationData->DeviceIdLength, 1042 HwInitializationData->DeviceId); 1043 1044 if (!SpiGetPciConfigData( 1045 DriverObject, PortDeviceObject, HwInitializationData, PortConfig, RegistryPath, 1046 ConfigInfo.BusNumber, &SlotNumber)) 1047 { 1048 /* Continue to the next bus, nothing here */ 1049 ConfigInfo.BusNumber++; 1050 DeviceExtension->PortConfig = NULL; 1051 ExFreePool(PortConfig); 1052 Again = FALSE; 1053 goto CreatePortConfig; 1054 } 1055 1056 if (!PortConfig->BusInterruptLevel) 1057 { 1058 /* Bypass this slot, because no interrupt was assigned */ 1059 DeviceExtension->PortConfig = NULL; 1060 ExFreePool(PortConfig); 1061 goto CreatePortConfig; 1062 } 1063 } 1064 else 1065 { 1066 DPRINT("Non-pci bus\n"); 1067 } 1068 1069 /* Note: HwFindAdapter is called once for each bus */ 1070 Again = FALSE; 1071 DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber); 1072 Result = (HwInitializationData->HwFindAdapter)( 1073 &DeviceExtension->MiniPortDeviceExtension, HwContext, 0, /* BusInformation */ 1074 ConfigInfo.Parameter, /* ArgumentString */ 1075 PortConfig, &Again); 1076 1077 DPRINT("HwFindAdapter() Result: %lu Again: %s\n", Result, (Again) ? "True" : "False"); 1078 1079 /* Free MapRegisterBase, it's not needed anymore */ 1080 if (DeviceExtension->MapRegisterBase != NULL) 1081 { 1082 ExFreePool(DeviceExtension->MapRegisterBase); 1083 DeviceExtension->MapRegisterBase = NULL; 1084 } 1085 1086 /* If result is nothing good... */ 1087 if (Result != SP_RETURN_FOUND) 1088 { 1089 DPRINT("HwFindAdapter() Result: %lu\n", Result); 1090 1091 if (Result == SP_RETURN_NOT_FOUND) 1092 { 1093 /* We can continue on the next bus */ 1094 ConfigInfo.BusNumber++; 1095 Again = FALSE; 1096 1097 DeviceExtension->PortConfig = NULL; 1098 ExFreePool(PortConfig); 1099 goto CreatePortConfig; 1100 } 1101 1102 /* Otherwise, break */ 1103 Status = STATUS_INTERNAL_ERROR; 1104 break; 1105 } 1106 1107 DPRINT( 1108 "ScsiPortInitialize(): Found HBA! (%x), adapter Id %d\n", 1109 PortConfig->BusInterruptVector, PortConfig->InitiatorBusId[0]); 1110 1111 /* If the SRB extension size was updated */ 1112 if (!DeviceExtension->NonCachedExtension && 1113 (PortConfig->SrbExtensionSize != DeviceExtension->SrbExtensionSize)) 1114 { 1115 /* Set it (rounding to LONGLONG again) */ 1116 DeviceExtension->SrbExtensionSize = 1117 (PortConfig->SrbExtensionSize + sizeof(LONGLONG)) & ~(sizeof(LONGLONG) - 1); 1118 } 1119 1120 /* The same with LUN extension size */ 1121 if (PortConfig->SpecificLuExtensionSize != DeviceExtension->LunExtensionSize) 1122 DeviceExtension->LunExtensionSize = PortConfig->SpecificLuExtensionSize; 1123 1124 if (!((HwInitializationData->AdapterInterfaceType == PCIBus) && 1125 (HwInitializationData->VendorIdLength > 0) && 1126 (HwInitializationData->VendorId != NULL) && 1127 (HwInitializationData->DeviceIdLength > 0) && 1128 (HwInitializationData->DeviceId != NULL))) 1129 { 1130 /* Construct a resource list */ 1131 ResourceList = SpiConfigToResource(DeviceExtension, PortConfig); 1132 1133 if (ResourceList) 1134 { 1135 UNICODE_STRING UnicodeString; 1136 RtlInitUnicodeString(&UnicodeString, L"ScsiAdapter"); 1137 DPRINT("Reporting resources\n"); 1138 Status = IoReportResourceUsage(&UnicodeString, 1139 DriverObject, 1140 NULL, 1141 0, 1142 PortDeviceObject, 1143 ResourceList, 1144 FIELD_OFFSET(CM_RESOURCE_LIST, 1145 List[0].PartialResourceList.PartialDescriptors) + 1146 ResourceList->List[0].PartialResourceList.Count * 1147 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR), 1148 FALSE, 1149 &Conflict); 1150 ExFreePool(ResourceList); 1151 1152 /* In case of a failure or a conflict, break */ 1153 if (Conflict || (!NT_SUCCESS(Status))) 1154 { 1155 if (Conflict) 1156 Status = STATUS_CONFLICTING_ADDRESSES; 1157 break; 1158 } 1159 } 1160 } 1161 1162 /* Reset the Conflict var */ 1163 Conflict = FALSE; 1164 1165 /* Copy all stuff which we ever need from PortConfig to the DeviceExtension */ 1166 if (PortConfig->MaximumNumberOfTargets > SCSI_MAXIMUM_TARGETS_PER_BUS) 1167 DeviceExtension->MaxTargedIds = SCSI_MAXIMUM_TARGETS_PER_BUS; 1168 else 1169 DeviceExtension->MaxTargedIds = PortConfig->MaximumNumberOfTargets; 1170 1171 DeviceExtension->BusNum = PortConfig->NumberOfBuses; 1172 DeviceExtension->CachesData = PortConfig->CachesData; 1173 DeviceExtension->ReceiveEvent = PortConfig->ReceiveEvent; 1174 DeviceExtension->SupportsTaggedQueuing = PortConfig->TaggedQueuing; 1175 DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu; 1176 1177 /* If something was disabled via registry - apply it */ 1178 if (ConfigInfo.DisableMultipleLun) 1179 DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu = FALSE; 1180 1181 if (ConfigInfo.DisableTaggedQueueing) 1182 DeviceExtension->SupportsTaggedQueuing = PortConfig->MultipleRequestPerLu = FALSE; 1183 1184 /* Check if we need to alloc SRB data */ 1185 if (DeviceExtension->SupportsTaggedQueuing || DeviceExtension->MultipleReqsPerLun) 1186 { 1187 DeviceExtension->NeedSrbDataAlloc = TRUE; 1188 } 1189 else 1190 { 1191 DeviceExtension->NeedSrbDataAlloc = FALSE; 1192 } 1193 1194 /* Get a pointer to the port capabilities */ 1195 PortCapabilities = &DeviceExtension->PortCapabilities; 1196 1197 /* Copy one field there */ 1198 DeviceExtension->MapBuffers = PortConfig->MapBuffers; 1199 PortCapabilities->AdapterUsesPio = PortConfig->MapBuffers; 1200 1201 if (DeviceExtension->AdapterObject == NULL && 1202 (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE || PortConfig->Master)) 1203 { 1204 DPRINT1("DMA is not supported yet\n"); 1205 ASSERT(FALSE); 1206 } 1207 1208 if (DeviceExtension->SrbExtensionBuffer == NULL && 1209 (DeviceExtension->SrbExtensionSize != 0 || PortConfig->AutoRequestSense)) 1210 { 1211 DeviceExtension->SupportsAutoSense = PortConfig->AutoRequestSense; 1212 DeviceExtension->NeedSrbExtensionAlloc = TRUE; 1213 1214 /* Allocate common buffer */ 1215 Status = SpiAllocateCommonBuffer(DeviceExtension, 0); 1216 1217 /* Check for failure */ 1218 if (!NT_SUCCESS(Status)) 1219 break; 1220 } 1221 1222 /* Allocate SrbData, if needed */ 1223 if (DeviceExtension->NeedSrbDataAlloc) 1224 { 1225 ULONG Count; 1226 PSCSI_REQUEST_BLOCK_INFO SrbData; 1227 1228 if (DeviceExtension->SrbDataCount != 0) 1229 Count = DeviceExtension->SrbDataCount; 1230 else 1231 Count = DeviceExtension->RequestsNumber * 2; 1232 1233 /* Allocate the data */ 1234 SrbData = ExAllocatePoolWithTag( 1235 NonPagedPool, Count * sizeof(SCSI_REQUEST_BLOCK_INFO), TAG_SCSIPORT); 1236 if (SrbData == NULL) 1237 return STATUS_INSUFFICIENT_RESOURCES; 1238 1239 RtlZeroMemory(SrbData, Count * sizeof(SCSI_REQUEST_BLOCK_INFO)); 1240 1241 DeviceExtension->SrbInfo = SrbData; 1242 DeviceExtension->FreeSrbInfo = SrbData; 1243 DeviceExtension->SrbDataCount = Count; 1244 1245 /* Link it to the list */ 1246 while (Count > 0) 1247 { 1248 SrbData->Requests.Flink = (PLIST_ENTRY)(SrbData + 1); 1249 SrbData++; 1250 Count--; 1251 } 1252 1253 /* Mark the last entry of the list */ 1254 SrbData--; 1255 SrbData->Requests.Flink = NULL; 1256 } 1257 1258 /* Initialize port capabilities */ 1259 PortCapabilities = &DeviceExtension->PortCapabilities; 1260 PortCapabilities->Length = sizeof(IO_SCSI_CAPABILITIES); 1261 PortCapabilities->MaximumTransferLength = PortConfig->MaximumTransferLength; 1262 1263 if (PortConfig->ReceiveEvent) 1264 PortCapabilities->SupportedAsynchronousEvents |= SRBEV_SCSI_ASYNC_NOTIFICATION; 1265 1266 PortCapabilities->TaggedQueuing = DeviceExtension->SupportsTaggedQueuing; 1267 PortCapabilities->AdapterScansDown = PortConfig->AdapterScansDown; 1268 1269 if (PortConfig->AlignmentMask > PortDeviceObject->AlignmentRequirement) 1270 PortDeviceObject->AlignmentRequirement = PortConfig->AlignmentMask; 1271 1272 PortCapabilities->AlignmentMask = PortDeviceObject->AlignmentRequirement; 1273 1274 if (PortCapabilities->MaximumPhysicalPages == 0) 1275 { 1276 PortCapabilities->MaximumPhysicalPages = 1277 BYTES_TO_PAGES(PortCapabilities->MaximumTransferLength); 1278 1279 /* Apply miniport's limits */ 1280 if (PortConfig->NumberOfPhysicalBreaks < PortCapabilities->MaximumPhysicalPages) 1281 { 1282 PortCapabilities->MaximumPhysicalPages = PortConfig->NumberOfPhysicalBreaks; 1283 } 1284 } 1285 1286 CallHWInitialize(DeviceExtension); 1287 1288 /* Start our timer */ 1289 IoStartTimer(PortDeviceObject); 1290 1291 /* Initialize bus scanning information */ 1292 BusConfigSize = FIELD_OFFSET( 1293 BUSES_CONFIGURATION_INFORMATION, 1294 BusScanInfo[DeviceExtension->PortConfig->NumberOfBuses]); 1295 DeviceExtension->BusesConfig = 1296 ExAllocatePoolWithTag(PagedPool, BusConfigSize, TAG_SCSIPORT); 1297 if (!DeviceExtension->BusesConfig) 1298 { 1299 DPRINT1("Out of resources!\n"); 1300 Status = STATUS_INSUFFICIENT_RESOURCES; 1301 break; 1302 } 1303 1304 /* Zero it */ 1305 RtlZeroMemory(DeviceExtension->BusesConfig, BusConfigSize); 1306 1307 /* Store number of buses there */ 1308 DeviceExtension->BusesConfig->NumberOfBuses = (UCHAR)DeviceExtension->BusNum; 1309 1310 /* Scan the adapter for devices */ 1311 SpiScanAdapter(DeviceExtension); 1312 1313 /* Build the registry device map */ 1314 SpiBuildDeviceMap(DeviceExtension, (PUNICODE_STRING)Argument2); 1315 1316 /* Create the dos device link */ 1317 swprintf(DosNameBuffer, L"\\??\\Scsi%lu:", SystemConfig->ScsiPortCount); 1318 RtlInitUnicodeString(&DosDeviceName, DosNameBuffer); 1319 IoCreateSymbolicLink(&DosDeviceName, &DeviceName); 1320 1321 /* Increase the port count */ 1322 SystemConfig->ScsiPortCount++; 1323 FirstConfigCall = FALSE; 1324 1325 /* Increase adapter number and bus number respectively */ 1326 ConfigInfo.AdapterNumber++; 1327 1328 if (!Again) 1329 ConfigInfo.BusNumber++; 1330 1331 DPRINT("Bus: %lu MaxBus: %lu\n", ConfigInfo.BusNumber, MaxBus); 1332 1333 DeviceFound = TRUE; 1334 } 1335 1336 /* Clean up the mess */ 1337 SpiCleanupAfterInit(DeviceExtension); 1338 1339 /* Close registry keys */ 1340 if (ConfigInfo.ServiceKey != NULL) 1341 ZwClose(ConfigInfo.ServiceKey); 1342 1343 if (ConfigInfo.DeviceKey != NULL) 1344 ZwClose(ConfigInfo.DeviceKey); 1345 1346 if (ConfigInfo.BusKey != NULL) 1347 ZwClose(ConfigInfo.BusKey); 1348 1349 if (ConfigInfo.AccessRanges != NULL) 1350 ExFreePool(ConfigInfo.AccessRanges); 1351 1352 if (ConfigInfo.Parameter != NULL) 1353 ExFreePool(ConfigInfo.Parameter); 1354 1355 DPRINT("ScsiPortInitialize() done, Status = 0x%08X, DeviceFound = %d!\n", 1356 Status, DeviceFound); 1357 1358 return (DeviceFound == FALSE) ? Status : STATUS_SUCCESS; 1359 } 1360 1361 /* 1362 * @unimplemented 1363 */ 1364 VOID NTAPI 1365 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension, 1366 IN PSCSI_REQUEST_BLOCK Srb, 1367 IN PVOID LogicalAddress, 1368 IN ULONG Length) 1369 { 1370 DPRINT1("ScsiPortIoMapTransfer()\n"); 1371 UNIMPLEMENTED; 1372 } 1373 1374 /* 1375 * @unimplemented 1376 */ 1377 VOID NTAPI 1378 ScsiPortLogError(IN PVOID HwDeviceExtension, 1379 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL, 1380 IN UCHAR PathId, 1381 IN UCHAR TargetId, 1382 IN UCHAR Lun, 1383 IN ULONG ErrorCode, 1384 IN ULONG UniqueId) 1385 { 1386 //PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 1387 1388 DPRINT1("ScsiPortLogError() called\n"); 1389 DPRINT1("PathId: 0x%02x TargetId: 0x%02x Lun: 0x%02x ErrorCode: 0x%08lx UniqueId: 0x%08lx\n", 1390 PathId, TargetId, Lun, ErrorCode, UniqueId); 1391 1392 //DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, SCSI_PORT_DEVICE_EXTENSION, MiniPortDeviceExtension); 1393 1394 1395 DPRINT("ScsiPortLogError() done\n"); 1396 } 1397 1398 /* 1399 * @implemented 1400 */ 1401 VOID NTAPI 1402 ScsiPortMoveMemory(OUT PVOID Destination, 1403 IN PVOID Source, 1404 IN ULONG Length) 1405 { 1406 RtlMoveMemory(Destination, 1407 Source, 1408 Length); 1409 } 1410 1411 1412 /* 1413 * @implemented 1414 */ 1415 VOID 1416 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType, IN PVOID HwDeviceExtension, ...) 1417 { 1418 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 1419 va_list ap; 1420 1421 DPRINT("ScsiPortNotification() called\n"); 1422 1423 DeviceExtension = 1424 CONTAINING_RECORD(HwDeviceExtension, SCSI_PORT_DEVICE_EXTENSION, MiniPortDeviceExtension); 1425 1426 DPRINT("DeviceExtension %p\n", DeviceExtension); 1427 1428 va_start(ap, HwDeviceExtension); 1429 1430 switch (NotificationType) 1431 { 1432 case RequestComplete: 1433 { 1434 PSCSI_REQUEST_BLOCK Srb; 1435 PSCSI_REQUEST_BLOCK_INFO SrbData; 1436 1437 Srb = (PSCSI_REQUEST_BLOCK)va_arg(ap, PSCSI_REQUEST_BLOCK); 1438 1439 DPRINT("Notify: RequestComplete (Srb %p)\n", Srb); 1440 1441 /* Make sure Srb is alright */ 1442 ASSERT(Srb->SrbStatus != SRB_STATUS_PENDING); 1443 ASSERT( 1444 Srb->Function != SRB_FUNCTION_EXECUTE_SCSI || 1445 Srb->SrbStatus != SRB_STATUS_SUCCESS || Srb->ScsiStatus == SCSISTAT_GOOD); 1446 1447 if (!(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE)) 1448 { 1449 /* It's been already completed */ 1450 va_end(ap); 1451 return; 1452 } 1453 1454 /* It's not active anymore */ 1455 Srb->SrbFlags &= ~SRB_FLAGS_IS_ACTIVE; 1456 1457 if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND) 1458 { 1459 /* TODO: Treat it specially */ 1460 ASSERT(FALSE); 1461 } 1462 else 1463 { 1464 /* Get the SRB data */ 1465 SrbData = SpiGetSrbData( 1466 DeviceExtension, Srb->PathId, Srb->TargetId, Srb->Lun, Srb->QueueTag); 1467 1468 /* Make sure there are no CompletedRequests and there is a Srb */ 1469 ASSERT(SrbData->CompletedRequests == NULL && SrbData->Srb != NULL); 1470 1471 /* If it's a read/write request, make sure it has data inside it */ 1472 if ((Srb->SrbStatus == SRB_STATUS_SUCCESS) && 1473 ((Srb->Cdb[0] == SCSIOP_READ) || (Srb->Cdb[0] == SCSIOP_WRITE))) 1474 { 1475 ASSERT(Srb->DataTransferLength); 1476 } 1477 1478 SrbData->CompletedRequests = DeviceExtension->InterruptData.CompletedRequests; 1479 DeviceExtension->InterruptData.CompletedRequests = SrbData; 1480 } 1481 } 1482 break; 1483 1484 case NextRequest: 1485 DPRINT("Notify: NextRequest\n"); 1486 DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY; 1487 break; 1488 1489 case NextLuRequest: 1490 { 1491 UCHAR PathId; 1492 UCHAR TargetId; 1493 UCHAR Lun; 1494 PSCSI_PORT_LUN_EXTENSION LunExtension; 1495 1496 PathId = (UCHAR)va_arg(ap, int); 1497 TargetId = (UCHAR)va_arg(ap, int); 1498 Lun = (UCHAR)va_arg(ap, int); 1499 1500 DPRINT( 1501 "Notify: NextLuRequest(PathId %u TargetId %u Lun %u)\n", PathId, TargetId, Lun); 1502 1503 /* Mark it in the flags field */ 1504 DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY; 1505 1506 /* Get the LUN extension */ 1507 LunExtension = SpiGetLunExtension(DeviceExtension, PathId, TargetId, Lun); 1508 1509 /* If returned LunExtension is NULL, break out */ 1510 if (!LunExtension) 1511 break; 1512 1513 /* This request should not be processed if */ 1514 if ((LunExtension->ReadyLun) || (LunExtension->SrbInfo.Srb)) 1515 { 1516 /* Nothing to do here */ 1517 break; 1518 } 1519 1520 /* Add this LUN to the list */ 1521 LunExtension->ReadyLun = DeviceExtension->InterruptData.ReadyLun; 1522 DeviceExtension->InterruptData.ReadyLun = LunExtension; 1523 } 1524 break; 1525 1526 case ResetDetected: 1527 DPRINT("Notify: ResetDetected\n"); 1528 /* Add RESET flags */ 1529 DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET | SCSI_PORT_RESET_REPORTED; 1530 break; 1531 1532 case CallDisableInterrupts: 1533 DPRINT1("UNIMPLEMENTED SCSI Notification called: CallDisableInterrupts!\n"); 1534 break; 1535 1536 case CallEnableInterrupts: 1537 DPRINT1("UNIMPLEMENTED SCSI Notification called: CallEnableInterrupts!\n"); 1538 break; 1539 1540 case RequestTimerCall: 1541 DPRINT("Notify: RequestTimerCall\n"); 1542 DeviceExtension->InterruptData.Flags |= SCSI_PORT_TIMER_NEEDED; 1543 DeviceExtension->InterruptData.HwScsiTimer = (PHW_TIMER)va_arg(ap, PHW_TIMER); 1544 DeviceExtension->InterruptData.MiniportTimerValue = (ULONG)va_arg(ap, ULONG); 1545 break; 1546 1547 case BusChangeDetected: 1548 DPRINT1("UNIMPLEMENTED SCSI Notification called: BusChangeDetected!\n"); 1549 break; 1550 1551 default: 1552 DPRINT1("Unsupported notification from WMI: %lu\n", NotificationType); 1553 break; 1554 } 1555 1556 va_end(ap); 1557 1558 /* Request a DPC after we're done with the interrupt */ 1559 DeviceExtension->InterruptData.Flags |= SCSI_PORT_NOTIFICATION_NEEDED; 1560 } 1561 1562 /* 1563 * @implemented 1564 */ 1565 BOOLEAN NTAPI 1566 ScsiPortValidateRange(IN PVOID HwDeviceExtension, 1567 IN INTERFACE_TYPE BusType, 1568 IN ULONG SystemIoBusNumber, 1569 IN SCSI_PHYSICAL_ADDRESS IoAddress, 1570 IN ULONG NumberOfBytes, 1571 IN BOOLEAN InIoSpace) 1572 { 1573 DPRINT("ScsiPortValidateRange()\n"); 1574 return(TRUE); 1575 } 1576 1577 1578 /* INTERNAL FUNCTIONS ********************************************************/ 1579 1580 static VOID 1581 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData, 1582 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor, 1583 IN PPORT_CONFIGURATION_INFORMATION PortConfig) 1584 { 1585 PACCESS_RANGE AccessRange; 1586 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialData; 1587 ULONG RangeNumber; 1588 ULONG Index; 1589 ULONG Interrupt = 0; 1590 ULONG Dma = 0; 1591 1592 RangeNumber = 0; 1593 1594 /* Loop through all entries */ 1595 for (Index = 0; Index < ResourceDescriptor->PartialResourceList.Count; Index++) 1596 { 1597 PartialData = &ResourceDescriptor->PartialResourceList.PartialDescriptors[Index]; 1598 1599 switch (PartialData->Type) 1600 { 1601 case CmResourceTypePort: 1602 /* Copy access ranges */ 1603 if (RangeNumber < HwInitializationData->NumberOfAccessRanges) 1604 { 1605 AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]); 1606 1607 AccessRange->RangeStart = PartialData->u.Port.Start; 1608 AccessRange->RangeLength = PartialData->u.Port.Length; 1609 1610 AccessRange->RangeInMemory = FALSE; 1611 RangeNumber++; 1612 } 1613 break; 1614 1615 case CmResourceTypeMemory: 1616 /* Copy access ranges */ 1617 if (RangeNumber < HwInitializationData->NumberOfAccessRanges) 1618 { 1619 AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]); 1620 1621 AccessRange->RangeStart = PartialData->u.Memory.Start; 1622 AccessRange->RangeLength = PartialData->u.Memory.Length; 1623 1624 AccessRange->RangeInMemory = TRUE; 1625 RangeNumber++; 1626 } 1627 break; 1628 1629 case CmResourceTypeInterrupt: 1630 1631 if (Interrupt == 0) 1632 { 1633 /* Copy interrupt data */ 1634 PortConfig->BusInterruptLevel = PartialData->u.Interrupt.Level; 1635 PortConfig->BusInterruptVector = PartialData->u.Interrupt.Vector; 1636 1637 /* Set interrupt mode accordingly to the resource */ 1638 if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED) 1639 { 1640 PortConfig->InterruptMode = Latched; 1641 } 1642 else if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE) 1643 { 1644 PortConfig->InterruptMode = LevelSensitive; 1645 } 1646 } 1647 else if (Interrupt == 1) 1648 { 1649 /* Copy interrupt data */ 1650 PortConfig->BusInterruptLevel2 = PartialData->u.Interrupt.Level; 1651 PortConfig->BusInterruptVector2 = PartialData->u.Interrupt.Vector; 1652 1653 /* Set interrupt mode accordingly to the resource */ 1654 if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED) 1655 { 1656 PortConfig->InterruptMode2 = Latched; 1657 } 1658 else if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE) 1659 { 1660 PortConfig->InterruptMode2 = LevelSensitive; 1661 } 1662 } 1663 1664 Interrupt++; 1665 break; 1666 1667 case CmResourceTypeDma: 1668 1669 if (Dma == 0) 1670 { 1671 PortConfig->DmaChannel = PartialData->u.Dma.Channel; 1672 PortConfig->DmaPort = PartialData->u.Dma.Port; 1673 1674 if (PartialData->Flags & CM_RESOURCE_DMA_8) 1675 PortConfig->DmaWidth = Width8Bits; 1676 else if ((PartialData->Flags & CM_RESOURCE_DMA_16) || 1677 (PartialData->Flags & CM_RESOURCE_DMA_8_AND_16)) //??? 1678 PortConfig->DmaWidth = Width16Bits; 1679 else if (PartialData->Flags & CM_RESOURCE_DMA_32) 1680 PortConfig->DmaWidth = Width32Bits; 1681 } 1682 else if (Dma == 1) 1683 { 1684 PortConfig->DmaChannel2 = PartialData->u.Dma.Channel; 1685 PortConfig->DmaPort2 = PartialData->u.Dma.Port; 1686 1687 if (PartialData->Flags & CM_RESOURCE_DMA_8) 1688 PortConfig->DmaWidth2 = Width8Bits; 1689 else if ((PartialData->Flags & CM_RESOURCE_DMA_16) || 1690 (PartialData->Flags & CM_RESOURCE_DMA_8_AND_16)) //??? 1691 PortConfig->DmaWidth2 = Width16Bits; 1692 else if (PartialData->Flags & CM_RESOURCE_DMA_32) 1693 PortConfig->DmaWidth2 = Width32Bits; 1694 } 1695 break; 1696 } 1697 } 1698 } 1699 1700 static PCM_RESOURCE_LIST 1701 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 1702 PPORT_CONFIGURATION_INFORMATION PortConfig) 1703 { 1704 PCONFIGURATION_INFORMATION ConfigInfo; 1705 PCM_RESOURCE_LIST ResourceList; 1706 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor; 1707 PACCESS_RANGE AccessRange; 1708 ULONG ListLength = 0, i, FullSize; 1709 ULONG Interrupt, Dma; 1710 1711 /* Get current Atdisk usage from the system */ 1712 ConfigInfo = IoGetConfigurationInformation(); 1713 1714 if (PortConfig->AtdiskPrimaryClaimed) 1715 ConfigInfo->AtDiskPrimaryAddressClaimed = TRUE; 1716 1717 if (PortConfig->AtdiskSecondaryClaimed) 1718 ConfigInfo->AtDiskSecondaryAddressClaimed = TRUE; 1719 1720 /* Do we use DMA? */ 1721 if (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE || 1722 PortConfig->DmaPort != SP_UNINITIALIZED_VALUE) 1723 { 1724 Dma = 1; 1725 1726 if (PortConfig->DmaChannel2 != SP_UNINITIALIZED_VALUE || 1727 PortConfig->DmaPort2 != SP_UNINITIALIZED_VALUE) 1728 Dma++; 1729 } 1730 else 1731 { 1732 Dma = 0; 1733 } 1734 ListLength += Dma; 1735 1736 /* How many interrupts to we have? */ 1737 Interrupt = DeviceExtension->InterruptCount; 1738 ListLength += Interrupt; 1739 1740 /* How many access ranges do we use? */ 1741 AccessRange = &((*(PortConfig->AccessRanges))[0]); 1742 for (i = 0; i < PortConfig->NumberOfAccessRanges; i++) 1743 { 1744 if (AccessRange->RangeLength != 0) 1745 ListLength++; 1746 1747 AccessRange++; 1748 } 1749 1750 /* Allocate the resource list, since we know its size now */ 1751 FullSize = sizeof(CM_RESOURCE_LIST) + (ListLength - 1) * 1752 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR); 1753 1754 ResourceList = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(PagedPool, FullSize, TAG_SCSIPORT); 1755 1756 if (!ResourceList) 1757 return NULL; 1758 1759 /* Zero it */ 1760 RtlZeroMemory(ResourceList, FullSize); 1761 1762 /* Initialize it */ 1763 ResourceList->Count = 1; 1764 ResourceList->List[0].InterfaceType = PortConfig->AdapterInterfaceType; 1765 ResourceList->List[0].BusNumber = PortConfig->SystemIoBusNumber; 1766 ResourceList->List[0].PartialResourceList.Count = ListLength; 1767 ResourceDescriptor = ResourceList->List[0].PartialResourceList.PartialDescriptors; 1768 1769 /* Copy access ranges array over */ 1770 for (i = 0; i < PortConfig->NumberOfAccessRanges; i++) 1771 { 1772 AccessRange = &((*(PortConfig->AccessRanges))[i]); 1773 1774 /* If the range is empty - skip it */ 1775 if (AccessRange->RangeLength == 0) 1776 continue; 1777 1778 if (AccessRange->RangeInMemory) 1779 { 1780 ResourceDescriptor->Type = CmResourceTypeMemory; 1781 ResourceDescriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE; 1782 } 1783 else 1784 { 1785 ResourceDescriptor->Type = CmResourceTypePort; 1786 ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO; 1787 } 1788 1789 ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; 1790 1791 ResourceDescriptor->u.Memory.Start = AccessRange->RangeStart; 1792 ResourceDescriptor->u.Memory.Length = AccessRange->RangeLength; 1793 1794 ResourceDescriptor++; 1795 } 1796 1797 /* If we use interrupt(s), copy them */ 1798 while (Interrupt) 1799 { 1800 ResourceDescriptor->Type = CmResourceTypeInterrupt; 1801 1802 if (PortConfig->AdapterInterfaceType == MicroChannel || 1803 ((Interrupt == 2) ? PortConfig->InterruptMode2 : PortConfig->InterruptMode) == LevelSensitive) 1804 { 1805 ResourceDescriptor->ShareDisposition = CmResourceShareShared; 1806 ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; 1807 } 1808 else 1809 { 1810 ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; 1811 ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED; 1812 } 1813 1814 ResourceDescriptor->u.Interrupt.Level = (Interrupt == 2) ? PortConfig->BusInterruptLevel2 : PortConfig->BusInterruptLevel; 1815 ResourceDescriptor->u.Interrupt.Vector = (Interrupt == 2) ? PortConfig->BusInterruptVector2 : PortConfig->BusInterruptVector; 1816 ResourceDescriptor->u.Interrupt.Affinity = 0; 1817 1818 ResourceDescriptor++; 1819 Interrupt--; 1820 } 1821 1822 /* Copy DMA data */ 1823 while (Dma) 1824 { 1825 ResourceDescriptor->Type = CmResourceTypeDma; 1826 ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; 1827 ResourceDescriptor->u.Dma.Channel = (Dma == 2) ? PortConfig->DmaChannel2 : PortConfig->DmaChannel; 1828 ResourceDescriptor->u.Dma.Port = (Dma == 2) ? PortConfig->DmaPort2 : PortConfig->DmaPort; 1829 ResourceDescriptor->Flags = 0; 1830 1831 if (((Dma == 2) ? PortConfig->DmaWidth2 : PortConfig->DmaWidth) == Width8Bits) 1832 ResourceDescriptor->Flags |= CM_RESOURCE_DMA_8; 1833 else if (((Dma == 2) ? PortConfig->DmaWidth2 : PortConfig->DmaWidth) == Width16Bits) 1834 ResourceDescriptor->Flags |= CM_RESOURCE_DMA_16; 1835 else 1836 ResourceDescriptor->Flags |= CM_RESOURCE_DMA_32; 1837 1838 if (((Dma == 2) ? PortConfig->DmaChannel2 : PortConfig->DmaChannel) == SP_UNINITIALIZED_VALUE) 1839 ResourceDescriptor->u.Dma.Channel = 0; 1840 1841 if (((Dma == 2) ? PortConfig->DmaPort2 : PortConfig->DmaPort) == SP_UNINITIALIZED_VALUE) 1842 ResourceDescriptor->u.Dma.Port = 0; 1843 1844 ResourceDescriptor++; 1845 Dma--; 1846 } 1847 1848 return ResourceList; 1849 } 1850 1851 1852 static BOOLEAN 1853 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject, 1854 IN PDEVICE_OBJECT DeviceObject, 1855 IN struct _HW_INITIALIZATION_DATA *HwInitializationData, 1856 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig, 1857 IN PUNICODE_STRING RegistryPath, 1858 IN ULONG BusNumber, 1859 IN OUT PPCI_SLOT_NUMBER NextSlotNumber) 1860 { 1861 PCI_COMMON_CONFIG PciConfig; 1862 PCI_SLOT_NUMBER SlotNumber; 1863 ULONG DataSize; 1864 ULONG DeviceNumber; 1865 ULONG FunctionNumber; 1866 CHAR VendorIdString[8]; 1867 CHAR DeviceIdString[8]; 1868 UNICODE_STRING UnicodeStr; 1869 PCM_RESOURCE_LIST ResourceList = NULL; 1870 NTSTATUS Status; 1871 1872 DPRINT ("SpiGetPciConfiguration() called\n"); 1873 1874 SlotNumber.u.AsULONG = 0; 1875 1876 /* Loop through all devices */ 1877 for (DeviceNumber = NextSlotNumber->u.bits.DeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++) 1878 { 1879 SlotNumber.u.bits.DeviceNumber = DeviceNumber; 1880 1881 /* Loop through all functions */ 1882 for (FunctionNumber = NextSlotNumber->u.bits.FunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++) 1883 { 1884 SlotNumber.u.bits.FunctionNumber = FunctionNumber; 1885 1886 /* Get PCI config bytes */ 1887 DataSize = HalGetBusData(PCIConfiguration, 1888 BusNumber, 1889 SlotNumber.u.AsULONG, 1890 &PciConfig, 1891 sizeof(ULONG)); 1892 1893 /* If result of HalGetBusData is 0, then the bus is wrong */ 1894 if (DataSize == 0) 1895 return FALSE; 1896 1897 /* Check if result is PCI_INVALID_VENDORID or too small */ 1898 if ((DataSize < sizeof(ULONG)) || 1899 (PciConfig.VendorID == PCI_INVALID_VENDORID)) 1900 { 1901 /* Continue to try the next function */ 1902 continue; 1903 } 1904 1905 sprintf (VendorIdString, "%04hx", PciConfig.VendorID); 1906 sprintf (DeviceIdString, "%04hx", PciConfig.DeviceID); 1907 1908 if (_strnicmp(VendorIdString, HwInitializationData->VendorId, HwInitializationData->VendorIdLength) || 1909 _strnicmp(DeviceIdString, HwInitializationData->DeviceId, HwInitializationData->DeviceIdLength)) 1910 { 1911 /* It is not our device */ 1912 continue; 1913 } 1914 1915 DPRINT("Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n", 1916 PciConfig.VendorID, 1917 PciConfig.DeviceID, 1918 BusNumber, 1919 SlotNumber.u.bits.DeviceNumber, 1920 SlotNumber.u.bits.FunctionNumber); 1921 1922 1923 RtlInitUnicodeString(&UnicodeStr, L"ScsiAdapter"); 1924 Status = HalAssignSlotResources(RegistryPath, 1925 &UnicodeStr, 1926 DriverObject, 1927 DeviceObject, 1928 PCIBus, 1929 BusNumber, 1930 SlotNumber.u.AsULONG, 1931 &ResourceList); 1932 1933 if (!NT_SUCCESS(Status)) 1934 break; 1935 1936 /* Create configuration information */ 1937 SpiResourceToConfig(HwInitializationData, 1938 ResourceList->List, 1939 PortConfig); 1940 1941 /* Free the resource list */ 1942 ExFreePool(ResourceList); 1943 1944 /* Set dev & fn numbers */ 1945 NextSlotNumber->u.bits.DeviceNumber = DeviceNumber; 1946 NextSlotNumber->u.bits.FunctionNumber = FunctionNumber + 1; 1947 1948 /* Save the slot number */ 1949 PortConfig->SlotNumber = SlotNumber.u.AsULONG; 1950 1951 return TRUE; 1952 } 1953 NextSlotNumber->u.bits.FunctionNumber = 0; 1954 } 1955 1956 NextSlotNumber->u.bits.DeviceNumber = 0; 1957 DPRINT ("No device found\n"); 1958 1959 return FALSE; 1960 } 1961 1962 1963 1964 /********************************************************************** 1965 * NAME INTERNAL 1966 * ScsiPortCreateClose 1967 * 1968 * DESCRIPTION 1969 * Answer requests for Create/Close calls: a null operation. 1970 * 1971 * RUN LEVEL 1972 * PASSIVE_LEVEL 1973 * 1974 * ARGUMENTS 1975 * DeviceObject 1976 * Pointer to a device object. 1977 * 1978 * Irp 1979 * Pointer to an IRP. 1980 * 1981 * RETURN VALUE 1982 * Status. 1983 */ 1984 1985 static NTSTATUS NTAPI 1986 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject, 1987 IN PIRP Irp) 1988 { 1989 DPRINT("ScsiPortCreateClose()\n"); 1990 1991 Irp->IoStatus.Status = STATUS_SUCCESS; 1992 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1993 1994 return STATUS_SUCCESS; 1995 } 1996 1997 IO_ALLOCATION_ACTION 1998 NTAPI 1999 SpiAdapterControl(PDEVICE_OBJECT DeviceObject, 2000 PIRP Irp, 2001 PVOID MapRegisterBase, 2002 PVOID Context) 2003 { 2004 PSCSI_REQUEST_BLOCK Srb; 2005 PSCSI_SG_ADDRESS ScatterGatherList; 2006 KIRQL CurrentIrql; 2007 PIO_STACK_LOCATION IrpStack; 2008 ULONG TotalLength = 0; 2009 PSCSI_REQUEST_BLOCK_INFO SrbInfo; 2010 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 2011 PUCHAR DataVA; 2012 BOOLEAN WriteToDevice; 2013 2014 /* Get pointers to SrbInfo and DeviceExtension */ 2015 SrbInfo = (PSCSI_REQUEST_BLOCK_INFO)Context; 2016 DeviceExtension = DeviceObject->DeviceExtension; 2017 2018 /* Get pointer to SRB */ 2019 IrpStack = IoGetCurrentIrpStackLocation(Irp); 2020 Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1; 2021 2022 /* Depending on the map registers number, we allocate 2023 either from NonPagedPool, or from our static list */ 2024 if (SrbInfo->NumberOfMapRegisters > MAX_SG_LIST) 2025 { 2026 SrbInfo->ScatterGather = ExAllocatePoolWithTag( 2027 NonPagedPool, SrbInfo->NumberOfMapRegisters * sizeof(SCSI_SG_ADDRESS), TAG_SCSIPORT); 2028 2029 if (SrbInfo->ScatterGather == NULL) 2030 ASSERT(FALSE); 2031 2032 Srb->SrbFlags |= SRB_FLAGS_SGLIST_FROM_POOL; 2033 } 2034 else 2035 { 2036 SrbInfo->ScatterGather = SrbInfo->ScatterGatherList; 2037 } 2038 2039 /* Use chosen SG list source */ 2040 ScatterGatherList = SrbInfo->ScatterGather; 2041 2042 /* Save map registers base */ 2043 SrbInfo->BaseOfMapRegister = MapRegisterBase; 2044 2045 /* Determine WriteToDevice flag */ 2046 WriteToDevice = Srb->SrbFlags & SRB_FLAGS_DATA_OUT ? TRUE : FALSE; 2047 2048 /* Get virtual address of the data buffer */ 2049 DataVA = (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress) + 2050 ((PCHAR)Srb->DataBuffer - SrbInfo->DataOffset); 2051 2052 /* Build the actual SG list */ 2053 while (TotalLength < Srb->DataTransferLength) 2054 { 2055 if (!ScatterGatherList) 2056 break; 2057 2058 ScatterGatherList->Length = Srb->DataTransferLength - TotalLength; 2059 ScatterGatherList->PhysicalAddress = IoMapTransfer(DeviceExtension->AdapterObject, 2060 Irp->MdlAddress, 2061 MapRegisterBase, 2062 DataVA + TotalLength, 2063 &ScatterGatherList->Length, 2064 WriteToDevice); 2065 2066 TotalLength += ScatterGatherList->Length; 2067 ScatterGatherList++; 2068 } 2069 2070 /* Schedule an active request */ 2071 InterlockedIncrement(&DeviceExtension->ActiveRequestCounter ); 2072 KeAcquireSpinLock(&DeviceExtension->SpinLock, &CurrentIrql); 2073 KeSynchronizeExecution(DeviceExtension->Interrupt[0], 2074 ScsiPortStartPacket, 2075 DeviceObject); 2076 KeReleaseSpinLock(&DeviceExtension->SpinLock, CurrentIrql); 2077 2078 return DeallocateObjectKeepRegisters; 2079 } 2080 2081 BOOLEAN 2082 NTAPI 2083 ScsiPortIsr( 2084 _In_ PKINTERRUPT Interrupt, 2085 _In_ PVOID ServiceContext) 2086 { 2087 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 2088 2089 DPRINT("ScsiPortIsr() called!\n"); 2090 2091 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext; 2092 2093 /* If interrupts are disabled - we don't expect any */ 2094 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_DISABLE_INTERRUPTS) 2095 return FALSE; 2096 2097 /* Call miniport's HwInterrupt routine */ 2098 if (DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension) == FALSE) 2099 { 2100 /* This interrupt doesn't belong to us */ 2101 return FALSE; 2102 } 2103 2104 /* If flag of notification is set - queue a DPC */ 2105 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED) 2106 { 2107 IoRequestDpc(DeviceExtension->DeviceObject, 2108 DeviceExtension->CurrentIrp, 2109 DeviceExtension); 2110 } 2111 2112 return TRUE; 2113 } 2114 2115 BOOLEAN 2116 NTAPI 2117 SpiProcessTimeout(PVOID ServiceContext) 2118 { 2119 PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)ServiceContext; 2120 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; 2121 ULONG Bus; 2122 2123 DPRINT("SpiProcessTimeout() entered\n"); 2124 2125 DeviceExtension->TimerCount = -1; 2126 2127 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET) 2128 { 2129 DeviceExtension->InterruptData.Flags &= ~SCSI_PORT_RESET; 2130 2131 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET_REQUEST) 2132 { 2133 DeviceExtension->InterruptData.Flags &= ~SCSI_PORT_RESET_REQUEST; 2134 ScsiPortStartPacket(ServiceContext); 2135 } 2136 2137 return FALSE; 2138 } 2139 else 2140 { 2141 DPRINT("Resetting the bus\n"); 2142 2143 for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++) 2144 { 2145 DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension, Bus); 2146 2147 /* Reset flags and set reset timeout to 4 seconds */ 2148 DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET; 2149 DeviceExtension->TimerCount = 4; 2150 } 2151 2152 /* If miniport requested - request a dpc for it */ 2153 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED) 2154 IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL); 2155 } 2156 2157 return TRUE; 2158 } 2159 2160 2161 BOOLEAN 2162 NTAPI 2163 SpiResetBus(PVOID ServiceContext) 2164 { 2165 PRESETBUS_PARAMS ResetParams = (PRESETBUS_PARAMS)ServiceContext; 2166 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 2167 2168 /* Perform the bus reset */ 2169 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ResetParams->DeviceExtension; 2170 DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension, 2171 ResetParams->PathId); 2172 2173 /* Set flags and start the timer */ 2174 DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET; 2175 DeviceExtension->TimerCount = 4; 2176 2177 /* If miniport requested - give him a DPC */ 2178 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED) 2179 IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL); 2180 2181 return TRUE; 2182 } 2183 2184 // ScsiPortIoTimer 2185 // DESCRIPTION: 2186 // This function handles timeouts and other time delayed processing 2187 // 2188 // RUN LEVEL: 2189 // 2190 // ARGUMENTS: 2191 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer 2192 // IN PVOID Context the Controller extension for the 2193 // controller the device is on 2194 // 2195 static VOID NTAPI 2196 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject, 2197 PVOID Context) 2198 { 2199 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 2200 PSCSI_PORT_LUN_EXTENSION LunExtension; 2201 ULONG Lun; 2202 PIRP Irp; 2203 2204 DPRINT("ScsiPortIoTimer()\n"); 2205 2206 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 2207 2208 /* Protect with the spinlock */ 2209 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock); 2210 2211 /* Check timeouts */ 2212 if (DeviceExtension->TimerCount > 0) 2213 { 2214 /* Decrease the timeout counter */ 2215 DeviceExtension->TimerCount--; 2216 2217 if (DeviceExtension->TimerCount == 0) 2218 { 2219 /* Timeout, process it */ 2220 if (KeSynchronizeExecution(DeviceExtension->Interrupt[0], 2221 SpiProcessTimeout, 2222 DeviceExtension->DeviceObject)) 2223 { 2224 DPRINT("Error happened during processing timeout, but nothing critical\n"); 2225 } 2226 } 2227 2228 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 2229 2230 /* We should exit now, since timeout is processed */ 2231 return; 2232 } 2233 2234 /* Per-Lun scanning of timeouts is needed... */ 2235 for (Lun = 0; Lun < LUS_NUMBER; Lun++) 2236 { 2237 LunExtension = DeviceExtension->LunExtensionList[Lun]; 2238 2239 while (LunExtension) 2240 { 2241 if (LunExtension->Flags & LUNEX_BUSY) 2242 { 2243 if (!(LunExtension->Flags & 2244 (LUNEX_NEED_REQUEST_SENSE | LUNEX_FROZEN_QUEUE))) 2245 { 2246 DPRINT("Retrying busy request\n"); 2247 2248 /* Clear flags, and retry busy request */ 2249 LunExtension->Flags &= ~(LUNEX_BUSY | LUNEX_FULL_QUEUE); 2250 Irp = LunExtension->BusyRequest; 2251 2252 /* Clearing busy request */ 2253 LunExtension->BusyRequest = NULL; 2254 2255 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 2256 2257 IoStartPacket(DeviceObject, Irp, (PULONG)NULL, NULL); 2258 2259 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock); 2260 } 2261 } 2262 else if (LunExtension->RequestTimeout == 0) 2263 { 2264 RESETBUS_PARAMS ResetParams; 2265 2266 LunExtension->RequestTimeout = -1; 2267 2268 DPRINT("Request timed out, resetting bus\n"); 2269 2270 /* Pass params to the bus reset routine */ 2271 ResetParams.PathId = LunExtension->PathId; 2272 ResetParams.DeviceExtension = DeviceExtension; 2273 2274 if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0], 2275 SpiResetBus, 2276 &ResetParams)) 2277 { 2278 DPRINT1("Reset failed\n"); 2279 } 2280 } 2281 else if (LunExtension->RequestTimeout > 0) 2282 { 2283 /* Decrement the timeout counter */ 2284 LunExtension->RequestTimeout--; 2285 } 2286 2287 LunExtension = LunExtension->Next; 2288 } 2289 } 2290 2291 /* Release the spinlock */ 2292 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 2293 } 2294 2295 VOID 2296 NTAPI 2297 SpiMiniportTimerDpc(IN struct _KDPC *Dpc, 2298 IN PVOID DeviceObject, 2299 IN PVOID SystemArgument1, 2300 IN PVOID SystemArgument2) 2301 { 2302 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 2303 2304 DPRINT("Miniport timer DPC\n"); 2305 2306 DeviceExtension = ((PDEVICE_OBJECT)DeviceObject)->DeviceExtension; 2307 2308 /* Acquire the spinlock */ 2309 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock); 2310 2311 /* Call the timer routine */ 2312 if (DeviceExtension->HwScsiTimer != NULL) 2313 { 2314 DeviceExtension->HwScsiTimer(&DeviceExtension->MiniPortDeviceExtension); 2315 } 2316 2317 /* Release the spinlock */ 2318 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 2319 2320 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED) 2321 { 2322 ScsiPortDpcForIsr(NULL, 2323 DeviceExtension->DeviceObject, 2324 NULL, 2325 NULL); 2326 } 2327 } 2328 2329 static NTSTATUS 2330 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 2331 PHW_INITIALIZATION_DATA HwInitData, 2332 PCONFIGURATION_INFO InternalConfigInfo, 2333 PPORT_CONFIGURATION_INFORMATION ConfigInfo, 2334 BOOLEAN ZeroStruct) 2335 { 2336 UNICODE_STRING UnicodeString; 2337 OBJECT_ATTRIBUTES ObjectAttributes; 2338 PCONFIGURATION_INFORMATION DdkConfigInformation; 2339 HANDLE RootKey, Key; 2340 BOOLEAN Found; 2341 WCHAR DeviceBuffer[16]; 2342 WCHAR StrBuffer[512]; 2343 ULONG Bus; 2344 NTSTATUS Status; 2345 2346 /* Zero out the struct if told so */ 2347 if (ZeroStruct) 2348 { 2349 /* First zero the portconfig */ 2350 RtlZeroMemory(ConfigInfo, sizeof(PORT_CONFIGURATION_INFORMATION)); 2351 2352 /* Then access ranges */ 2353 RtlZeroMemory(InternalConfigInfo->AccessRanges, 2354 HwInitData->NumberOfAccessRanges * sizeof(ACCESS_RANGE)); 2355 2356 /* Initialize the struct */ 2357 ConfigInfo->Length = sizeof(PORT_CONFIGURATION_INFORMATION); 2358 ConfigInfo->AdapterInterfaceType = HwInitData->AdapterInterfaceType; 2359 ConfigInfo->InterruptMode = Latched; 2360 ConfigInfo->DmaChannel = SP_UNINITIALIZED_VALUE; 2361 ConfigInfo->DmaPort = SP_UNINITIALIZED_VALUE; 2362 ConfigInfo->DmaChannel2 = SP_UNINITIALIZED_VALUE; 2363 ConfigInfo->DmaPort2 = SP_UNINITIALIZED_VALUE; 2364 ConfigInfo->MaximumTransferLength = SP_UNINITIALIZED_VALUE; 2365 ConfigInfo->NumberOfAccessRanges = HwInitData->NumberOfAccessRanges; 2366 ConfigInfo->MaximumNumberOfTargets = 8; 2367 2368 /* Store parameters */ 2369 ConfigInfo->NeedPhysicalAddresses = HwInitData->NeedPhysicalAddresses; 2370 ConfigInfo->MapBuffers = HwInitData->MapBuffers; 2371 ConfigInfo->AutoRequestSense = HwInitData->AutoRequestSense; 2372 ConfigInfo->ReceiveEvent = HwInitData->ReceiveEvent; 2373 ConfigInfo->TaggedQueuing = HwInitData->TaggedQueuing; 2374 ConfigInfo->MultipleRequestPerLu = HwInitData->MultipleRequestPerLu; 2375 2376 /* Get the disk usage */ 2377 DdkConfigInformation = IoGetConfigurationInformation(); 2378 ConfigInfo->AtdiskPrimaryClaimed = DdkConfigInformation->AtDiskPrimaryAddressClaimed; 2379 ConfigInfo->AtdiskSecondaryClaimed = DdkConfigInformation->AtDiskSecondaryAddressClaimed; 2380 2381 /* Initiator bus id is not set */ 2382 for (Bus = 0; Bus < 8; Bus++) 2383 ConfigInfo->InitiatorBusId[Bus] = (CCHAR)SP_UNINITIALIZED_VALUE; 2384 } 2385 2386 ConfigInfo->NumberOfPhysicalBreaks = 17; 2387 2388 /* Clear this information */ 2389 InternalConfigInfo->DisableTaggedQueueing = FALSE; 2390 InternalConfigInfo->DisableMultipleLun = FALSE; 2391 2392 /* Store Bus Number */ 2393 ConfigInfo->SystemIoBusNumber = InternalConfigInfo->BusNumber; 2394 2395 TryNextAd: 2396 2397 if (ConfigInfo->AdapterInterfaceType == Internal) 2398 { 2399 /* Open registry key for HW database */ 2400 InitializeObjectAttributes(&ObjectAttributes, 2401 DeviceExtension->DeviceObject->DriverObject->HardwareDatabase, 2402 OBJ_CASE_INSENSITIVE, 2403 NULL, 2404 NULL); 2405 2406 Status = ZwOpenKey(&RootKey, 2407 KEY_READ, 2408 &ObjectAttributes); 2409 2410 if (NT_SUCCESS(Status)) 2411 { 2412 /* Create name for it */ 2413 swprintf(StrBuffer, L"ScsiAdapter\\%lu", 2414 InternalConfigInfo->AdapterNumber); 2415 2416 RtlInitUnicodeString(&UnicodeString, StrBuffer); 2417 2418 /* Open device key */ 2419 InitializeObjectAttributes(&ObjectAttributes, 2420 &UnicodeString, 2421 OBJ_CASE_INSENSITIVE, 2422 RootKey, 2423 NULL); 2424 2425 Status = ZwOpenKey(&Key, 2426 KEY_READ, 2427 &ObjectAttributes); 2428 2429 ZwClose(RootKey); 2430 2431 if (NT_SUCCESS(Status)) 2432 { 2433 if (InternalConfigInfo->LastAdapterNumber != InternalConfigInfo->AdapterNumber) 2434 { 2435 DPRINT("Hardware info found at %S\n", StrBuffer); 2436 2437 /* Parse it */ 2438 SpiParseDeviceInfo(DeviceExtension, 2439 Key, 2440 ConfigInfo, 2441 InternalConfigInfo, 2442 (PUCHAR)StrBuffer); 2443 2444 InternalConfigInfo->BusNumber = 0; 2445 } 2446 else 2447 { 2448 /* Try the next adapter */ 2449 InternalConfigInfo->AdapterNumber++; 2450 goto TryNextAd; 2451 } 2452 } 2453 else 2454 { 2455 /* Info was not found, exit */ 2456 DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status); 2457 return STATUS_DEVICE_DOES_NOT_EXIST; 2458 } 2459 } 2460 else 2461 { 2462 DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status); 2463 } 2464 } 2465 2466 /* Look at device params */ 2467 Key = NULL; 2468 if (InternalConfigInfo->Parameter) 2469 { 2470 ExFreePool(InternalConfigInfo->Parameter); 2471 InternalConfigInfo->Parameter = NULL; 2472 } 2473 2474 if (InternalConfigInfo->ServiceKey != NULL) 2475 { 2476 swprintf(DeviceBuffer, L"Device%lu", InternalConfigInfo->AdapterNumber); 2477 RtlInitUnicodeString(&UnicodeString, DeviceBuffer); 2478 2479 /* Open the service key */ 2480 InitializeObjectAttributes(&ObjectAttributes, 2481 &UnicodeString, 2482 OBJ_CASE_INSENSITIVE, 2483 InternalConfigInfo->ServiceKey, 2484 NULL); 2485 2486 Status = ZwOpenKey(&Key, 2487 KEY_READ, 2488 &ObjectAttributes); 2489 } 2490 2491 /* Parse device key */ 2492 if (InternalConfigInfo->DeviceKey != NULL) 2493 { 2494 SpiParseDeviceInfo(DeviceExtension, 2495 InternalConfigInfo->DeviceKey, 2496 ConfigInfo, 2497 InternalConfigInfo, 2498 (PUCHAR)StrBuffer); 2499 } 2500 2501 /* Then parse hw info */ 2502 if (Key != NULL) 2503 { 2504 if (InternalConfigInfo->LastAdapterNumber != InternalConfigInfo->AdapterNumber) 2505 { 2506 SpiParseDeviceInfo(DeviceExtension, 2507 Key, 2508 ConfigInfo, 2509 InternalConfigInfo, 2510 (PUCHAR)StrBuffer); 2511 2512 /* Close the key */ 2513 ZwClose(Key); 2514 } 2515 else 2516 { 2517 /* Adapter not found, go try the next one */ 2518 InternalConfigInfo->AdapterNumber++; 2519 2520 /* Close the key */ 2521 ZwClose(Key); 2522 2523 goto TryNextAd; 2524 } 2525 } 2526 2527 /* Update the last adapter number */ 2528 InternalConfigInfo->LastAdapterNumber = InternalConfigInfo->AdapterNumber; 2529 2530 /* Do we have this kind of bus at all? */ 2531 Found = FALSE; 2532 Status = IoQueryDeviceDescription(&HwInitData->AdapterInterfaceType, 2533 &InternalConfigInfo->BusNumber, 2534 NULL, 2535 NULL, 2536 NULL, 2537 NULL, 2538 SpQueryDeviceCallout, 2539 &Found); 2540 2541 /* This bus was not found */ 2542 if (!Found) 2543 { 2544 INTERFACE_TYPE InterfaceType = Eisa; 2545 2546 /* Check for EISA */ 2547 if (HwInitData->AdapterInterfaceType == Isa) 2548 { 2549 Status = IoQueryDeviceDescription(&InterfaceType, 2550 &InternalConfigInfo->BusNumber, 2551 NULL, 2552 NULL, 2553 NULL, 2554 NULL, 2555 SpQueryDeviceCallout, 2556 &Found); 2557 2558 /* Return respectively */ 2559 if (Found) 2560 return STATUS_SUCCESS; 2561 else 2562 return STATUS_DEVICE_DOES_NOT_EXIST; 2563 } 2564 else 2565 { 2566 return STATUS_DEVICE_DOES_NOT_EXIST; 2567 } 2568 } 2569 else 2570 { 2571 return STATUS_SUCCESS; 2572 } 2573 } 2574 2575 static VOID 2576 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 2577 IN HANDLE Key, 2578 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo, 2579 IN PCONFIGURATION_INFO InternalConfigInfo, 2580 IN PUCHAR Buffer) 2581 { 2582 PKEY_VALUE_FULL_INFORMATION KeyValueInformation; 2583 PCM_FULL_RESOURCE_DESCRIPTOR FullResource; 2584 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor; 2585 PCM_SCSI_DEVICE_DATA ScsiDeviceData; 2586 ULONG Length, Count, Dma = 0, Interrupt = 0; 2587 ULONG Index = 0, RangeCount = 0; 2588 UNICODE_STRING UnicodeString; 2589 ANSI_STRING AnsiString; 2590 NTSTATUS Status = STATUS_SUCCESS; 2591 2592 2593 KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION) Buffer; 2594 2595 /* Loop through all values in the device node */ 2596 while(TRUE) 2597 { 2598 Status = ZwEnumerateValueKey(Key, 2599 Index, 2600 KeyValueFullInformation, 2601 Buffer, 2602 512, 2603 &Length); 2604 2605 if (!NT_SUCCESS(Status)) 2606 return; 2607 2608 Index++; 2609 2610 /* Length for DWORD is ok? */ 2611 if (KeyValueInformation->Type == REG_DWORD && 2612 KeyValueInformation->DataLength != sizeof(ULONG)) 2613 { 2614 continue; 2615 } 2616 2617 /* Get MaximumLogicalUnit */ 2618 if (_wcsnicmp(KeyValueInformation->Name, L"MaximumLogicalUnit", 2619 KeyValueInformation->NameLength/2) == 0) 2620 { 2621 2622 if (KeyValueInformation->Type != REG_DWORD) 2623 { 2624 DPRINT("Bad data type for MaximumLogicalUnit\n"); 2625 continue; 2626 } 2627 2628 DeviceExtension->MaxLunCount = *((PUCHAR) 2629 (Buffer + KeyValueInformation->DataOffset)); 2630 2631 /* Check / reset if needed */ 2632 if (DeviceExtension->MaxLunCount > SCSI_MAXIMUM_LOGICAL_UNITS) 2633 DeviceExtension->MaxLunCount = SCSI_MAXIMUM_LOGICAL_UNITS; 2634 2635 DPRINT("MaximumLogicalUnit = %d\n", DeviceExtension->MaxLunCount); 2636 } 2637 2638 /* Get InitiatorTargetId */ 2639 if (_wcsnicmp(KeyValueInformation->Name, L"InitiatorTargetId", 2640 KeyValueInformation->NameLength / 2) == 0) 2641 { 2642 2643 if (KeyValueInformation->Type != REG_DWORD) 2644 { 2645 DPRINT("Bad data type for InitiatorTargetId\n"); 2646 continue; 2647 } 2648 2649 ConfigInfo->InitiatorBusId[0] = *((PUCHAR) 2650 (Buffer + KeyValueInformation->DataOffset)); 2651 2652 /* Check / reset if needed */ 2653 if (ConfigInfo->InitiatorBusId[0] > ConfigInfo->MaximumNumberOfTargets - 1) 2654 ConfigInfo->InitiatorBusId[0] = (CCHAR)-1; 2655 2656 DPRINT("InitiatorTargetId = %d\n", ConfigInfo->InitiatorBusId[0]); 2657 } 2658 2659 /* Get ScsiDebug */ 2660 if (_wcsnicmp(KeyValueInformation->Name, L"ScsiDebug", 2661 KeyValueInformation->NameLength/2) == 0) 2662 { 2663 DPRINT("ScsiDebug key not supported\n"); 2664 } 2665 2666 /* Check for a breakpoint */ 2667 if (_wcsnicmp(KeyValueInformation->Name, L"BreakPointOnEntry", 2668 KeyValueInformation->NameLength/2) == 0) 2669 { 2670 DPRINT1("Breakpoint on entry requested!\n"); 2671 DbgBreakPoint(); 2672 } 2673 2674 /* Get DisableSynchronousTransfers */ 2675 if (_wcsnicmp(KeyValueInformation->Name, L"DisableSynchronousTransfers", 2676 KeyValueInformation->NameLength/2) == 0) 2677 { 2678 DeviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER; 2679 DPRINT("Synch transfers disabled\n"); 2680 } 2681 2682 /* Get DisableDisconnects */ 2683 if (_wcsnicmp(KeyValueInformation->Name, L"DisableDisconnects", 2684 KeyValueInformation->NameLength/2) == 0) 2685 { 2686 DeviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT; 2687 DPRINT("Disconnects disabled\n"); 2688 } 2689 2690 /* Get DisableTaggedQueuing */ 2691 if (_wcsnicmp(KeyValueInformation->Name, L"DisableTaggedQueuing", 2692 KeyValueInformation->NameLength/2) == 0) 2693 { 2694 InternalConfigInfo->DisableTaggedQueueing = TRUE; 2695 DPRINT("Tagged queueing disabled\n"); 2696 } 2697 2698 /* Get DisableMultipleRequests */ 2699 if (_wcsnicmp(KeyValueInformation->Name, L"DisableMultipleRequests", 2700 KeyValueInformation->NameLength/2) == 0) 2701 { 2702 InternalConfigInfo->DisableMultipleLun = TRUE; 2703 DPRINT("Multiple requests disabled\n"); 2704 } 2705 2706 /* Get DriverParameters */ 2707 if (_wcsnicmp(KeyValueInformation->Name, L"DriverParameters", 2708 KeyValueInformation->NameLength/2) == 0) 2709 { 2710 /* Skip if nothing */ 2711 if (KeyValueInformation->DataLength == 0) 2712 continue; 2713 2714 /* If there was something previously allocated - free it */ 2715 if (InternalConfigInfo->Parameter != NULL) 2716 ExFreePool(InternalConfigInfo->Parameter); 2717 2718 /* Allocate it */ 2719 InternalConfigInfo->Parameter = ExAllocatePoolWithTag(NonPagedPool, 2720 KeyValueInformation->DataLength, TAG_SCSIPORT); 2721 2722 if (InternalConfigInfo->Parameter != NULL) 2723 { 2724 if (KeyValueInformation->Type != REG_SZ) 2725 { 2726 /* Just copy */ 2727 RtlCopyMemory( 2728 InternalConfigInfo->Parameter, 2729 (PCCHAR)KeyValueInformation + KeyValueInformation->DataOffset, 2730 KeyValueInformation->DataLength); 2731 } 2732 else 2733 { 2734 /* If it's a unicode string, convert it to ansi */ 2735 UnicodeString.Length = (USHORT)KeyValueInformation->DataLength; 2736 UnicodeString.MaximumLength = (USHORT)KeyValueInformation->DataLength; 2737 UnicodeString.Buffer = 2738 (PWSTR)((PCCHAR)KeyValueInformation + KeyValueInformation->DataOffset); 2739 2740 AnsiString.Length = 0; 2741 AnsiString.MaximumLength = (USHORT)KeyValueInformation->DataLength; 2742 AnsiString.Buffer = (PCHAR)InternalConfigInfo->Parameter; 2743 2744 Status = RtlUnicodeStringToAnsiString(&AnsiString, 2745 &UnicodeString, 2746 FALSE); 2747 2748 /* In case of error, free the allocated space */ 2749 if (!NT_SUCCESS(Status)) 2750 { 2751 ExFreePool(InternalConfigInfo->Parameter); 2752 InternalConfigInfo->Parameter = NULL; 2753 } 2754 2755 } 2756 } 2757 2758 DPRINT("Found driver parameter\n"); 2759 } 2760 2761 /* Get MaximumSGList */ 2762 if (_wcsnicmp(KeyValueInformation->Name, L"MaximumSGList", 2763 KeyValueInformation->NameLength/2) == 0) 2764 { 2765 if (KeyValueInformation->Type != REG_DWORD) 2766 { 2767 DPRINT("Bad data type for MaximumSGList\n"); 2768 continue; 2769 } 2770 2771 ConfigInfo->NumberOfPhysicalBreaks = *((PUCHAR)(Buffer + KeyValueInformation->DataOffset)); 2772 2773 /* Check / fix */ 2774 if (ConfigInfo->NumberOfPhysicalBreaks > SCSI_MAXIMUM_PHYSICAL_BREAKS) 2775 { 2776 ConfigInfo->NumberOfPhysicalBreaks = SCSI_MAXIMUM_PHYSICAL_BREAKS; 2777 } 2778 else if (ConfigInfo->NumberOfPhysicalBreaks < SCSI_MINIMUM_PHYSICAL_BREAKS) 2779 { 2780 ConfigInfo->NumberOfPhysicalBreaks = SCSI_MINIMUM_PHYSICAL_BREAKS; 2781 } 2782 2783 DPRINT("MaximumSGList = %d\n", ConfigInfo->NumberOfPhysicalBreaks); 2784 } 2785 2786 /* Get NumberOfRequests */ 2787 if (_wcsnicmp(KeyValueInformation->Name, L"NumberOfRequests", 2788 KeyValueInformation->NameLength/2) == 0) 2789 { 2790 if (KeyValueInformation->Type != REG_DWORD) 2791 { 2792 DPRINT("NumberOfRequests has wrong data type\n"); 2793 continue; 2794 } 2795 2796 DeviceExtension->RequestsNumber = *((PUCHAR)(Buffer + KeyValueInformation->DataOffset)); 2797 2798 /* Check / fix */ 2799 if (DeviceExtension->RequestsNumber < 16) 2800 { 2801 DeviceExtension->RequestsNumber = 16; 2802 } 2803 else if (DeviceExtension->RequestsNumber > 512) 2804 { 2805 DeviceExtension->RequestsNumber = 512; 2806 } 2807 2808 DPRINT("Number Of Requests = %d\n", DeviceExtension->RequestsNumber); 2809 } 2810 2811 /* Get resource list */ 2812 if (_wcsnicmp(KeyValueInformation->Name, L"ResourceList", 2813 KeyValueInformation->NameLength/2) == 0 || 2814 _wcsnicmp(KeyValueInformation->Name, L"Configuration Data", 2815 KeyValueInformation->NameLength/2) == 0 ) 2816 { 2817 if (KeyValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR || 2818 KeyValueInformation->DataLength < sizeof(REG_FULL_RESOURCE_DESCRIPTOR)) 2819 { 2820 DPRINT("Bad data type for ResourceList\n"); 2821 continue; 2822 } 2823 else 2824 { 2825 DPRINT("Found ResourceList\n"); 2826 } 2827 2828 FullResource = (PCM_FULL_RESOURCE_DESCRIPTOR)(Buffer + KeyValueInformation->DataOffset); 2829 2830 /* Copy some info from it */ 2831 InternalConfigInfo->BusNumber = FullResource->BusNumber; 2832 ConfigInfo->SystemIoBusNumber = FullResource->BusNumber; 2833 2834 /* Loop through it */ 2835 for (Count = 0; Count < FullResource->PartialResourceList.Count; Count++) 2836 { 2837 /* Get partial descriptor */ 2838 PartialDescriptor = 2839 &FullResource->PartialResourceList.PartialDescriptors[Count]; 2840 2841 /* Check datalength */ 2842 if ((ULONG)((PCHAR)(PartialDescriptor + 1) - 2843 (PCHAR)FullResource) > KeyValueInformation->DataLength) 2844 { 2845 DPRINT("Resource data is of incorrect size\n"); 2846 break; 2847 } 2848 2849 switch (PartialDescriptor->Type) 2850 { 2851 case CmResourceTypePort: 2852 if (RangeCount >= ConfigInfo->NumberOfAccessRanges) 2853 { 2854 DPRINT("Too many access ranges\n"); 2855 continue; 2856 } 2857 2858 InternalConfigInfo->AccessRanges[RangeCount].RangeInMemory = FALSE; 2859 InternalConfigInfo->AccessRanges[RangeCount].RangeStart = PartialDescriptor->u.Port.Start; 2860 InternalConfigInfo->AccessRanges[RangeCount].RangeLength = PartialDescriptor->u.Port.Length; 2861 RangeCount++; 2862 2863 break; 2864 2865 case CmResourceTypeMemory: 2866 if (RangeCount >= ConfigInfo->NumberOfAccessRanges) 2867 { 2868 DPRINT("Too many access ranges\n"); 2869 continue; 2870 } 2871 2872 InternalConfigInfo->AccessRanges[RangeCount].RangeInMemory = TRUE; 2873 InternalConfigInfo->AccessRanges[RangeCount].RangeStart = PartialDescriptor->u.Memory.Start; 2874 InternalConfigInfo->AccessRanges[RangeCount].RangeLength = PartialDescriptor->u.Memory.Length; 2875 RangeCount++; 2876 2877 break; 2878 2879 case CmResourceTypeInterrupt: 2880 2881 if (Interrupt == 0) 2882 { 2883 ConfigInfo->BusInterruptLevel = 2884 PartialDescriptor->u.Interrupt.Level; 2885 2886 ConfigInfo->BusInterruptVector = 2887 PartialDescriptor->u.Interrupt.Vector; 2888 2889 ConfigInfo->InterruptMode = (PartialDescriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive; 2890 } 2891 else if (Interrupt == 1) 2892 { 2893 ConfigInfo->BusInterruptLevel2 = 2894 PartialDescriptor->u.Interrupt.Level; 2895 2896 ConfigInfo->BusInterruptVector2 = 2897 PartialDescriptor->u.Interrupt.Vector; 2898 2899 ConfigInfo->InterruptMode2 = (PartialDescriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive; 2900 } 2901 2902 Interrupt++; 2903 break; 2904 2905 case CmResourceTypeDma: 2906 2907 if (Dma == 0) 2908 { 2909 ConfigInfo->DmaChannel = PartialDescriptor->u.Dma.Channel; 2910 ConfigInfo->DmaPort = PartialDescriptor->u.Dma.Port; 2911 2912 if (PartialDescriptor->Flags & CM_RESOURCE_DMA_8) 2913 ConfigInfo->DmaWidth = Width8Bits; 2914 else if ((PartialDescriptor->Flags & CM_RESOURCE_DMA_16) || 2915 (PartialDescriptor->Flags & CM_RESOURCE_DMA_8_AND_16)) //??? 2916 ConfigInfo->DmaWidth = Width16Bits; 2917 else if (PartialDescriptor->Flags & CM_RESOURCE_DMA_32) 2918 ConfigInfo->DmaWidth = Width32Bits; 2919 } 2920 else if (Dma == 1) 2921 { 2922 ConfigInfo->DmaChannel2 = PartialDescriptor->u.Dma.Channel; 2923 ConfigInfo->DmaPort2 = PartialDescriptor->u.Dma.Port; 2924 2925 if (PartialDescriptor->Flags & CM_RESOURCE_DMA_8) 2926 ConfigInfo->DmaWidth2 = Width8Bits; 2927 else if ((PartialDescriptor->Flags & CM_RESOURCE_DMA_16) || 2928 (PartialDescriptor->Flags & CM_RESOURCE_DMA_8_AND_16)) //??? 2929 ConfigInfo->DmaWidth2 = Width16Bits; 2930 else if (PartialDescriptor->Flags & CM_RESOURCE_DMA_32) 2931 ConfigInfo->DmaWidth2 = Width32Bits; 2932 } 2933 2934 Dma++; 2935 break; 2936 2937 case CmResourceTypeDeviceSpecific: 2938 if (PartialDescriptor->u.DeviceSpecificData.DataSize < 2939 sizeof(CM_SCSI_DEVICE_DATA) || 2940 (PCHAR) (PartialDescriptor + 1) - (PCHAR)FullResource + 2941 PartialDescriptor->u.DeviceSpecificData.DataSize > 2942 KeyValueInformation->DataLength) 2943 { 2944 DPRINT("Resource data length is incorrect"); 2945 break; 2946 } 2947 2948 /* Set only one field from it */ 2949 ScsiDeviceData = (PCM_SCSI_DEVICE_DATA) (PartialDescriptor+1); 2950 ConfigInfo->InitiatorBusId[0] = ScsiDeviceData->HostIdentifier; 2951 break; 2952 } 2953 } 2954 } 2955 } 2956 } 2957 2958 NTSTATUS 2959 NTAPI 2960 SpQueryDeviceCallout(IN PVOID Context, 2961 IN PUNICODE_STRING PathName, 2962 IN INTERFACE_TYPE BusType, 2963 IN ULONG BusNumber, 2964 IN PKEY_VALUE_FULL_INFORMATION *BusInformation, 2965 IN CONFIGURATION_TYPE ControllerType, 2966 IN ULONG ControllerNumber, 2967 IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation, 2968 IN CONFIGURATION_TYPE PeripheralType, 2969 IN ULONG PeripheralNumber, 2970 IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation) 2971 { 2972 PBOOLEAN Found = (PBOOLEAN)Context; 2973 /* We just set our Found variable to TRUE */ 2974 2975 *Found = TRUE; 2976 return STATUS_SUCCESS; 2977 } 2978 2979 IO_ALLOCATION_ACTION 2980 NTAPI 2981 ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject, 2982 IN PIRP Irp, 2983 IN PVOID MapRegisterBase, 2984 IN PVOID Context) 2985 { 2986 KIRQL Irql; 2987 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; 2988 2989 /* Guard access with the spinlock */ 2990 KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql); 2991 2992 /* Save MapRegisterBase we've got here */ 2993 DeviceExtension->MapRegisterBase = MapRegisterBase; 2994 2995 /* Start pending request */ 2996 KeSynchronizeExecution(DeviceExtension->Interrupt[0], 2997 ScsiPortStartPacket, DeviceObject); 2998 2999 /* Release spinlock we took */ 3000 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql); 3001 3002 return KeepObject; 3003 } 3004 3005 #undef ScsiPortConvertPhysicalAddressToUlong 3006 /* 3007 * @implemented 3008 */ 3009 ULONG NTAPI 3010 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address) 3011 { 3012 DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n"); 3013 return(Address.u.LowPart); 3014 } 3015 3016 /* EOF */ 3017