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
SpiStatusSrbToNt(_In_ UCHAR SrbStatus)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
SpiHandleAttachRelease(_In_ PSCSI_PORT_LUN_EXTENSION LunExtension,_Inout_ PIRP Irp)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
ScsiPortDispatchScsi(_In_ PDEVICE_OBJECT DeviceObject,_Inout_ PIRP Irp)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
SpiGetNextRequestFromLun(_In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,_Inout_ PSCSI_PORT_LUN_EXTENSION LunExtension,_Inout_opt_ PKIRQL OldIrql)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
SpiSenseCompletionRoutine(_In_ PDEVICE_OBJECT DeviceObject,_In_ PIRP Irp,_In_opt_ PVOID Context)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
SpiSendRequestSense(_In_ PSCSI_PORT_LUN_EXTENSION LunExtension,_In_ PSCSI_REQUEST_BLOCK InitialSrb)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
SpiProcessCompletedRequest(_In_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,_Inout_ PSCSI_REQUEST_BLOCK_INFO SrbInfo,_Out_ PBOOLEAN NeedToCallStartIo)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
ScsiPortStartPacket(_In_ PVOID Context)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
SpiSaveInterruptData(IN PVOID Context)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
ScsiPortDpcForIsr(_In_ PKDPC Dpc,_In_ PDEVICE_OBJECT DpcDeviceObject,_Inout_ PIRP DpcIrp,_In_opt_ PVOID DpcContext)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
SpiAllocateSrbStructures(_Inout_ PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,_Inout_ PSCSI_PORT_LUN_EXTENSION LunExtension,_Inout_ PSCSI_REQUEST_BLOCK Srb)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
ScsiPortStartIo(_Inout_ PDEVICE_OBJECT DeviceObject,_Inout_ PIRP Irp)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