ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

retry.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.