xref: /reactos/drivers/storage/port/scsiport/scsi.c (revision 8f9ef68e)
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