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