ReactOS  0.4.14-dev-55-g2da92ac
retry.c
Go to the documentation of this file.
1 /*++
2 
3 Copyright (C) Microsoft Corporation, 1991 - 1999
4 
5 Module Name:
6 
7  retry.c
8 
9 Abstract:
10 
11  Packet retry 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 
26 /*
27  * InterpretTransferPacketError
28  *
29  * Interpret the SRB error into a meaningful IRP status.
30  * ClassInterpretSenseInfo also may modify the SRB for the retry.
31  *
32  * Return TRUE iff packet should be retried.
33  */
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 }
171 
172 /*
173  * RetryTransferPacket
174  *
175  * Retry sending a TRANSFER_PACKET.
176  *
177  * Return TRUE iff the packet is complete.
178  * (if so the status in pkt->irp is the final status).
179  */
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 }
276 
281 {
284 }
285 
287 {
288  ASSERT(Len > 0);
289  ASSERT(!Pkt->InLowMemRetry);
290  Pkt->InLowMemRetry = TRUE;
291  Pkt->LowMemRetry_remainingBufPtr = BufPtr;
293  Pkt->LowMemRetry_nextChunkTargetLocation = TargetLocation;
294 }
295 
296 /*
297  * StepLowMemRetry
298  *
299  * During extreme low-memory stress, this function retries
300  * a packet in small one-page chunks, sent serially.
301  *
302  * Returns TRUE iff the packet is done.
303  */
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 IN
Definition: typedefs.h:38
#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
struct _CDB::_MEDIA_REMOVAL MEDIA_REMOVAL
#define DBGGETSCSIOPSTR(_pSrb)
Definition: debug.h:140
#define TEST_FLAG(Flags, Bit)
Definition: classpnp.h:156
#define SCSIOP_MODE_SENSE
Definition: cdrw_hw.h:896
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
#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
PUCHAR LowMemRetry_remainingBufPtr
Definition: classp.h:320
KDPC RetryTimerDPC
Definition: classp.h:304
#define STATUS_VERIFY_REQUIRED
Definition: udferr_usr.h:130
UCHAR SrbStatus
Definition: srb.h:243
#define SRB_STATUS(Status)
Definition: srb.h:381
VOID NTAPI SubmitTransferPacket(PTRANSFER_PACKET Pkt)
Definition: xferpkt.c:460
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
uint32_t ULONG_PTR
Definition: typedefs.h:63
#define SP_UNTAGGED
Definition: srb.h:225
#define IRP_MJ_SCSI
T MIN(T a, T b)
Definition: polytest.cpp:79
#define STATUS_IO_DEVICE_ERROR
Definition: udferr_usr.h:179
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
long LONG
Definition: pedump.c:60
PDEVICE_OBJECT Fdo
Definition: classp.h:290
#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
#define SCSIOP_MODE_SENSE10
Definition: cdrw_hw.h:946
union _CDB * PCDB
VOID NTAPI KeInitializeTimer(OUT PKTIMER Timer)
Definition: timerobj.c:233
#define SL_OVERRIDE_VERIFY_VOLUME
Definition: iotypes.h:1780
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 InterlockedExchangeAdd
Definition: interlocked.h:181
#define MAXIMUM_RETRIES
Definition: class2.h:14
BOOLEAN NTAPI RetryTransferPacket(PTRANSFER_PACKET Pkt)
Definition: retry.c:180
struct _CDB::_MODE_SENSE MODE_SENSE
LARGE_INTEGER LowMemRetry_nextChunkTargetLocation
Definition: classp.h:322
_In_opt_ PVOID _In_opt_ PVOID SystemArgument1
Definition: ketypes.h:675
_In_ LARGE_INTEGER _In_opt_ PKDPC Dpc
Definition: kefuncs.h:524
PIRP OriginalIrp
Definition: classp.h:296
if(!(yy_init))
Definition: macro.lex.yy.c:714
#define SRB_FLAGS_DISABLE_SYNCH_TRANSFER
Definition: srb.h:389
struct _TRANSFER_PACKET * PTRANSFER_PACKET
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 Len
Definition: deflate.h:82
#define SRB_STATUS_DATA_OVERRUN
Definition: srb.h:349
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define SRB_FLAGS_DISABLE_DISCONNECT
Definition: srb.h:388
Definition: ketypes.h:687
#define SCSIOP_MEDIUM_REMOVAL
Definition: cdrw_hw.h:902
ULONG LowPart
Definition: typedefs.h:104
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define SRB_STATUS_SELECTION_TIMEOUT
Definition: srb.h:342
KTIMER RetryTimer
Definition: classp.h:303
#define SET_FLAG(Flags, Bit)
Definition: classpnp.h:154
_In_opt_ PVOID _In_opt_ PVOID _In_opt_ PVOID SystemArgument2
Definition: ketypes.h:675
T MAX(T a, T b)
Definition: polytest.cpp:85
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2745
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
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
#define SCSIOP_READ_CAPACITY
Definition: cdrw_hw.h:904
PVOID SenseInfoBuffer
Definition: srb.h:256
PUCHAR BufPtrCopy
Definition: classp.h:337
unsigned int ULONG
Definition: retypes.h:1
BOOLEAN NTAPI InterpretTransferPacketError(PTRANSFER_PACKET Pkt)
Definition: retry.c:34
UCHAR AdditionalSenseCode
Definition: cdrw_hw.h:1175
VOID NTAPI KeInitializeDpc(IN PKDPC Dpc, IN PKDEFERRED_ROUTINE DeferredRoutine, IN PVOID DeferredContext)
Definition: dpc.c:711
return STATUS_SUCCESS
Definition: btrfs.c:2966
signed int * PLONG
Definition: retypes.h:5
ULONG BufLenCopy
Definition: classp.h:338
#define SRB_FLAGS_QUEUE_ACTION_ENABLE
Definition: srb.h:387
LONGLONG QuadPart
Definition: typedefs.h:112
#define STATUS_DEVICE_NOT_READY
Definition: shellext.h:65
_In_opt_ PVOID DeferredContext
Definition: ketypes.h:675