xref: /reactos/drivers/storage/port/scsiport/scsi.c (revision c8d07514)
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     //ULONG SequenceNumber;
657 
658     Srb = SrbInfo->Srb;
659     Irp = Srb->OriginalRequest;
660     PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp);
661 
662     /* Get Lun extension */
663     LunExtension = IoStack->DeviceObject->DeviceExtension;
664     ASSERT(LunExtension && !LunExtension->Common.IsFDO);
665 
666     if (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION &&
667         DeviceExtension->MapBuffers &&
668         Irp->MdlAddress)
669     {
670         /* MDL is shared if transfer is broken into smaller parts */
671         Srb->DataBuffer = (PCCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress) +
672             ((PCCHAR)Srb->DataBuffer - SrbInfo->DataOffset);
673 
674         /* In case of data going in, flush the buffers */
675         if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
676         {
677             KeFlushIoBuffers(Irp->MdlAddress,
678                              TRUE,
679                              FALSE);
680         }
681     }
682 
683     /* Flush adapter if needed */
684     if (SrbInfo->BaseOfMapRegister)
685     {
686         /* TODO: Implement */
687         ASSERT(FALSE);
688     }
689 
690     /* Clear the request */
691     SrbInfo->Srb = NULL;
692 
693     /* If disconnect is disabled... */
694     if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
695     {
696         /* Acquire the spinlock since we mess with flags */
697         KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
698 
699         /* Set corresponding flag */
700         DeviceExtension->Flags |= SCSI_PORT_DISCONNECT_ALLOWED;
701 
702         /* Clear the timer if needed */
703         if (!(DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET))
704             DeviceExtension->TimerCount = -1;
705 
706         /* Spinlock is not needed anymore */
707         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
708 
709         if (!(DeviceExtension->Flags & SCSI_PORT_REQUEST_PENDING) &&
710             !(DeviceExtension->Flags & SCSI_PORT_DEVICE_BUSY) &&
711             !(*NeedToCallStartIo))
712         {
713             /* We're not busy, but we have a request pending */
714             IoStartNextPacket(DeviceExtension->Common.DeviceObject, FALSE);
715         }
716     }
717 
718     /* Scatter/gather */
719     if (Srb->SrbFlags & SRB_FLAGS_SGLIST_FROM_POOL)
720     {
721         /* TODO: Implement */
722         ASSERT(FALSE);
723     }
724 
725     /* Acquire spinlock (we're freeing SrbExtension) */
726     KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
727 
728     /* Free it (if needed) */
729     if (Srb->SrbExtension)
730     {
731         if (Srb->SenseInfoBuffer != NULL && DeviceExtension->SupportsAutoSense)
732         {
733             ASSERT(Srb->SenseInfoBuffer == NULL || SrbInfo->SaveSenseRequest != NULL);
734 
735             if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)
736             {
737                 /* Copy sense data to the buffer */
738                 RtlCopyMemory(SrbInfo->SaveSenseRequest,
739                               Srb->SenseInfoBuffer,
740                               Srb->SenseInfoBufferLength);
741             }
742 
743             /* And restore the pointer */
744             Srb->SenseInfoBuffer = SrbInfo->SaveSenseRequest;
745         }
746 
747         /* Put it into the free srb extensions list */
748         *((PVOID *)Srb->SrbExtension) = DeviceExtension->FreeSrbExtensions;
749         DeviceExtension->FreeSrbExtensions = Srb->SrbExtension;
750     }
751 
752     /* Save transfer length in the IRP */
753     Irp->IoStatus.Information = Srb->DataTransferLength;
754 
755     //SequenceNumber = SrbInfo->SequenceNumber;
756     SrbInfo->SequenceNumber = 0;
757 
758     /* Decrement the queue count */
759     LunExtension->QueueCount--;
760 
761     /* Free Srb, if needed*/
762     if (Srb->QueueTag != SP_UNTAGGED)
763     {
764         /* Put it into the free list */
765         SrbInfo->Requests.Blink = NULL;
766         SrbInfo->Requests.Flink = (PLIST_ENTRY)DeviceExtension->FreeSrbInfo;
767         DeviceExtension->FreeSrbInfo = SrbInfo;
768     }
769 
770     /* SrbInfo is not used anymore */
771     SrbInfo = NULL;
772 
773     if (DeviceExtension->Flags & SCSI_PORT_REQUEST_PENDING)
774     {
775         /* Clear the flag */
776         DeviceExtension->Flags &= ~SCSI_PORT_REQUEST_PENDING;
777 
778         /* Note the caller about StartIo */
779         *NeedToCallStartIo = TRUE;
780     }
781 
782     if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
783     {
784         /* Start the packet */
785         Irp->IoStatus.Status = STATUS_SUCCESS;
786 
787         if (!(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE) &&
788             LunExtension->RequestTimeout == -1)
789         {
790             /* Start the next packet. SpiGetNextRequestFromLun will release the lock for us */
791             SpiGetNextRequestFromLun(DeviceExtension, LunExtension, NULL);
792         }
793         else
794         {
795             /* Release the spinlock */
796             KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
797         }
798 
799         DPRINT("IoCompleting request IRP 0x%p\n", Irp);
800 
801         IoCompleteRequest(Irp, IO_DISK_INCREMENT);
802 
803         /* Decrement number of active requests, and analyze the result */
804         Result = InterlockedDecrement(&DeviceExtension->ActiveRequestCounter);
805 
806         if (Result < 0 &&
807             !DeviceExtension->MapRegisters &&
808             DeviceExtension->AdapterObject != NULL)
809         {
810             /* Nullify map registers */
811             DeviceExtension->MapRegisterBase = NULL;
812             IoFreeAdapterChannel(DeviceExtension->AdapterObject);
813         }
814 
815          /* Exit, we're done */
816         return;
817     }
818 
819     /* Decrement number of active requests, and analyze the result */
820     Result = InterlockedDecrement(&DeviceExtension->ActiveRequestCounter);
821 
822     if (Result < 0 &&
823         !DeviceExtension->MapRegisters &&
824         DeviceExtension->AdapterObject != NULL)
825     {
826         /* Result is negative, so this is a slave, free map registers */
827         DeviceExtension->MapRegisterBase = NULL;
828         IoFreeAdapterChannel(DeviceExtension->AdapterObject);
829     }
830 
831     /* Convert status */
832     Irp->IoStatus.Status = SpiStatusSrbToNt(Srb->SrbStatus);
833 
834     /* It's not a bypass, it's busy or the queue is full? */
835     if ((Srb->ScsiStatus == SCSISTAT_BUSY ||
836          Srb->SrbStatus == SRB_STATUS_BUSY ||
837          Srb->ScsiStatus == SCSISTAT_QUEUE_FULL) &&
838          !(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE))
839     {
840 
841         DPRINT("Busy SRB status %x\n", Srb->SrbStatus);
842 
843         /* Requeue, if needed */
844         if (LunExtension->Flags & (LUNEX_FROZEN_QUEUE | LUNEX_BUSY))
845         {
846             DPRINT("it's being requeued\n");
847 
848             Srb->SrbStatus = SRB_STATUS_PENDING;
849             Srb->ScsiStatus = 0;
850 
851             if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue,
852                                           &Irp->Tail.Overlay.DeviceQueueEntry,
853                                           Srb->QueueSortKey))
854             {
855                 /* It's a big f.ck up if we got here */
856                 Srb->SrbStatus = SRB_STATUS_ERROR;
857                 Srb->ScsiStatus = SCSISTAT_BUSY;
858 
859                 ASSERT(FALSE);
860                 goto Error;
861             }
862 
863             /* Release the spinlock */
864             KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
865 
866         }
867         else if (LunExtension->AttemptCount++ < 20)
868         {
869             /* LUN is still busy */
870             Srb->ScsiStatus = 0;
871             Srb->SrbStatus = SRB_STATUS_PENDING;
872 
873             LunExtension->BusyRequest = Irp;
874             LunExtension->Flags |= LUNEX_BUSY;
875 
876             /* Release the spinlock */
877             KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
878         }
879         else
880         {
881 Error:
882             /* Freeze the queue*/
883             Srb->SrbStatus |= SRB_STATUS_QUEUE_FROZEN;
884             LunExtension->Flags |= LUNEX_FROZEN_QUEUE;
885 
886             /* "Unfull" the queue */
887             LunExtension->Flags &= ~LUNEX_FULL_QUEUE;
888 
889             /* Release the spinlock */
890             KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
891 
892             /* Return status that the device is not ready */
893             Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
894             IoCompleteRequest(Irp, IO_DISK_INCREMENT);
895         }
896 
897         return;
898     }
899 
900     /* Start the next request, if LUN is idle, and this is sense request */
901     if (((Srb->ScsiStatus != SCSISTAT_CHECK_CONDITION) ||
902         (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) ||
903         !Srb->SenseInfoBuffer || !Srb->SenseInfoBufferLength)
904         && (Srb->SrbFlags & SRB_FLAGS_NO_QUEUE_FREEZE))
905     {
906         if (LunExtension->RequestTimeout == -1)
907             SpiGetNextRequestFromLun(DeviceExtension, LunExtension, NULL);
908         else
909             KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
910     }
911     else
912     {
913         /* Freeze the queue */
914         Srb->SrbStatus |= SRB_STATUS_QUEUE_FROZEN;
915         LunExtension->Flags |= LUNEX_FROZEN_QUEUE;
916 
917         /* Do we need a request sense? */
918         if (Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION &&
919             !(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
920             Srb->SenseInfoBuffer && Srb->SenseInfoBufferLength)
921         {
922             /* If LUN is busy, we have to requeue it in order to allow request sense */
923             if (LunExtension->Flags & LUNEX_BUSY)
924             {
925                 DPRINT("Requeuing busy request to allow request sense\n");
926 
927                 if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue,
928                     &LunExtension->BusyRequest->Tail.Overlay.DeviceQueueEntry,
929                     Srb->QueueSortKey))
930                 {
931                     /* We should never get here */
932                     ASSERT(FALSE);
933 
934                     KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
935                     IoCompleteRequest(Irp, IO_DISK_INCREMENT);
936                     return;
937 
938                 }
939 
940                 /* Clear busy flags */
941                 LunExtension->Flags &= ~(LUNEX_FULL_QUEUE | LUNEX_BUSY);
942             }
943 
944             /* Release the spinlock */
945             KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
946 
947             /* Send RequestSense */
948             SpiSendRequestSense(LunExtension, Srb);
949 
950             /* Exit */
951             return;
952         }
953 
954         /* Release the spinlock */
955         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
956     }
957 
958     /* Complete the request */
959     IoCompleteRequest(Irp, IO_DISK_INCREMENT);
960 }
961 
962 BOOLEAN
963 NTAPI
964 ScsiPortStartPacket(
965     _In_ PVOID Context)
966 {
967     PIO_STACK_LOCATION IrpStack;
968     PSCSI_REQUEST_BLOCK Srb;
969     PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)Context;
970     PSCSI_PORT_COMMON_EXTENSION CommonExtension = DeviceObject->DeviceExtension;
971     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
972     PSCSI_PORT_LUN_EXTENSION LunExtension;
973     PSCSI_REQUEST_BLOCK_INFO SrbInfo;
974     BOOLEAN Result;
975     BOOLEAN StartTimer;
976 
977     DPRINT("ScsiPortStartPacket() called\n");
978 
979     IrpStack = IoGetCurrentIrpStackLocation(DeviceObject->CurrentIrp);
980     Srb = IrpStack->Parameters.Scsi.Srb;
981 
982     if (CommonExtension->IsFDO) // IsFDO
983     {
984         DeviceExtension = DeviceObject->DeviceExtension;
985         LunExtension = IrpStack->DeviceObject->DeviceExtension;
986         ASSERT(LunExtension && !LunExtension->Common.IsFDO);
987     }
988     else
989     {
990         LunExtension = DeviceObject->DeviceExtension;
991         DeviceExtension = LunExtension->Common.LowerDevice->DeviceExtension;
992     }
993 
994     /* Check if we are in a reset state */
995     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET)
996     {
997         /* Mark the we've got requests while being in the reset state */
998         DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET_REQUEST;
999         return TRUE;
1000     }
1001 
1002     /* Set the time out value */
1003     DeviceExtension->TimerCount = Srb->TimeOutValue;
1004 
1005     /* We are busy */
1006     DeviceExtension->Flags |= SCSI_PORT_DEVICE_BUSY;
1007 
1008     if (LunExtension->RequestTimeout != -1)
1009     {
1010         /* Timer already active */
1011         StartTimer = FALSE;
1012     }
1013     else
1014     {
1015         /* It hasn't been initialized yet */
1016         LunExtension->RequestTimeout = Srb->TimeOutValue;
1017         StartTimer = TRUE;
1018     }
1019 
1020     if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
1021     {
1022         /* Handle bypass-requests */
1023 
1024         /* Is this an abort request? */
1025         if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
1026         {
1027             /* Get pointer to SRB info structure */
1028             SrbInfo = SpiGetSrbData(DeviceExtension, LunExtension, Srb->QueueTag);
1029 
1030             /* Check if the request is still "active" */
1031             if (SrbInfo == NULL ||
1032                 SrbInfo->Srb == NULL ||
1033                 !(SrbInfo->Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE))
1034             {
1035                 /* It's not, mark it as active then */
1036                 Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
1037 
1038                 if (StartTimer)
1039                     LunExtension->RequestTimeout = -1;
1040 
1041                 DPRINT("Request has been already completed, but abort request came\n");
1042                 Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
1043 
1044                 /* Notify about request complete */
1045                 ScsiPortNotification(RequestComplete,
1046                                      DeviceExtension->MiniPortDeviceExtension,
1047                                      Srb);
1048 
1049                 /* and about readiness for the next request */
1050                 ScsiPortNotification(NextRequest,
1051                                      DeviceExtension->MiniPortDeviceExtension);
1052 
1053                 /* They might ask for some work, so queue the DPC for them */
1054                 IoRequestDpc(DeviceExtension->Common.DeviceObject, NULL, NULL);
1055 
1056                 /* We're done in this branch */
1057                 return TRUE;
1058             }
1059         }
1060         else
1061         {
1062             /* Add number of queued requests */
1063             LunExtension->QueueCount++;
1064         }
1065 
1066         /* Bypass requests don't need request sense */
1067         LunExtension->Flags &= ~LUNEX_NEED_REQUEST_SENSE;
1068 
1069         /* Is disconnect disabled for this request? */
1070         if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
1071         {
1072             /* Set the corresponding flag */
1073             DeviceExtension->Flags &= ~SCSI_PORT_DISCONNECT_ALLOWED;
1074         }
1075 
1076         /* Transfer timeout value from Srb to Lun */
1077         LunExtension->RequestTimeout = Srb->TimeOutValue;
1078     }
1079     else
1080     {
1081         if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
1082         {
1083             /* It's a disconnect, so no more requests can go */
1084             DeviceExtension->Flags &= ~SCSI_PORT_DISCONNECT_ALLOWED;
1085         }
1086 
1087         LunExtension->Flags |= SCSI_PORT_LU_ACTIVE;
1088 
1089         /* Increment queue count */
1090         LunExtension->QueueCount++;
1091 
1092         /* If it's tagged - special thing */
1093         if (Srb->QueueTag != SP_UNTAGGED)
1094         {
1095             SrbInfo = &DeviceExtension->SrbInfo[Srb->QueueTag - 1];
1096 
1097             /* Chek for consistency */
1098             ASSERT(SrbInfo->Requests.Blink == NULL);
1099 
1100             /* Insert it into the list of requests */
1101             InsertTailList(&LunExtension->SrbInfo.Requests, &SrbInfo->Requests);
1102         }
1103     }
1104 
1105     /* Mark this Srb active */
1106     Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
1107 
1108     /* Call HwStartIo routine */
1109     Result = DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
1110                                         Srb);
1111 
1112     /* If notification is needed, then request a DPC */
1113     if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
1114         IoRequestDpc(DeviceExtension->Common.DeviceObject, NULL, NULL);
1115 
1116     return Result;
1117 }
1118 
1119 BOOLEAN
1120 NTAPI
1121 SpiSaveInterruptData(IN PVOID Context)
1122 {
1123     PSCSI_PORT_SAVE_INTERRUPT InterruptContext = Context;
1124     PSCSI_PORT_LUN_EXTENSION LunExtension;
1125     PSCSI_REQUEST_BLOCK Srb;
1126     PSCSI_REQUEST_BLOCK_INFO SrbInfo, NextSrbInfo;
1127     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1128     BOOLEAN IsTimed;
1129 
1130     /* Get pointer to the device extension */
1131     DeviceExtension = InterruptContext->DeviceExtension;
1132 
1133     /* If we don't have anything pending - return */
1134     if (!(DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED))
1135         return FALSE;
1136 
1137     /* Actually save the interrupt data */
1138     *InterruptContext->InterruptData = DeviceExtension->InterruptData;
1139 
1140     /* Clear the data stored in the device extension */
1141     DeviceExtension->InterruptData.Flags &=
1142         (SCSI_PORT_RESET | SCSI_PORT_RESET_REQUEST | SCSI_PORT_DISABLE_INTERRUPTS);
1143     DeviceExtension->InterruptData.CompletedAbort = NULL;
1144     DeviceExtension->InterruptData.ReadyLun = NULL;
1145     DeviceExtension->InterruptData.CompletedRequests = NULL;
1146 
1147     /* Loop through the list of completed requests */
1148     SrbInfo = InterruptContext->InterruptData->CompletedRequests;
1149 
1150     while (SrbInfo)
1151     {
1152         /* Make sure we have SRV */
1153         ASSERT(SrbInfo->Srb);
1154 
1155         /* Get SRB and LunExtension */
1156         Srb = SrbInfo->Srb;
1157 
1158         PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Srb->OriginalRequest);
1159         LunExtension = IoStack->DeviceObject->DeviceExtension;
1160         ASSERT(LunExtension && !LunExtension->Common.IsFDO);
1161 
1162         /* We have to check special cases if request is unsuccessful*/
1163         if (Srb->SrbStatus != SRB_STATUS_SUCCESS)
1164         {
1165             /* Check if we need request sense by a few conditions */
1166             if (Srb->SenseInfoBuffer && Srb->SenseInfoBufferLength &&
1167                 Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION &&
1168                 !(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID))
1169             {
1170                 if (LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE)
1171                 {
1172                     /* It means: we tried to send REQUEST SENSE, but failed */
1173 
1174                     Srb->ScsiStatus = 0;
1175                     Srb->SrbStatus = SRB_STATUS_REQUEST_SENSE_FAILED;
1176                 }
1177                 else
1178                 {
1179                     /* Set the corresponding flag, so that REQUEST SENSE
1180                        will be sent */
1181                     LunExtension->Flags |= LUNEX_NEED_REQUEST_SENSE;
1182                 }
1183 
1184             }
1185 
1186             /* Check for a full queue */
1187             if (Srb->ScsiStatus == SCSISTAT_QUEUE_FULL)
1188             {
1189                 /* TODO: Implement when it's encountered */
1190                 ASSERT(FALSE);
1191             }
1192         }
1193 
1194         /* Let's decide if we need to watch timeout or not */
1195         if (Srb->QueueTag == SP_UNTAGGED)
1196         {
1197             IsTimed = TRUE;
1198         }
1199         else
1200         {
1201             if (LunExtension->SrbInfo.Requests.Flink == &SrbInfo->Requests)
1202                 IsTimed = TRUE;
1203             else
1204                 IsTimed = FALSE;
1205 
1206             /* Remove it from the queue */
1207             RemoveEntryList(&SrbInfo->Requests);
1208         }
1209 
1210         if (IsTimed)
1211         {
1212             /* We have to maintain timeout counter */
1213             if (IsListEmpty(&LunExtension->SrbInfo.Requests))
1214             {
1215                 LunExtension->RequestTimeout = -1;
1216             }
1217             else
1218             {
1219                 NextSrbInfo = CONTAINING_RECORD(LunExtension->SrbInfo.Requests.Flink,
1220                                                 SCSI_REQUEST_BLOCK_INFO,
1221                                                 Requests);
1222 
1223                 Srb = NextSrbInfo->Srb;
1224 
1225                 /* Update timeout counter */
1226                 LunExtension->RequestTimeout = Srb->TimeOutValue;
1227             }
1228         }
1229 
1230         SrbInfo = SrbInfo->CompletedRequests;
1231     }
1232 
1233     return TRUE;
1234 }
1235 
1236 VOID
1237 NTAPI
1238 ScsiPortDpcForIsr(
1239     _In_ PKDPC Dpc,
1240     _In_ PDEVICE_OBJECT DpcDeviceObject,
1241     _Inout_ PIRP DpcIrp,
1242     _In_opt_ PVOID DpcContext)
1243 {
1244     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DpcDeviceObject->DeviceExtension;
1245     SCSI_PORT_INTERRUPT_DATA InterruptData;
1246     SCSI_PORT_SAVE_INTERRUPT Context;
1247     PSCSI_PORT_LUN_EXTENSION LunExtension;
1248     BOOLEAN NeedToStartIo;
1249     PSCSI_REQUEST_BLOCK_INFO SrbInfo;
1250     LARGE_INTEGER TimerValue;
1251 
1252     DPRINT("ScsiPortDpcForIsr(Dpc %p  DpcDeviceObject %p  DpcIrp %p  DpcContext %p)\n",
1253            Dpc, DpcDeviceObject, DpcIrp, DpcContext);
1254 
1255     /* We need to acquire spinlock */
1256     KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
1257 
1258     RtlZeroMemory(&InterruptData, sizeof(SCSI_PORT_INTERRUPT_DATA));
1259 
1260 TryAgain:
1261 
1262     /* Interrupt structure must be snapshotted, and only then analyzed */
1263     Context.InterruptData = &InterruptData;
1264     Context.DeviceExtension = DeviceExtension;
1265 
1266     if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0],
1267                                 SpiSaveInterruptData,
1268                                 &Context))
1269     {
1270         /* Nothing - just return (don't forget to release the spinlock */
1271         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
1272         DPRINT("ScsiPortDpcForIsr() done\n");
1273         return;
1274     }
1275 
1276     /* If flush of adapters is needed - do it */
1277     if (InterruptData.Flags & SCSI_PORT_FLUSH_ADAPTERS)
1278     {
1279         /* TODO: Implement */
1280         ASSERT(FALSE);
1281     }
1282 
1283     /* Check for IoMapTransfer */
1284     if (InterruptData.Flags & SCSI_PORT_MAP_TRANSFER)
1285     {
1286         /* TODO: Implement */
1287         ASSERT(FALSE);
1288     }
1289 
1290     /* Check if timer is needed */
1291     if (InterruptData.Flags & SCSI_PORT_TIMER_NEEDED)
1292     {
1293         /* Save the timer routine */
1294         DeviceExtension->HwScsiTimer = InterruptData.HwScsiTimer;
1295 
1296         if (InterruptData.MiniportTimerValue == 0)
1297         {
1298             /* Cancel the timer */
1299             KeCancelTimer(&DeviceExtension->MiniportTimer);
1300         }
1301         else
1302         {
1303             /* Convert timer value */
1304             TimerValue.QuadPart = Int32x32To64(InterruptData.MiniportTimerValue, -10);
1305 
1306             /* Set the timer */
1307             KeSetTimer(&DeviceExtension->MiniportTimer,
1308                        TimerValue,
1309                        &DeviceExtension->MiniportTimerDpc);
1310         }
1311     }
1312 
1313     /* If it's ready for the next request */
1314     if (InterruptData.Flags & SCSI_PORT_NEXT_REQUEST_READY)
1315     {
1316         /* Check for a duplicate request (NextRequest+NextLuRequest) */
1317         if ((DeviceExtension->Flags &
1318             (SCSI_PORT_DEVICE_BUSY | SCSI_PORT_DISCONNECT_ALLOWED)) ==
1319             (SCSI_PORT_DEVICE_BUSY | SCSI_PORT_DISCONNECT_ALLOWED))
1320         {
1321             /* Clear busy flag set by ScsiPortStartPacket() */
1322             DeviceExtension->Flags &= ~SCSI_PORT_DEVICE_BUSY;
1323 
1324             if (!(InterruptData.Flags & SCSI_PORT_RESET))
1325             {
1326                 /* Ready for next, and no reset is happening */
1327                 DeviceExtension->TimerCount = -1;
1328             }
1329         }
1330         else
1331         {
1332             /* Not busy, but not ready for the next request */
1333             DeviceExtension->Flags &= ~SCSI_PORT_DEVICE_BUSY;
1334             InterruptData.Flags &= ~SCSI_PORT_NEXT_REQUEST_READY;
1335         }
1336     }
1337 
1338     /* Any resets? */
1339     if (InterruptData.Flags & SCSI_PORT_RESET_REPORTED)
1340     {
1341         /* Hold for a bit */
1342         DeviceExtension->TimerCount = 4;
1343     }
1344 
1345     /* Any ready LUN? */
1346     if (InterruptData.ReadyLun != NULL)
1347     {
1348 
1349         /* Process all LUNs from the list*/
1350         while (TRUE)
1351         {
1352             /* Remove it from the list first (as processed) */
1353             LunExtension = InterruptData.ReadyLun;
1354             InterruptData.ReadyLun = LunExtension->ReadyLun;
1355             LunExtension->ReadyLun = NULL;
1356 
1357             /* Get next request for this LUN */
1358             SpiGetNextRequestFromLun(DeviceExtension, LunExtension, NULL);
1359 
1360             /* Still ready requests exist?
1361                If yes - get spinlock, if no - stop here */
1362             if (InterruptData.ReadyLun != NULL)
1363                 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
1364             else
1365                 break;
1366         }
1367     }
1368     else
1369     {
1370         /* Release the spinlock */
1371         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
1372     }
1373 
1374     /* If we ready for next packet, start it */
1375     if (InterruptData.Flags & SCSI_PORT_NEXT_REQUEST_READY)
1376         IoStartNextPacket(DeviceExtension->Common.DeviceObject, FALSE);
1377 
1378     NeedToStartIo = FALSE;
1379 
1380     /* Loop the completed request list */
1381     while (InterruptData.CompletedRequests)
1382     {
1383         /* Remove the request */
1384         SrbInfo = InterruptData.CompletedRequests;
1385         InterruptData.CompletedRequests = SrbInfo->CompletedRequests;
1386         SrbInfo->CompletedRequests = NULL;
1387 
1388         /* Process it */
1389         SpiProcessCompletedRequest(DeviceExtension,
1390                                   SrbInfo,
1391                                   &NeedToStartIo);
1392     }
1393 
1394     /* Loop abort request list */
1395     while (InterruptData.CompletedAbort)
1396     {
1397         LunExtension = InterruptData.CompletedAbort;
1398 
1399         /* Remove the request */
1400         InterruptData.CompletedAbort = LunExtension->CompletedAbortRequests;
1401 
1402         /* Get spinlock since we're going to change flags */
1403         KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
1404 
1405         /* TODO: Put SrbExtension to the list of free extensions */
1406         ASSERT(FALSE);
1407     }
1408 
1409     /* If we need - call StartIo routine */
1410     if (NeedToStartIo)
1411     {
1412         /* Make sure CurrentIrp is not null! */
1413         ASSERT(DpcDeviceObject->CurrentIrp != NULL);
1414         ScsiPortStartIo(DpcDeviceObject, DpcDeviceObject->CurrentIrp);
1415     }
1416 
1417     /* Everything has been done, check */
1418     if (InterruptData.Flags & SCSI_PORT_ENABLE_INT_REQUEST)
1419     {
1420         /* Synchronize using spinlock */
1421         KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
1422 
1423         /* Request an interrupt */
1424         DeviceExtension->HwInterrupt(DeviceExtension->MiniPortDeviceExtension);
1425 
1426         ASSERT(DeviceExtension->Flags & SCSI_PORT_DISABLE_INT_REQUESET);
1427 
1428         /* Should interrupts be enabled again? */
1429         if (DeviceExtension->Flags & SCSI_PORT_DISABLE_INT_REQUESET)
1430         {
1431             /* Clear this flag */
1432             DeviceExtension->Flags &= ~SCSI_PORT_DISABLE_INT_REQUESET;
1433 
1434             /* Call a special routine to do this */
1435             ASSERT(FALSE);
1436 #if 0
1437             KeSynchronizeExecution(DeviceExtension->Interrupt,
1438                                    SpiEnableInterrupts,
1439                                    DeviceExtension);
1440 #endif
1441         }
1442 
1443         /* If we need a notification again - loop */
1444         if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
1445             goto TryAgain;
1446 
1447         /* Release the spinlock */
1448         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
1449     }
1450 
1451     DPRINT("ScsiPortDpcForIsr() done\n");
1452 }
1453 
1454 static
1455 PSCSI_REQUEST_BLOCK_INFO
1456 SpiAllocateSrbStructures(
1457     _Inout_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1458     _Inout_ PSCSI_PORT_LUN_EXTENSION LunExtension,
1459     _Inout_ PSCSI_REQUEST_BLOCK Srb)
1460 {
1461     PCHAR SrbExtension;
1462     PSCSI_REQUEST_BLOCK_INFO SrbInfo;
1463 
1464     /* Spinlock must be held while this function executes */
1465     KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
1466 
1467     /* Allocate SRB data structure */
1468     if (DeviceExtension->NeedSrbDataAlloc)
1469     {
1470         /* Treat the abort request in a special way */
1471         if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
1472         {
1473             SrbInfo = SpiGetSrbData(DeviceExtension, LunExtension, Srb->QueueTag);
1474         }
1475         else if (Srb->SrbFlags &
1476                  (SRB_FLAGS_QUEUE_ACTION_ENABLE | SRB_FLAGS_NO_QUEUE_FREEZE) &&
1477                  !(Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)
1478                  )
1479         {
1480             /* Do not process tagged commands if need request sense is set */
1481             if (LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE)
1482             {
1483                 ASSERT(!(LunExtension->Flags & LUNEX_REQUEST_PENDING));
1484 
1485                 LunExtension->PendingRequest = Srb->OriginalRequest;
1486                 LunExtension->Flags |= LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE;
1487 
1488                 /* Release the spinlock and return */
1489                 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
1490                 return NULL;
1491             }
1492 
1493             ASSERT(LunExtension->SrbInfo.Srb == NULL);
1494             SrbInfo = DeviceExtension->FreeSrbInfo;
1495 
1496             if (SrbInfo == NULL)
1497             {
1498                 /* No SRB structures left in the list. We have to leave
1499                    and wait while we are called again */
1500 
1501                 DeviceExtension->Flags |= SCSI_PORT_REQUEST_PENDING;
1502                 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
1503                 return NULL;
1504             }
1505 
1506             DeviceExtension->FreeSrbInfo = (PSCSI_REQUEST_BLOCK_INFO)SrbInfo->Requests.Flink;
1507 
1508             /* QueueTag must never be 0, so +1 to it */
1509             Srb->QueueTag = (UCHAR)(SrbInfo - DeviceExtension->SrbInfo) + 1;
1510         }
1511         else
1512         {
1513             /* Usual untagged command */
1514             if (
1515                 (!IsListEmpty(&LunExtension->SrbInfo.Requests) ||
1516                 LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE) &&
1517                 !(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)
1518                 )
1519             {
1520                 /* Mark it as pending and leave */
1521                 ASSERT(!(LunExtension->Flags & LUNEX_REQUEST_PENDING));
1522                 LunExtension->Flags |= LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE;
1523                 LunExtension->PendingRequest = Srb->OriginalRequest;
1524 
1525                 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
1526                 return(NULL);
1527             }
1528 
1529             Srb->QueueTag = SP_UNTAGGED;
1530             SrbInfo = &LunExtension->SrbInfo;
1531         }
1532     }
1533     else
1534     {
1535         Srb->QueueTag = SP_UNTAGGED;
1536         SrbInfo = &LunExtension->SrbInfo;
1537     }
1538 
1539     /* Allocate SRB extension structure */
1540     if (DeviceExtension->NeedSrbExtensionAlloc)
1541     {
1542         /* Check the list of free extensions */
1543         SrbExtension = DeviceExtension->FreeSrbExtensions;
1544 
1545         /* If no free extensions... */
1546         if (SrbExtension == NULL)
1547         {
1548             /* Free SRB data */
1549             if (Srb->Function != SRB_FUNCTION_ABORT_COMMAND &&
1550                 Srb->QueueTag != SP_UNTAGGED)
1551             {
1552                 SrbInfo->Requests.Blink = NULL;
1553                 SrbInfo->Requests.Flink = (PLIST_ENTRY)DeviceExtension->FreeSrbInfo;
1554                 DeviceExtension->FreeSrbInfo = SrbInfo;
1555             }
1556 
1557             /* Return, in order to be called again later */
1558             DeviceExtension->Flags |= SCSI_PORT_REQUEST_PENDING;
1559             KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
1560             return NULL;
1561         }
1562 
1563         /* Remove that free SRB extension from the list (since
1564            we're going to use it) */
1565         DeviceExtension->FreeSrbExtensions = *((PVOID *)SrbExtension);
1566 
1567         /* Spinlock can be released now */
1568         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
1569 
1570         Srb->SrbExtension = SrbExtension;
1571 
1572         if (Srb->SenseInfoBuffer != NULL &&
1573             DeviceExtension->SupportsAutoSense)
1574         {
1575             /* Store pointer to the SenseInfo buffer */
1576             SrbInfo->SaveSenseRequest = Srb->SenseInfoBuffer;
1577 
1578             /* Does data fit the buffer? */
1579             if (Srb->SenseInfoBufferLength > sizeof(SENSE_DATA))
1580             {
1581                 /* No, disabling autosense at all */
1582                 Srb->SrbFlags |= SRB_FLAGS_DISABLE_AUTOSENSE;
1583             }
1584             else
1585             {
1586                 /* Yes, update the buffer pointer */
1587                 Srb->SenseInfoBuffer = SrbExtension + DeviceExtension->SrbExtensionSize;
1588             }
1589         }
1590     }
1591     else
1592     {
1593         /* Cleanup... */
1594         Srb->SrbExtension = NULL;
1595         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
1596     }
1597 
1598     return SrbInfo;
1599 }
1600 
1601 VOID
1602 NTAPI
1603 ScsiPortStartIo(
1604     _Inout_ PDEVICE_OBJECT DeviceObject,
1605     _Inout_ PIRP Irp)
1606 {
1607     PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1608     PSCSI_PORT_LUN_EXTENSION LunExtension;
1609     PIO_STACK_LOCATION IrpStack;
1610     PSCSI_REQUEST_BLOCK Srb;
1611     PSCSI_REQUEST_BLOCK_INFO SrbInfo;
1612     LONG CounterResult;
1613     NTSTATUS Status;
1614 
1615     DPRINT("ScsiPortStartIo() called!\n");
1616 
1617     DeviceExtension = DeviceObject->DeviceExtension;
1618     IrpStack = IoGetCurrentIrpStackLocation(Irp);
1619     LunExtension = IrpStack->DeviceObject->DeviceExtension;
1620 
1621     ASSERT(DeviceExtension->Common.IsFDO);
1622     ASSERT(!LunExtension->Common.IsFDO);
1623 
1624     DPRINT("LunExtension %p DeviceExtension %p\n", LunExtension, DeviceExtension);
1625 
1626     Srb = IrpStack->Parameters.Scsi.Srb;
1627 
1628     /* Apply "default" flags */
1629     Srb->SrbFlags |= DeviceExtension->SrbFlags;
1630 
1631     if (DeviceExtension->NeedSrbDataAlloc ||
1632         DeviceExtension->NeedSrbExtensionAlloc)
1633     {
1634         /* Allocate them */
1635         SrbInfo = SpiAllocateSrbStructures(DeviceExtension,
1636                                            LunExtension,
1637                                            Srb);
1638 
1639         /* Couldn't alloc one or both data structures, return */
1640         if (SrbInfo == NULL)
1641         {
1642             /* We have to call IoStartNextPacket, because this request
1643                was not started */
1644             if (LunExtension->Flags & LUNEX_REQUEST_PENDING)
1645                 IoStartNextPacket(DeviceObject, FALSE);
1646 
1647             return;
1648         }
1649     }
1650     else
1651     {
1652         /* No allocations are needed */
1653         SrbInfo = &LunExtension->SrbInfo;
1654         Srb->SrbExtension = NULL;
1655         Srb->QueueTag = SP_UNTAGGED;
1656     }
1657 
1658     /* Increase sequence number of SRB */
1659     if (!SrbInfo->SequenceNumber)
1660     {
1661         /* Increase global sequence number */
1662         DeviceExtension->SequenceNumber++;
1663 
1664         /* Assign it */
1665         SrbInfo->SequenceNumber = DeviceExtension->SequenceNumber;
1666     }
1667 
1668     /* Check some special SRBs */
1669     if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)
1670     {
1671         /* Some special handling */
1672         DPRINT1("Abort command! Unimplemented now\n");
1673     }
1674     else
1675     {
1676         SrbInfo->Srb = Srb;
1677     }
1678 
1679     if (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION)
1680     {
1681         // Store the MDL virtual address in SrbInfo structure
1682         SrbInfo->DataOffset = MmGetMdlVirtualAddress(Irp->MdlAddress);
1683 
1684         if (DeviceExtension->MapBuffers)
1685         {
1686             /* Calculate offset within DataBuffer */
1687             SrbInfo->DataOffset = MmGetSystemAddressForMdl(Irp->MdlAddress);
1688             Srb->DataBuffer = SrbInfo->DataOffset +
1689                 (ULONG)((PUCHAR)Srb->DataBuffer -
1690                 (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress));
1691         }
1692 
1693         if (DeviceExtension->AdapterObject)
1694         {
1695             /* Flush buffers */
1696             KeFlushIoBuffers(Irp->MdlAddress,
1697                              Srb->SrbFlags & SRB_FLAGS_DATA_IN ? TRUE : FALSE,
1698                              TRUE);
1699         }
1700 
1701         if (DeviceExtension->MapRegisters)
1702         {
1703             /* Calculate number of needed map registers */
1704             SrbInfo->NumberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
1705                     Srb->DataBuffer,
1706                     Srb->DataTransferLength);
1707 
1708             /* Allocate adapter channel */
1709             Status = IoAllocateAdapterChannel(DeviceExtension->AdapterObject,
1710                                               DeviceExtension->Common.DeviceObject,
1711                                               SrbInfo->NumberOfMapRegisters,
1712                                               SpiAdapterControl,
1713                                               SrbInfo);
1714 
1715             if (!NT_SUCCESS(Status))
1716             {
1717                 DPRINT1("IoAllocateAdapterChannel() failed!\n");
1718 
1719                 Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
1720                 ScsiPortNotification(RequestComplete,
1721                                      DeviceExtension + 1,
1722                                      Srb);
1723 
1724                 ScsiPortNotification(NextRequest,
1725                                      DeviceExtension + 1);
1726 
1727                 /* Request DPC for that work */
1728                 IoRequestDpc(DeviceExtension->Common.DeviceObject, NULL, NULL);
1729             }
1730 
1731             /* Control goes to SpiAdapterControl */
1732             return;
1733         }
1734     }
1735 
1736     /* Increase active request counter */
1737     CounterResult = InterlockedIncrement(&DeviceExtension->ActiveRequestCounter);
1738 
1739     if (CounterResult == 0 &&
1740         DeviceExtension->AdapterObject != NULL &&
1741         !DeviceExtension->MapRegisters)
1742     {
1743         IoAllocateAdapterChannel(
1744             DeviceExtension->AdapterObject,
1745             DeviceObject,
1746             DeviceExtension->PortCapabilities.MaximumPhysicalPages,
1747             ScsiPortAllocateAdapterChannel,
1748             LunExtension
1749             );
1750 
1751         return;
1752     }
1753 
1754     KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
1755 
1756     if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0],
1757                                 ScsiPortStartPacket,
1758                                 DeviceObject))
1759     {
1760         DPRINT("Synchronization failed!\n");
1761 
1762         Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
1763         Irp->IoStatus.Information = 0;
1764         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
1765 
1766         IoCompleteRequest(Irp, IO_NO_INCREMENT);
1767     }
1768     else
1769     {
1770         /* Release the spinlock only */
1771         KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
1772     }
1773 
1774 
1775     DPRINT("ScsiPortStartIo() done\n");
1776 }
1777