1 /*++
2
3 Copyright (C) Microsoft Corporation, 1991 - 2010
4
5 Module Name:
6
7 xferpkt.c
8
9 Abstract:
10
11 Packet routines for CLASSPNP
12
13 Environment:
14
15 kernel mode only
16
17 Notes:
18
19
20 Revision History:
21
22 --*/
23
24 #include "classp.h"
25 #include "debug.h"
26
27 #ifdef DEBUG_USE_WPP
28 #include "xferpkt.tmh"
29 #endif
30
31 #ifdef ALLOC_PRAGMA
32 #pragma alloc_text(PAGE, InitializeTransferPackets)
33 #pragma alloc_text(PAGE, DestroyAllTransferPackets)
34 #pragma alloc_text(PAGE, SetupEjectionTransferPacket)
35 #pragma alloc_text(PAGE, SetupModeSenseTransferPacket)
36 #pragma alloc_text(PAGE, CleanupTransferPacketToWorkingSetSizeWorker)
37 #pragma alloc_text(PAGE, ClasspSetupPopulateTokenTransferPacket)
38 #endif
39
40 /*
41 * InitializeTransferPackets
42 *
43 * Allocate/initialize TRANSFER_PACKETs and related resources.
44 */
InitializeTransferPackets(PDEVICE_OBJECT Fdo)45 NTSTATUS InitializeTransferPackets(PDEVICE_OBJECT Fdo)
46 {
47 PCOMMON_DEVICE_EXTENSION commonExt = Fdo->DeviceExtension;
48 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
49 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
50 PSTORAGE_ADAPTER_DESCRIPTOR adapterDesc = commonExt->PartitionZeroExtension->AdapterDescriptor;
51 PSTORAGE_DEVICE_IO_CAPABILITY_DESCRIPTOR devIoCapabilityDesc = NULL;
52 STORAGE_PROPERTY_ID propertyId;
53 OSVERSIONINFOEXW osVersionInfo;
54 ULONG hwMaxPages;
55 ULONG arraySize;
56 ULONG index;
57 ULONG maxOutstandingIOPerLUN;
58 ULONG minWorkingSetTransferPackets;
59 ULONG maxWorkingSetTransferPackets;
60
61 NTSTATUS status = STATUS_SUCCESS;
62
63 PAGED_CODE();
64
65 //
66 // Precompute the maximum transfer length
67 //
68 NT_ASSERT(adapterDesc->MaximumTransferLength);
69
70 hwMaxPages = adapterDesc->MaximumPhysicalPages ? adapterDesc->MaximumPhysicalPages-1 : 0;
71
72 fdoData->HwMaxXferLen = MIN(adapterDesc->MaximumTransferLength, hwMaxPages << PAGE_SHIFT);
73 fdoData->HwMaxXferLen = MAX(fdoData->HwMaxXferLen, PAGE_SIZE);
74
75 //
76 // Allocate per-node free packet lists
77 //
78 arraySize = KeQueryHighestNodeNumber() + 1;
79 fdoData->FreeTransferPacketsLists =
80 ExAllocatePoolWithTag(NonPagedPoolNxCacheAligned,
81 sizeof(PNL_SLIST_HEADER) * arraySize,
82 CLASS_TAG_PRIVATE_DATA);
83
84 if (fdoData->FreeTransferPacketsLists == NULL) {
85 status = STATUS_INSUFFICIENT_RESOURCES;
86 return status;
87 }
88
89 for (index = 0; index < arraySize; index++) {
90 InitializeSListHead(&(fdoData->FreeTransferPacketsLists[index].SListHeader));
91 fdoData->FreeTransferPacketsLists[index].NumTotalTransferPackets = 0;
92 fdoData->FreeTransferPacketsLists[index].NumFreeTransferPackets = 0;
93 }
94
95 InitializeListHead(&fdoData->AllTransferPacketsList);
96
97 //
98 // Set the packet threshold numbers based on the Windows Client or Server SKU.
99 //
100
101 osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
102 status = RtlGetVersion((POSVERSIONINFOW) &osVersionInfo);
103
104 NT_ASSERT( NT_SUCCESS(status));
105
106 //
107 // Retrieve info on IO capability supported by port drivers
108 //
109
110 propertyId = StorageDeviceIoCapabilityProperty;
111 status = ClassGetDescriptor(fdoExt->CommonExtension.LowerDeviceObject,
112 &propertyId,
113 (PVOID *)&devIoCapabilityDesc);
114
115 if (NT_SUCCESS(status) && (devIoCapabilityDesc != NULL)) {
116 maxOutstandingIOPerLUN = devIoCapabilityDesc->LunMaxIoCount;
117 FREE_POOL(devIoCapabilityDesc);
118
119 #if DBG
120 fdoData->MaxOutstandingIOPerLUN = maxOutstandingIOPerLUN;
121 #endif
122
123 } else {
124 maxOutstandingIOPerLUN = MAX_OUTSTANDING_IO_PER_LUN_DEFAULT;
125
126 #if DBG
127 fdoData->MaxOutstandingIOPerLUN = 0;
128 #endif
129
130 }
131
132 //
133 // StorageDeviceIoCapabilityProperty support is optional so
134 // ignore any failures.
135 //
136
137 status = STATUS_SUCCESS;
138
139
140 if ((osVersionInfo.wProductType != VER_NT_DOMAIN_CONTROLLER) &&
141 (osVersionInfo.wProductType != VER_NT_SERVER)) {
142
143 // this is Client SKU
144
145 minWorkingSetTransferPackets = MIN_WORKINGSET_TRANSFER_PACKETS_Client;
146
147 // Note: the reason we use max here is to guarantee a reasonable large max number
148 // in the case where the port driver may return a very small supported outstanding
149 // IOs. For example, even EMMC drive only reports 1 outstanding IO supported, we
150 // may still want to set this value to be at least
151 // MAX_WORKINGSET_TRANSFER_PACKETS_Client.
152 maxWorkingSetTransferPackets = max(MAX_WORKINGSET_TRANSFER_PACKETS_Client,
153 2 * maxOutstandingIOPerLUN);
154
155 } else {
156
157 // this is Server SKU
158 // Note: the addition max here to make sure we set the min to be at least
159 // MIN_WORKINGSET_TRANSFER_PACKETS_Server_LowerBound no matter what maxOutstandingIOPerLUN
160 // reported. We shouldn't set this value to be smaller than client system.
161 // In other words, the minWorkingSetTransferPackets for server will always between
162 // MIN_WORKINGSET_TRANSFER_PACKETS_Server_LowerBound and MIN_WORKINGSET_TRANSFER_PACKETS_Server_UpperBound
163
164 minWorkingSetTransferPackets =
165 max(MIN_WORKINGSET_TRANSFER_PACKETS_Server_LowerBound,
166 min(MIN_WORKINGSET_TRANSFER_PACKETS_Server_UpperBound,
167 maxOutstandingIOPerLUN));
168
169 maxWorkingSetTransferPackets = max(MAX_WORKINGSET_TRANSFER_PACKETS_Server,
170 2 * maxOutstandingIOPerLUN);
171 }
172
173
174 fdoData->LocalMinWorkingSetTransferPackets = minWorkingSetTransferPackets;
175 fdoData->LocalMaxWorkingSetTransferPackets = maxWorkingSetTransferPackets;
176
177 //
178 // Allow class driver to override the settings
179 //
180 if (commonExt->DriverExtension->WorkingSet != NULL) {
181 PCLASS_WORKING_SET workingSet = commonExt->DriverExtension->WorkingSet;
182
183 // override only if non-zero
184 if (workingSet->XferPacketsWorkingSetMinimum != 0)
185 {
186 fdoData->LocalMinWorkingSetTransferPackets = workingSet->XferPacketsWorkingSetMinimum;
187 // adjust maximum upwards if needed
188 if (fdoData->LocalMaxWorkingSetTransferPackets < fdoData->LocalMinWorkingSetTransferPackets)
189 {
190 fdoData->LocalMaxWorkingSetTransferPackets = fdoData->LocalMinWorkingSetTransferPackets;
191 }
192 }
193 // override only if non-zero
194 if (workingSet->XferPacketsWorkingSetMaximum != 0)
195 {
196 fdoData->LocalMaxWorkingSetTransferPackets = workingSet->XferPacketsWorkingSetMaximum;
197 // adjust minimum downwards if needed
198 if (fdoData->LocalMinWorkingSetTransferPackets > fdoData->LocalMaxWorkingSetTransferPackets)
199 {
200 fdoData->LocalMinWorkingSetTransferPackets = fdoData->LocalMaxWorkingSetTransferPackets;
201 }
202 }
203 // that's all the adjustments required/allowed
204 } // end working set size special code
205
206 for (index = 0; index < arraySize; index++) {
207 while (fdoData->FreeTransferPacketsLists[index].NumFreeTransferPackets < MIN_INITIAL_TRANSFER_PACKETS){
208 PTRANSFER_PACKET pkt = NewTransferPacket(Fdo);
209 if (pkt) {
210 InterlockedIncrement((volatile LONG *)&(fdoData->FreeTransferPacketsLists[index].NumTotalTransferPackets));
211 pkt->AllocateNode = index;
212 EnqueueFreeTransferPacket(Fdo, pkt);
213 } else {
214 status = STATUS_INSUFFICIENT_RESOURCES;
215 break;
216 }
217 }
218 fdoData->FreeTransferPacketsLists[index].DbgPeakNumTransferPackets = fdoData->FreeTransferPacketsLists[index].NumTotalTransferPackets;
219 }
220
221 //
222 // Pre-initialize our SCSI_REQUEST_BLOCK template with all
223 // the constant fields. This will save a little time for each xfer.
224 // NOTE: a CdbLength field of 10 may not always be appropriate
225 //
226
227 if (NT_SUCCESS(status)) {
228 if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
229 ULONG ByteSize = 0;
230
231 #if (NTDDI_VERSION >= NTDDI_WINBLUE)
232 if ((fdoExt->MiniportDescriptor != NULL) &&
233 (fdoExt->MiniportDescriptor->Size >= RTL_SIZEOF_THROUGH_FIELD(STORAGE_MINIPORT_DESCRIPTOR, ExtraIoInfoSupported)) &&
234 (fdoExt->MiniportDescriptor->ExtraIoInfoSupported == TRUE)) {
235 status = CreateStorageRequestBlock((PSTORAGE_REQUEST_BLOCK *)&fdoData->SrbTemplate,
236 fdoExt->AdapterDescriptor->AddressType,
237 DefaultStorageRequestBlockAllocateRoutine,
238 &ByteSize,
239 2,
240 SrbExDataTypeScsiCdb16,
241 SrbExDataTypeIoInfo
242 );
243 } else {
244 status = CreateStorageRequestBlock((PSTORAGE_REQUEST_BLOCK *)&fdoData->SrbTemplate,
245 fdoExt->AdapterDescriptor->AddressType,
246 DefaultStorageRequestBlockAllocateRoutine,
247 &ByteSize,
248 1,
249 SrbExDataTypeScsiCdb16
250 );
251 }
252 #else
253 status = CreateStorageRequestBlock((PSTORAGE_REQUEST_BLOCK *)&fdoData->SrbTemplate,
254 fdoExt->AdapterDescriptor->AddressType,
255 DefaultStorageRequestBlockAllocateRoutine,
256 &ByteSize,
257 1,
258 SrbExDataTypeScsiCdb16
259 );
260 #endif
261 if (NT_SUCCESS(status)) {
262 ((PSTORAGE_REQUEST_BLOCK) fdoData->SrbTemplate)->SrbFunction = SRB_FUNCTION_EXECUTE_SCSI;
263 } else {
264 NT_ASSERT(FALSE);
265 }
266 } else {
267 fdoData->SrbTemplate = ExAllocatePoolWithTag(NonPagedPoolNx, sizeof(SCSI_REQUEST_BLOCK), '-brs');
268 if (fdoData->SrbTemplate == NULL) {
269 status = STATUS_INSUFFICIENT_RESOURCES;
270 } else {
271 RtlZeroMemory(fdoData->SrbTemplate, sizeof(SCSI_REQUEST_BLOCK));
272 fdoData->SrbTemplate->Length = sizeof(SCSI_REQUEST_BLOCK);
273 fdoData->SrbTemplate->Function = SRB_FUNCTION_EXECUTE_SCSI;
274 }
275 }
276 }
277
278 if (status == STATUS_SUCCESS) {
279 SrbSetRequestAttribute(fdoData->SrbTemplate, SRB_SIMPLE_TAG_REQUEST);
280 SrbSetSenseInfoBufferLength(fdoData->SrbTemplate, SENSE_BUFFER_SIZE_EX);
281 SrbSetCdbLength(fdoData->SrbTemplate, 10);
282 }
283
284 return status;
285 }
286
287
DestroyAllTransferPackets(PDEVICE_OBJECT Fdo)288 VOID DestroyAllTransferPackets(PDEVICE_OBJECT Fdo)
289 {
290 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
291 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
292 TRANSFER_PACKET *pkt;
293 ULONG index;
294 ULONG arraySize;
295
296 PAGED_CODE();
297
298 //
299 // fdoData->FreeTransferPacketsLists could be NULL if
300 // there was an error during start device.
301 //
302 if (fdoData->FreeTransferPacketsLists != NULL) {
303
304 NT_ASSERT(IsListEmpty(&fdoData->DeferredClientIrpList));
305
306 arraySize = KeQueryHighestNodeNumber() + 1;
307 for (index = 0; index < arraySize; index++) {
308 pkt = DequeueFreeTransferPacketEx(Fdo, FALSE, index);
309 while (pkt) {
310 DestroyTransferPacket(pkt);
311 InterlockedDecrement((volatile LONG *)&(fdoData->FreeTransferPacketsLists[index].NumTotalTransferPackets));
312 pkt = DequeueFreeTransferPacketEx(Fdo, FALSE, index);
313 }
314
315 NT_ASSERT(fdoData->FreeTransferPacketsLists[index].NumTotalTransferPackets == 0);
316 }
317 }
318
319 FREE_POOL(fdoData->SrbTemplate);
320 }
321
__drv_allocatesMem(Mem)322 __drv_allocatesMem(Mem)
323 #ifdef _MSC_VER
324 #pragma warning(suppress:28195) // This function may not allocate memory in some error cases.
325 #endif
326 PTRANSFER_PACKET NewTransferPacket(PDEVICE_OBJECT Fdo)
327 {
328 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
329 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
330 PTRANSFER_PACKET newPkt = NULL;
331 ULONG transferLength = (ULONG)-1;
332 NTSTATUS status = STATUS_SUCCESS;
333
334 if (NT_SUCCESS(status)) {
335 status = RtlULongAdd(fdoData->HwMaxXferLen, PAGE_SIZE, &transferLength);
336 if (!NT_SUCCESS(status)) {
337
338 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "Integer overflow in calculating transfer packet size."));
339 status = STATUS_INTEGER_OVERFLOW;
340 }
341 }
342
343 /*
344 * Allocate the actual packet.
345 */
346 if (NT_SUCCESS(status)) {
347 newPkt = ExAllocatePoolWithTag(NonPagedPoolNx, sizeof(TRANSFER_PACKET), 'pnPC');
348 if (newPkt == NULL) {
349 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "Failed to allocate transfer packet."));
350 status = STATUS_INSUFFICIENT_RESOURCES;
351 } else {
352 RtlZeroMemory(newPkt, sizeof(TRANSFER_PACKET));
353 newPkt->AllocateNode = KeGetCurrentNodeNumber();
354 if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
355 #if (NTDDI_VERSION >= NTDDI_WINBLUE)
356 if ((fdoExt->MiniportDescriptor != NULL) &&
357 (fdoExt->MiniportDescriptor->Size >= RTL_SIZEOF_THROUGH_FIELD(STORAGE_MINIPORT_DESCRIPTOR, ExtraIoInfoSupported)) &&
358 (fdoExt->MiniportDescriptor->ExtraIoInfoSupported == TRUE)) {
359 status = CreateStorageRequestBlock((PSTORAGE_REQUEST_BLOCK *)&newPkt->Srb,
360 fdoExt->AdapterDescriptor->AddressType,
361 DefaultStorageRequestBlockAllocateRoutine,
362 NULL,
363 2,
364 SrbExDataTypeScsiCdb16,
365 SrbExDataTypeIoInfo
366 );
367 } else {
368 status = CreateStorageRequestBlock((PSTORAGE_REQUEST_BLOCK *)&newPkt->Srb,
369 fdoExt->AdapterDescriptor->AddressType,
370 DefaultStorageRequestBlockAllocateRoutine,
371 NULL,
372 1,
373 SrbExDataTypeScsiCdb16
374 );
375 }
376 #else
377 status = CreateStorageRequestBlock((PSTORAGE_REQUEST_BLOCK *)&newPkt->Srb,
378 fdoExt->AdapterDescriptor->AddressType,
379 DefaultStorageRequestBlockAllocateRoutine,
380 NULL,
381 1,
382 SrbExDataTypeScsiCdb16
383 );
384 #endif
385 } else {
386 #ifdef _MSC_VER
387 #pragma prefast(suppress:6014, "The allocated memory that Pkt->Srb points to will be freed in DestroyTransferPacket().")
388 #endif
389 newPkt->Srb = ExAllocatePoolWithTag(NonPagedPoolNx, sizeof(SCSI_REQUEST_BLOCK), '-brs');
390 if (newPkt->Srb == NULL) {
391 status = STATUS_INSUFFICIENT_RESOURCES;
392 }
393
394 }
395
396 if (status != STATUS_SUCCESS)
397 {
398 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "Failed to allocate SRB."));
399 FREE_POOL(newPkt);
400 }
401 }
402 }
403
404 /*
405 * Allocate Irp for the packet.
406 */
407 if (NT_SUCCESS(status) && newPkt != NULL) {
408 newPkt->Irp = IoAllocateIrp(Fdo->StackSize, FALSE);
409 if (newPkt->Irp == NULL) {
410 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "Failed to allocate IRP for transfer packet."));
411 status = STATUS_INSUFFICIENT_RESOURCES;
412 }
413 }
414
415 /*
416 * Allocate a MDL. Add one page to the length to insure an extra page
417 * entry is allocated if the buffer does not start on page boundaries.
418 */
419 if (NT_SUCCESS(status) && newPkt != NULL) {
420
421 NT_ASSERT(transferLength != (ULONG)-1);
422
423 newPkt->PartialMdl = IoAllocateMdl(NULL,
424 transferLength,
425 FALSE,
426 FALSE,
427 NULL);
428 if (newPkt->PartialMdl == NULL) {
429 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "Failed to allocate MDL for transfer packet."));
430 status = STATUS_INSUFFICIENT_RESOURCES;
431 } else {
432 NT_ASSERT(newPkt->PartialMdl->Size >= (CSHORT)(sizeof(MDL) + BYTES_TO_PAGES(fdoData->HwMaxXferLen) * sizeof(PFN_NUMBER)));
433 }
434
435 }
436
437 /*
438 * Allocate per-packet retry history, if required
439 */
440 if (NT_SUCCESS(status) &&
441 (fdoData->InterpretSenseInfo != NULL) &&
442 (newPkt != NULL)
443 ) {
444 // attempt to allocate also the history
445 ULONG historyByteCount = 0;
446
447 // SAL annotation and ClassInitializeEx() should both catch this case
448 NT_ASSERT(fdoData->InterpretSenseInfo->HistoryCount != 0);
449 _Analysis_assume_(fdoData->InterpretSenseInfo->HistoryCount != 0);
450
451 historyByteCount = sizeof(SRB_HISTORY_ITEM) * fdoData->InterpretSenseInfo->HistoryCount;
452 historyByteCount += sizeof(SRB_HISTORY) - sizeof(SRB_HISTORY_ITEM);
453
454 newPkt->RetryHistory = (PSRB_HISTORY)ExAllocatePoolWithTag(NonPagedPoolNx, historyByteCount, 'hrPC');
455
456 if (newPkt->RetryHistory == NULL) {
457 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "Failed to allocate MDL for transfer packet."));
458 status = STATUS_INSUFFICIENT_RESOURCES;
459 } else {
460 // call this routine directly once since it's the first initialization of
461 // the structure and the internal maximum count field is not yet setup.
462 HistoryInitializeRetryLogs(newPkt->RetryHistory, fdoData->InterpretSenseInfo->HistoryCount);
463 }
464 }
465
466 /*
467 * Enqueue the packet in our static AllTransferPacketsList
468 * (just so we can find it during debugging if its stuck somewhere).
469 */
470 if (NT_SUCCESS(status) && newPkt != NULL)
471 {
472 KIRQL oldIrql;
473 newPkt->Fdo = Fdo;
474 #if DBG
475 newPkt->DbgPktId = InterlockedIncrement((volatile LONG *)&fdoData->DbgMaxPktId);
476 #endif
477 KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
478 InsertTailList(&fdoData->AllTransferPacketsList, &newPkt->AllPktsListEntry);
479 KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
480
481 } else {
482 // free any resources acquired above (in reverse order)
483 if (newPkt != NULL) {
484 FREE_POOL(newPkt->RetryHistory);
485 if (newPkt->PartialMdl != NULL) { IoFreeMdl(newPkt->PartialMdl); }
486 if (newPkt->Irp != NULL) { IoFreeIrp(newPkt->Irp); }
487 if (newPkt->Srb != NULL) { FREE_POOL(newPkt->Srb); }
488 FREE_POOL(newPkt);
489 }
490 }
491
492 return newPkt;
493 }
494
495
496 /*
497 * DestroyTransferPacket
498 *
499 */
DestroyTransferPacket(_In_ __drv_freesMem (mem)PTRANSFER_PACKET Pkt)500 VOID DestroyTransferPacket(_In_ __drv_freesMem(mem) PTRANSFER_PACKET Pkt)
501 {
502 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension;
503 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
504 KIRQL oldIrql;
505
506 NT_ASSERT(!Pkt->SlistEntry.Next);
507 // NT_ASSERT(!Pkt->OriginalIrp);
508
509 KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
510
511 /*
512 * Delete the packet from our all-packets queue.
513 */
514 NT_ASSERT(!IsListEmpty(&Pkt->AllPktsListEntry));
515 NT_ASSERT(!IsListEmpty(&fdoData->AllTransferPacketsList));
516 RemoveEntryList(&Pkt->AllPktsListEntry);
517 InitializeListHead(&Pkt->AllPktsListEntry);
518
519 KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
520
521 IoFreeMdl(Pkt->PartialMdl);
522 IoFreeIrp(Pkt->Irp);
523 FREE_POOL(Pkt->RetryHistory);
524 FREE_POOL(Pkt->Srb);
525 FREE_POOL(Pkt);
526 }
527
528
EnqueueFreeTransferPacket(PDEVICE_OBJECT Fdo,__drv_aliasesMem PTRANSFER_PACKET Pkt)529 VOID EnqueueFreeTransferPacket(PDEVICE_OBJECT Fdo, __drv_aliasesMem PTRANSFER_PACKET Pkt)
530 {
531 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
532 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
533 ULONG allocateNode;
534 KIRQL oldIrql;
535
536 NT_ASSERT(!Pkt->SlistEntry.Next);
537
538 allocateNode = Pkt->AllocateNode;
539 InterlockedPushEntrySList(&(fdoData->FreeTransferPacketsLists[allocateNode].SListHeader), &Pkt->SlistEntry);
540 InterlockedIncrement((volatile LONG *)&(fdoData->FreeTransferPacketsLists[allocateNode].NumFreeTransferPackets));
541
542 /*
543 * If the total number of packets is larger than LocalMinWorkingSetTransferPackets,
544 * that means that we've been in stress. If all those packets are now
545 * free, then we are now out of stress and can free the extra packets.
546 * Attempt to free down to LocalMaxWorkingSetTransferPackets immediately, and
547 * down to LocalMinWorkingSetTransferPackets lazily (one at a time).
548 * However, since we're at DPC, do this is a work item. If the device is removed
549 * or we are unable to allocate the work item, do NOT free more than
550 * MAX_CLEANUP_TRANSFER_PACKETS_AT_ONCE. Subsequent IO completions will end up freeing
551 * up the rest, even if it is MAX_CLEANUP_TRANSFER_PACKETS_AT_ONCE at a time.
552 */
553 if (fdoData->FreeTransferPacketsLists[allocateNode].NumFreeTransferPackets >=
554 fdoData->FreeTransferPacketsLists[allocateNode].NumTotalTransferPackets) {
555
556 /*
557 * 1. Immediately snap down to our UPPER threshold.
558 */
559 if (fdoData->FreeTransferPacketsLists[allocateNode].NumTotalTransferPackets >
560 fdoData->LocalMaxWorkingSetTransferPackets) {
561
562 ULONG isRemoved;
563 PIO_WORKITEM workItem = NULL;
564
565 workItem = IoAllocateWorkItem(Fdo);
566
567 //
568 // Acquire a remove lock in order to make sure the device object and its
569 // private data structures will exist when the workitem fires.
570 // The remove lock will be released by the workitem (CleanupTransferPacketToWorkingSetSize).
571 //
572 isRemoved = ClassAcquireRemoveLock(Fdo, (PIRP)workItem);
573
574 if (workItem && !isRemoved) {
575
576 TracePrint((TRACE_LEVEL_INFORMATION,
577 TRACE_FLAG_GENERAL,
578 "EnqueueFreeTransferPacket: Device (%p), queuing work item to clean up free transfer packets.\n",
579 Fdo));
580
581 //
582 // Queue a work item to trim down the total number of transfer packets to with the
583 // working size.
584 //
585 IoQueueWorkItemEx(workItem, CleanupTransferPacketToWorkingSetSizeWorker, DelayedWorkQueue, (PVOID)(ULONG_PTR)allocateNode);
586
587 } else {
588
589 if (workItem) {
590 IoFreeWorkItem(workItem);
591 }
592
593 if (isRemoved != REMOVE_COMPLETE) {
594 ClassReleaseRemoveLock(Fdo, (PIRP)workItem);
595 }
596
597 TracePrint((TRACE_LEVEL_ERROR,
598 TRACE_FLAG_GENERAL,
599 "EnqueueFreeTransferPacket: Device (%p), Failed to allocate memory for the work item.\n",
600 Fdo));
601
602 CleanupTransferPacketToWorkingSetSize(Fdo, TRUE, allocateNode);
603 }
604 }
605
606 /*
607 * 2. Lazily work down to our LOWER threshold (by only freeing one packet at a time).
608 */
609 if (fdoData->FreeTransferPacketsLists[allocateNode].NumTotalTransferPackets >
610 fdoData->LocalMinWorkingSetTransferPackets){
611 /*
612 * Check the counter again with lock held. This eliminates a race condition
613 * while still allowing us to not grab the spinlock in the common codepath.
614 *
615 * Note that the spinlock does not synchronize with threads dequeuing free
616 * packets to send (DequeueFreeTransferPacket does that with a lightweight
617 * interlocked exchange); the spinlock prevents multiple threads in this function
618 * from deciding to free too many extra packets at once.
619 */
620 PTRANSFER_PACKET pktToDelete = NULL;
621
622 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, "Exiting stress, lazily freeing one of %d/%d packets from node %d.",
623 fdoData->FreeTransferPacketsLists[allocateNode].NumTotalTransferPackets,
624 fdoData->LocalMinWorkingSetTransferPackets,
625 allocateNode));
626
627 KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
628 if ((fdoData->FreeTransferPacketsLists[allocateNode].NumFreeTransferPackets >=
629 fdoData->FreeTransferPacketsLists[allocateNode].NumTotalTransferPackets) &&
630 (fdoData->FreeTransferPacketsLists[allocateNode].NumTotalTransferPackets >
631 fdoData->LocalMinWorkingSetTransferPackets)){
632
633 pktToDelete = DequeueFreeTransferPacketEx(Fdo, FALSE, allocateNode);
634 if (pktToDelete) {
635 InterlockedDecrement((volatile LONG *)&(fdoData->FreeTransferPacketsLists[allocateNode].NumTotalTransferPackets));
636 } else {
637 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW,
638 "Extremely unlikely condition (non-fatal): %d packets dequeued at once for Fdo %p. NumTotalTransferPackets=%d (2). Node=%d",
639 fdoData->LocalMinWorkingSetTransferPackets,
640 Fdo,
641 fdoData->FreeTransferPacketsLists[allocateNode].NumTotalTransferPackets,
642 allocateNode));
643 }
644 }
645 KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
646
647 if (pktToDelete) {
648 DestroyTransferPacket(pktToDelete);
649 }
650 }
651
652 }
653
654 }
655
DequeueFreeTransferPacket(PDEVICE_OBJECT Fdo,BOOLEAN AllocIfNeeded)656 PTRANSFER_PACKET DequeueFreeTransferPacket(PDEVICE_OBJECT Fdo, BOOLEAN AllocIfNeeded)
657 {
658 return DequeueFreeTransferPacketEx(Fdo, AllocIfNeeded, KeGetCurrentNodeNumber());
659 }
660
DequeueFreeTransferPacketEx(_In_ PDEVICE_OBJECT Fdo,_In_ BOOLEAN AllocIfNeeded,_In_ ULONG Node)661 PTRANSFER_PACKET DequeueFreeTransferPacketEx(
662 _In_ PDEVICE_OBJECT Fdo,
663 _In_ BOOLEAN AllocIfNeeded,
664 _In_ ULONG Node)
665 {
666 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
667 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
668 PTRANSFER_PACKET pkt;
669 PSLIST_ENTRY slistEntry;
670
671 slistEntry = InterlockedPopEntrySList(&(fdoData->FreeTransferPacketsLists[Node].SListHeader));
672
673 if (slistEntry) {
674 slistEntry->Next = NULL;
675 pkt = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry);
676 InterlockedDecrement((volatile LONG *)&(fdoData->FreeTransferPacketsLists[Node].NumFreeTransferPackets));
677
678 // when dequeuing the packet, also reset the history data
679 HISTORYINITIALIZERETRYLOGS(pkt);
680
681 } else {
682 if (AllocIfNeeded) {
683 /*
684 * We are in stress and have run out of lookaside packets.
685 * In order to service the current transfer,
686 * allocate an extra packet.
687 * We will free it lazily when we are out of stress.
688 */
689 pkt = NewTransferPacket(Fdo);
690 if (pkt) {
691 InterlockedIncrement((volatile LONG *)&fdoData->FreeTransferPacketsLists[Node].NumTotalTransferPackets);
692 fdoData->FreeTransferPacketsLists[Node].DbgPeakNumTransferPackets =
693 max(fdoData->FreeTransferPacketsLists[Node].DbgPeakNumTransferPackets,
694 fdoData->FreeTransferPacketsLists[Node].NumTotalTransferPackets);
695 } else {
696 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "DequeueFreeTransferPacket: packet allocation failed"));
697 }
698 } else {
699 pkt = NULL;
700 }
701 }
702
703 return pkt;
704 }
705
706
707
708 /*
709 * SetupReadWriteTransferPacket
710 *
711 * This function is called once to set up the first attempt to send a packet.
712 * It is not called before a retry, as SRB fields may be modified for the retry.
713 *
714 * Set up the Srb of the TRANSFER_PACKET for the transfer.
715 * The Irp is set up in SubmitTransferPacket because it must be reset
716 * for each packet submission.
717 */
SetupReadWriteTransferPacket(PTRANSFER_PACKET Pkt,PVOID Buf,ULONG Len,LARGE_INTEGER DiskLocation,PIRP OriginalIrp)718 VOID SetupReadWriteTransferPacket( PTRANSFER_PACKET Pkt,
719 PVOID Buf,
720 ULONG Len,
721 LARGE_INTEGER DiskLocation,
722 PIRP OriginalIrp)
723 {
724 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension;
725 PCOMMON_DEVICE_EXTENSION commonExtension = Pkt->Fdo->DeviceExtension;
726 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
727 PIO_STACK_LOCATION origCurSp = IoGetCurrentIrpStackLocation(OriginalIrp);
728 UCHAR majorFunc = origCurSp->MajorFunction;
729 LARGE_INTEGER logicalBlockAddr;
730 ULONG numTransferBlocks;
731 PCDB pCdb;
732 ULONG srbLength;
733 ULONG timeoutValue = fdoExt->TimeOutValue;
734
735 logicalBlockAddr.QuadPart = Int64ShrlMod32(DiskLocation.QuadPart, fdoExt->SectorShift);
736 numTransferBlocks = Len >> fdoExt->SectorShift;
737
738 /*
739 * This field is useful when debugging, since low-memory conditions are
740 * handled differently for CDROM (which is the only driver using StartIO)
741 */
742 Pkt->DriverUsesStartIO = (commonExtension->DriverExtension->InitData.ClassStartIo != NULL);
743
744 /*
745 * Slap the constant SRB fields in from our pre-initialized template.
746 * We'll then only have to fill in the unique fields for this transfer.
747 * Tell lower drivers to sort the SRBs by the logical block address
748 * so that disk seeks are minimized.
749 */
750 if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
751 srbLength = ((PSTORAGE_REQUEST_BLOCK) fdoData->SrbTemplate)->SrbLength;
752 NT_ASSERT(((PSTORAGE_REQUEST_BLOCK) Pkt->Srb)->SrbLength >= srbLength);
753 } else {
754 srbLength = fdoData->SrbTemplate->Length;
755 }
756 RtlCopyMemory(Pkt->Srb, fdoData->SrbTemplate, srbLength); // copies _contents_ of SRB blocks
757 SrbSetDataBuffer(Pkt->Srb, Buf);
758 SrbSetDataTransferLength(Pkt->Srb, Len);
759 SrbSetQueueSortKey(Pkt->Srb, logicalBlockAddr.LowPart);
760 if (logicalBlockAddr.QuadPart > 0xFFFFFFFF) {
761 //
762 // If the requested LBA is more than max ULONG set the
763 // QueueSortKey to the maximum value, so that these
764 // requests can be added towards the end of the queue.
765 //
766
767 SrbSetQueueSortKey(Pkt->Srb, 0xFFFFFFFF);
768 }
769 SrbSetOriginalRequest(Pkt->Srb, Pkt->Irp);
770 SrbSetSenseInfoBuffer(Pkt->Srb, &Pkt->SrbErrorSenseData);
771
772
773 SrbSetTimeOutValue(Pkt->Srb, timeoutValue);
774
775 /*
776 * Arrange values in CDB in big-endian format.
777 */
778 pCdb = SrbGetCdb(Pkt->Srb);
779 if (pCdb) {
780 if (TEST_FLAG(fdoExt->DeviceFlags, DEV_USE_16BYTE_CDB)) {
781 REVERSE_BYTES_QUAD(&pCdb->CDB16.LogicalBlock, &logicalBlockAddr);
782 REVERSE_BYTES(&pCdb->CDB16.TransferLength, &numTransferBlocks);
783 pCdb->CDB16.OperationCode = (majorFunc==IRP_MJ_READ) ? SCSIOP_READ16 : SCSIOP_WRITE16;
784 SrbSetCdbLength(Pkt->Srb, 16);
785 } else {
786 pCdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&logicalBlockAddr.LowPart)->Byte3;
787 pCdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&logicalBlockAddr.LowPart)->Byte2;
788 pCdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&logicalBlockAddr.LowPart)->Byte1;
789 pCdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&logicalBlockAddr.LowPart)->Byte0;
790 pCdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&numTransferBlocks)->Byte1;
791 pCdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&numTransferBlocks)->Byte0;
792 pCdb->CDB10.OperationCode = (majorFunc==IRP_MJ_READ) ? SCSIOP_READ : SCSIOP_WRITE;
793 }
794 }
795
796 /*
797 * Set SRB and IRP flags
798 */
799 SrbAssignSrbFlags(Pkt->Srb, fdoExt->SrbFlags);
800 if (TEST_FLAG(OriginalIrp->Flags, IRP_PAGING_IO) ||
801 TEST_FLAG(OriginalIrp->Flags, IRP_SYNCHRONOUS_PAGING_IO)){
802 SrbSetSrbFlags(Pkt->Srb, SRB_CLASS_FLAGS_PAGING);
803 }
804 SrbSetSrbFlags(Pkt->Srb, (majorFunc==IRP_MJ_READ) ? SRB_FLAGS_DATA_IN : SRB_FLAGS_DATA_OUT);
805
806 /*
807 * Allow caching only if this is not a write-through request.
808 * If write-through and caching is enabled on the device, force
809 * media access.
810 * Ignore SL_WRITE_THROUGH for reads; it's only set because the file handle was opened with WRITE_THROUGH.
811 */
812 if ((majorFunc == IRP_MJ_WRITE) && TEST_FLAG(origCurSp->Flags, SL_WRITE_THROUGH) && pCdb) {
813 pCdb->CDB10.ForceUnitAccess = fdoExt->CdbForceUnitAccess;
814 } else {
815 SrbSetSrbFlags(Pkt->Srb, SRB_FLAGS_ADAPTER_CACHE_ENABLE);
816 }
817
818 /*
819 * Remember the buf and len in the SRB because miniports
820 * can overwrite SRB.DataTransferLength and we may need it again
821 * for the retry.
822 */
823 Pkt->BufPtrCopy = Buf;
824 Pkt->BufLenCopy = Len;
825 Pkt->TargetLocationCopy = DiskLocation;
826
827 Pkt->OriginalIrp = OriginalIrp;
828 Pkt->NumRetries = fdoData->MaxNumberOfIoRetries;
829 Pkt->SyncEventPtr = NULL;
830 Pkt->CompleteOriginalIrpWhenLastPacketCompletes = TRUE;
831 #if !defined(__REACTOS__) && NTDDI_VERSION >= NTDDI_WINBLUE
832 Pkt->NumIoTimeoutRetries = fdoData->MaxNumberOfIoRetries;
833 Pkt->NumThinProvisioningRetries = 0;
834 #endif
835
836
837 if (pCdb) {
838 DBGLOGFLUSHINFO(fdoData, TRUE, (BOOLEAN)(pCdb->CDB10.ForceUnitAccess), FALSE);
839 } else {
840 DBGLOGFLUSHINFO(fdoData, TRUE, FALSE, FALSE);
841 }
842 }
843
844
845 /*
846 * SubmitTransferPacket
847 *
848 * Set up the IRP for the TRANSFER_PACKET submission and send it down.
849 */
SubmitTransferPacket(PTRANSFER_PACKET Pkt)850 NTSTATUS SubmitTransferPacket(PTRANSFER_PACKET Pkt)
851 {
852 PCOMMON_DEVICE_EXTENSION commonExtension = Pkt->Fdo->DeviceExtension;
853 PDEVICE_OBJECT nextDevObj = commonExtension->LowerDeviceObject;
854 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Pkt->Fdo->DeviceExtension;
855 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
856 BOOLEAN idleRequest = FALSE;
857 PIO_STACK_LOCATION nextSp;
858
859 NT_ASSERT(Pkt->Irp->CurrentLocation == Pkt->Irp->StackCount+1);
860
861 /*
862 * Attach the SRB to the IRP.
863 * The reused IRP's stack location has to be rewritten for each retry
864 * call because IoCompleteRequest clears the stack locations.
865 */
866 IoReuseIrp(Pkt->Irp, STATUS_NOT_SUPPORTED);
867
868
869 nextSp = IoGetNextIrpStackLocation(Pkt->Irp);
870 nextSp->MajorFunction = IRP_MJ_SCSI;
871 nextSp->Parameters.Scsi.Srb = (PSCSI_REQUEST_BLOCK)Pkt->Srb;
872
873 SrbSetScsiStatus(Pkt->Srb, 0);
874 Pkt->Srb->SrbStatus = 0;
875 SrbSetSenseInfoBufferLength(Pkt->Srb, SENSE_BUFFER_SIZE_EX);
876
877 if (Pkt->CompleteOriginalIrpWhenLastPacketCompletes) {
878 /*
879 * Only dereference the "original IRP"'s stack location
880 * if its a real client irp (as opposed to a static irp
881 * we're using just for result status for one of the non-IO scsi commands).
882 *
883 * For read/write, propagate the storage-specific IRP stack location flags
884 * (e.g. SL_OVERRIDE_VERIFY_VOLUME, SL_WRITE_THROUGH).
885 */
886 PIO_STACK_LOCATION origCurSp = IoGetCurrentIrpStackLocation(Pkt->OriginalIrp);
887 nextSp->Flags = origCurSp->Flags;
888 }
889
890 //
891 // If the request is not split, we can use the original IRP MDL. If the
892 // request needs to be split, we need to use a partial MDL. The partial MDL
893 // is needed because more than one driver might be mapping the same MDL
894 // and this causes problems.
895 //
896 if (Pkt->UsePartialMdl == FALSE) {
897 Pkt->Irp->MdlAddress = Pkt->OriginalIrp->MdlAddress;
898 } else {
899 IoBuildPartialMdl(Pkt->OriginalIrp->MdlAddress, Pkt->PartialMdl, SrbGetDataBuffer(Pkt->Srb), SrbGetDataTransferLength(Pkt->Srb));
900 Pkt->Irp->MdlAddress = Pkt->PartialMdl;
901 }
902
903
904 DBGLOGSENDPACKET(Pkt);
905 HISTORYLOGSENDPACKET(Pkt);
906
907 //
908 // Set the original irp here for SFIO.
909 //
910 ClasspSrbSetOriginalIrp(Pkt->Srb, (PVOID) (Pkt->OriginalIrp));
911
912 //
913 // No need to lock for IdlePrioritySupported, since it will
914 // be modified only at initialization time.
915 //
916 if (fdoData->IdlePrioritySupported == TRUE) {
917 idleRequest = ClasspIsIdleRequest(Pkt->OriginalIrp);
918 if (idleRequest) {
919 InterlockedIncrement(&fdoData->ActiveIdleIoCount);
920 } else {
921 InterlockedIncrement(&fdoData->ActiveIoCount);
922 }
923 }
924
925 IoSetCompletionRoutine(Pkt->Irp, TransferPktComplete, Pkt, TRUE, TRUE, TRUE);
926 return IoCallDriver(nextDevObj, Pkt->Irp);
927 }
928
929
930 NTSTATUS
931 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
TransferPktComplete(IN PDEVICE_OBJECT NullFdo,IN PIRP Irp,IN PVOID Context)932 TransferPktComplete(IN PDEVICE_OBJECT NullFdo, IN PIRP Irp, IN PVOID Context)
933 {
934 PTRANSFER_PACKET pkt = (PTRANSFER_PACKET)Context;
935 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = pkt->Fdo->DeviceExtension;
936 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
937 BOOLEAN packetDone = FALSE;
938 BOOLEAN idleRequest = FALSE;
939 ULONG transferLength;
940 LARGE_INTEGER completionTime;
941 ULONGLONG lastIoCompletionTime;
942
943 UNREFERENCED_PARAMETER(NullFdo);
944
945 /*
946 * Put all the assertions and spew in here so we don't have to look at them.
947 */
948 DBGLOGRETURNPACKET(pkt);
949 DBGCHECKRETURNEDPKT(pkt);
950 HISTORYLOGRETURNEDPACKET(pkt);
951
952
953 completionTime = ClasspGetCurrentTime();
954
955 //
956 // Record the time at which the last IO completed while snapping the old
957 // value to be used later. This can occur on multiple threads and hence
958 // could be overwritten with an older value. This is OK because this value
959 // is maintained as a heuristic.
960 //
961
962 #ifdef _WIN64
963 #ifndef __REACTOS__
964 lastIoCompletionTime = ReadULong64NoFence((volatile ULONG64*)&fdoData->LastIoCompletionTime.QuadPart);
965 WriteULong64NoFence((volatile ULONG64*)&fdoData->LastIoCompletionTime.QuadPart,
966 completionTime.QuadPart);
967 #else
968 lastIoCompletionTime = *(volatile ULONG64*)&fdoData->LastIoCompletionTime.QuadPart;
969 *((volatile ULONG64*)&fdoData->LastIoCompletionTime.QuadPart) = completionTime.QuadPart;
970 #endif
971 #else
972 lastIoCompletionTime = InterlockedExchangeNoFence64((volatile LONG64*)&fdoData->LastIoCompletionTime.QuadPart,
973 completionTime.QuadPart);
974 #endif
975
976 if (fdoData->IdlePrioritySupported == TRUE) {
977 idleRequest = ClasspIsIdleRequest(pkt->OriginalIrp);
978 if (idleRequest) {
979 InterlockedDecrement(&fdoData->ActiveIdleIoCount);
980 NT_ASSERT(fdoData->ActiveIdleIoCount >= 0);
981 } else {
982 fdoData->LastNonIdleIoTime = completionTime;
983 InterlockedDecrement(&fdoData->ActiveIoCount);
984 NT_ASSERT(fdoData->ActiveIoCount >= 0);
985 }
986 }
987
988 //
989 // If partial MDL was used, unmap the pages. When the packet is retried, the
990 // MDL will be recreated. If the packet is done, the MDL will be ready to be reused.
991 //
992 if (pkt->UsePartialMdl) {
993 MmPrepareMdlForReuse(pkt->PartialMdl);
994 }
995
996 if (SRB_STATUS(pkt->Srb->SrbStatus) == SRB_STATUS_SUCCESS) {
997
998 NT_ASSERT(NT_SUCCESS(Irp->IoStatus.Status));
999
1000 transferLength = SrbGetDataTransferLength(pkt->Srb);
1001
1002 fdoData->LoggedTURFailureSinceLastIO = FALSE;
1003
1004 /*
1005 * The port driver should not have allocated a sense buffer
1006 * if the SRB succeeded.
1007 */
1008 NT_ASSERT(!PORT_ALLOCATED_SENSE_EX(fdoExt, pkt->Srb));
1009
1010 /*
1011 * Add this packet's transferred length to the original IRP's.
1012 */
1013 InterlockedExchangeAdd((PLONG)&pkt->OriginalIrp->IoStatus.Information,
1014 (LONG)transferLength);
1015
1016
1017 if ((pkt->InLowMemRetry) ||
1018 (pkt->DriverUsesStartIO && pkt->LowMemRetry_remainingBufLen > 0)) {
1019 packetDone = StepLowMemRetry(pkt);
1020 } else {
1021 packetDone = TRUE;
1022 }
1023
1024 }
1025 else {
1026 /*
1027 * The packet failed. We may retry it if possible.
1028 */
1029 BOOLEAN shouldRetry;
1030
1031 /*
1032 * Make sure IRP status matches SRB error status (since we propagate it).
1033 */
1034 if (NT_SUCCESS(Irp->IoStatus.Status)){
1035 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
1036 }
1037
1038 /*
1039 * The packet failed.
1040 * So when sending the packet down we either saw either an error or STATUS_PENDING,
1041 * and so we returned STATUS_PENDING for the original IRP.
1042 * So now we must mark the original irp pending to match that, _regardless_ of
1043 * whether we actually switch threads here by retrying.
1044 * (We also have to mark the irp pending if the lower driver marked the irp pending;
1045 * that is dealt with farther down).
1046 */
1047 if (pkt->CompleteOriginalIrpWhenLastPacketCompletes){
1048 IoMarkIrpPending(pkt->OriginalIrp);
1049 }
1050
1051 /*
1052 * Interpret the SRB error (to a meaningful IRP status)
1053 * and determine if we should retry this packet.
1054 * This call looks at the returned SENSE info to figure out what to do.
1055 */
1056 shouldRetry = InterpretTransferPacketError(pkt);
1057
1058 /*
1059 * If the SRB queue is locked-up, release it.
1060 * Do this after calling the error handler.
1061 */
1062 if (pkt->Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN){
1063 ClassReleaseQueue(pkt->Fdo);
1064 }
1065
1066
1067 if (NT_SUCCESS(Irp->IoStatus.Status)){
1068 /*
1069 * The error was recovered above in the InterpretTransferPacketError() call.
1070 */
1071
1072 NT_ASSERT(!shouldRetry);
1073
1074 /*
1075 * In the case of a recovered error,
1076 * add the transfer length to the original Irp as we would in the success case.
1077 */
1078 InterlockedExchangeAdd((PLONG)&pkt->OriginalIrp->IoStatus.Information,
1079 (LONG)SrbGetDataTransferLength(pkt->Srb));
1080
1081 if ((pkt->InLowMemRetry) ||
1082 (pkt->DriverUsesStartIO && pkt->LowMemRetry_remainingBufLen > 0)) {
1083 packetDone = StepLowMemRetry(pkt);
1084 } else {
1085 packetDone = TRUE;
1086 }
1087 } else {
1088 if (shouldRetry && (pkt->NumRetries > 0)){
1089 packetDone = RetryTransferPacket(pkt);
1090 } else if (shouldRetry && (pkt->RetryHistory != NULL)){
1091 // don't limit retries if class driver has custom interpretation routines
1092 packetDone = RetryTransferPacket(pkt);
1093 } else {
1094 packetDone = TRUE;
1095 }
1096 }
1097 }
1098
1099 /*
1100 * If the packet is completed, put it back in the free list.
1101 * If it is the last packet servicing the original request, complete the original irp.
1102 */
1103 if (packetDone){
1104 LONG numPacketsRemaining;
1105 PIRP deferredIrp;
1106 PDEVICE_OBJECT Fdo = pkt->Fdo;
1107 UCHAR uniqueAddr = 0;
1108
1109 /*
1110 * In case a remove is pending, bump the lock count so we don't get freed
1111 * right after we complete the original irp.
1112 */
1113 ClassAcquireRemoveLock(Fdo, (PVOID)&uniqueAddr);
1114
1115
1116 /*
1117 * Sometimes the port driver can allocates a new 'sense' buffer
1118 * to report transfer errors, e.g. when the default sense buffer
1119 * is too small. If so, it is up to us to free it.
1120 * Now that we're done using the sense info, free it if appropriate.
1121 * Then clear the sense buffer so it doesn't pollute future errors returned in this packet.
1122 */
1123 if (PORT_ALLOCATED_SENSE_EX(fdoExt, pkt->Srb)) {
1124 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, "Freeing port-allocated sense buffer for pkt %ph.", pkt));
1125 FREE_PORT_ALLOCATED_SENSE_BUFFER_EX(fdoExt, pkt->Srb);
1126 SrbSetSenseInfoBuffer(pkt->Srb, &pkt->SrbErrorSenseData);
1127 SrbSetSenseInfoBufferLength(pkt->Srb, sizeof(pkt->SrbErrorSenseData));
1128 } else {
1129 NT_ASSERT(SrbGetSenseInfoBuffer(pkt->Srb) == &pkt->SrbErrorSenseData);
1130 NT_ASSERT(SrbGetSenseInfoBufferLength(pkt->Srb) <= sizeof(pkt->SrbErrorSenseData));
1131 }
1132
1133 RtlZeroMemory(&pkt->SrbErrorSenseData, sizeof(pkt->SrbErrorSenseData));
1134
1135 /*
1136 * Call IoSetMasterIrpStatus to set appropriate status
1137 * for the Master IRP.
1138 */
1139 IoSetMasterIrpStatus(pkt->OriginalIrp, Irp->IoStatus.Status);
1140
1141 if (!NT_SUCCESS(Irp->IoStatus.Status)){
1142 /*
1143 * If the original I/O originated in user space (i.e. it is thread-queued),
1144 * and the error is user-correctable (e.g. media is missing, for removable media),
1145 * alert the user.
1146 * Since this is only one of possibly several packets completing for the original IRP,
1147 * we may do this more than once for a single request. That's ok; this allows
1148 * us to test each returned status with IoIsErrorUserInduced().
1149 */
1150 if (IoIsErrorUserInduced(Irp->IoStatus.Status) &&
1151 pkt->CompleteOriginalIrpWhenLastPacketCompletes &&
1152 pkt->OriginalIrp->Tail.Overlay.Thread){
1153
1154 IoSetHardErrorOrVerifyDevice(pkt->OriginalIrp, Fdo);
1155 }
1156 }
1157
1158 /*
1159 * We use a field in the original IRP to count
1160 * down the transfer pieces as they complete.
1161 */
1162 numPacketsRemaining = InterlockedDecrement(
1163 (PLONG)&pkt->OriginalIrp->Tail.Overlay.DriverContext[0]);
1164
1165 if (numPacketsRemaining > 0){
1166 /*
1167 * More transfer pieces remain for the original request.
1168 * Wait for them to complete before completing the original irp.
1169 */
1170 } else {
1171
1172 /*
1173 * All the transfer pieces are done.
1174 * Complete the original irp if appropriate.
1175 */
1176 NT_ASSERT(numPacketsRemaining == 0);
1177 if (pkt->CompleteOriginalIrpWhenLastPacketCompletes){
1178
1179 IO_PAGING_PRIORITY priority = (TEST_FLAG(pkt->OriginalIrp->Flags, IRP_PAGING_IO)) ? IoGetPagingIoPriority(pkt->OriginalIrp) : IoPagingPriorityInvalid;
1180 KIRQL oldIrql;
1181
1182 if (NT_SUCCESS(pkt->OriginalIrp->IoStatus.Status)){
1183 NT_ASSERT((ULONG)pkt->OriginalIrp->IoStatus.Information == IoGetCurrentIrpStackLocation(pkt->OriginalIrp)->Parameters.Read.Length);
1184 ClasspPerfIncrementSuccessfulIo(fdoExt);
1185 }
1186 ClassReleaseRemoveLock(Fdo, pkt->OriginalIrp);
1187
1188 /*
1189 * We submitted all the downward irps, including this last one, on the thread
1190 * that the OriginalIrp came in on. So the OriginalIrp is completing on a
1191 * different thread iff this last downward irp is completing on a different thread.
1192 * If BlkCache is loaded, for example, it will often complete
1193 * requests out of the cache on the same thread, therefore not marking the downward
1194 * irp pending and not requiring us to do so here. If the downward request is completing
1195 * on the same thread, then by not marking the OriginalIrp pending we can save an APC
1196 * and get extra perf benefit out of BlkCache.
1197 * Note that if the packet ever cycled due to retry or LowMemRetry,
1198 * we set the pending bit in those codepaths.
1199 */
1200 if (pkt->Irp->PendingReturned){
1201 IoMarkIrpPending(pkt->OriginalIrp);
1202 }
1203
1204
1205 ClassCompleteRequest(Fdo, pkt->OriginalIrp, IO_DISK_INCREMENT);
1206
1207 //
1208 // Drop the count only after completing the request, to give
1209 // Mm some amount of time to issue its next critical request
1210 //
1211
1212 if (priority == IoPagingPriorityHigh)
1213 {
1214 KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
1215
1216 if (fdoData->MaxInterleavedNormalIo < ClassMaxInterleavePerCriticalIo)
1217 {
1218 fdoData->MaxInterleavedNormalIo = 0;
1219 } else {
1220 fdoData->MaxInterleavedNormalIo -= ClassMaxInterleavePerCriticalIo;
1221 }
1222
1223 fdoData->NumHighPriorityPagingIo--;
1224
1225 if (fdoData->NumHighPriorityPagingIo == 0)
1226 {
1227 LARGE_INTEGER period;
1228
1229 //
1230 // Exiting throttle mode
1231 //
1232
1233 KeQuerySystemTime(&fdoData->ThrottleStopTime);
1234
1235 period.QuadPart = fdoData->ThrottleStopTime.QuadPart - fdoData->ThrottleStartTime.QuadPart;
1236 fdoData->LongestThrottlePeriod.QuadPart = max(fdoData->LongestThrottlePeriod.QuadPart, period.QuadPart);
1237 }
1238
1239 KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
1240 }
1241
1242 if (idleRequest) {
1243 ClasspCompleteIdleRequest(fdoExt);
1244 }
1245
1246 /*
1247 * We may have been called by one of the class drivers (e.g. cdrom)
1248 * via the legacy API ClassSplitRequest.
1249 * This is the only case for which the packet engine is called for an FDO
1250 * with a StartIo routine; in that case, we have to call IoStartNextPacket
1251 * now that the original irp has been completed.
1252 */
1253 if (fdoExt->CommonExtension.DriverExtension->InitData.ClassStartIo) {
1254 if (TEST_FLAG(SrbGetSrbFlags(pkt->Srb), SRB_FLAGS_DONT_START_NEXT_PACKET)){
1255 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, "SRB_FLAGS_DONT_START_NEXT_PACKET should never be set here (?)"));
1256 } else {
1257 KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
1258 IoStartNextPacket(Fdo, TRUE); // yes, some IO is now cancellable
1259 KeLowerIrql(oldIrql);
1260 }
1261 }
1262 }
1263 }
1264
1265 /*
1266 * If the packet was synchronous, write the final result back to the issuer's status buffer
1267 * and signal his event.
1268 */
1269 if (pkt->SyncEventPtr){
1270 KeSetEvent(pkt->SyncEventPtr, 0, FALSE);
1271 pkt->SyncEventPtr = NULL;
1272 }
1273
1274 /*
1275 * If the operation isn't a normal read/write, but needs to do more
1276 * operation-specific processing, call the operation's continuation
1277 * routine. The operation may create and queue another transfer packet
1278 * within this routine, but pkt is still freed after returning from the
1279 * continuation routine.
1280 */
1281 if (pkt->ContinuationRoutine != NULL){
1282 pkt->ContinuationRoutine(pkt->ContinuationContext);
1283 pkt->ContinuationRoutine = NULL;
1284 }
1285
1286 /*
1287 * Free the completed packet.
1288 */
1289 pkt->UsePartialMdl = FALSE;
1290 // pkt->OriginalIrp = NULL;
1291 pkt->InLowMemRetry = FALSE;
1292 EnqueueFreeTransferPacket(Fdo, pkt);
1293
1294 /*
1295 * Now that we have freed some resources,
1296 * try again to send one of the previously deferred irps.
1297 */
1298 deferredIrp = DequeueDeferredClientIrp(Fdo);
1299 if (deferredIrp){
1300 ServiceTransferRequest(Fdo, deferredIrp, TRUE);
1301 }
1302
1303 ClassReleaseRemoveLock(Fdo, (PVOID)&uniqueAddr);
1304 }
1305
1306 return STATUS_MORE_PROCESSING_REQUIRED;
1307 }
1308
1309
1310 /*
1311 * SetupEjectionTransferPacket
1312 *
1313 * Set up a transferPacket for a synchronous Ejection Control transfer.
1314 */
SetupEjectionTransferPacket(TRANSFER_PACKET * Pkt,BOOLEAN PreventMediaRemoval,PKEVENT SyncEventPtr,PIRP OriginalIrp)1315 VOID SetupEjectionTransferPacket( TRANSFER_PACKET *Pkt,
1316 BOOLEAN PreventMediaRemoval,
1317 PKEVENT SyncEventPtr,
1318 PIRP OriginalIrp)
1319 {
1320 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension;
1321 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
1322 PCDB pCdb;
1323 ULONG srbLength;
1324
1325 PAGED_CODE();
1326
1327 if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1328 srbLength = ((PSTORAGE_REQUEST_BLOCK) fdoData->SrbTemplate)->SrbLength;
1329 NT_ASSERT(((PSTORAGE_REQUEST_BLOCK) Pkt->Srb)->SrbLength >= srbLength);
1330 } else {
1331 srbLength = fdoData->SrbTemplate->Length;
1332 }
1333 RtlCopyMemory(Pkt->Srb, fdoData->SrbTemplate, srbLength); // copies _contents_ of SRB blocks
1334
1335 SrbSetRequestAttribute(Pkt->Srb, SRB_SIMPLE_TAG_REQUEST);
1336 SrbSetCdbLength(Pkt->Srb, 6);
1337 SrbSetOriginalRequest(Pkt->Srb, Pkt->Irp);
1338 SrbSetSenseInfoBuffer(Pkt->Srb, &Pkt->SrbErrorSenseData);
1339 SrbSetSenseInfoBufferLength(Pkt->Srb, sizeof(Pkt->SrbErrorSenseData));
1340 SrbSetTimeOutValue(Pkt->Srb, fdoExt->TimeOutValue);
1341
1342 SrbAssignSrbFlags(Pkt->Srb, fdoExt->SrbFlags | SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_QUEUE_FREEZE);
1343
1344 pCdb = SrbGetCdb(Pkt->Srb);
1345 if (pCdb) {
1346 pCdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
1347 pCdb->MEDIA_REMOVAL.Prevent = PreventMediaRemoval;
1348 }
1349
1350 Pkt->BufPtrCopy = NULL;
1351 Pkt->BufLenCopy = 0;
1352
1353 Pkt->OriginalIrp = OriginalIrp;
1354 Pkt->NumRetries = NUM_LOCKMEDIAREMOVAL_RETRIES;
1355 Pkt->SyncEventPtr = SyncEventPtr;
1356 Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE;
1357 }
1358
1359
1360 /*
1361 * SetupModeSenseTransferPacket
1362 *
1363 * Set up a transferPacket for a synchronous Mode Sense transfer.
1364 */
SetupModeSenseTransferPacket(TRANSFER_PACKET * Pkt,PKEVENT SyncEventPtr,PVOID ModeSenseBuffer,UCHAR ModeSenseBufferLen,UCHAR PageMode,UCHAR SubPage,PIRP OriginalIrp,UCHAR PageControl)1365 VOID SetupModeSenseTransferPacket(TRANSFER_PACKET *Pkt,
1366 PKEVENT SyncEventPtr,
1367 PVOID ModeSenseBuffer,
1368 UCHAR ModeSenseBufferLen,
1369 UCHAR PageMode,
1370 UCHAR SubPage,
1371 PIRP OriginalIrp,
1372 UCHAR PageControl)
1373
1374 {
1375 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension;
1376 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
1377 PCDB pCdb;
1378 ULONG srbLength;
1379
1380 PAGED_CODE();
1381
1382 if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1383 srbLength = ((PSTORAGE_REQUEST_BLOCK) fdoData->SrbTemplate)->SrbLength;
1384 NT_ASSERT(((PSTORAGE_REQUEST_BLOCK) Pkt->Srb)->SrbLength >= srbLength);
1385 } else {
1386 srbLength = fdoData->SrbTemplate->Length;
1387 }
1388 RtlCopyMemory(Pkt->Srb, fdoData->SrbTemplate, srbLength); // copies _contents_ of SRB blocks
1389
1390 SrbSetRequestAttribute(Pkt->Srb, SRB_SIMPLE_TAG_REQUEST);
1391 SrbSetCdbLength(Pkt->Srb, 6);
1392 SrbSetOriginalRequest(Pkt->Srb, Pkt->Irp);
1393 SrbSetSenseInfoBuffer(Pkt->Srb, &Pkt->SrbErrorSenseData);
1394 SrbSetSenseInfoBufferLength(Pkt->Srb, sizeof(Pkt->SrbErrorSenseData));
1395 SrbSetTimeOutValue(Pkt->Srb, fdoExt->TimeOutValue);
1396 SrbSetDataBuffer(Pkt->Srb, ModeSenseBuffer);
1397 SrbSetDataTransferLength(Pkt->Srb, ModeSenseBufferLen);
1398
1399
1400 SrbAssignSrbFlags(Pkt->Srb, fdoExt->SrbFlags | SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_QUEUE_FREEZE);
1401
1402 pCdb = SrbGetCdb(Pkt->Srb);
1403 if (pCdb) {
1404 pCdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
1405 pCdb->MODE_SENSE.PageCode = PageMode;
1406 pCdb->MODE_SENSE.SubPageCode = SubPage;
1407 pCdb->MODE_SENSE.Pc = PageControl;
1408 pCdb->MODE_SENSE.AllocationLength = (UCHAR)ModeSenseBufferLen;
1409 }
1410
1411 Pkt->BufPtrCopy = ModeSenseBuffer;
1412 Pkt->BufLenCopy = ModeSenseBufferLen;
1413
1414 Pkt->OriginalIrp = OriginalIrp;
1415 Pkt->NumRetries = NUM_MODESENSE_RETRIES;
1416 Pkt->SyncEventPtr = SyncEventPtr;
1417 Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE;
1418 }
1419
1420 /*
1421 * SetupModeSelectTransferPacket
1422 *
1423 * Set up a transferPacket for a synchronous Mode Select transfer.
1424 */
SetupModeSelectTransferPacket(TRANSFER_PACKET * Pkt,PKEVENT SyncEventPtr,PVOID ModeSelectBuffer,UCHAR ModeSelectBufferLen,BOOLEAN SavePages,PIRP OriginalIrp)1425 VOID SetupModeSelectTransferPacket(TRANSFER_PACKET *Pkt,
1426 PKEVENT SyncEventPtr,
1427 PVOID ModeSelectBuffer,
1428 UCHAR ModeSelectBufferLen,
1429 BOOLEAN SavePages,
1430 PIRP OriginalIrp)
1431
1432 {
1433 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension;
1434 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
1435 PCDB pCdb;
1436 ULONG srbLength;
1437
1438 if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1439 srbLength = ((PSTORAGE_REQUEST_BLOCK) fdoData->SrbTemplate)->SrbLength;
1440 NT_ASSERT(((PSTORAGE_REQUEST_BLOCK) Pkt->Srb)->SrbLength >= srbLength);
1441 } else {
1442 srbLength = fdoData->SrbTemplate->Length;
1443 }
1444 RtlCopyMemory(Pkt->Srb, fdoData->SrbTemplate, srbLength); // copies _contents_ of SRB blocks
1445
1446 SrbSetRequestAttribute(Pkt->Srb, SRB_SIMPLE_TAG_REQUEST);
1447 SrbSetCdbLength(Pkt->Srb, 6);
1448 SrbSetOriginalRequest(Pkt->Srb, Pkt->Irp);
1449 SrbSetSenseInfoBuffer(Pkt->Srb, &Pkt->SrbErrorSenseData);
1450 SrbSetSenseInfoBufferLength(Pkt->Srb, sizeof(Pkt->SrbErrorSenseData));
1451 SrbSetTimeOutValue(Pkt->Srb, fdoExt->TimeOutValue);
1452 SrbSetDataBuffer(Pkt->Srb, ModeSelectBuffer);
1453 SrbSetDataTransferLength(Pkt->Srb, ModeSelectBufferLen);
1454
1455 SrbAssignSrbFlags(Pkt->Srb, fdoExt->SrbFlags | SRB_FLAGS_DATA_OUT | SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_QUEUE_FREEZE);
1456
1457 pCdb = SrbGetCdb(Pkt->Srb);
1458 if (pCdb) {
1459 pCdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
1460 pCdb->MODE_SELECT.SPBit = SavePages;
1461 pCdb->MODE_SELECT.PFBit = 1;
1462 pCdb->MODE_SELECT.ParameterListLength = (UCHAR)ModeSelectBufferLen;
1463 }
1464
1465 Pkt->BufPtrCopy = ModeSelectBuffer;
1466 Pkt->BufLenCopy = ModeSelectBufferLen;
1467
1468 Pkt->OriginalIrp = OriginalIrp;
1469 Pkt->NumRetries = NUM_MODESELECT_RETRIES;
1470 Pkt->SyncEventPtr = SyncEventPtr;
1471 Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE;
1472 }
1473
1474
1475 /*
1476 * SetupDriveCapacityTransferPacket
1477 *
1478 * Set up a transferPacket for a synchronous Drive Capacity transfer.
1479 */
SetupDriveCapacityTransferPacket(TRANSFER_PACKET * Pkt,PVOID ReadCapacityBuffer,ULONG ReadCapacityBufferLen,PKEVENT SyncEventPtr,PIRP OriginalIrp,BOOLEAN Use16ByteCdb)1480 VOID SetupDriveCapacityTransferPacket( TRANSFER_PACKET *Pkt,
1481 PVOID ReadCapacityBuffer,
1482 ULONG ReadCapacityBufferLen,
1483 PKEVENT SyncEventPtr,
1484 PIRP OriginalIrp,
1485 BOOLEAN Use16ByteCdb)
1486 {
1487 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension;
1488 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
1489 PCDB pCdb;
1490 ULONG srbLength;
1491 ULONG timeoutValue = fdoExt->TimeOutValue;
1492
1493 if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1494 srbLength = ((PSTORAGE_REQUEST_BLOCK) fdoData->SrbTemplate)->SrbLength;
1495 NT_ASSERT(((PSTORAGE_REQUEST_BLOCK) Pkt->Srb)->SrbLength >= srbLength);
1496 } else {
1497 srbLength = fdoData->SrbTemplate->Length;
1498 }
1499 RtlCopyMemory(Pkt->Srb, fdoData->SrbTemplate, srbLength); // copies _contents_ of SRB blocks
1500
1501 SrbSetRequestAttribute(Pkt->Srb, SRB_SIMPLE_TAG_REQUEST);
1502 SrbSetOriginalRequest(Pkt->Srb, Pkt->Irp);
1503 SrbSetSenseInfoBuffer(Pkt->Srb, &Pkt->SrbErrorSenseData);
1504 SrbSetSenseInfoBufferLength(Pkt->Srb, sizeof(Pkt->SrbErrorSenseData));
1505
1506
1507 SrbSetTimeOutValue(Pkt->Srb, timeoutValue);
1508 SrbSetDataBuffer(Pkt->Srb, ReadCapacityBuffer);
1509 SrbSetDataTransferLength(Pkt->Srb, ReadCapacityBufferLen);
1510
1511 SrbAssignSrbFlags(Pkt->Srb, fdoExt->SrbFlags | SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_QUEUE_FREEZE);
1512
1513 pCdb = SrbGetCdb(Pkt->Srb);
1514 if (pCdb) {
1515 if (Use16ByteCdb == TRUE) {
1516 NT_ASSERT(ReadCapacityBufferLen >= sizeof(READ_CAPACITY_DATA_EX));
1517 SrbSetCdbLength(Pkt->Srb, 16);
1518 pCdb->CDB16.OperationCode = SCSIOP_READ_CAPACITY16;
1519 REVERSE_BYTES(&pCdb->CDB16.TransferLength, &ReadCapacityBufferLen);
1520 pCdb->AsByte[1] = 0x10; // Service Action
1521 } else {
1522 SrbSetCdbLength(Pkt->Srb, 10);
1523 pCdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
1524 }
1525 }
1526
1527 Pkt->BufPtrCopy = ReadCapacityBuffer;
1528 Pkt->BufLenCopy = ReadCapacityBufferLen;
1529
1530 Pkt->OriginalIrp = OriginalIrp;
1531 Pkt->NumRetries = NUM_DRIVECAPACITY_RETRIES;
1532 #if !defined(__REACTOS__) && NTDDI_VERSION >= NTDDI_WINBLUE
1533 Pkt->NumIoTimeoutRetries = NUM_DRIVECAPACITY_RETRIES;
1534 #endif
1535
1536 Pkt->SyncEventPtr = SyncEventPtr;
1537 Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE;
1538 }
1539
1540
1541 #if 0
1542 /*
1543 * SetupSendStartUnitTransferPacket
1544 *
1545 * Set up a transferPacket for a synchronous Send Start Unit transfer.
1546 */
1547 VOID SetupSendStartUnitTransferPacket( TRANSFER_PACKET *Pkt,
1548 PIRP OriginalIrp)
1549 {
1550 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension;
1551 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
1552 PCDB pCdb;
1553
1554 PAGED_CODE();
1555
1556 RtlZeroMemory(&Pkt->Srb, sizeof(SCSI_REQUEST_BLOCK));
1557
1558 /*
1559 * Initialize the SRB.
1560 * Use a very long timeout value to give the drive time to spin up.
1561 */
1562 Pkt->Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
1563 Pkt->Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1564 Pkt->Srb->TimeOutValue = START_UNIT_TIMEOUT;
1565 Pkt->Srb->CdbLength = 6;
1566 Pkt->Srb->OriginalRequest = Pkt->Irp;
1567 Pkt->Srb->SenseInfoBuffer = &Pkt->SrbErrorSenseData;
1568 Pkt->Srb->SenseInfoBufferLength = sizeof(Pkt->SrbErrorSenseData);
1569 Pkt->Srb->Lun = 0;
1570
1571 SET_FLAG(Pkt->Srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);
1572 SET_FLAG(Pkt->Srb->SrbFlags, SRB_FLAGS_DISABLE_AUTOSENSE);
1573 SET_FLAG(Pkt->Srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
1574
1575 pCdb = (PCDB)Pkt->Srb->Cdb;
1576 pCdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
1577 pCdb->START_STOP.Start = 1;
1578 pCdb->START_STOP.Immediate = 0;
1579 pCdb->START_STOP.LogicalUnitNumber = 0;
1580
1581 Pkt->OriginalIrp = OriginalIrp;
1582 Pkt->NumRetries = 0;
1583 Pkt->SyncEventPtr = NULL;
1584 Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE;
1585 }
1586 #endif
1587
1588
1589 VOID
1590 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */
CleanupTransferPacketToWorkingSetSizeWorker(_In_ PVOID Fdo,_In_opt_ PVOID Context,_In_ PIO_WORKITEM IoWorkItem)1591 CleanupTransferPacketToWorkingSetSizeWorker(
1592 _In_ PVOID Fdo,
1593 _In_opt_ PVOID Context,
1594 _In_ PIO_WORKITEM IoWorkItem
1595 )
1596 {
1597 ULONG node = (ULONG) (ULONG_PTR)Context;
1598
1599 PAGED_CODE();
1600
1601 CleanupTransferPacketToWorkingSetSize((PDEVICE_OBJECT)Fdo, FALSE, node);
1602
1603 //
1604 // Release the remove lock acquired in EnqueueFreeTransferPacket
1605 //
1606 ClassReleaseRemoveLock((PDEVICE_OBJECT)Fdo, (PIRP)IoWorkItem);
1607
1608 if (IoWorkItem != NULL) {
1609 IoFreeWorkItem(IoWorkItem);
1610 }
1611 }
1612
1613
1614 VOID
CleanupTransferPacketToWorkingSetSize(_In_ PDEVICE_OBJECT Fdo,_In_ BOOLEAN LimitNumPktToDelete,_In_ ULONG Node)1615 CleanupTransferPacketToWorkingSetSize(
1616 _In_ PDEVICE_OBJECT Fdo,
1617 _In_ BOOLEAN LimitNumPktToDelete,
1618 _In_ ULONG Node
1619 )
1620
1621 /*
1622 Routine Description:
1623
1624 This function frees the resources for the free transfer packets attempting
1625 to bring them down within the working set size.
1626
1627 Arguments:
1628 Fdo: The FDO that represents the device whose transfer packet size needs to be trimmed.
1629 LimitNumPktToDelete: Flag to indicate if the number of packets freed in one call should be capped.
1630 Node: NUMA node transfer packet is associated with.
1631
1632 --*/
1633
1634 {
1635 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
1636 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
1637 KIRQL oldIrql;
1638 SINGLE_LIST_ENTRY pktList;
1639 PSINGLE_LIST_ENTRY slistEntry;
1640 PTRANSFER_PACKET pktToDelete;
1641 ULONG requiredNumPktToDelete = fdoData->FreeTransferPacketsLists[Node].NumTotalTransferPackets -
1642 fdoData->LocalMaxWorkingSetTransferPackets;
1643
1644 if (LimitNumPktToDelete) {
1645 requiredNumPktToDelete = MIN(requiredNumPktToDelete, MAX_CLEANUP_TRANSFER_PACKETS_AT_ONCE);
1646 }
1647
1648 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW, "CleanupTransferPacketToWorkingSetSize (%p): Exiting stress, block freeing %d packets.", Fdo, requiredNumPktToDelete));
1649
1650 /*
1651 * Check the counter again with lock held. This eliminates a race condition
1652 * while still allowing us to not grab the spinlock in the common codepath.
1653 *
1654 * Note that the spinlock does not synchronize with threads dequeuing free
1655 * packets to send (DequeueFreeTransferPacket does that with a lightweight
1656 * interlocked exchange); the spinlock prevents multiple threads in this function
1657 * from deciding to free too many extra packets at once.
1658 */
1659 SimpleInitSlistHdr(&pktList);
1660 KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
1661 while ((fdoData->FreeTransferPacketsLists[Node].NumFreeTransferPackets >= fdoData->FreeTransferPacketsLists[Node].NumTotalTransferPackets) &&
1662 (fdoData->FreeTransferPacketsLists[Node].NumTotalTransferPackets > fdoData->LocalMaxWorkingSetTransferPackets) &&
1663 (requiredNumPktToDelete--)){
1664
1665 pktToDelete = DequeueFreeTransferPacketEx(Fdo, FALSE, Node);
1666 if (pktToDelete){
1667 SimplePushSlist(&pktList,
1668 (PSINGLE_LIST_ENTRY)&pktToDelete->SlistEntry);
1669 InterlockedDecrement((volatile LONG *)&fdoData->FreeTransferPacketsLists[Node].NumTotalTransferPackets);
1670 } else {
1671 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_RW,
1672 "Extremely unlikely condition (non-fatal): %d packets dequeued at once for Fdo %p. NumTotalTransferPackets=%d (1). Node=%d",
1673 fdoData->LocalMaxWorkingSetTransferPackets,
1674 Fdo,
1675 fdoData->FreeTransferPacketsLists[Node].NumTotalTransferPackets,
1676 Node));
1677 break;
1678 }
1679 }
1680 KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
1681
1682 slistEntry = SimplePopSlist(&pktList);
1683 while (slistEntry) {
1684 pktToDelete = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry);
1685 DestroyTransferPacket(pktToDelete);
1686 slistEntry = SimplePopSlist(&pktList);
1687 }
1688
1689 return;
1690 }
1691
1692
1693 _IRQL_requires_max_(APC_LEVEL)
_IRQL_requires_min_(PASSIVE_LEVEL)1694 _IRQL_requires_min_(PASSIVE_LEVEL)
1695 _IRQL_requires_same_
1696 VOID
1697 ClasspSetupPopulateTokenTransferPacket(
1698 _In_ __drv_aliasesMem POFFLOAD_READ_CONTEXT OffloadReadContext,
1699 _In_ PTRANSFER_PACKET Pkt,
1700 _In_ ULONG Length,
1701 _In_reads_bytes_(Length) PUCHAR PopulateTokenBuffer,
1702 _In_ PIRP OriginalIrp,
1703 _In_ ULONG ListIdentifier
1704 )
1705
1706 /*++
1707
1708 Routine description:
1709
1710 This routine is called once to set up a packet for PopulateToken.
1711 It builds up the SRB by setting the appropriate fields.
1712
1713 Arguments:
1714
1715 Pkt - The transfer packet to be sent down to the lower driver
1716 SyncEventPtr - The event that gets signaled once the IRP contained in the packet completes
1717 Length - Length of the buffer being sent as part of the command
1718 PopulateTokenBuffer - The buffer that contains the LBA ranges information for the PopulateToken operation
1719 OriginalIrp - The Io request to be processed
1720 ListIdentifier - The identifier that will be used to correlate a subsequent command to retrieve the token
1721
1722 Return Value:
1723
1724 Nothing
1725
1726 --*/
1727
1728 {
1729 PFUNCTIONAL_DEVICE_EXTENSION fdoExt;
1730 PCLASS_PRIVATE_FDO_DATA fdoData;
1731 PCDB pCdb;
1732 ULONG srbLength;
1733
1734 PAGED_CODE();
1735
1736 TracePrint((TRACE_LEVEL_VERBOSE,
1737 TRACE_FLAG_IOCTL,
1738 "ClasspSetupPopulateTokenTransferPacket (%p): Entering function. Irp %p\n",
1739 Pkt->Fdo,
1740 OriginalIrp));
1741
1742 fdoExt = Pkt->Fdo->DeviceExtension;
1743 fdoData = fdoExt->PrivateFdoData;
1744
1745 if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1746 srbLength = ((PSTORAGE_REQUEST_BLOCK) fdoData->SrbTemplate)->SrbLength;
1747 NT_ASSERT(((PSTORAGE_REQUEST_BLOCK) Pkt->Srb)->SrbLength >= srbLength);
1748 } else {
1749 srbLength = fdoData->SrbTemplate->Length;
1750 }
1751 RtlCopyMemory(Pkt->Srb, fdoData->SrbTemplate, srbLength); // copies _contents_ of SRB blocks
1752
1753 SrbSetRequestAttribute(Pkt->Srb, SRB_SIMPLE_TAG_REQUEST);
1754 SrbSetCdbLength(Pkt->Srb, 16);
1755 SrbSetOriginalRequest(Pkt->Srb, Pkt->Irp);
1756 SrbSetSenseInfoBuffer(Pkt->Srb, &Pkt->SrbErrorSenseData);
1757 SrbSetSenseInfoBufferLength(Pkt->Srb, sizeof(Pkt->SrbErrorSenseData));
1758 SrbSetTimeOutValue(Pkt->Srb, fdoExt->TimeOutValue);
1759 SrbSetDataBuffer(Pkt->Srb, PopulateTokenBuffer);
1760 SrbSetDataTransferLength(Pkt->Srb, Length);
1761
1762 SrbAssignSrbFlags(Pkt->Srb, fdoExt->SrbFlags | SRB_FLAGS_DATA_OUT | SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_QUEUE_FREEZE);
1763
1764 pCdb = SrbGetCdb(Pkt->Srb);
1765 if (pCdb) {
1766 pCdb->TOKEN_OPERATION.OperationCode = SCSIOP_POPULATE_TOKEN;
1767 pCdb->TOKEN_OPERATION.ServiceAction = SERVICE_ACTION_POPULATE_TOKEN;
1768
1769 REVERSE_BYTES(&pCdb->TOKEN_OPERATION.ListIdentifier, &ListIdentifier);
1770 REVERSE_BYTES(&pCdb->TOKEN_OPERATION.ParameterListLength, &Length);
1771 }
1772
1773 Pkt->BufPtrCopy = PopulateTokenBuffer;
1774 Pkt->BufLenCopy = Length;
1775
1776 Pkt->OriginalIrp = OriginalIrp;
1777 Pkt->NumRetries = NUM_POPULATE_TOKEN_RETRIES;
1778 Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE;
1779
1780 Pkt->ContinuationRoutine = ClasspPopulateTokenTransferPacketDone;
1781 Pkt->ContinuationContext = OffloadReadContext;
1782
1783 TracePrint((TRACE_LEVEL_VERBOSE,
1784 TRACE_FLAG_IOCTL,
1785 "ClasspSetupPopulateTokenTransferPacket (%p): Exiting function with Irp %p\n",
1786 Pkt->Fdo,
1787 OriginalIrp));
1788
1789 return;
1790 }
1791
1792
1793 _IRQL_requires_max_(APC_LEVEL)
_IRQL_requires_min_(PASSIVE_LEVEL)1794 _IRQL_requires_min_(PASSIVE_LEVEL)
1795 _IRQL_requires_same_
1796 VOID
1797 ClasspSetupReceivePopulateTokenInformationTransferPacket(
1798 _In_ POFFLOAD_READ_CONTEXT OffloadReadContext,
1799 _In_ PTRANSFER_PACKET Pkt,
1800 _In_ ULONG Length,
1801 _In_reads_bytes_(Length) PUCHAR ReceivePopulateTokenInformationBuffer,
1802 _In_ PIRP OriginalIrp,
1803 _In_ ULONG ListIdentifier
1804 )
1805
1806 /*++
1807
1808 Routine description:
1809
1810 This routine is called once to set up a packet for read token retrieval.
1811 It builds up the SRB by setting the appropriate fields.
1812
1813 Arguments:
1814
1815 Pkt - The transfer packet to be sent down to the lower driver
1816 Length - Length of the buffer being sent as part of the command
1817 ReceivePopulateTokenInformationBuffer - The buffer into which the target will pass back the token
1818 OriginalIrp - The Io request to be processed
1819 ListIdentifier - The identifier that will be used to correlate this command with its corresponding previous populate token operation
1820
1821 Return Value:
1822
1823 Nothing
1824
1825 --*/
1826
1827 {
1828 PFUNCTIONAL_DEVICE_EXTENSION fdoExt;
1829 PCLASS_PRIVATE_FDO_DATA fdoData;
1830 PCDB pCdb;
1831 ULONG srbLength;
1832
1833 TracePrint((TRACE_LEVEL_VERBOSE,
1834 TRACE_FLAG_IOCTL,
1835 "ClasspSetupReceivePopulateTokenInformationTransferPacket (%p): Entering function. Irp %p\n",
1836 Pkt->Fdo,
1837 OriginalIrp));
1838
1839 fdoExt = Pkt->Fdo->DeviceExtension;
1840 fdoData = fdoExt->PrivateFdoData;
1841
1842 if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1843 srbLength = ((PSTORAGE_REQUEST_BLOCK) fdoData->SrbTemplate)->SrbLength;
1844 NT_ASSERT(((PSTORAGE_REQUEST_BLOCK) Pkt->Srb)->SrbLength >= srbLength);
1845 } else {
1846 srbLength = fdoData->SrbTemplate->Length;
1847 }
1848 RtlCopyMemory(Pkt->Srb, fdoData->SrbTemplate, srbLength); // copies _contents_ of SRB blocks
1849
1850 SrbSetRequestAttribute(Pkt->Srb, SRB_SIMPLE_TAG_REQUEST);
1851 SrbSetCdbLength(Pkt->Srb, 16);
1852 SrbSetOriginalRequest(Pkt->Srb, Pkt->Irp);
1853 SrbSetSenseInfoBuffer(Pkt->Srb, &Pkt->SrbErrorSenseData);
1854 SrbSetSenseInfoBufferLength(Pkt->Srb, sizeof(Pkt->SrbErrorSenseData));
1855 SrbSetTimeOutValue(Pkt->Srb, fdoExt->TimeOutValue);
1856 SrbSetDataBuffer(Pkt->Srb, ReceivePopulateTokenInformationBuffer);
1857 SrbSetDataTransferLength(Pkt->Srb, Length);
1858
1859 SrbAssignSrbFlags(Pkt->Srb, fdoExt->SrbFlags | SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_QUEUE_FREEZE);
1860
1861 pCdb = SrbGetCdb(Pkt->Srb);
1862 if (pCdb) {
1863 pCdb->RECEIVE_TOKEN_INFORMATION.OperationCode = SCSIOP_RECEIVE_ROD_TOKEN_INFORMATION;
1864 pCdb->RECEIVE_TOKEN_INFORMATION.ServiceAction = SERVICE_ACTION_RECEIVE_TOKEN_INFORMATION;
1865
1866 REVERSE_BYTES(&pCdb->RECEIVE_TOKEN_INFORMATION.ListIdentifier, &ListIdentifier);
1867 REVERSE_BYTES(&pCdb->RECEIVE_TOKEN_INFORMATION.AllocationLength, &Length);
1868 }
1869
1870 Pkt->BufPtrCopy = ReceivePopulateTokenInformationBuffer;
1871 Pkt->BufLenCopy = Length;
1872
1873 Pkt->OriginalIrp = OriginalIrp;
1874 Pkt->NumRetries = NUM_POPULATE_TOKEN_RETRIES;
1875 Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE;
1876
1877 Pkt->ContinuationRoutine = ClasspReceivePopulateTokenInformationTransferPacketDone;
1878 Pkt->ContinuationContext = OffloadReadContext;
1879
1880 TracePrint((TRACE_LEVEL_VERBOSE,
1881 TRACE_FLAG_IOCTL,
1882 "ClasspSetupReceivePopulateTokenInformationTransferPacket (%p): Exiting function with Irp %p\n",
1883 Pkt->Fdo,
1884 OriginalIrp));
1885
1886 return;
1887 }
1888
1889
1890 _IRQL_requires_max_(APC_LEVEL)
_IRQL_requires_min_(PASSIVE_LEVEL)1891 _IRQL_requires_min_(PASSIVE_LEVEL)
1892 _IRQL_requires_same_
1893 VOID
1894 ClasspSetupWriteUsingTokenTransferPacket(
1895 _In_ __drv_aliasesMem POFFLOAD_WRITE_CONTEXT OffloadWriteContext,
1896 _In_ PTRANSFER_PACKET Pkt,
1897 _In_ ULONG Length,
1898 _In_reads_bytes_ (Length) PUCHAR WriteUsingTokenBuffer,
1899 _In_ PIRP OriginalIrp,
1900 _In_ ULONG ListIdentifier
1901 )
1902
1903 /*++
1904
1905 Routine description:
1906
1907 This routine is called once to set up a packet for WriteUsingToken.
1908 It builds up the SRB by setting the appropriate fields. It is not called
1909 before a retry as the SRB fields may be modified for the retry.
1910
1911 The IRP is set up in SubmitTransferPacket because it must be reset for
1912 each packet submission.
1913
1914 Arguments:
1915
1916 Pkt - The transfer packet to be sent down to the lower driver
1917 Length - Length of the buffer being sent as part of the command
1918 WriteUsingTokenBuffer - The buffer that contains the read token and the write LBA ranges information for the WriteUsingToken operation
1919 OriginalIrp - The Io request to be processed
1920 ListIdentifier - The identifier that will be used to correlate a subsequent command to retrieve extended results in case of command failure
1921
1922 Return Value:
1923
1924 Nothing
1925
1926 --*/
1927
1928 {
1929 PFUNCTIONAL_DEVICE_EXTENSION fdoExt;
1930 PCLASS_PRIVATE_FDO_DATA fdoData;
1931 PCDB pCdb;
1932 ULONG srbLength;
1933
1934 TracePrint((TRACE_LEVEL_VERBOSE,
1935 TRACE_FLAG_IOCTL,
1936 "ClasspSetupWriteUsingTokenTransferPacket (%p): Entering function. Irp %p\n",
1937 Pkt->Fdo,
1938 OriginalIrp));
1939
1940 fdoExt = Pkt->Fdo->DeviceExtension;
1941 fdoData = fdoExt->PrivateFdoData;
1942
1943 if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
1944 srbLength = ((PSTORAGE_REQUEST_BLOCK) fdoData->SrbTemplate)->SrbLength;
1945 NT_ASSERT(((PSTORAGE_REQUEST_BLOCK) Pkt->Srb)->SrbLength >= srbLength);
1946 } else {
1947 srbLength = fdoData->SrbTemplate->Length;
1948 }
1949 RtlCopyMemory(Pkt->Srb, fdoData->SrbTemplate, srbLength); // copies _contents_ of SRB blocks
1950
1951 SrbSetRequestAttribute(Pkt->Srb, SRB_SIMPLE_TAG_REQUEST);
1952 SrbSetCdbLength(Pkt->Srb, 16);
1953 SrbSetOriginalRequest(Pkt->Srb, Pkt->Irp);
1954 SrbSetSenseInfoBuffer(Pkt->Srb, &Pkt->SrbErrorSenseData);
1955 SrbSetSenseInfoBufferLength(Pkt->Srb, sizeof(Pkt->SrbErrorSenseData));
1956 SrbSetTimeOutValue(Pkt->Srb, fdoExt->TimeOutValue);
1957 SrbSetDataBuffer(Pkt->Srb, WriteUsingTokenBuffer);
1958 SrbSetDataTransferLength(Pkt->Srb, Length);
1959
1960 SrbAssignSrbFlags(Pkt->Srb, fdoExt->SrbFlags | SRB_FLAGS_DATA_OUT | SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_QUEUE_FREEZE);
1961
1962 pCdb = SrbGetCdb(Pkt->Srb);
1963 if (pCdb) {
1964 pCdb->TOKEN_OPERATION.OperationCode = SCSIOP_WRITE_USING_TOKEN;
1965 pCdb->TOKEN_OPERATION.ServiceAction = SERVICE_ACTION_WRITE_USING_TOKEN;
1966
1967 REVERSE_BYTES(&pCdb->TOKEN_OPERATION.ParameterListLength, &Length);
1968 REVERSE_BYTES(&pCdb->TOKEN_OPERATION.ListIdentifier, &ListIdentifier);
1969 }
1970
1971 Pkt->BufPtrCopy = WriteUsingTokenBuffer;
1972 Pkt->BufLenCopy = Length;
1973
1974 Pkt->OriginalIrp = OriginalIrp;
1975 Pkt->NumRetries = NUM_WRITE_USING_TOKEN_RETRIES;
1976 Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE;
1977
1978 Pkt->ContinuationRoutine = ClasspWriteUsingTokenTransferPacketDone;
1979 Pkt->ContinuationContext = OffloadWriteContext;
1980
1981 TracePrint((TRACE_LEVEL_VERBOSE,
1982 TRACE_FLAG_IOCTL,
1983 "ClasspSetupWriteUsingTokenTransferPacket (%p): Exiting function with Irp %p\n",
1984 Pkt->Fdo,
1985 OriginalIrp));
1986
1987 return;
1988 }
1989
1990
1991 _IRQL_requires_max_(APC_LEVEL)
_IRQL_requires_min_(PASSIVE_LEVEL)1992 _IRQL_requires_min_(PASSIVE_LEVEL)
1993 _IRQL_requires_same_
1994 VOID
1995 ClasspSetupReceiveWriteUsingTokenInformationTransferPacket(
1996 _In_ POFFLOAD_WRITE_CONTEXT OffloadWriteContext,
1997 _In_ PTRANSFER_PACKET Pkt,
1998 _In_ ULONG Length,
1999 _In_reads_bytes_ (Length) PUCHAR ReceiveWriteUsingTokenInformationBuffer,
2000 _In_ PIRP OriginalIrp,
2001 _In_ ULONG ListIdentifier
2002 )
2003
2004 /*++
2005
2006 Routine description:
2007
2008 This routine is called once to set up a packet for extended results for
2009 WriteUsingToken operation. It builds up the SRB by setting the appropriate fields.
2010
2011 Arguments:
2012
2013 Pkt - The transfer packet to be sent down to the lower driver
2014 SyncEventPtr - The event that gets signaled once the IRP contained in the packet completes
2015 Length - Length of the buffer being sent as part of the command
2016 ReceiveWriteUsingTokenInformationBuffer - The buffer into which the target will pass back the extended results
2017 OriginalIrp - The Io request to be processed
2018 ListIdentifier - The identifier that will be used to correlate this command with its corresponding previous write using token operation
2019
2020 Return Value:
2021
2022 Nothing
2023
2024 --*/
2025
2026 {
2027 PFUNCTIONAL_DEVICE_EXTENSION fdoExt;
2028 PCLASS_PRIVATE_FDO_DATA fdoData;
2029 PCDB pCdb;
2030 ULONG srbLength;
2031
2032 TracePrint((TRACE_LEVEL_VERBOSE,
2033 TRACE_FLAG_IOCTL,
2034 "ClasspSetupReceiveWriteUsingTokenInformationTransferPacket (%p): Entering function. Irp %p\n",
2035 Pkt->Fdo,
2036 OriginalIrp));
2037
2038 fdoExt = Pkt->Fdo->DeviceExtension;
2039 fdoData = fdoExt->PrivateFdoData;
2040
2041 if (fdoExt->AdapterDescriptor->SrbType == SRB_TYPE_STORAGE_REQUEST_BLOCK) {
2042 srbLength = ((PSTORAGE_REQUEST_BLOCK) fdoData->SrbTemplate)->SrbLength;
2043 NT_ASSERT(((PSTORAGE_REQUEST_BLOCK) Pkt->Srb)->SrbLength >= srbLength);
2044 } else {
2045 srbLength = fdoData->SrbTemplate->Length;
2046 }
2047 RtlCopyMemory(Pkt->Srb, fdoData->SrbTemplate, srbLength); // copies _contents_ of SRB blocks
2048
2049 SrbSetRequestAttribute(Pkt->Srb, SRB_SIMPLE_TAG_REQUEST);
2050 SrbSetCdbLength(Pkt->Srb, 16);
2051 SrbSetOriginalRequest(Pkt->Srb, Pkt->Irp);
2052 SrbSetSenseInfoBuffer(Pkt->Srb, &Pkt->SrbErrorSenseData);
2053 SrbSetSenseInfoBufferLength(Pkt->Srb, sizeof(Pkt->SrbErrorSenseData));
2054 SrbSetTimeOutValue(Pkt->Srb, fdoExt->TimeOutValue);
2055 SrbSetDataBuffer(Pkt->Srb, ReceiveWriteUsingTokenInformationBuffer);
2056 SrbSetDataTransferLength(Pkt->Srb, Length);
2057
2058 SrbAssignSrbFlags(Pkt->Srb, fdoExt->SrbFlags | SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_NO_QUEUE_FREEZE);
2059
2060 pCdb = SrbGetCdb(Pkt->Srb);
2061 if (pCdb) {
2062 pCdb->RECEIVE_TOKEN_INFORMATION.OperationCode = SCSIOP_RECEIVE_ROD_TOKEN_INFORMATION;
2063 pCdb->RECEIVE_TOKEN_INFORMATION.ServiceAction = SERVICE_ACTION_RECEIVE_TOKEN_INFORMATION;
2064
2065 REVERSE_BYTES(&pCdb->RECEIVE_TOKEN_INFORMATION.AllocationLength, &Length);
2066 REVERSE_BYTES(&pCdb->RECEIVE_TOKEN_INFORMATION.ListIdentifier, &ListIdentifier);
2067 }
2068
2069 Pkt->BufPtrCopy = ReceiveWriteUsingTokenInformationBuffer;
2070 Pkt->BufLenCopy = Length;
2071
2072 Pkt->OriginalIrp = OriginalIrp;
2073 Pkt->NumRetries = NUM_WRITE_USING_TOKEN_RETRIES;
2074 Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE;
2075
2076 Pkt->ContinuationRoutine = (PCONTINUATION_ROUTINE) ClasspReceiveWriteUsingTokenInformationTransferPacketDone;
2077 Pkt->ContinuationContext = OffloadWriteContext;
2078
2079 TracePrint((TRACE_LEVEL_VERBOSE,
2080 TRACE_FLAG_IOCTL,
2081 "ClasspSetupReceiveWriteUsingTokenInformationTransferPacket (%p): Exiting function with Irp %p\n",
2082 Pkt->Fdo,
2083 OriginalIrp));
2084
2085 return;
2086 }
2087
2088
2089