1 /* 2 * PROJECT: ReactOS Storage Stack 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: SCSI Port driver SCSI requests handling 5 * COPYRIGHT: Eric Kohl (eric.kohl@reactos.org) 6 * Aleksey Bragin (aleksey@reactos.org) 7 * 2020 Victor Perevertkin (victor.perevertkin@reactos.org) 8 */ 9 10 #include "scsiport.h" 11 12 #define NDEBUG 13 #include <debug.h> 14 15 16 static 17 NTSTATUS 18 SpiStatusSrbToNt( 19 _In_ UCHAR SrbStatus) 20 { 21 switch (SRB_STATUS(SrbStatus)) 22 { 23 case SRB_STATUS_TIMEOUT: 24 case SRB_STATUS_COMMAND_TIMEOUT: 25 return STATUS_IO_TIMEOUT; 26 27 case SRB_STATUS_BAD_SRB_BLOCK_LENGTH: 28 case SRB_STATUS_BAD_FUNCTION: 29 return STATUS_INVALID_DEVICE_REQUEST; 30 31 case SRB_STATUS_NO_DEVICE: 32 case SRB_STATUS_INVALID_LUN: 33 case SRB_STATUS_INVALID_TARGET_ID: 34 case SRB_STATUS_NO_HBA: 35 return STATUS_DEVICE_DOES_NOT_EXIST; 36 37 case SRB_STATUS_DATA_OVERRUN: 38 return STATUS_BUFFER_OVERFLOW; 39 40 case SRB_STATUS_SELECTION_TIMEOUT: 41 return STATUS_DEVICE_NOT_CONNECTED; 42 43 default: 44 return STATUS_IO_DEVICE_ERROR; 45 } 46 47 return STATUS_IO_DEVICE_ERROR; 48 } 49 50 static 51 NTSTATUS 52 SpiHandleAttachRelease( 53 _In_ PSCSI_PORT_LUN_EXTENSION LunExtension, 54 _Inout_ PIRP Irp) 55 { 56 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = 57 LunExtension->Common.LowerDevice->DeviceExtension; 58 PDEVICE_OBJECT DeviceObject; 59 KIRQL Irql; 60 61 /* Get pointer to the SRB */ 62 PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp); 63 PSCSI_REQUEST_BLOCK Srb = IrpStack->Parameters.Scsi.Srb; 64 65 /* Get spinlock */ 66 KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql); 67 68 /* Release, if asked */ 69 if (Srb->Function == SRB_FUNCTION_RELEASE_DEVICE) 70 { 71 LunExtension->DeviceClaimed = FALSE; 72 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql); 73 Srb->SrbStatus = SRB_STATUS_SUCCESS; 74 75 return STATUS_SUCCESS; 76 } 77 78 /* Attach, if not already claimed */ 79 if (LunExtension->DeviceClaimed) 80 { 81 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql); 82 Srb->SrbStatus = SRB_STATUS_BUSY; 83 84 return STATUS_DEVICE_BUSY; 85 } 86 87 /* Save the device object */ 88 DeviceObject = LunExtension->Common.DeviceObject; 89 90 if (Srb->Function == SRB_FUNCTION_CLAIM_DEVICE) 91 LunExtension->DeviceClaimed = TRUE; 92 93 if (Srb->Function == SRB_FUNCTION_ATTACH_DEVICE) 94 LunExtension->Common.DeviceObject = Srb->DataBuffer; 95 96 Srb->DataBuffer = DeviceObject; 97 98 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql); 99 Srb->SrbStatus = SRB_STATUS_SUCCESS; 100 101 return STATUS_SUCCESS; 102 } 103 104 /********************************************************************** 105 * NAME INTERNAL 106 * ScsiPortDispatchScsi 107 * 108 * DESCRIPTION 109 * Answer requests for SCSI calls 110 * 111 * RUN LEVEL 112 * PASSIVE_LEVEL 113 * 114 * ARGUMENTS 115 * Standard dispatch arguments 116 * 117 * RETURNS 118 * NTSTATUS 119 */ 120 121 NTSTATUS 122 NTAPI 123 ScsiPortDispatchScsi( 124 _In_ PDEVICE_OBJECT DeviceObject, 125 _Inout_ PIRP Irp) 126 { 127 PSCSI_PORT_DEVICE_EXTENSION portExt; 128 PSCSI_PORT_LUN_EXTENSION lunExt; 129 PIO_STACK_LOCATION Stack; 130 PSCSI_REQUEST_BLOCK Srb; 131 KIRQL Irql; 132 NTSTATUS Status = STATUS_SUCCESS; 133 PIRP NextIrp, IrpList; 134 PKDEVICE_QUEUE_ENTRY Entry; 135 136 DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n", DeviceObject, Irp); 137 138 Stack = IoGetCurrentIrpStackLocation(Irp); 139 Srb = Stack->Parameters.Scsi.Srb; 140 lunExt = DeviceObject->DeviceExtension; 141 ASSERT(!lunExt->Common.IsFDO); 142 portExt = lunExt->Common.LowerDevice->DeviceExtension; 143 144 if (Srb == NULL) 145 { 146 DPRINT1("ScsiPortDispatchScsi() called with Srb = NULL!\n"); 147 Status = STATUS_UNSUCCESSFUL; 148 149 Irp->IoStatus.Status = Status; 150 Irp->IoStatus.Information = 0; 151 152 IoCompleteRequest(Irp, IO_NO_INCREMENT); 153 154 return Status; 155 } 156 157 DPRINT("Srb: %p, Srb->Function: %lu\n", Srb, Srb->Function); 158 159 Srb->PathId = lunExt->PathId; 160 Srb->TargetId = lunExt->TargetId; 161 Srb->Lun = lunExt->Lun; 162 163 if (lunExt == NULL) 164 { 165 DPRINT("ScsiPortDispatchScsi() called with an invalid LUN\n"); 166 Status = STATUS_NO_SUCH_DEVICE; 167 168 Srb->SrbStatus = SRB_STATUS_NO_DEVICE; 169 Irp->IoStatus.Status = Status; 170 Irp->IoStatus.Information = 0; 171 172 IoCompleteRequest(Irp, IO_NO_INCREMENT); 173 174 return Status; 175 } 176 177 switch (Srb->Function) 178 { 179 case SRB_FUNCTION_SHUTDOWN: 180 case SRB_FUNCTION_FLUSH: 181 DPRINT(" SRB_FUNCTION_SHUTDOWN or FLUSH\n"); 182 if (portExt->CachesData == FALSE) 183 { 184 /* All success here */ 185 Srb->SrbStatus = SRB_STATUS_SUCCESS; 186 Irp->IoStatus.Status = STATUS_SUCCESS; 187 IoCompleteRequest(Irp, IO_NO_INCREMENT); 188 return STATUS_SUCCESS; 189 } 190 /* Fall through to a usual execute operation */ 191 192 case SRB_FUNCTION_EXECUTE_SCSI: 193 case SRB_FUNCTION_IO_CONTROL: 194 DPRINT(" SRB_FUNCTION_EXECUTE_SCSI or SRB_FUNCTION_IO_CONTROL\n"); 195 /* Mark IRP as pending in all cases */ 196 IoMarkIrpPending(Irp); 197 198 if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE) 199 { 200 /* Start IO directly */ 201 IoStartPacket(portExt->Common.DeviceObject, Irp, NULL, NULL); 202 } 203 else 204 { 205 KIRQL oldIrql; 206 207 /* We need to be at DISPATCH_LEVEL */ 208 KeRaiseIrql(DISPATCH_LEVEL, &oldIrql); 209 210 /* Insert IRP into the queue */ 211 if (!KeInsertByKeyDeviceQueue(&lunExt->DeviceQueue, 212 &Irp->Tail.Overlay.DeviceQueueEntry, 213 Srb->QueueSortKey)) 214 { 215 /* It means the queue is empty, and we just start this request */ 216 IoStartPacket(portExt->Common.DeviceObject, Irp, NULL, NULL); 217 } 218 219 /* Back to the old IRQL */ 220 KeLowerIrql(oldIrql); 221 } 222 return STATUS_PENDING; 223 224 case SRB_FUNCTION_CLAIM_DEVICE: 225 case SRB_FUNCTION_ATTACH_DEVICE: 226 DPRINT(" SRB_FUNCTION_CLAIM_DEVICE or ATTACH\n"); 227 228 /* Reference device object and keep the device object */ 229 Status = SpiHandleAttachRelease(lunExt, Irp); 230 break; 231 232 case SRB_FUNCTION_RELEASE_DEVICE: 233 DPRINT(" SRB_FUNCTION_RELEASE_DEVICE\n"); 234 235 /* Dereference device object and clear the device object */ 236 Status = SpiHandleAttachRelease(lunExt, Irp); 237 break; 238 239 case SRB_FUNCTION_RELEASE_QUEUE: 240 DPRINT(" SRB_FUNCTION_RELEASE_QUEUE\n"); 241 242 /* Guard with the spinlock */ 243 KeAcquireSpinLock(&portExt->SpinLock, &Irql); 244 245 if (!(lunExt->Flags & LUNEX_FROZEN_QUEUE)) 246 { 247 DPRINT("Queue is not frozen really\n"); 248 249 KeReleaseSpinLock(&portExt->SpinLock, Irql); 250 Srb->SrbStatus = SRB_STATUS_SUCCESS; 251 Status = STATUS_SUCCESS; 252 break; 253 254 } 255 256 /* Unfreeze the queue */ 257 lunExt->Flags &= ~LUNEX_FROZEN_QUEUE; 258 259 if (lunExt->SrbInfo.Srb == NULL) 260 { 261 /* Get next logical unit request. SpiGetNextRequestFromLun releases the lock. */ 262 SpiGetNextRequestFromLun(portExt, lunExt, &Irql); 263 } 264 else 265 { 266 DPRINT("The queue has active request\n"); 267 KeReleaseSpinLock(&portExt->SpinLock, Irql); 268 } 269 270 Srb->SrbStatus = SRB_STATUS_SUCCESS; 271 Status = STATUS_SUCCESS; 272 break; 273 274 case SRB_FUNCTION_FLUSH_QUEUE: 275 DPRINT(" SRB_FUNCTION_FLUSH_QUEUE\n"); 276 277 /* Guard with the spinlock */ 278 KeAcquireSpinLock(&portExt->SpinLock, &Irql); 279 280 if (!(lunExt->Flags & LUNEX_FROZEN_QUEUE)) 281 { 282 DPRINT("Queue is not frozen really\n"); 283 284 KeReleaseSpinLock(&portExt->SpinLock, Irql); 285 Status = STATUS_INVALID_DEVICE_REQUEST; 286 break; 287 } 288 289 /* Make sure there is no active request */ 290 ASSERT(lunExt->SrbInfo.Srb == NULL); 291 292 /* Compile a list from the device queue */ 293 IrpList = NULL; 294 while ((Entry = KeRemoveDeviceQueue(&lunExt->DeviceQueue)) != NULL) 295 { 296 NextIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry); 297 298 /* Get the Srb */ 299 Stack = IoGetCurrentIrpStackLocation(NextIrp); 300 Srb = Stack->Parameters.Scsi.Srb; 301 302 /* Set statuse */ 303 Srb->SrbStatus = SRB_STATUS_REQUEST_FLUSHED; 304 NextIrp->IoStatus.Status = STATUS_UNSUCCESSFUL; 305 306 /* Add then to the list */ 307 NextIrp->Tail.Overlay.ListEntry.Flink = (PLIST_ENTRY)IrpList; 308 IrpList = NextIrp; 309 } 310 311 /* Unfreeze the queue */ 312 lunExt->Flags &= ~LUNEX_FROZEN_QUEUE; 313 314 /* Release the spinlock */ 315 KeReleaseSpinLock(&portExt->SpinLock, Irql); 316 317 /* Complete those requests */ 318 while (IrpList) 319 { 320 NextIrp = IrpList; 321 IrpList = (PIRP)NextIrp->Tail.Overlay.ListEntry.Flink; 322 323 IoCompleteRequest(NextIrp, 0); 324 } 325 326 Status = STATUS_SUCCESS; 327 break; 328 329 default: 330 DPRINT1("SRB function not implemented (Function %lu)\n", Srb->Function); 331 Status = STATUS_NOT_IMPLEMENTED; 332 break; 333 } 334 335 Irp->IoStatus.Status = Status; 336 IoCompleteRequest(Irp, IO_NO_INCREMENT); 337 338 return Status; 339 } 340 341 VOID 342 SpiGetNextRequestFromLun( 343 _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 344 _Inout_ PSCSI_PORT_LUN_EXTENSION LunExtension, 345 _Inout_opt_ PKIRQL OldIrql 346 ) 347 { 348 PIO_STACK_LOCATION IrpStack; 349 PIRP NextIrp; 350 PKDEVICE_QUEUE_ENTRY Entry; 351 PSCSI_REQUEST_BLOCK Srb; 352 353 354 /* If LUN is not active or queue is more than maximum allowed */ 355 if (LunExtension->QueueCount >= LunExtension->MaxQueueCount || 356 !(LunExtension->Flags & SCSI_PORT_LU_ACTIVE)) 357 { 358 /* Release the spinlock and exit */ 359 if (OldIrql != NULL) 360 KeReleaseSpinLock(&DeviceExtension->SpinLock, *OldIrql); 361 else 362 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 363 return; 364 } 365 366 /* Check if we can get a next request */ 367 if (LunExtension->Flags & 368 (LUNEX_NEED_REQUEST_SENSE | LUNEX_BUSY | 369 LUNEX_FULL_QUEUE | LUNEX_FROZEN_QUEUE | LUNEX_REQUEST_PENDING)) 370 { 371 /* Pending requests can only be started if the queue is empty */ 372 if (IsListEmpty(&LunExtension->SrbInfo.Requests) && 373 !(LunExtension->Flags & 374 (LUNEX_BUSY | LUNEX_FROZEN_QUEUE | LUNEX_FULL_QUEUE | LUNEX_NEED_REQUEST_SENSE))) 375 { 376 /* Make sure we have SRB */ 377 ASSERT(LunExtension->SrbInfo.Srb == NULL); 378 379 /* Clear active and pending flags */ 380 LunExtension->Flags &= ~(LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE); 381 382 /* Get next Irp, and clear pending requests list */ 383 NextIrp = LunExtension->PendingRequest; 384 LunExtension->PendingRequest = NULL; 385 386 /* Set attempt counter to zero */ 387 LunExtension->AttemptCount = 0; 388 389 /* Release the spinlock */ 390 if (OldIrql != NULL) 391 KeReleaseSpinLock(&DeviceExtension->SpinLock, *OldIrql); 392 else 393 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 394 395 /* Start the next pending request */ 396 IoStartPacket(DeviceExtension->Common.DeviceObject, NextIrp, (PULONG)NULL, NULL); 397 398 return; 399 } 400 else 401 { 402 /* Release the spinlock, without clearing any flags and exit */ 403 if (OldIrql != NULL) 404 KeReleaseSpinLock(&DeviceExtension->SpinLock, *OldIrql); 405 else 406 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 407 408 return; 409 } 410 } 411 412 /* Reset active flag */ 413 LunExtension->Flags &= ~SCSI_PORT_LU_ACTIVE; 414 415 /* Set attempt counter to zero */ 416 LunExtension->AttemptCount = 0; 417 418 /* Remove packet from the device queue */ 419 Entry = KeRemoveByKeyDeviceQueue(&LunExtension->DeviceQueue, LunExtension->SortKey); 420 421 if (Entry != NULL) 422 { 423 /* Get pointer to the next irp */ 424 NextIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry); 425 426 /* Get point to the SRB */ 427 IrpStack = IoGetCurrentIrpStackLocation(NextIrp); 428 Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1; 429 430 /* Set new key*/ 431 LunExtension->SortKey = Srb->QueueSortKey; 432 LunExtension->SortKey++; 433 434 /* Release the spinlock */ 435 if (OldIrql != NULL) 436 KeReleaseSpinLock(&DeviceExtension->SpinLock, *OldIrql); 437 else 438 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 439 440 /* Start the next pending request */ 441 IoStartPacket(DeviceExtension->Common.DeviceObject, NextIrp, (PULONG)NULL, NULL); 442 } 443 else 444 { 445 /* Release the spinlock */ 446 if (OldIrql != NULL) 447 KeReleaseSpinLock(&DeviceExtension->SpinLock, *OldIrql); 448 else 449 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 450 } 451 } 452 453 IO_COMPLETION_ROUTINE SpiSenseCompletionRoutine; 454 455 NTSTATUS 456 NTAPI 457 SpiSenseCompletionRoutine( 458 _In_ PDEVICE_OBJECT DeviceObject, 459 _In_ PIRP Irp, 460 _In_opt_ PVOID Context) 461 { 462 PIO_STACK_LOCATION ioStack = IoGetNextIrpStackLocation(Irp); 463 PSCSI_PORT_LUN_EXTENSION lunExt = ioStack->DeviceObject->DeviceExtension; 464 PSCSI_PORT_DEVICE_EXTENSION portExt = lunExt->Common.LowerDevice->DeviceExtension; 465 PSCSI_REQUEST_BLOCK Srb = (PSCSI_REQUEST_BLOCK)Context; 466 PSCSI_REQUEST_BLOCK InitialSrb; 467 PIRP InitialIrp; 468 469 DPRINT("SpiCompletionRoutine() entered, IRP %p \n", Irp); 470 471 if ((Srb->Function == SRB_FUNCTION_RESET_BUS) || 472 (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)) 473 { 474 /* Deallocate SRB and IRP and exit */ 475 ExFreePool(Srb); 476 IoFreeIrp(Irp); 477 478 return STATUS_MORE_PROCESSING_REQUIRED; 479 } 480 481 /* Get a pointer to the SRB and IRP which were initially sent */ 482 InitialSrb = *((PVOID *)(Srb+1)); 483 InitialIrp = InitialSrb->OriginalRequest; 484 485 if ((SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS) || 486 (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN)) 487 { 488 /* Sense data is OK */ 489 InitialSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID; 490 491 /* Set length to be the same */ 492 InitialSrb->SenseInfoBufferLength = (UCHAR)Srb->DataTransferLength; 493 } 494 495 /* Make sure initial SRB's queue is frozen */ 496 ASSERT(InitialSrb->SrbStatus & SRB_STATUS_QUEUE_FROZEN); 497 498 // The queue is frozen, but the SRB had a SRB_FLAGS_NO_QUEUE_FREEZE => unfreeze the queue 499 if ((InitialSrb->SrbFlags & SRB_FLAGS_NO_QUEUE_FREEZE) && 500 (InitialSrb->SrbStatus & SRB_STATUS_QUEUE_FROZEN)) 501 { 502 KIRQL irql; 503 504 KeAcquireSpinLock(&portExt->SpinLock, &irql); 505 506 ASSERT(lunExt->Flags & LUNEX_FROZEN_QUEUE); 507 508 lunExt->Flags &= ~LUNEX_FROZEN_QUEUE; 509 lunExt->Flags &= ~LUNEX_NEED_REQUEST_SENSE; 510 511 // SpiGetNextRequestFromLun releases the lock 512 SpiGetNextRequestFromLun(portExt, lunExt, &irql); 513 514 InitialSrb->SrbStatus &= ~SRB_STATUS_QUEUE_FROZEN; 515 } 516 517 /* Complete this request */ 518 IoCompleteRequest(InitialIrp, IO_DISK_INCREMENT); 519 520 /* Deallocate everything (internal) */ 521 ExFreePool(Srb); 522 523 if (Irp->MdlAddress != NULL) 524 { 525 MmUnlockPages(Irp->MdlAddress); 526 IoFreeMdl(Irp->MdlAddress); 527 Irp->MdlAddress = NULL; 528 } 529 530 IoFreeIrp(Irp); 531 return STATUS_MORE_PROCESSING_REQUIRED; 532 } 533 534 static 535 VOID 536 SpiSendRequestSense( 537 _In_ PSCSI_PORT_LUN_EXTENSION LunExtension, 538 _In_ PSCSI_REQUEST_BLOCK InitialSrb) 539 { 540 PSCSI_REQUEST_BLOCK Srb; 541 PCDB Cdb; 542 PIRP Irp; 543 PIO_STACK_LOCATION IrpStack; 544 LARGE_INTEGER LargeInt; 545 PVOID *Ptr; 546 547 DPRINT("SpiSendRequestSense() entered, InitialSrb %p\n", InitialSrb); 548 549 /* Allocate Srb */ 550 Srb = ExAllocatePoolWithTag(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK) + sizeof(PVOID), TAG_SCSIPORT); 551 RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK)); 552 553 /* Allocate IRP */ 554 LargeInt.QuadPart = (LONGLONG) 1; 555 Irp = IoBuildAsynchronousFsdRequest(IRP_MJ_READ, 556 LunExtension->Common.DeviceObject, 557 InitialSrb->SenseInfoBuffer, 558 InitialSrb->SenseInfoBufferLength, 559 &LargeInt, 560 NULL); 561 562 IoSetCompletionRoutine(Irp, 563 SpiSenseCompletionRoutine, 564 Srb, 565 TRUE, 566 TRUE, 567 TRUE); 568 569 if (!Srb) 570 { 571 DPRINT("SpiSendRequestSense() failed, Srb %p\n", Srb); 572 return; 573 } 574 575 IrpStack = IoGetNextIrpStackLocation(Irp); 576 IrpStack->MajorFunction = IRP_MJ_SCSI; 577 578 /* Put Srb address into Irp... */ 579 IrpStack->Parameters.Others.Argument1 = (PVOID)Srb; 580 581 /* ...and vice versa */ 582 Srb->OriginalRequest = Irp; 583 584 /* Save Srb */ 585 Ptr = (PVOID *)(Srb+1); 586 *Ptr = InitialSrb; 587 588 /* Build CDB for REQUEST SENSE */ 589 Srb->CdbLength = 6; 590 Cdb = (PCDB)Srb->Cdb; 591 592 Cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE; 593 Cdb->CDB6INQUIRY.LogicalUnitNumber = 0; 594 Cdb->CDB6INQUIRY.Reserved1 = 0; 595 Cdb->CDB6INQUIRY.PageCode = 0; 596 Cdb->CDB6INQUIRY.IReserved = 0; 597 Cdb->CDB6INQUIRY.AllocationLength = (UCHAR)InitialSrb->SenseInfoBufferLength; 598 Cdb->CDB6INQUIRY.Control = 0; 599 600 /* Set address */ 601 Srb->TargetId = InitialSrb->TargetId; 602 Srb->Lun = InitialSrb->Lun; 603 Srb->PathId = InitialSrb->PathId; 604 605 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 606 Srb->Length = sizeof(SCSI_REQUEST_BLOCK); 607 608 /* Timeout will be 2 seconds */ 609 Srb->TimeOutValue = 2; 610 611 /* No auto request sense */ 612 Srb->SenseInfoBufferLength = 0; 613 Srb->SenseInfoBuffer = NULL; 614 615 /* Set necessary flags */ 616 Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_BYPASS_FROZEN_QUEUE | 617 SRB_FLAGS_DISABLE_DISCONNECT; 618 619 // pass some InitialSrb flags 620 if (InitialSrb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER) 621 Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER; 622 623 if (InitialSrb->SrbFlags & SRB_FLAGS_BYPASS_LOCKED_QUEUE) 624 Srb->SrbFlags |= SRB_FLAGS_BYPASS_LOCKED_QUEUE; 625 626 if (InitialSrb->SrbFlags & SRB_FLAGS_NO_QUEUE_FREEZE) 627 Srb->SrbFlags |= SRB_FLAGS_NO_QUEUE_FREEZE; 628 629 Srb->DataBuffer = InitialSrb->SenseInfoBuffer; 630 631 /* Fill the transfer length */ 632 Srb->DataTransferLength = InitialSrb->SenseInfoBufferLength; 633 634 /* Clear statuses */ 635 Srb->ScsiStatus = Srb->SrbStatus = 0; 636 Srb->NextSrb = 0; 637 638 /* Call the driver */ 639 (VOID)IoCallDriver(LunExtension->Common.DeviceObject, Irp); 640 641 DPRINT("SpiSendRequestSense() done\n"); 642 } 643 644 645 static 646 VOID 647 SpiProcessCompletedRequest( 648 _In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 649 _Inout_ PSCSI_REQUEST_BLOCK_INFO SrbInfo, 650 _Out_ PBOOLEAN NeedToCallStartIo) 651 { 652 PSCSI_REQUEST_BLOCK Srb; 653 PSCSI_PORT_LUN_EXTENSION LunExtension; 654 LONG Result; 655 PIRP Irp; 656 657 Srb = SrbInfo->Srb; 658 Irp = Srb->OriginalRequest; 659 PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp); 660 661 /* Get Lun extension */ 662 LunExtension = IoStack->DeviceObject->DeviceExtension; 663 ASSERT(LunExtension && !LunExtension->Common.IsFDO); 664 665 if (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION && 666 DeviceExtension->MapBuffers && 667 Irp->MdlAddress) 668 { 669 /* MDL is shared if transfer is broken into smaller parts */ 670 Srb->DataBuffer = (PCCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress) + 671 ((PCCHAR)Srb->DataBuffer - SrbInfo->DataOffset); 672 673 /* In case of data going in, flush the buffers */ 674 if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) 675 { 676 KeFlushIoBuffers(Irp->MdlAddress, 677 TRUE, 678 FALSE); 679 } 680 } 681 682 /* Flush adapter if needed */ 683 if (SrbInfo->BaseOfMapRegister && SrbInfo->ScatterGather) 684 { 685 ULONG transferLen = 0; 686 BOOLEAN isWrite = !!(Srb->SrbFlags & SRB_FLAGS_DATA_OUT); 687 ULONG i; 688 689 for (i = 0; 690 i < SrbInfo->NumberOfMapRegisters && transferLen < Srb->DataTransferLength; 691 i++) 692 { 693 transferLen += SrbInfo->ScatterGather[i].Length; 694 } 695 696 IoFlushAdapterBuffers(DeviceExtension->AdapterObject, 697 Irp->MdlAddress, 698 SrbInfo->BaseOfMapRegister, 699 Srb->DataBuffer, 700 transferLen, 701 isWrite); 702 } 703 704 /* Clear the request */ 705 SrbInfo->Srb = NULL; 706 707 /* If disconnect is disabled... */ 708 if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT) 709 { 710 /* Acquire the spinlock since we mess with flags */ 711 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock); 712 713 /* Set corresponding flag */ 714 DeviceExtension->Flags |= SCSI_PORT_DISCONNECT_ALLOWED; 715 716 /* Clear the timer if needed */ 717 if (!(DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET)) 718 DeviceExtension->TimerCount = -1; 719 720 /* Spinlock is not needed anymore */ 721 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 722 723 if (!(DeviceExtension->Flags & SCSI_PORT_REQUEST_PENDING) && 724 !(DeviceExtension->Flags & SCSI_PORT_DEVICE_BUSY) && 725 !(*NeedToCallStartIo)) 726 { 727 /* We're not busy, but we have a request pending */ 728 IoStartNextPacket(DeviceExtension->Common.DeviceObject, FALSE); 729 } 730 } 731 732 /* Scatter/gather */ 733 if (Srb->SrbFlags & SRB_FLAGS_SGLIST_FROM_POOL) 734 { 735 ExFreePoolWithTag(SrbInfo->ScatterGather, TAG_SCSIPORT); 736 SrbInfo->ScatterGather = NULL; 737 } 738 739 /* Free Map Registers */ 740 if (SrbInfo->NumberOfMapRegisters) 741 { 742 IoFreeMapRegisters(DeviceExtension->AdapterObject, 743 SrbInfo->BaseOfMapRegister, 744 SrbInfo->NumberOfMapRegisters); 745 } 746 747 /* Acquire spinlock (we're freeing SrbExtension) */ 748 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock); 749 750 /* Free it (if needed) */ 751 if (Srb->SrbExtension) 752 { 753 if (Srb->SenseInfoBuffer != NULL && DeviceExtension->SupportsAutoSense) 754 { 755 ASSERT(Srb->SenseInfoBuffer == NULL || SrbInfo->SaveSenseRequest != NULL); 756 757 if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) 758 { 759 /* Copy sense data to the buffer */ 760 RtlCopyMemory(SrbInfo->SaveSenseRequest, 761 Srb->SenseInfoBuffer, 762 Srb->SenseInfoBufferLength); 763 } 764 765 /* And restore the pointer */ 766 Srb->SenseInfoBuffer = SrbInfo->SaveSenseRequest; 767 } 768 769 /* Put it into the free srb extensions list */ 770 *((PVOID *)Srb->SrbExtension) = DeviceExtension->FreeSrbExtensions; 771 DeviceExtension->FreeSrbExtensions = Srb->SrbExtension; 772 } 773 774 /* Save transfer length in the IRP */ 775 Irp->IoStatus.Information = Srb->DataTransferLength; 776 777 //SequenceNumber = SrbInfo->SequenceNumber; 778 SrbInfo->SequenceNumber = 0; 779 780 /* Decrement the queue count */ 781 LunExtension->QueueCount--; 782 783 /* Free Srb, if needed*/ 784 if (Srb->QueueTag != SP_UNTAGGED) 785 { 786 /* Put it into the free list */ 787 SrbInfo->Requests.Blink = NULL; 788 SrbInfo->Requests.Flink = (PLIST_ENTRY)DeviceExtension->FreeSrbInfo; 789 DeviceExtension->FreeSrbInfo = SrbInfo; 790 } 791 792 /* SrbInfo is not used anymore */ 793 SrbInfo = NULL; 794 795 if (DeviceExtension->Flags & SCSI_PORT_REQUEST_PENDING) 796 { 797 /* Clear the flag */ 798 DeviceExtension->Flags &= ~SCSI_PORT_REQUEST_PENDING; 799 800 /* Note the caller about StartIo */ 801 *NeedToCallStartIo = TRUE; 802 } 803 804 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS) 805 { 806 /* Start the packet */ 807 Irp->IoStatus.Status = STATUS_SUCCESS; 808 809 if (!(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE) && 810 LunExtension->RequestTimeout == -1) 811 { 812 /* Start the next packet. SpiGetNextRequestFromLun will release the lock for us */ 813 SpiGetNextRequestFromLun(DeviceExtension, LunExtension, NULL); 814 } 815 else 816 { 817 /* Release the spinlock */ 818 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 819 } 820 821 DPRINT("IoCompleting request IRP 0x%p\n", Irp); 822 823 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 824 825 /* Decrement number of active requests, and analyze the result */ 826 Result = InterlockedDecrement(&DeviceExtension->ActiveRequestCounter); 827 828 if (Result < 0 && 829 !DeviceExtension->MapRegisters && 830 DeviceExtension->AdapterObject != NULL) 831 { 832 /* Nullify map registers */ 833 DeviceExtension->MapRegisterBase = NULL; 834 IoFreeAdapterChannel(DeviceExtension->AdapterObject); 835 } 836 837 /* Exit, we're done */ 838 return; 839 } 840 841 /* Decrement number of active requests, and analyze the result */ 842 Result = InterlockedDecrement(&DeviceExtension->ActiveRequestCounter); 843 844 if (Result < 0 && 845 !DeviceExtension->MapRegisters && 846 DeviceExtension->AdapterObject != NULL) 847 { 848 /* Result is negative, so this is a slave, free map registers */ 849 DeviceExtension->MapRegisterBase = NULL; 850 IoFreeAdapterChannel(DeviceExtension->AdapterObject); 851 } 852 853 /* Convert status */ 854 Irp->IoStatus.Status = SpiStatusSrbToNt(Srb->SrbStatus); 855 856 /* It's not a bypass, it's busy or the queue is full? */ 857 if ((Srb->ScsiStatus == SCSISTAT_BUSY || 858 Srb->SrbStatus == SRB_STATUS_BUSY || 859 Srb->ScsiStatus == SCSISTAT_QUEUE_FULL) && 860 !(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)) 861 { 862 863 DPRINT("Busy SRB status %x\n", Srb->SrbStatus); 864 865 /* Requeue, if needed */ 866 if (LunExtension->Flags & (LUNEX_FROZEN_QUEUE | LUNEX_BUSY)) 867 { 868 DPRINT("it's being requeued\n"); 869 870 Srb->SrbStatus = SRB_STATUS_PENDING; 871 Srb->ScsiStatus = 0; 872 873 if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue, 874 &Irp->Tail.Overlay.DeviceQueueEntry, 875 Srb->QueueSortKey)) 876 { 877 /* It's a big f.ck up if we got here */ 878 Srb->SrbStatus = SRB_STATUS_ERROR; 879 Srb->ScsiStatus = SCSISTAT_BUSY; 880 881 ASSERT(FALSE); 882 goto Error; 883 } 884 885 /* Release the spinlock */ 886 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 887 888 } 889 else if (LunExtension->AttemptCount++ < 20) 890 { 891 /* LUN is still busy */ 892 Srb->ScsiStatus = 0; 893 Srb->SrbStatus = SRB_STATUS_PENDING; 894 895 LunExtension->BusyRequest = Irp; 896 LunExtension->Flags |= LUNEX_BUSY; 897 898 /* Release the spinlock */ 899 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 900 } 901 else 902 { 903 Error: 904 /* Freeze the queue*/ 905 Srb->SrbStatus |= SRB_STATUS_QUEUE_FROZEN; 906 LunExtension->Flags |= LUNEX_FROZEN_QUEUE; 907 908 /* "Unfull" the queue */ 909 LunExtension->Flags &= ~LUNEX_FULL_QUEUE; 910 911 /* Release the spinlock */ 912 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 913 914 /* Return status that the device is not ready */ 915 Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY; 916 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 917 } 918 919 return; 920 } 921 922 /* Start the next request, if LUN is idle, and this is sense request */ 923 if (((Srb->ScsiStatus != SCSISTAT_CHECK_CONDITION) || 924 (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) || 925 !Srb->SenseInfoBuffer || !Srb->SenseInfoBufferLength) 926 && (Srb->SrbFlags & SRB_FLAGS_NO_QUEUE_FREEZE)) 927 { 928 if (LunExtension->RequestTimeout == -1) 929 SpiGetNextRequestFromLun(DeviceExtension, LunExtension, NULL); 930 else 931 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 932 } 933 else 934 { 935 /* Freeze the queue */ 936 Srb->SrbStatus |= SRB_STATUS_QUEUE_FROZEN; 937 LunExtension->Flags |= LUNEX_FROZEN_QUEUE; 938 939 /* Do we need a request sense? */ 940 if (Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION && 941 !(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) && 942 Srb->SenseInfoBuffer && Srb->SenseInfoBufferLength) 943 { 944 /* If LUN is busy, we have to requeue it in order to allow request sense */ 945 if (LunExtension->Flags & LUNEX_BUSY) 946 { 947 DPRINT("Requeuing busy request to allow request sense\n"); 948 949 if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue, 950 &LunExtension->BusyRequest->Tail.Overlay.DeviceQueueEntry, 951 Srb->QueueSortKey)) 952 { 953 /* We should never get here */ 954 ASSERT(FALSE); 955 956 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 957 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 958 return; 959 960 } 961 962 /* Clear busy flags */ 963 LunExtension->Flags &= ~(LUNEX_FULL_QUEUE | LUNEX_BUSY); 964 } 965 966 /* Release the spinlock */ 967 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 968 969 /* Send RequestSense */ 970 SpiSendRequestSense(LunExtension, Srb); 971 972 /* Exit */ 973 return; 974 } 975 976 /* Release the spinlock */ 977 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 978 } 979 980 /* Complete the request */ 981 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 982 } 983 984 BOOLEAN 985 NTAPI 986 ScsiPortStartPacket( 987 _In_ PVOID Context) 988 { 989 PIO_STACK_LOCATION IrpStack; 990 PSCSI_REQUEST_BLOCK Srb; 991 PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)Context; 992 PSCSI_PORT_COMMON_EXTENSION CommonExtension = DeviceObject->DeviceExtension; 993 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 994 PSCSI_PORT_LUN_EXTENSION LunExtension; 995 PSCSI_REQUEST_BLOCK_INFO SrbInfo; 996 BOOLEAN Result; 997 BOOLEAN StartTimer; 998 999 DPRINT("ScsiPortStartPacket() called\n"); 1000 1001 IrpStack = IoGetCurrentIrpStackLocation(DeviceObject->CurrentIrp); 1002 Srb = IrpStack->Parameters.Scsi.Srb; 1003 1004 if (CommonExtension->IsFDO) // IsFDO 1005 { 1006 DeviceExtension = DeviceObject->DeviceExtension; 1007 LunExtension = IrpStack->DeviceObject->DeviceExtension; 1008 ASSERT(LunExtension && !LunExtension->Common.IsFDO); 1009 } 1010 else 1011 { 1012 LunExtension = DeviceObject->DeviceExtension; 1013 DeviceExtension = LunExtension->Common.LowerDevice->DeviceExtension; 1014 } 1015 1016 /* Check if we are in a reset state */ 1017 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET) 1018 { 1019 /* Mark the we've got requests while being in the reset state */ 1020 DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET_REQUEST; 1021 return TRUE; 1022 } 1023 1024 /* Set the time out value */ 1025 DeviceExtension->TimerCount = Srb->TimeOutValue; 1026 1027 /* We are busy */ 1028 DeviceExtension->Flags |= SCSI_PORT_DEVICE_BUSY; 1029 1030 if (LunExtension->RequestTimeout != -1) 1031 { 1032 /* Timer already active */ 1033 StartTimer = FALSE; 1034 } 1035 else 1036 { 1037 /* It hasn't been initialized yet */ 1038 LunExtension->RequestTimeout = Srb->TimeOutValue; 1039 StartTimer = TRUE; 1040 } 1041 1042 if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE) 1043 { 1044 /* Handle bypass-requests */ 1045 1046 /* Is this an abort request? */ 1047 if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND) 1048 { 1049 /* Get pointer to SRB info structure */ 1050 SrbInfo = SpiGetSrbData(DeviceExtension, LunExtension, Srb->QueueTag); 1051 1052 /* Check if the request is still "active" */ 1053 if (SrbInfo == NULL || 1054 SrbInfo->Srb == NULL || 1055 !(SrbInfo->Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE)) 1056 { 1057 /* It's not, mark it as active then */ 1058 Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE; 1059 1060 if (StartTimer) 1061 LunExtension->RequestTimeout = -1; 1062 1063 DPRINT("Request has been already completed, but abort request came\n"); 1064 Srb->SrbStatus = SRB_STATUS_ABORT_FAILED; 1065 1066 /* Notify about request complete */ 1067 ScsiPortNotification(RequestComplete, 1068 DeviceExtension->MiniPortDeviceExtension, 1069 Srb); 1070 1071 /* and about readiness for the next request */ 1072 ScsiPortNotification(NextRequest, 1073 DeviceExtension->MiniPortDeviceExtension); 1074 1075 /* They might ask for some work, so queue the DPC for them */ 1076 IoRequestDpc(DeviceExtension->Common.DeviceObject, NULL, NULL); 1077 1078 /* We're done in this branch */ 1079 return TRUE; 1080 } 1081 } 1082 else 1083 { 1084 /* Add number of queued requests */ 1085 LunExtension->QueueCount++; 1086 } 1087 1088 /* Bypass requests don't need request sense */ 1089 LunExtension->Flags &= ~LUNEX_NEED_REQUEST_SENSE; 1090 1091 /* Is disconnect disabled for this request? */ 1092 if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT) 1093 { 1094 /* Set the corresponding flag */ 1095 DeviceExtension->Flags &= ~SCSI_PORT_DISCONNECT_ALLOWED; 1096 } 1097 1098 /* Transfer timeout value from Srb to Lun */ 1099 LunExtension->RequestTimeout = Srb->TimeOutValue; 1100 } 1101 else 1102 { 1103 if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT) 1104 { 1105 /* It's a disconnect, so no more requests can go */ 1106 DeviceExtension->Flags &= ~SCSI_PORT_DISCONNECT_ALLOWED; 1107 } 1108 1109 LunExtension->Flags |= SCSI_PORT_LU_ACTIVE; 1110 1111 /* Increment queue count */ 1112 LunExtension->QueueCount++; 1113 1114 /* If it's tagged - special thing */ 1115 if (Srb->QueueTag != SP_UNTAGGED) 1116 { 1117 SrbInfo = &DeviceExtension->SrbInfo[Srb->QueueTag - 1]; 1118 1119 /* Chek for consistency */ 1120 ASSERT(SrbInfo->Requests.Blink == NULL); 1121 1122 /* Insert it into the list of requests */ 1123 InsertTailList(&LunExtension->SrbInfo.Requests, &SrbInfo->Requests); 1124 } 1125 } 1126 1127 /* Mark this Srb active */ 1128 Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE; 1129 1130 /* Call HwStartIo routine */ 1131 Result = DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension, 1132 Srb); 1133 1134 /* If notification is needed, then request a DPC */ 1135 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED) 1136 IoRequestDpc(DeviceExtension->Common.DeviceObject, NULL, NULL); 1137 1138 return Result; 1139 } 1140 1141 BOOLEAN 1142 NTAPI 1143 SpiSaveInterruptData(IN PVOID Context) 1144 { 1145 PSCSI_PORT_SAVE_INTERRUPT InterruptContext = Context; 1146 PSCSI_PORT_LUN_EXTENSION LunExtension; 1147 PSCSI_REQUEST_BLOCK Srb; 1148 PSCSI_REQUEST_BLOCK_INFO SrbInfo, NextSrbInfo; 1149 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 1150 BOOLEAN IsTimed; 1151 1152 /* Get pointer to the device extension */ 1153 DeviceExtension = InterruptContext->DeviceExtension; 1154 1155 /* If we don't have anything pending - return */ 1156 if (!(DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)) 1157 return FALSE; 1158 1159 /* Actually save the interrupt data */ 1160 *InterruptContext->InterruptData = DeviceExtension->InterruptData; 1161 1162 /* Clear the data stored in the device extension */ 1163 DeviceExtension->InterruptData.Flags &= 1164 (SCSI_PORT_RESET | SCSI_PORT_RESET_REQUEST | SCSI_PORT_DISABLE_INTERRUPTS); 1165 DeviceExtension->InterruptData.CompletedAbort = NULL; 1166 DeviceExtension->InterruptData.ReadyLun = NULL; 1167 DeviceExtension->InterruptData.CompletedRequests = NULL; 1168 1169 /* Loop through the list of completed requests */ 1170 SrbInfo = InterruptContext->InterruptData->CompletedRequests; 1171 1172 while (SrbInfo) 1173 { 1174 /* Make sure we have SRV */ 1175 ASSERT(SrbInfo->Srb); 1176 1177 /* Get SRB and LunExtension */ 1178 Srb = SrbInfo->Srb; 1179 1180 PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Srb->OriginalRequest); 1181 LunExtension = IoStack->DeviceObject->DeviceExtension; 1182 ASSERT(LunExtension && !LunExtension->Common.IsFDO); 1183 1184 /* We have to check special cases if request is unsuccessful*/ 1185 if (Srb->SrbStatus != SRB_STATUS_SUCCESS) 1186 { 1187 /* Check if we need request sense by a few conditions */ 1188 if (Srb->SenseInfoBuffer && Srb->SenseInfoBufferLength && 1189 Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION && 1190 !(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)) 1191 { 1192 if (LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE) 1193 { 1194 /* It means: we tried to send REQUEST SENSE, but failed */ 1195 1196 Srb->ScsiStatus = 0; 1197 Srb->SrbStatus = SRB_STATUS_REQUEST_SENSE_FAILED; 1198 } 1199 else 1200 { 1201 /* Set the corresponding flag, so that REQUEST SENSE 1202 will be sent */ 1203 LunExtension->Flags |= LUNEX_NEED_REQUEST_SENSE; 1204 } 1205 1206 } 1207 1208 /* Check for a full queue */ 1209 if (Srb->ScsiStatus == SCSISTAT_QUEUE_FULL) 1210 { 1211 /* TODO: Implement when it's encountered */ 1212 ASSERT(FALSE); 1213 } 1214 } 1215 1216 /* Let's decide if we need to watch timeout or not */ 1217 if (Srb->QueueTag == SP_UNTAGGED) 1218 { 1219 IsTimed = TRUE; 1220 } 1221 else 1222 { 1223 if (LunExtension->SrbInfo.Requests.Flink == &SrbInfo->Requests) 1224 IsTimed = TRUE; 1225 else 1226 IsTimed = FALSE; 1227 1228 /* Remove it from the queue */ 1229 RemoveEntryList(&SrbInfo->Requests); 1230 } 1231 1232 if (IsTimed) 1233 { 1234 /* We have to maintain timeout counter */ 1235 if (IsListEmpty(&LunExtension->SrbInfo.Requests)) 1236 { 1237 LunExtension->RequestTimeout = -1; 1238 } 1239 else 1240 { 1241 NextSrbInfo = CONTAINING_RECORD(LunExtension->SrbInfo.Requests.Flink, 1242 SCSI_REQUEST_BLOCK_INFO, 1243 Requests); 1244 1245 Srb = NextSrbInfo->Srb; 1246 1247 /* Update timeout counter */ 1248 LunExtension->RequestTimeout = Srb->TimeOutValue; 1249 } 1250 } 1251 1252 SrbInfo = SrbInfo->CompletedRequests; 1253 } 1254 1255 return TRUE; 1256 } 1257 1258 VOID 1259 NTAPI 1260 ScsiPortDpcForIsr( 1261 _In_ PKDPC Dpc, 1262 _In_ PDEVICE_OBJECT DpcDeviceObject, 1263 _Inout_ PIRP DpcIrp, 1264 _In_opt_ PVOID DpcContext) 1265 { 1266 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DpcDeviceObject->DeviceExtension; 1267 SCSI_PORT_INTERRUPT_DATA InterruptData; 1268 SCSI_PORT_SAVE_INTERRUPT Context; 1269 PSCSI_PORT_LUN_EXTENSION LunExtension; 1270 BOOLEAN NeedToStartIo; 1271 PSCSI_REQUEST_BLOCK_INFO SrbInfo; 1272 LARGE_INTEGER TimerValue; 1273 1274 DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n", 1275 Dpc, DpcDeviceObject, DpcIrp, DpcContext); 1276 1277 /* We need to acquire spinlock */ 1278 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock); 1279 1280 RtlZeroMemory(&InterruptData, sizeof(SCSI_PORT_INTERRUPT_DATA)); 1281 1282 TryAgain: 1283 1284 /* Interrupt structure must be snapshotted, and only then analyzed */ 1285 Context.InterruptData = &InterruptData; 1286 Context.DeviceExtension = DeviceExtension; 1287 1288 if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0], 1289 SpiSaveInterruptData, 1290 &Context)) 1291 { 1292 /* Nothing - just return (don't forget to release the spinlock */ 1293 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 1294 DPRINT("ScsiPortDpcForIsr() done\n"); 1295 return; 1296 } 1297 1298 /* If flush of adapters is needed - do it */ 1299 if (InterruptData.Flags & SCSI_PORT_FLUSH_ADAPTERS) 1300 { 1301 /* TODO: Implement */ 1302 ASSERT(FALSE); 1303 } 1304 1305 /* Check for IoMapTransfer */ 1306 if (InterruptData.Flags & SCSI_PORT_MAP_TRANSFER) 1307 { 1308 /* TODO: Implement */ 1309 ASSERT(FALSE); 1310 } 1311 1312 /* Check if timer is needed */ 1313 if (InterruptData.Flags & SCSI_PORT_TIMER_NEEDED) 1314 { 1315 /* Save the timer routine */ 1316 DeviceExtension->HwScsiTimer = InterruptData.HwScsiTimer; 1317 1318 if (InterruptData.MiniportTimerValue == 0) 1319 { 1320 /* Cancel the timer */ 1321 KeCancelTimer(&DeviceExtension->MiniportTimer); 1322 } 1323 else 1324 { 1325 /* Convert timer value */ 1326 TimerValue.QuadPart = Int32x32To64(InterruptData.MiniportTimerValue, -10); 1327 1328 /* Set the timer */ 1329 KeSetTimer(&DeviceExtension->MiniportTimer, 1330 TimerValue, 1331 &DeviceExtension->MiniportTimerDpc); 1332 } 1333 } 1334 1335 /* If it's ready for the next request */ 1336 if (InterruptData.Flags & SCSI_PORT_NEXT_REQUEST_READY) 1337 { 1338 /* Check for a duplicate request (NextRequest+NextLuRequest) */ 1339 if ((DeviceExtension->Flags & 1340 (SCSI_PORT_DEVICE_BUSY | SCSI_PORT_DISCONNECT_ALLOWED)) == 1341 (SCSI_PORT_DEVICE_BUSY | SCSI_PORT_DISCONNECT_ALLOWED)) 1342 { 1343 /* Clear busy flag set by ScsiPortStartPacket() */ 1344 DeviceExtension->Flags &= ~SCSI_PORT_DEVICE_BUSY; 1345 1346 if (!(InterruptData.Flags & SCSI_PORT_RESET)) 1347 { 1348 /* Ready for next, and no reset is happening */ 1349 DeviceExtension->TimerCount = -1; 1350 } 1351 } 1352 else 1353 { 1354 /* Not busy, but not ready for the next request */ 1355 DeviceExtension->Flags &= ~SCSI_PORT_DEVICE_BUSY; 1356 InterruptData.Flags &= ~SCSI_PORT_NEXT_REQUEST_READY; 1357 } 1358 } 1359 1360 /* Any resets? */ 1361 if (InterruptData.Flags & SCSI_PORT_RESET_REPORTED) 1362 { 1363 /* Hold for a bit */ 1364 DeviceExtension->TimerCount = 4; 1365 } 1366 1367 /* Any ready LUN? */ 1368 if (InterruptData.ReadyLun != NULL) 1369 { 1370 1371 /* Process all LUNs from the list*/ 1372 while (TRUE) 1373 { 1374 /* Remove it from the list first (as processed) */ 1375 LunExtension = InterruptData.ReadyLun; 1376 InterruptData.ReadyLun = LunExtension->ReadyLun; 1377 LunExtension->ReadyLun = NULL; 1378 1379 /* Get next request for this LUN */ 1380 SpiGetNextRequestFromLun(DeviceExtension, LunExtension, NULL); 1381 1382 /* Still ready requests exist? 1383 If yes - get spinlock, if no - stop here */ 1384 if (InterruptData.ReadyLun != NULL) 1385 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock); 1386 else 1387 break; 1388 } 1389 } 1390 else 1391 { 1392 /* Release the spinlock */ 1393 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 1394 } 1395 1396 /* If we ready for next packet, start it */ 1397 if (InterruptData.Flags & SCSI_PORT_NEXT_REQUEST_READY) 1398 IoStartNextPacket(DeviceExtension->Common.DeviceObject, FALSE); 1399 1400 NeedToStartIo = FALSE; 1401 1402 /* Loop the completed request list */ 1403 while (InterruptData.CompletedRequests) 1404 { 1405 /* Remove the request */ 1406 SrbInfo = InterruptData.CompletedRequests; 1407 InterruptData.CompletedRequests = SrbInfo->CompletedRequests; 1408 SrbInfo->CompletedRequests = NULL; 1409 1410 /* Process it */ 1411 SpiProcessCompletedRequest(DeviceExtension, 1412 SrbInfo, 1413 &NeedToStartIo); 1414 } 1415 1416 /* Loop abort request list */ 1417 while (InterruptData.CompletedAbort) 1418 { 1419 LunExtension = InterruptData.CompletedAbort; 1420 1421 /* Remove the request */ 1422 InterruptData.CompletedAbort = LunExtension->CompletedAbortRequests; 1423 1424 /* Get spinlock since we're going to change flags */ 1425 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock); 1426 1427 /* TODO: Put SrbExtension to the list of free extensions */ 1428 ASSERT(FALSE); 1429 } 1430 1431 /* If we need - call StartIo routine */ 1432 if (NeedToStartIo) 1433 { 1434 /* Make sure CurrentIrp is not null! */ 1435 ASSERT(DpcDeviceObject->CurrentIrp != NULL); 1436 ScsiPortStartIo(DpcDeviceObject, DpcDeviceObject->CurrentIrp); 1437 } 1438 1439 /* Everything has been done, check */ 1440 if (InterruptData.Flags & SCSI_PORT_ENABLE_INT_REQUEST) 1441 { 1442 /* Synchronize using spinlock */ 1443 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock); 1444 1445 /* Request an interrupt */ 1446 DeviceExtension->HwInterrupt(DeviceExtension->MiniPortDeviceExtension); 1447 1448 ASSERT(DeviceExtension->Flags & SCSI_PORT_DISABLE_INT_REQUESET); 1449 1450 /* Should interrupts be enabled again? */ 1451 if (DeviceExtension->Flags & SCSI_PORT_DISABLE_INT_REQUESET) 1452 { 1453 /* Clear this flag */ 1454 DeviceExtension->Flags &= ~SCSI_PORT_DISABLE_INT_REQUESET; 1455 1456 /* Call a special routine to do this */ 1457 ASSERT(FALSE); 1458 #if 0 1459 KeSynchronizeExecution(DeviceExtension->Interrupt, 1460 SpiEnableInterrupts, 1461 DeviceExtension); 1462 #endif 1463 } 1464 1465 /* If we need a notification again - loop */ 1466 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED) 1467 goto TryAgain; 1468 1469 /* Release the spinlock */ 1470 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 1471 } 1472 1473 DPRINT("ScsiPortDpcForIsr() done\n"); 1474 } 1475 1476 static 1477 PSCSI_REQUEST_BLOCK_INFO 1478 SpiAllocateSrbStructures( 1479 _Inout_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 1480 _Inout_ PSCSI_PORT_LUN_EXTENSION LunExtension, 1481 _Inout_ PSCSI_REQUEST_BLOCK Srb) 1482 { 1483 PCHAR SrbExtension; 1484 PSCSI_REQUEST_BLOCK_INFO SrbInfo; 1485 1486 /* Spinlock must be held while this function executes */ 1487 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock); 1488 1489 /* Allocate SRB data structure */ 1490 if (DeviceExtension->NeedSrbDataAlloc) 1491 { 1492 /* Treat the abort request in a special way */ 1493 if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND) 1494 { 1495 SrbInfo = SpiGetSrbData(DeviceExtension, LunExtension, Srb->QueueTag); 1496 } 1497 else if (Srb->SrbFlags & 1498 (SRB_FLAGS_QUEUE_ACTION_ENABLE | SRB_FLAGS_NO_QUEUE_FREEZE) && 1499 !(Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT) 1500 ) 1501 { 1502 /* Do not process tagged commands if need request sense is set */ 1503 if (LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE) 1504 { 1505 ASSERT(!(LunExtension->Flags & LUNEX_REQUEST_PENDING)); 1506 1507 LunExtension->PendingRequest = Srb->OriginalRequest; 1508 LunExtension->Flags |= LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE; 1509 1510 /* Release the spinlock and return */ 1511 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 1512 return NULL; 1513 } 1514 1515 ASSERT(LunExtension->SrbInfo.Srb == NULL); 1516 SrbInfo = DeviceExtension->FreeSrbInfo; 1517 1518 if (SrbInfo == NULL) 1519 { 1520 /* No SRB structures left in the list. We have to leave 1521 and wait while we are called again */ 1522 1523 DeviceExtension->Flags |= SCSI_PORT_REQUEST_PENDING; 1524 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 1525 return NULL; 1526 } 1527 1528 DeviceExtension->FreeSrbInfo = (PSCSI_REQUEST_BLOCK_INFO)SrbInfo->Requests.Flink; 1529 1530 /* QueueTag must never be 0, so +1 to it */ 1531 Srb->QueueTag = (UCHAR)(SrbInfo - DeviceExtension->SrbInfo) + 1; 1532 } 1533 else 1534 { 1535 /* Usual untagged command */ 1536 if ( 1537 (!IsListEmpty(&LunExtension->SrbInfo.Requests) || 1538 LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE) && 1539 !(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE) 1540 ) 1541 { 1542 /* Mark it as pending and leave */ 1543 ASSERT(!(LunExtension->Flags & LUNEX_REQUEST_PENDING)); 1544 LunExtension->Flags |= LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE; 1545 LunExtension->PendingRequest = Srb->OriginalRequest; 1546 1547 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 1548 return(NULL); 1549 } 1550 1551 Srb->QueueTag = SP_UNTAGGED; 1552 SrbInfo = &LunExtension->SrbInfo; 1553 } 1554 } 1555 else 1556 { 1557 Srb->QueueTag = SP_UNTAGGED; 1558 SrbInfo = &LunExtension->SrbInfo; 1559 } 1560 1561 /* Allocate SRB extension structure */ 1562 if (DeviceExtension->NeedSrbExtensionAlloc) 1563 { 1564 /* Check the list of free extensions */ 1565 SrbExtension = DeviceExtension->FreeSrbExtensions; 1566 1567 /* If no free extensions... */ 1568 if (SrbExtension == NULL) 1569 { 1570 /* Free SRB data */ 1571 if (Srb->Function != SRB_FUNCTION_ABORT_COMMAND && 1572 Srb->QueueTag != SP_UNTAGGED) 1573 { 1574 SrbInfo->Requests.Blink = NULL; 1575 SrbInfo->Requests.Flink = (PLIST_ENTRY)DeviceExtension->FreeSrbInfo; 1576 DeviceExtension->FreeSrbInfo = SrbInfo; 1577 } 1578 1579 /* Return, in order to be called again later */ 1580 DeviceExtension->Flags |= SCSI_PORT_REQUEST_PENDING; 1581 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 1582 return NULL; 1583 } 1584 1585 /* Remove that free SRB extension from the list (since 1586 we're going to use it) */ 1587 DeviceExtension->FreeSrbExtensions = *((PVOID *)SrbExtension); 1588 1589 /* Spinlock can be released now */ 1590 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 1591 1592 Srb->SrbExtension = SrbExtension; 1593 1594 if (Srb->SenseInfoBuffer != NULL && 1595 DeviceExtension->SupportsAutoSense) 1596 { 1597 /* Store pointer to the SenseInfo buffer */ 1598 SrbInfo->SaveSenseRequest = Srb->SenseInfoBuffer; 1599 1600 /* Does data fit the buffer? */ 1601 if (Srb->SenseInfoBufferLength > sizeof(SENSE_DATA)) 1602 { 1603 /* No, disabling autosense at all */ 1604 Srb->SrbFlags |= SRB_FLAGS_DISABLE_AUTOSENSE; 1605 } 1606 else 1607 { 1608 /* Yes, update the buffer pointer */ 1609 Srb->SenseInfoBuffer = SrbExtension + DeviceExtension->SrbExtensionSize; 1610 } 1611 } 1612 } 1613 else 1614 { 1615 /* Cleanup... */ 1616 Srb->SrbExtension = NULL; 1617 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 1618 } 1619 1620 return SrbInfo; 1621 } 1622 1623 VOID 1624 NTAPI 1625 ScsiPortStartIo( 1626 _Inout_ PDEVICE_OBJECT DeviceObject, 1627 _Inout_ PIRP Irp) 1628 { 1629 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 1630 PSCSI_PORT_LUN_EXTENSION LunExtension; 1631 PIO_STACK_LOCATION IrpStack; 1632 PSCSI_REQUEST_BLOCK Srb; 1633 PSCSI_REQUEST_BLOCK_INFO SrbInfo; 1634 LONG CounterResult; 1635 NTSTATUS Status; 1636 1637 DPRINT("ScsiPortStartIo() called!\n"); 1638 1639 DeviceExtension = DeviceObject->DeviceExtension; 1640 IrpStack = IoGetCurrentIrpStackLocation(Irp); 1641 LunExtension = IrpStack->DeviceObject->DeviceExtension; 1642 1643 ASSERT(DeviceExtension->Common.IsFDO); 1644 ASSERT(!LunExtension->Common.IsFDO); 1645 1646 DPRINT("LunExtension %p DeviceExtension %p\n", LunExtension, DeviceExtension); 1647 1648 Srb = IrpStack->Parameters.Scsi.Srb; 1649 1650 /* Apply "default" flags */ 1651 Srb->SrbFlags |= DeviceExtension->SrbFlags; 1652 1653 if (DeviceExtension->NeedSrbDataAlloc || 1654 DeviceExtension->NeedSrbExtensionAlloc) 1655 { 1656 /* Allocate them */ 1657 SrbInfo = SpiAllocateSrbStructures(DeviceExtension, 1658 LunExtension, 1659 Srb); 1660 1661 /* Couldn't alloc one or both data structures, return */ 1662 if (SrbInfo == NULL) 1663 { 1664 /* We have to call IoStartNextPacket, because this request 1665 was not started */ 1666 if (LunExtension->Flags & LUNEX_REQUEST_PENDING) 1667 IoStartNextPacket(DeviceObject, FALSE); 1668 1669 return; 1670 } 1671 } 1672 else 1673 { 1674 /* No allocations are needed */ 1675 SrbInfo = &LunExtension->SrbInfo; 1676 Srb->SrbExtension = NULL; 1677 Srb->QueueTag = SP_UNTAGGED; 1678 } 1679 1680 /* Increase sequence number of SRB */ 1681 if (!SrbInfo->SequenceNumber) 1682 { 1683 /* Increase global sequence number */ 1684 DeviceExtension->SequenceNumber++; 1685 1686 /* Assign it */ 1687 SrbInfo->SequenceNumber = DeviceExtension->SequenceNumber; 1688 } 1689 1690 /* Check some special SRBs */ 1691 if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND) 1692 { 1693 /* Some special handling */ 1694 DPRINT1("Abort command! Unimplemented now\n"); 1695 } 1696 else 1697 { 1698 SrbInfo->Srb = Srb; 1699 } 1700 1701 if (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION) 1702 { 1703 // Store the MDL virtual address in SrbInfo structure 1704 SrbInfo->DataOffset = MmGetMdlVirtualAddress(Irp->MdlAddress); 1705 1706 if (DeviceExtension->MapBuffers) 1707 { 1708 /* Calculate offset within DataBuffer */ 1709 SrbInfo->DataOffset = MmGetSystemAddressForMdl(Irp->MdlAddress); 1710 Srb->DataBuffer = SrbInfo->DataOffset + 1711 (ULONG)((PUCHAR)Srb->DataBuffer - 1712 (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress)); 1713 } 1714 1715 if (DeviceExtension->AdapterObject) 1716 { 1717 /* Flush buffers */ 1718 KeFlushIoBuffers(Irp->MdlAddress, 1719 Srb->SrbFlags & SRB_FLAGS_DATA_IN ? TRUE : FALSE, 1720 TRUE); 1721 } 1722 1723 if (DeviceExtension->MapRegisters) 1724 { 1725 /* Calculate number of needed map registers */ 1726 SrbInfo->NumberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES( 1727 Srb->DataBuffer, 1728 Srb->DataTransferLength); 1729 1730 /* Allocate adapter channel */ 1731 Status = IoAllocateAdapterChannel(DeviceExtension->AdapterObject, 1732 DeviceExtension->Common.DeviceObject, 1733 SrbInfo->NumberOfMapRegisters, 1734 SpiAdapterControl, 1735 SrbInfo); 1736 1737 if (!NT_SUCCESS(Status)) 1738 { 1739 DPRINT1("IoAllocateAdapterChannel() failed!\n"); 1740 1741 Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; 1742 ScsiPortNotification(RequestComplete, 1743 DeviceExtension + 1, 1744 Srb); 1745 1746 ScsiPortNotification(NextRequest, 1747 DeviceExtension + 1); 1748 1749 /* Request DPC for that work */ 1750 IoRequestDpc(DeviceExtension->Common.DeviceObject, NULL, NULL); 1751 } 1752 1753 /* Control goes to SpiAdapterControl */ 1754 return; 1755 } 1756 } 1757 1758 /* Increase active request counter */ 1759 CounterResult = InterlockedIncrement(&DeviceExtension->ActiveRequestCounter); 1760 1761 if (CounterResult == 0 && 1762 DeviceExtension->AdapterObject != NULL && 1763 !DeviceExtension->MapRegisters) 1764 { 1765 IoAllocateAdapterChannel( 1766 DeviceExtension->AdapterObject, 1767 DeviceObject, 1768 DeviceExtension->PortCapabilities.MaximumPhysicalPages, 1769 ScsiPortAllocateAdapterChannel, 1770 LunExtension 1771 ); 1772 1773 return; 1774 } 1775 1776 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock); 1777 1778 if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0], 1779 ScsiPortStartPacket, 1780 DeviceObject)) 1781 { 1782 DPRINT("Synchronization failed!\n"); 1783 1784 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; 1785 Irp->IoStatus.Information = 0; 1786 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 1787 1788 IoCompleteRequest(Irp, IO_NO_INCREMENT); 1789 } 1790 else 1791 { 1792 /* Release the spinlock only */ 1793 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 1794 } 1795 1796 1797 DPRINT("ScsiPortStartIo() done\n"); 1798 } 1799