Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenretry.c
Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (C) Microsoft Corporation, 1991 - 1999 00004 00005 Module Name: 00006 00007 retry.c 00008 00009 Abstract: 00010 00011 Packet retry routines for CLASSPNP 00012 00013 Environment: 00014 00015 kernel mode only 00016 00017 Notes: 00018 00019 00020 Revision History: 00021 00022 --*/ 00023 00024 #include "classp.h" 00025 #include "debug.h" 00026 00027 00028 00029 /* 00030 * InterpretTransferPacketError 00031 * 00032 * Interpret the SRB error into a meaningful IRP status. 00033 * ClassInterpretSenseInfo also may modify the SRB for the retry. 00034 * 00035 * Return TRUE iff packet should be retried. 00036 */ 00037 BOOLEAN InterpretTransferPacketError(PTRANSFER_PACKET Pkt) 00038 { 00039 BOOLEAN shouldRetry = FALSE; 00040 PCDB pCdb = (PCDB)Pkt->Srb.Cdb; 00041 00042 /* 00043 * Interpret the error using the returned sense info first. 00044 */ 00045 Pkt->RetryIntervalSec = 0; 00046 if (pCdb->MEDIA_REMOVAL.OperationCode == SCSIOP_MEDIUM_REMOVAL){ 00047 /* 00048 * This is an Ejection Control SRB. Interpret its sense info specially. 00049 */ 00050 shouldRetry = ClassInterpretSenseInfo( 00051 Pkt->Fdo, 00052 &Pkt->Srb, 00053 IRP_MJ_SCSI, 00054 0, 00055 MAXIMUM_RETRIES - Pkt->NumRetries, 00056 &Pkt->Irp->IoStatus.Status, 00057 &Pkt->RetryIntervalSec); 00058 if (shouldRetry){ 00059 /* 00060 * If the device is not ready, wait at least 2 seconds before retrying. 00061 */ 00062 PSENSE_DATA senseInfoBuffer = Pkt->Srb.SenseInfoBuffer; 00063 ASSERT(senseInfoBuffer); 00064 if (((Pkt->Irp->IoStatus.Status == STATUS_DEVICE_NOT_READY) && 00065 (senseInfoBuffer->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY)) || 00066 (SRB_STATUS(Pkt->Srb.SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT)){ 00067 00068 Pkt->RetryIntervalSec = MAX(Pkt->RetryIntervalSec, 2); 00069 } 00070 } 00071 } 00072 else if ((pCdb->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE) || 00073 (pCdb->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE10)){ 00074 /* 00075 * This is an Mode Sense SRB. Interpret its sense info specially. 00076 */ 00077 shouldRetry = ClassInterpretSenseInfo( 00078 Pkt->Fdo, 00079 &Pkt->Srb, 00080 IRP_MJ_SCSI, 00081 0, 00082 MAXIMUM_RETRIES - Pkt->NumRetries, 00083 &Pkt->Irp->IoStatus.Status, 00084 &Pkt->RetryIntervalSec); 00085 if (shouldRetry){ 00086 /* 00087 * If the device is not ready, wait at least 2 seconds before retrying. 00088 */ 00089 PSENSE_DATA senseInfoBuffer = Pkt->Srb.SenseInfoBuffer; 00090 ASSERT(senseInfoBuffer); 00091 if (((Pkt->Irp->IoStatus.Status == STATUS_DEVICE_NOT_READY) && 00092 (senseInfoBuffer->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY)) || 00093 (SRB_STATUS(Pkt->Srb.SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT)){ 00094 00095 Pkt->RetryIntervalSec = MAX(Pkt->RetryIntervalSec, 2); 00096 } 00097 } 00098 00099 /* 00100 * Some special cases for mode sense. 00101 */ 00102 if (Pkt->Irp->IoStatus.Status == STATUS_VERIFY_REQUIRED){ 00103 shouldRetry = TRUE; 00104 } 00105 else if (SRB_STATUS(Pkt->Srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN){ 00106 /* 00107 * This is a HACK. 00108 * Atapi returns SRB_STATUS_DATA_OVERRUN when it really means 00109 * underrun (i.e. success, and the buffer is longer than needed). 00110 * So treat this as a success. 00111 */ 00112 Pkt->Irp->IoStatus.Status = STATUS_SUCCESS; 00113 InterlockedExchangeAdd((PLONG)&Pkt->OriginalIrp->IoStatus.Information, (LONG)Pkt->Srb.DataTransferLength); 00114 shouldRetry = FALSE; 00115 } 00116 } 00117 else if (pCdb->CDB10.OperationCode == SCSIOP_READ_CAPACITY){ 00118 /* 00119 * This is a Drive Capacity SRB. Interpret its sense info specially. 00120 */ 00121 shouldRetry = ClassInterpretSenseInfo( 00122 Pkt->Fdo, 00123 &Pkt->Srb, 00124 IRP_MJ_SCSI, 00125 0, 00126 MAXIMUM_RETRIES - Pkt->NumRetries, 00127 &Pkt->Irp->IoStatus.Status, 00128 &Pkt->RetryIntervalSec); 00129 if (Pkt->Irp->IoStatus.Status == STATUS_VERIFY_REQUIRED){ 00130 shouldRetry = TRUE; 00131 } 00132 } 00133 else if ((pCdb->CDB10.OperationCode == SCSIOP_READ) || 00134 (pCdb->CDB10.OperationCode == SCSIOP_WRITE)){ 00135 /* 00136 * This is a Read/Write Data packet. 00137 */ 00138 PIO_STACK_LOCATION origCurrentSp = IoGetCurrentIrpStackLocation(Pkt->OriginalIrp); 00139 00140 shouldRetry = ClassInterpretSenseInfo( 00141 Pkt->Fdo, 00142 &Pkt->Srb, 00143 origCurrentSp->MajorFunction, 00144 0, 00145 MAXIMUM_RETRIES - Pkt->NumRetries, 00146 &Pkt->Irp->IoStatus.Status, 00147 &Pkt->RetryIntervalSec); 00148 /* 00149 * Deal with some special cases. 00150 */ 00151 if (Pkt->Irp->IoStatus.Status == STATUS_INSUFFICIENT_RESOURCES){ 00152 /* 00153 * We are in extreme low-memory stress. 00154 * We will retry in smaller chunks. 00155 */ 00156 shouldRetry = TRUE; 00157 } 00158 else if (TEST_FLAG(origCurrentSp->Flags, SL_OVERRIDE_VERIFY_VOLUME) && 00159 (Pkt->Irp->IoStatus.Status == STATUS_VERIFY_REQUIRED)){ 00160 /* 00161 * We are still verifying a (possibly) reloaded disk/cdrom. 00162 * So retry the request. 00163 */ 00164 Pkt->Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR; 00165 shouldRetry = TRUE; 00166 } 00167 } 00168 else { 00169 DBGERR(("Unhandled SRB Function %xh in error path for packet %p (did miniport change Srb.Cdb.OperationCode ?)", (ULONG)pCdb->CDB10.OperationCode, Pkt)); 00170 } 00171 00172 return shouldRetry; 00173 } 00174 00175 00176 /* 00177 * RetryTransferPacket 00178 * 00179 * Retry sending a TRANSFER_PACKET. 00180 * 00181 * Return TRUE iff the packet is complete. 00182 * (if so the status in pkt->irp is the final status). 00183 */ 00184 BOOLEAN RetryTransferPacket(PTRANSFER_PACKET Pkt) 00185 { 00186 BOOLEAN packetDone; 00187 00188 DBGTRACE(ClassDebugTrace, ("retrying failed transfer (pkt=%ph, op=%s)", Pkt, DBGGETSCSIOPSTR(&Pkt->Srb))); 00189 00190 ASSERT(Pkt->NumRetries > 0); 00191 Pkt->NumRetries--; 00192 00193 /* 00194 * Tone down performance on the retry. 00195 * This increases the chance for success on the retry. 00196 * We've seen instances of drives that fail consistently but then start working 00197 * once this scale-down is applied. 00198 */ 00199 SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_DISABLE_DISCONNECT); 00200 SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER); 00201 CLEAR_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE); 00202 Pkt->Srb.QueueTag = SP_UNTAGGED; 00203 00204 if (Pkt->Irp->IoStatus.Status == STATUS_INSUFFICIENT_RESOURCES){ 00205 PCDB pCdb = (PCDB)Pkt->Srb.Cdb; 00206 BOOLEAN isReadWrite = ((pCdb->CDB10.OperationCode == SCSIOP_READ) || 00207 (pCdb->CDB10.OperationCode == SCSIOP_WRITE)); 00208 00209 if (Pkt->InLowMemRetry || !isReadWrite){ 00210 /* 00211 * This should never happen. 00212 * The memory manager guarantees that at least four pages will 00213 * be available to allow forward progress in the port driver. 00214 * So a one-page transfer should never fail with insufficient resources. 00215 */ 00216 ASSERT(isReadWrite && !Pkt->InLowMemRetry); 00217 packetDone = TRUE; 00218 } 00219 else { 00220 /* 00221 * We are in low-memory stress. 00222 * Start the low-memory retry state machine, which tries to 00223 * resend the packet in little one-page chunks. 00224 */ 00225 InitLowMemRetry( Pkt, 00226 Pkt->BufPtrCopy, 00227 Pkt->BufLenCopy, 00228 Pkt->TargetLocationCopy); 00229 StepLowMemRetry(Pkt); 00230 packetDone = FALSE; 00231 } 00232 } 00233 else { 00234 /* 00235 * Retry the packet by simply resending it after a delay. 00236 * Put the packet back in the pending queue and 00237 * schedule a timer to retry the transfer. 00238 * 00239 * Do not call SetupReadWriteTransferPacket again because: 00240 * (1) The minidriver may have set some bits 00241 * in the SRB that it needs again and 00242 * (2) doing so would reset numRetries. 00243 * 00244 * BECAUSE we do not call SetupReadWriteTransferPacket again, 00245 * we have to reset a couple fields in the SRB that 00246 * some miniports overwrite when they fail an SRB. 00247 */ 00248 00249 Pkt->Srb.DataBuffer = Pkt->BufPtrCopy; 00250 Pkt->Srb.DataTransferLength = Pkt->BufLenCopy; 00251 00252 if (Pkt->RetryIntervalSec == 0){ 00253 /* 00254 * Always delay by at least a little when retrying. 00255 * Some problems (e.g. CRC errors) are not recoverable without a slight delay. 00256 */ 00257 LARGE_INTEGER timerPeriod; 00258 00259 timerPeriod.HighPart = -1; 00260 timerPeriod.LowPart = -(LONG)((ULONG)MINIMUM_RETRY_UNITS*KeQueryTimeIncrement()); 00261 KeInitializeTimer(&Pkt->RetryTimer); 00262 KeInitializeDpc(&Pkt->RetryTimerDPC, TransferPacketRetryTimerDpc, Pkt); 00263 KeSetTimer(&Pkt->RetryTimer, timerPeriod, &Pkt->RetryTimerDPC); 00264 } 00265 else { 00266 LARGE_INTEGER timerPeriod; 00267 00268 ASSERT(Pkt->RetryIntervalSec < 100); // sanity check 00269 timerPeriod.HighPart = -1; 00270 timerPeriod.LowPart = Pkt->RetryIntervalSec*-10000000; 00271 KeInitializeTimer(&Pkt->RetryTimer); 00272 KeInitializeDpc(&Pkt->RetryTimerDPC, TransferPacketRetryTimerDpc, Pkt); 00273 KeSetTimer(&Pkt->RetryTimer, timerPeriod, &Pkt->RetryTimerDPC); 00274 } 00275 packetDone = FALSE; 00276 } 00277 00278 return packetDone; 00279 } 00280 00281 00282 VOID TransferPacketRetryTimerDpc( IN PKDPC Dpc, 00283 IN PVOID DeferredContext, 00284 IN PVOID SystemArgument1, 00285 IN PVOID SystemArgument2) 00286 { 00287 PTRANSFER_PACKET pkt = (PTRANSFER_PACKET)DeferredContext; 00288 SubmitTransferPacket(pkt); 00289 } 00290 00291 00292 VOID InitLowMemRetry(PTRANSFER_PACKET Pkt, PVOID BufPtr, ULONG Len, LARGE_INTEGER TargetLocation) 00293 { 00294 ASSERT(Len > 0); 00295 ASSERT(!Pkt->InLowMemRetry); 00296 Pkt->InLowMemRetry = TRUE; 00297 Pkt->LowMemRetry_remainingBufPtr = BufPtr; 00298 Pkt->LowMemRetry_remainingBufLen = Len; 00299 Pkt->LowMemRetry_nextChunkTargetLocation = TargetLocation; 00300 } 00301 00302 00303 /* 00304 * StepLowMemRetry 00305 * 00306 * During extreme low-memory stress, this function retries 00307 * a packet in small one-page chunks, sent serially. 00308 * 00309 * Returns TRUE iff the packet is done. 00310 */ 00311 BOOLEAN StepLowMemRetry(PTRANSFER_PACKET Pkt) 00312 { 00313 BOOLEAN packetDone; 00314 00315 if (Pkt->LowMemRetry_remainingBufLen == 0){ 00316 packetDone = TRUE; 00317 } 00318 else { 00319 ULONG thisChunkLen; 00320 ULONG bytesToNextPageBoundary; 00321 00322 /* 00323 * Make sure the little chunk we send is <= a page length 00324 * AND that it does not cross any page boundaries. 00325 */ 00326 bytesToNextPageBoundary = PAGE_SIZE-(ULONG)((ULONG_PTR)Pkt->LowMemRetry_remainingBufPtr%PAGE_SIZE); 00327 thisChunkLen = MIN(Pkt->LowMemRetry_remainingBufLen, bytesToNextPageBoundary); 00328 00329 /* 00330 * Set up the transfer packet for the new little chunk. 00331 * This will reset numRetries so that we retry each chunk as required. 00332 */ 00333 SetupReadWriteTransferPacket(Pkt, 00334 Pkt->LowMemRetry_remainingBufPtr, 00335 thisChunkLen, 00336 Pkt->LowMemRetry_nextChunkTargetLocation, 00337 Pkt->OriginalIrp); 00338 00339 Pkt->LowMemRetry_remainingBufPtr += thisChunkLen; 00340 Pkt->LowMemRetry_remainingBufLen -= thisChunkLen; 00341 Pkt->LowMemRetry_nextChunkTargetLocation.QuadPart += thisChunkLen; 00342 00343 SubmitTransferPacket(Pkt); 00344 packetDone = FALSE; 00345 } 00346 00347 return packetDone; 00348 } 00349 Generated on Fri May 25 2012 04:26:37 for ReactOS by
1.7.6.1
|