ReactOS  0.4.14-dev-323-g6fe6a88
retry.c File Reference
#include "classp.h"
Include dependency graph for retry.c:

Go to the source code of this file.

Functions

BOOLEAN NTAPI InterpretTransferPacketError (PTRANSFER_PACKET Pkt)
 
BOOLEAN NTAPI RetryTransferPacket (PTRANSFER_PACKET Pkt)
 
VOID NTAPI TransferPacketRetryTimerDpc (IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
 
VOID NTAPI InitLowMemRetry (PTRANSFER_PACKET Pkt, PVOID BufPtr, ULONG Len, LARGE_INTEGER TargetLocation)
 
BOOLEAN NTAPI StepLowMemRetry (PTRANSFER_PACKET Pkt)
 

Function Documentation

◆ InitLowMemRetry()

VOID NTAPI InitLowMemRetry ( PTRANSFER_PACKET  Pkt,
PVOID  BufPtr,
ULONG  Len,
LARGE_INTEGER  TargetLocation 
)

Definition at line 286 of file retry.c.

287 {
288  ASSERT(Len > 0);
289  ASSERT(!Pkt->InLowMemRetry);
290  Pkt->InLowMemRetry = TRUE;
291  Pkt->LowMemRetry_remainingBufPtr = BufPtr;
293  Pkt->LowMemRetry_nextChunkTargetLocation = TargetLocation;
294 }
#define TRUE
Definition: types.h:120
PUCHAR LowMemRetry_remainingBufPtr
Definition: classp.h:320
BOOLEAN InLowMemRetry
Definition: classp.h:319
LARGE_INTEGER LowMemRetry_nextChunkTargetLocation
Definition: classp.h:322
#define Len
Definition: deflate.h:82
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
ULONG LowMemRetry_remainingBufLen
Definition: classp.h:321

Referenced by RetryTransferPacket(), and ServiceTransferRequest().

◆ InterpretTransferPacketError()

BOOLEAN NTAPI InterpretTransferPacketError ( PTRANSFER_PACKET  Pkt)

Definition at line 34 of file retry.c.

35 {
36  BOOLEAN shouldRetry = FALSE;
37  PCDB pCdb = (PCDB)Pkt->Srb.Cdb;
38 
39  /*
40  * Interpret the error using the returned sense info first.
41  */
42  Pkt->RetryIntervalSec = 0;
43  if (pCdb->MEDIA_REMOVAL.OperationCode == SCSIOP_MEDIUM_REMOVAL){
44  /*
45  * This is an Ejection Control SRB. Interpret its sense info specially.
46  */
47  shouldRetry = ClassInterpretSenseInfo(
48  Pkt->Fdo,
49  &Pkt->Srb,
51  0,
53  &Pkt->Irp->IoStatus.Status,
54  &Pkt->RetryIntervalSec);
55  if (shouldRetry){
56  /*
57  * If the device is not ready, wait at least 2 seconds before retrying.
58  */
59  PSENSE_DATA senseInfoBuffer = Pkt->Srb.SenseInfoBuffer;
60  ASSERT(senseInfoBuffer);
61  if (((Pkt->Irp->IoStatus.Status == STATUS_DEVICE_NOT_READY) &&
62  (senseInfoBuffer->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY)) ||
64 
65  Pkt->RetryIntervalSec = MAX(Pkt->RetryIntervalSec, 2);
66  }
67  }
68  }
69  else if ((pCdb->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE) ||
70  (pCdb->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE10)){
71  /*
72  * This is an Mode Sense SRB. Interpret its sense info specially.
73  */
74  shouldRetry = ClassInterpretSenseInfo(
75  Pkt->Fdo,
76  &Pkt->Srb,
78  0,
80  &Pkt->Irp->IoStatus.Status,
81  &Pkt->RetryIntervalSec);
82  if (shouldRetry){
83  /*
84  * If the device is not ready, wait at least 2 seconds before retrying.
85  */
86  PSENSE_DATA senseInfoBuffer = Pkt->Srb.SenseInfoBuffer;
87  ASSERT(senseInfoBuffer);
88  if (((Pkt->Irp->IoStatus.Status == STATUS_DEVICE_NOT_READY) &&
89  (senseInfoBuffer->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY)) ||
91 
92  Pkt->RetryIntervalSec = MAX(Pkt->RetryIntervalSec, 2);
93  }
94  }
95 
96  /*
97  * Some special cases for mode sense.
98  */
99  if (Pkt->Irp->IoStatus.Status == STATUS_VERIFY_REQUIRED){
100  shouldRetry = TRUE;
101  }
102  else if (SRB_STATUS(Pkt->Srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN){
103  /*
104  * This is a HACK.
105  * Atapi returns SRB_STATUS_DATA_OVERRUN when it really means
106  * underrun (i.e. success, and the buffer is longer than needed).
107  * So treat this as a success.
108  */
109  Pkt->Irp->IoStatus.Status = STATUS_SUCCESS;
110  InterlockedExchangeAdd((PLONG)&Pkt->OriginalIrp->IoStatus.Information, (LONG)Pkt->Srb.DataTransferLength);
111  shouldRetry = FALSE;
112  }
113  }
114  else if (pCdb->CDB10.OperationCode == SCSIOP_READ_CAPACITY){
115  /*
116  * This is a Drive Capacity SRB. Interpret its sense info specially.
117  */
118  shouldRetry = ClassInterpretSenseInfo(
119  Pkt->Fdo,
120  &Pkt->Srb,
121  IRP_MJ_SCSI,
122  0,
124  &Pkt->Irp->IoStatus.Status,
125  &Pkt->RetryIntervalSec);
126  if (Pkt->Irp->IoStatus.Status == STATUS_VERIFY_REQUIRED){
127  shouldRetry = TRUE;
128  }
129  }
130  else if ((pCdb->CDB10.OperationCode == SCSIOP_READ) ||
131  (pCdb->CDB10.OperationCode == SCSIOP_WRITE)){
132  /*
133  * This is a Read/Write Data packet.
134  */
136 
137  shouldRetry = ClassInterpretSenseInfo(
138  Pkt->Fdo,
139  &Pkt->Srb,
140  origCurrentSp->MajorFunction,
141  0,
143  &Pkt->Irp->IoStatus.Status,
144  &Pkt->RetryIntervalSec);
145  /*
146  * Deal with some special cases.
147  */
148  if (Pkt->Irp->IoStatus.Status == STATUS_INSUFFICIENT_RESOURCES){
149  /*
150  * We are in extreme low-memory stress.
151  * We will retry in smaller chunks.
152  */
153  shouldRetry = TRUE;
154  }
155  else if (TEST_FLAG(origCurrentSp->Flags, SL_OVERRIDE_VERIFY_VOLUME) &&
156  (Pkt->Irp->IoStatus.Status == STATUS_VERIFY_REQUIRED)){
157  /*
158  * We are still verifying a (possibly) reloaded disk/cdrom.
159  * So retry the request.
160  */
161  Pkt->Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR;
162  shouldRetry = TRUE;
163  }
164  }
165  else {
166  DBGERR(("Unhandled SRB Function %xh in error path for packet %p (did miniport change Srb.Cdb.OperationCode ?)", (ULONG)pCdb->CDB10.OperationCode, Pkt));
167  }
168 
169  return shouldRetry;
170 }
#define TRUE
Definition: types.h:120
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
UCHAR Cdb[16]
Definition: srb.h:271
struct _CDB::_MEDIA_REMOVAL MEDIA_REMOVAL
#define TEST_FLAG(Flags, Bit)
Definition: classpnp.h:156
#define SCSIOP_MODE_SENSE
Definition: cdrw_hw.h:896
ULONG DataTransferLength
Definition: srb.h:253
Definition: cdrw_hw.h:28
#define DBGERR(args_in_parens)
Definition: debug.h:135
SCSI_REQUEST_BLOCK Srb
Definition: classp.h:353
#define SCSI_ADSENSE_LUN_NOT_READY
Definition: cdrw_hw.h:1218
struct _CDB::_CDB10 CDB10
#define STATUS_VERIFY_REQUIRED
Definition: udferr_usr.h:130
UCHAR SrbStatus
Definition: srb.h:243
#define SRB_STATUS(Status)
Definition: srb.h:381
ULONG NumRetries
Definition: classp.h:302
ULONG RetryIntervalSec
Definition: classp.h:305
#define IRP_MJ_SCSI
#define STATUS_IO_DEVICE_ERROR
Definition: udferr_usr.h:179
long LONG
Definition: pedump.c:60
PDEVICE_OBJECT Fdo
Definition: classp.h:290
#define SCSIOP_READ
Definition: cdrw_hw.h:905
#define SCSIOP_WRITE
Definition: cdrw_hw.h:906
unsigned char BOOLEAN
#define SCSIOP_MODE_SENSE10
Definition: cdrw_hw.h:946
union _CDB * PCDB
#define SL_OVERRIDE_VERIFY_VOLUME
Definition: iotypes.h:1780
#define InterlockedExchangeAdd
Definition: interlocked.h:181
#define MAXIMUM_RETRIES
Definition: class2.h:14
struct _CDB::_MODE_SENSE MODE_SENSE
PIRP OriginalIrp
Definition: classp.h:296
if(!(yy_init))
Definition: macro.lex.yy.c:714
BOOLEAN NTAPI ClassInterpretSenseInfo(IN PDEVICE_OBJECT Fdo, IN PSCSI_REQUEST_BLOCK Srb, IN UCHAR MajorFunctionCode, IN ULONG IoDeviceCode, IN ULONG RetryCount, OUT NTSTATUS *Status, OUT OPTIONAL ULONG *RetryInterval)
Definition: class.c:2994
#define SRB_STATUS_DATA_OVERRUN
Definition: srb.h:349
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define SCSIOP_MEDIUM_REMOVAL
Definition: cdrw_hw.h:902
#define SRB_STATUS_SELECTION_TIMEOUT
Definition: srb.h:342
T MAX(T a, T b)
Definition: polytest.cpp:85
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2745
#define SCSIOP_READ_CAPACITY
Definition: cdrw_hw.h:904
PVOID SenseInfoBuffer
Definition: srb.h:256
unsigned int ULONG
Definition: retypes.h:1
UCHAR AdditionalSenseCode
Definition: cdrw_hw.h:1175
return STATUS_SUCCESS
Definition: btrfs.c:2938
signed int * PLONG
Definition: retypes.h:5
#define STATUS_DEVICE_NOT_READY
Definition: shellext.h:70

Referenced by TransferPktComplete().

◆ RetryTransferPacket()

BOOLEAN NTAPI RetryTransferPacket ( PTRANSFER_PACKET  Pkt)

Definition at line 180 of file retry.c.

181 {
182  BOOLEAN packetDone;
183 
184  DBGTRACE(ClassDebugTrace, ("retrying failed transfer (pkt=%ph, op=%s)", Pkt, DBGGETSCSIOPSTR(&Pkt->Srb)));
185 
186  ASSERT(Pkt->NumRetries > 0);
187  Pkt->NumRetries--;
188 
189  /*
190  * Tone down performance on the retry.
191  * This increases the chance for success on the retry.
192  * We've seen instances of drives that fail consistently but then start working
193  * once this scale-down is applied.
194  */
198  Pkt->Srb.QueueTag = SP_UNTAGGED;
199 
200  if (Pkt->Irp->IoStatus.Status == STATUS_INSUFFICIENT_RESOURCES){
201  PCDB pCdb = (PCDB)Pkt->Srb.Cdb;
202  BOOLEAN isReadWrite = ((pCdb->CDB10.OperationCode == SCSIOP_READ) ||
203  (pCdb->CDB10.OperationCode == SCSIOP_WRITE));
204 
205  if (Pkt->InLowMemRetry || !isReadWrite){
206  /*
207  * This should never happen.
208  * The memory manager guarantees that at least four pages will
209  * be available to allow forward progress in the port driver.
210  * So a one-page transfer should never fail with insufficient resources.
211  */
212  ASSERT(isReadWrite && !Pkt->InLowMemRetry);
213  packetDone = TRUE;
214  }
215  else {
216  /*
217  * We are in low-memory stress.
218  * Start the low-memory retry state machine, which tries to
219  * resend the packet in little one-page chunks.
220  */
221  InitLowMemRetry( Pkt,
222  Pkt->BufPtrCopy,
223  Pkt->BufLenCopy,
224  Pkt->TargetLocationCopy);
225  StepLowMemRetry(Pkt);
226  packetDone = FALSE;
227  }
228  }
229  else {
230  /*
231  * Retry the packet by simply resending it after a delay.
232  * Put the packet back in the pending queue and
233  * schedule a timer to retry the transfer.
234  *
235  * Do not call SetupReadWriteTransferPacket again because:
236  * (1) The minidriver may have set some bits
237  * in the SRB that it needs again and
238  * (2) doing so would reset numRetries.
239  *
240  * BECAUSE we do not call SetupReadWriteTransferPacket again,
241  * we have to reset a couple fields in the SRB that
242  * some miniports overwrite when they fail an SRB.
243  */
244 
245  Pkt->Srb.DataBuffer = Pkt->BufPtrCopy;
246  Pkt->Srb.DataTransferLength = Pkt->BufLenCopy;
247 
248  if (Pkt->RetryIntervalSec == 0){
249  /*
250  * Always delay by at least a little when retrying.
251  * Some problems (e.g. CRC errors) are not recoverable without a slight delay.
252  */
253  LARGE_INTEGER timerPeriod;
254 
255  timerPeriod.HighPart = -1;
259  KeSetTimer(&Pkt->RetryTimer, timerPeriod, &Pkt->RetryTimerDPC);
260  }
261  else {
262  LARGE_INTEGER timerPeriod;
263 
264  ASSERT(Pkt->RetryIntervalSec < 100); // sanity check
265  timerPeriod.HighPart = -1;
266  timerPeriod.LowPart = Pkt->RetryIntervalSec*-10000000;
269  KeSetTimer(&Pkt->RetryTimer, timerPeriod, &Pkt->RetryTimerDPC);
270  }
271  packetDone = FALSE;
272  }
273 
274  return packetDone;
275 }
#define TRUE
Definition: types.h:120
BOOLEAN NTAPI KeSetTimer(IN OUT PKTIMER Timer, IN LARGE_INTEGER DueTime, IN PKDPC Dpc OPTIONAL)
Definition: timerobj.c:281
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
BOOLEAN NTAPI StepLowMemRetry(PTRANSFER_PACKET Pkt)
Definition: retry.c:304
ULONG SrbFlags
Definition: srb.h:252
UCHAR Cdb[16]
Definition: srb.h:271
#define DBGGETSCSIOPSTR(_pSrb)
Definition: debug.h:140
PVOID DataBuffer
Definition: srb.h:255
ULONG DataTransferLength
Definition: srb.h:253
Definition: cdrw_hw.h:28
ULONG NTAPI KeQueryTimeIncrement(VOID)
Definition: clock.c:153
SCSI_REQUEST_BLOCK Srb
Definition: classp.h:353
struct _CDB::_CDB10 CDB10
KDPC RetryTimerDPC
Definition: classp.h:304
ULONG NumRetries
Definition: classp.h:302
LARGE_INTEGER TargetLocationCopy
Definition: classp.h:339
ULONG RetryIntervalSec
Definition: classp.h:305
#define DBGTRACE(dbgTraceLevel, args_in_parens)
Definition: debug.h:136
#define SP_UNTAGGED
Definition: srb.h:225
long LONG
Definition: pedump.c:60
#define SCSIOP_READ
Definition: cdrw_hw.h:905
#define CLEAR_FLAG(Flags, Bit)
Definition: classpnp.h:155
#define SCSIOP_WRITE
Definition: cdrw_hw.h:906
unsigned char BOOLEAN
union _CDB * PCDB
VOID NTAPI KeInitializeTimer(OUT PKTIMER Timer)
Definition: timerobj.c:233
VOID NTAPI InitLowMemRetry(PTRANSFER_PACKET Pkt, PVOID BufPtr, ULONG Len, LARGE_INTEGER TargetLocation)
Definition: retry.c:286
UCHAR QueueTag
Definition: srb.h:248
BOOLEAN InLowMemRetry
Definition: classp.h:319
#define SRB_FLAGS_DISABLE_SYNCH_TRANSFER
Definition: srb.h:389
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define SRB_FLAGS_DISABLE_DISCONNECT
Definition: srb.h:388
ULONG LowPart
Definition: typedefs.h:104
KTIMER RetryTimer
Definition: classp.h:303
#define SET_FLAG(Flags, Bit)
Definition: classpnp.h:154
VOID NTAPI TransferPacketRetryTimerDpc(IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
Definition: retry.c:277
#define MINIMUM_RETRY_UNITS
Definition: classp.h:472
PUCHAR BufPtrCopy
Definition: classp.h:337
unsigned int ULONG
Definition: retypes.h:1
VOID NTAPI KeInitializeDpc(IN PKDPC Dpc, IN PKDEFERRED_ROUTINE DeferredRoutine, IN PVOID DeferredContext)
Definition: dpc.c:711
ULONG BufLenCopy
Definition: classp.h:338
#define SRB_FLAGS_QUEUE_ACTION_ENABLE
Definition: srb.h:387

Referenced by TransferPktComplete().

◆ StepLowMemRetry()

BOOLEAN NTAPI StepLowMemRetry ( PTRANSFER_PACKET  Pkt)

Definition at line 304 of file retry.c.

305 {
306  BOOLEAN packetDone;
307 
308  if (Pkt->LowMemRetry_remainingBufLen == 0){
309  packetDone = TRUE;
310  }
311  else {
312  ULONG thisChunkLen;
313  ULONG bytesToNextPageBoundary;
314 
315  /*
316  * Make sure the little chunk we send is <= a page length
317  * AND that it does not cross any page boundaries.
318  */
319  bytesToNextPageBoundary = PAGE_SIZE-(ULONG)((ULONG_PTR)Pkt->LowMemRetry_remainingBufPtr%PAGE_SIZE);
320  thisChunkLen = MIN(Pkt->LowMemRetry_remainingBufLen, bytesToNextPageBoundary);
321 
322  /*
323  * Set up the transfer packet for the new little chunk.
324  * This will reset numRetries so that we retry each chunk as required.
325  */
328  thisChunkLen,
330  Pkt->OriginalIrp);
331 
332  Pkt->LowMemRetry_remainingBufPtr += thisChunkLen;
333  Pkt->LowMemRetry_remainingBufLen -= thisChunkLen;
334  Pkt->LowMemRetry_nextChunkTargetLocation.QuadPart += thisChunkLen;
335 
337  packetDone = FALSE;
338  }
339 
340  return packetDone;
341 }
#define TRUE
Definition: types.h:120
PUCHAR LowMemRetry_remainingBufPtr
Definition: classp.h:320
VOID NTAPI SubmitTransferPacket(PTRANSFER_PACKET Pkt)
Definition: xferpkt.c:460
uint32_t ULONG_PTR
Definition: typedefs.h:63
T MIN(T a, T b)
Definition: polytest.cpp:79
unsigned char BOOLEAN
LARGE_INTEGER LowMemRetry_nextChunkTargetLocation
Definition: classp.h:322
PIRP OriginalIrp
Definition: classp.h:296
#define PAGE_SIZE
Definition: env_spec_w32.h:49
VOID NTAPI SetupReadWriteTransferPacket(PTRANSFER_PACKET pkt, PVOID Buf, ULONG Len, LARGE_INTEGER DiskLocation, PIRP OriginalIrp)
Definition: xferpkt.c:372
ULONG LowMemRetry_remainingBufLen
Definition: classp.h:321
unsigned int ULONG
Definition: retypes.h:1
LONGLONG QuadPart
Definition: typedefs.h:112

Referenced by RetryTransferPacket(), ServiceTransferRequest(), and TransferPktComplete().

◆ TransferPacketRetryTimerDpc()

VOID NTAPI TransferPacketRetryTimerDpc ( IN PKDPC  Dpc,
IN PVOID  DeferredContext,
IN PVOID  SystemArgument1,
IN PVOID  SystemArgument2 
)

Definition at line 277 of file retry.c.

281 {
284 }
VOID NTAPI SubmitTransferPacket(PTRANSFER_PACKET Pkt)
Definition: xferpkt.c:460
struct _TRANSFER_PACKET * PTRANSFER_PACKET
_In_opt_ PVOID DeferredContext
Definition: ketypes.h:675

Referenced by RetryTransferPacket().