xref: /reactos/drivers/storage/class/cdrom/sense.c (revision 3088717b)
1*3088717bSVictor Perevertkin /*--
2*3088717bSVictor Perevertkin 
3*3088717bSVictor Perevertkin Copyright (C) Microsoft Corporation. All rights reserved.
4*3088717bSVictor Perevertkin 
5*3088717bSVictor Perevertkin Module Name:
6*3088717bSVictor Perevertkin 
7*3088717bSVictor Perevertkin     sense.c
8*3088717bSVictor Perevertkin 
9*3088717bSVictor Perevertkin Abstract:
10*3088717bSVictor Perevertkin 
11*3088717bSVictor Perevertkin     This file contains the methods needed to accurately
12*3088717bSVictor Perevertkin     determine how to retry requests on CDROM device types.
13*3088717bSVictor Perevertkin 
14*3088717bSVictor Perevertkin Environment:
15*3088717bSVictor Perevertkin 
16*3088717bSVictor Perevertkin     kernel mode only
17*3088717bSVictor Perevertkin 
18*3088717bSVictor Perevertkin Revision History:
19*3088717bSVictor Perevertkin 
20*3088717bSVictor Perevertkin --*/
21*3088717bSVictor Perevertkin 
22*3088717bSVictor Perevertkin #include "stddef.h"
23*3088717bSVictor Perevertkin #include "string.h"
24*3088717bSVictor Perevertkin 
25*3088717bSVictor Perevertkin #include "ntddk.h"
26*3088717bSVictor Perevertkin #include "ntddstor.h"
27*3088717bSVictor Perevertkin #include "cdrom.h"
28*3088717bSVictor Perevertkin #include "ntstrsafe.h"
29*3088717bSVictor Perevertkin 
30*3088717bSVictor Perevertkin 
31*3088717bSVictor Perevertkin #ifdef DEBUG_USE_WPP
32*3088717bSVictor Perevertkin #include "sense.tmh"
33*3088717bSVictor Perevertkin #endif
34*3088717bSVictor Perevertkin 
35*3088717bSVictor Perevertkin // Forward declarations
36*3088717bSVictor Perevertkin VOID
37*3088717bSVictor Perevertkin SenseInfoInterpretRefineByIoControl(
38*3088717bSVictor Perevertkin     _In_      PCDROM_DEVICE_EXTENSION   DeviceExtension,
39*3088717bSVictor Perevertkin     _In_      ULONG                     IoControlCode,
40*3088717bSVictor Perevertkin     _In_      BOOLEAN                   OverrideVerifyVolume,
41*3088717bSVictor Perevertkin     _Inout_   BOOLEAN*                  Retry,
42*3088717bSVictor Perevertkin     _Inout_   NTSTATUS*                 Status
43*3088717bSVictor Perevertkin     );
44*3088717bSVictor Perevertkin 
45*3088717bSVictor Perevertkin 
46*3088717bSVictor Perevertkin #ifdef ALLOC_PRAGMA
47*3088717bSVictor Perevertkin 
48*3088717bSVictor Perevertkin #pragma alloc_text(PAGE, SenseInfoInterpretRefineByIoControl)
49*3088717bSVictor Perevertkin 
50*3088717bSVictor Perevertkin #endif
51*3088717bSVictor Perevertkin 
52*3088717bSVictor Perevertkin 
53*3088717bSVictor Perevertkin //
54*3088717bSVictor Perevertkin // FROM CLASSPNP\CLASSP.H
55*3088717bSVictor Perevertkin //  Lots of retries of synchronized SCSI commands that devices may not
56*3088717bSVictor Perevertkin //  even support really slows down the system (especially while booting).
57*3088717bSVictor Perevertkin //  (Even GetDriveCapacity may be failed on purpose if an external disk is powered off).
58*3088717bSVictor Perevertkin //  If a disk cannot return a small initialization buffer at startup
59*3088717bSVictor Perevertkin //  in two attempts (with delay interval) then we cannot expect it to return
60*3088717bSVictor Perevertkin //  data consistently with four retries.
61*3088717bSVictor Perevertkin //  So don't set the retry counts as high here as for data SRBs.
62*3088717bSVictor Perevertkin //
63*3088717bSVictor Perevertkin //  If we find that these requests are failing consecutively,
64*3088717bSVictor Perevertkin //  despite the retry interval, on otherwise reliable media,
65*3088717bSVictor Perevertkin //  then we should either increase the retry interval for
66*3088717bSVictor Perevertkin //  that failure or (by all means) increase these retry counts as appropriate.
67*3088717bSVictor Perevertkin //
68*3088717bSVictor Perevertkin 
69*3088717bSVictor Perevertkin #define TOTAL_COUNT_RETRY_DEFAULT       4
70*3088717bSVictor Perevertkin #define TOTAL_COUNT_RETRY_LOCK_MEDIA    1
71*3088717bSVictor Perevertkin #define TOTAL_COUNT_RETRY_MODESENSE     1
72*3088717bSVictor Perevertkin #define TOTAL_COUNT_RETRY_READ_CAPACITY 1
73*3088717bSVictor Perevertkin 
74*3088717bSVictor Perevertkin 
75*3088717bSVictor Perevertkin #define TOTAL_SECONDS_RETRY_TIME_WRITE          160
76*3088717bSVictor Perevertkin #define TOTAL_SECONDS_RETRY_TIME_MEDIUM_REMOVAL 120
77*3088717bSVictor Perevertkin 
78*3088717bSVictor Perevertkin typedef struct _ERROR_LOG_CONTEXT {
79*3088717bSVictor Perevertkin     BOOLEAN     LogError;
80*3088717bSVictor Perevertkin     BOOLEAN     ErrorUnhandled;
81*3088717bSVictor Perevertkin     NTSTATUS    ErrorCode;
82*3088717bSVictor Perevertkin     ULONG       UniqueErrorValue;
83*3088717bSVictor Perevertkin     ULONG       BadSector;
84*3088717bSVictor Perevertkin } ERROR_LOG_CONTEXT, *PERROR_LOG_CONTEXT;
85*3088717bSVictor Perevertkin 
86*3088717bSVictor Perevertkin NTSTATUS
DeviceErrorHandlerForMmc(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension,_In_ PSCSI_REQUEST_BLOCK Srb,_Inout_ PNTSTATUS Status,_Inout_ PBOOLEAN Retry)87*3088717bSVictor Perevertkin DeviceErrorHandlerForMmc(
88*3088717bSVictor Perevertkin     _In_ PCDROM_DEVICE_EXTENSION  DeviceExtension,
89*3088717bSVictor Perevertkin     _In_ PSCSI_REQUEST_BLOCK      Srb,
90*3088717bSVictor Perevertkin     _Inout_ PNTSTATUS             Status,
91*3088717bSVictor Perevertkin     _Inout_ PBOOLEAN              Retry
92*3088717bSVictor Perevertkin     )
93*3088717bSVictor Perevertkin /*++
94*3088717bSVictor Perevertkin 
95*3088717bSVictor Perevertkin Routine Description:
96*3088717bSVictor Perevertkin 
97*3088717bSVictor Perevertkin     this routine will be used for error handler for all MMC devices.
98*3088717bSVictor Perevertkin     it's invoked by DeviceErrorHandler()that invoked by SenseInfoInterpret() or GESN
99*3088717bSVictor Perevertkin 
100*3088717bSVictor Perevertkin     This routine just checks for media change sense/asc/ascq and
101*3088717bSVictor Perevertkin     also for other events, such as bus resets.  this is used to
102*3088717bSVictor Perevertkin     determine if the device behaviour has changed, to allow for
103*3088717bSVictor Perevertkin     read and write operations to be allowed and/or disallowed.
104*3088717bSVictor Perevertkin 
105*3088717bSVictor Perevertkin Arguments:
106*3088717bSVictor Perevertkin 
107*3088717bSVictor Perevertkin     DeviceExtension - device context
108*3088717bSVictor Perevertkin     Srb - SRB structure for analyze
109*3088717bSVictor Perevertkin 
110*3088717bSVictor Perevertkin Return Value:
111*3088717bSVictor Perevertkin 
112*3088717bSVictor Perevertkin     NTSTATUS
113*3088717bSVictor Perevertkin     Status -
114*3088717bSVictor Perevertkin     Retry -
115*3088717bSVictor Perevertkin 
116*3088717bSVictor Perevertkin --*/
117*3088717bSVictor Perevertkin {
118*3088717bSVictor Perevertkin     BOOLEAN mediaChange = FALSE;
119*3088717bSVictor Perevertkin     PCDB    cdb = (PCDB)Srb->Cdb;
120*3088717bSVictor Perevertkin 
121*3088717bSVictor Perevertkin     if (TEST_FLAG(Srb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID))
122*3088717bSVictor Perevertkin     {
123*3088717bSVictor Perevertkin         PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
124*3088717bSVictor Perevertkin 
125*3088717bSVictor Perevertkin         // the following sense keys could indicate a change in capabilities.
126*3088717bSVictor Perevertkin 
127*3088717bSVictor Perevertkin         // we used to expect this to be serialized, and only hit from our
128*3088717bSVictor Perevertkin         // own routine. we now allow some requests to continue during our
129*3088717bSVictor Perevertkin         // processing of the capabilities update in order to allow
130*3088717bSVictor Perevertkin         // IoReadPartitionTable() to succeed.
131*3088717bSVictor Perevertkin         switch (senseBuffer->SenseKey & 0xf)
132*3088717bSVictor Perevertkin         {
133*3088717bSVictor Perevertkin 
134*3088717bSVictor Perevertkin         case SCSI_SENSE_NOT_READY:
135*3088717bSVictor Perevertkin         {
136*3088717bSVictor Perevertkin             if (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_NO_MEDIA_IN_DEVICE)
137*3088717bSVictor Perevertkin             {
138*3088717bSVictor Perevertkin                 if (DeviceExtension->DeviceAdditionalData.Mmc.WriteAllowed)
139*3088717bSVictor Perevertkin                 {
140*3088717bSVictor Perevertkin                     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
141*3088717bSVictor Perevertkin                                "DeviceErrorHandlerForMmc: media removed, writes will be "
142*3088717bSVictor Perevertkin                                "failed until new media detected\n"));
143*3088717bSVictor Perevertkin                 }
144*3088717bSVictor Perevertkin 
145*3088717bSVictor Perevertkin                 // NOTE - REF #0002
146*3088717bSVictor Perevertkin                 DeviceExtension->DeviceAdditionalData.Mmc.WriteAllowed = FALSE;
147*3088717bSVictor Perevertkin             }
148*3088717bSVictor Perevertkin             else if (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY)
149*3088717bSVictor Perevertkin             {
150*3088717bSVictor Perevertkin                 if (senseBuffer->AdditionalSenseCodeQualifier == SCSI_SENSEQ_BECOMING_READY)
151*3088717bSVictor Perevertkin                 {
152*3088717bSVictor Perevertkin                     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
153*3088717bSVictor Perevertkin                                "DeviceErrorHandlerForMmc: media becoming ready, "
154*3088717bSVictor Perevertkin                                "SHOULD notify shell of change time by sending "
155*3088717bSVictor Perevertkin                                "GESN request immediately!\n"));
156*3088717bSVictor Perevertkin                 }
157*3088717bSVictor Perevertkin                 else if (((senseBuffer->AdditionalSenseCodeQualifier == SCSI_SENSEQ_OPERATION_IN_PROGRESS) ||
158*3088717bSVictor Perevertkin                             (senseBuffer->AdditionalSenseCodeQualifier == SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS)
159*3088717bSVictor Perevertkin                             ) &&
160*3088717bSVictor Perevertkin                            ((Srb->Cdb[0] == SCSIOP_READ) ||
161*3088717bSVictor Perevertkin                             (Srb->Cdb[0] == SCSIOP_READ6) ||
162*3088717bSVictor Perevertkin                             (Srb->Cdb[0] == SCSIOP_READ_CAPACITY) ||
163*3088717bSVictor Perevertkin                             (Srb->Cdb[0] == SCSIOP_READ_CD) ||
164*3088717bSVictor Perevertkin                             (Srb->Cdb[0] == SCSIOP_READ_CD_MSF) ||
165*3088717bSVictor Perevertkin                             (Srb->Cdb[0] == SCSIOP_READ_TOC) ||
166*3088717bSVictor Perevertkin                             (Srb->Cdb[0] == SCSIOP_WRITE) ||
167*3088717bSVictor Perevertkin                             (Srb->Cdb[0] == SCSIOP_WRITE6) ||
168*3088717bSVictor Perevertkin                             (Srb->Cdb[0] == SCSIOP_READ_TRACK_INFORMATION) ||
169*3088717bSVictor Perevertkin                             (Srb->Cdb[0] == SCSIOP_READ_DISK_INFORMATION)
170*3088717bSVictor Perevertkin                             )
171*3088717bSVictor Perevertkin                            )
172*3088717bSVictor Perevertkin                 {
173*3088717bSVictor Perevertkin                     TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL,
174*3088717bSVictor Perevertkin                                "DeviceErrorHandlerForMmc: LONG_WRITE or "
175*3088717bSVictor Perevertkin                                "OP_IN_PROGRESS for limited subset of cmds -- "
176*3088717bSVictor Perevertkin                                "setting retry to TRUE\n"));
177*3088717bSVictor Perevertkin                     *Retry = TRUE;
178*3088717bSVictor Perevertkin                     *Status = STATUS_DEVICE_BUSY;
179*3088717bSVictor Perevertkin                 }
180*3088717bSVictor Perevertkin             }
181*3088717bSVictor Perevertkin             break;
182*3088717bSVictor Perevertkin         } // end SCSI_SENSE_NOT_READY
183*3088717bSVictor Perevertkin 
184*3088717bSVictor Perevertkin         case SCSI_SENSE_UNIT_ATTENTION:
185*3088717bSVictor Perevertkin         {
186*3088717bSVictor Perevertkin             switch (senseBuffer->AdditionalSenseCode)
187*3088717bSVictor Perevertkin             {
188*3088717bSVictor Perevertkin             case SCSI_ADSENSE_MEDIUM_CHANGED:
189*3088717bSVictor Perevertkin             {
190*3088717bSVictor Perevertkin                 // always update if the medium may have changed
191*3088717bSVictor Perevertkin 
192*3088717bSVictor Perevertkin                 // NOTE - REF #0002
193*3088717bSVictor Perevertkin                 DeviceExtension->DeviceAdditionalData.Mmc.WriteAllowed = FALSE;
194*3088717bSVictor Perevertkin                 DeviceExtension->DeviceAdditionalData.Mmc.UpdateState = CdromMmcUpdateRequired;
195*3088717bSVictor Perevertkin 
196*3088717bSVictor Perevertkin                 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
197*3088717bSVictor Perevertkin                            "DeviceErrorHandlerForMmc: media change detected, need to "
198*3088717bSVictor Perevertkin                            "update drive capabilities\n"));
199*3088717bSVictor Perevertkin                 mediaChange = TRUE;
200*3088717bSVictor Perevertkin                 break;
201*3088717bSVictor Perevertkin 
202*3088717bSVictor Perevertkin             } // end SCSI_ADSENSE_MEDIUM_CHANGED
203*3088717bSVictor Perevertkin 
204*3088717bSVictor Perevertkin             case SCSI_ADSENSE_BUS_RESET:
205*3088717bSVictor Perevertkin             {
206*3088717bSVictor Perevertkin                 // NOTE - REF #0002
207*3088717bSVictor Perevertkin                 DeviceExtension->DeviceAdditionalData.Mmc.WriteAllowed = FALSE;
208*3088717bSVictor Perevertkin                 DeviceExtension->DeviceAdditionalData.Mmc.UpdateState = CdromMmcUpdateRequired;
209*3088717bSVictor Perevertkin 
210*3088717bSVictor Perevertkin                 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
211*3088717bSVictor Perevertkin                            "DeviceErrorHandlerForMmc: bus reset detected, need to "
212*3088717bSVictor Perevertkin                            "update drive capabilities\n"));
213*3088717bSVictor Perevertkin                 break;
214*3088717bSVictor Perevertkin 
215*3088717bSVictor Perevertkin             } // end SCSI_ADSENSE_BUS_RESET
216*3088717bSVictor Perevertkin 
217*3088717bSVictor Perevertkin             case SCSI_ADSENSE_OPERATOR_REQUEST:
218*3088717bSVictor Perevertkin             {
219*3088717bSVictor Perevertkin 
220*3088717bSVictor Perevertkin                 BOOLEAN b = FALSE;
221*3088717bSVictor Perevertkin 
222*3088717bSVictor Perevertkin                 switch (senseBuffer->AdditionalSenseCodeQualifier)
223*3088717bSVictor Perevertkin                 {
224*3088717bSVictor Perevertkin                 case SCSI_SENSEQ_MEDIUM_REMOVAL:
225*3088717bSVictor Perevertkin                 {
226*3088717bSVictor Perevertkin                     // eject notification currently handled by classpnp
227*3088717bSVictor Perevertkin                     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
228*3088717bSVictor Perevertkin                                "DeviceErrorHandlerForMmc: Eject requested by user\n"));
229*3088717bSVictor Perevertkin                     *Retry = TRUE;
230*3088717bSVictor Perevertkin                     *Status = STATUS_DEVICE_BUSY;
231*3088717bSVictor Perevertkin                     break;
232*3088717bSVictor Perevertkin                 }
233*3088717bSVictor Perevertkin 
234*3088717bSVictor Perevertkin                 case SCSI_SENSEQ_WRITE_PROTECT_DISABLE:
235*3088717bSVictor Perevertkin                     b = TRUE;
236*3088717bSVictor Perevertkin                 case SCSI_SENSEQ_WRITE_PROTECT_ENABLE:
237*3088717bSVictor Perevertkin                 {
238*3088717bSVictor Perevertkin                     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
239*3088717bSVictor Perevertkin                                "DeviceErrorHandlerForMmc: Write protect %s requested "
240*3088717bSVictor Perevertkin                                "by user\n",
241*3088717bSVictor Perevertkin                                (b ? "disable" : "enable")));
242*3088717bSVictor Perevertkin                     *Retry = TRUE;
243*3088717bSVictor Perevertkin                     *Status = STATUS_DEVICE_BUSY;
244*3088717bSVictor Perevertkin                     // NOTE - REF #0002
245*3088717bSVictor Perevertkin                     DeviceExtension->DeviceAdditionalData.Mmc.WriteAllowed = FALSE;
246*3088717bSVictor Perevertkin                     DeviceExtension->DeviceAdditionalData.Mmc.UpdateState = CdromMmcUpdateRequired;
247*3088717bSVictor Perevertkin 
248*3088717bSVictor Perevertkin                     break;
249*3088717bSVictor Perevertkin                 }
250*3088717bSVictor Perevertkin 
251*3088717bSVictor Perevertkin                 } // end of AdditionalSenseCodeQualifier switch
252*3088717bSVictor Perevertkin 
253*3088717bSVictor Perevertkin 
254*3088717bSVictor Perevertkin                 break;
255*3088717bSVictor Perevertkin 
256*3088717bSVictor Perevertkin             } // end SCSI_ADSENSE_OPERATOR_REQUEST
257*3088717bSVictor Perevertkin 
258*3088717bSVictor Perevertkin             default:
259*3088717bSVictor Perevertkin             {
260*3088717bSVictor Perevertkin                 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL,
261*3088717bSVictor Perevertkin                            "DeviceErrorHandlerForMmc: Unit attention %02x/%02x\n",
262*3088717bSVictor Perevertkin                            senseBuffer->AdditionalSenseCode,
263*3088717bSVictor Perevertkin                            senseBuffer->AdditionalSenseCodeQualifier));
264*3088717bSVictor Perevertkin                 break;
265*3088717bSVictor Perevertkin             }
266*3088717bSVictor Perevertkin 
267*3088717bSVictor Perevertkin             } // end of AdditionSenseCode switch
268*3088717bSVictor Perevertkin             break;
269*3088717bSVictor Perevertkin 
270*3088717bSVictor Perevertkin         } // end SCSI_SENSE_UNIT_ATTENTION
271*3088717bSVictor Perevertkin 
272*3088717bSVictor Perevertkin         case SCSI_SENSE_ILLEGAL_REQUEST:
273*3088717bSVictor Perevertkin         {
274*3088717bSVictor Perevertkin             if (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_WRITE_PROTECT)
275*3088717bSVictor Perevertkin             {
276*3088717bSVictor Perevertkin                 if (DeviceExtension->DeviceAdditionalData.Mmc.WriteAllowed)
277*3088717bSVictor Perevertkin                 {
278*3088717bSVictor Perevertkin                     TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL,
279*3088717bSVictor Perevertkin                                "DeviceErrorHandlerForMmc: media was writable, but "
280*3088717bSVictor Perevertkin                                "failed request with WRITE_PROTECT error...\n"));
281*3088717bSVictor Perevertkin                 }
282*3088717bSVictor Perevertkin                 // NOTE - REF #0002
283*3088717bSVictor Perevertkin                 // do not update all the capabilities just because
284*3088717bSVictor Perevertkin                 // we can't write to the disc.
285*3088717bSVictor Perevertkin                 DeviceExtension->DeviceAdditionalData.Mmc.WriteAllowed = FALSE;
286*3088717bSVictor Perevertkin             }
287*3088717bSVictor Perevertkin             break;
288*3088717bSVictor Perevertkin         } // end SCSI_SENSE_ILLEGAL_REQUEST
289*3088717bSVictor Perevertkin 
290*3088717bSVictor Perevertkin         } // end of SenseKey switch
291*3088717bSVictor Perevertkin 
292*3088717bSVictor Perevertkin         // Check if we failed to set the DVD region key and send appropriate error
293*3088717bSVictor Perevertkin         if (cdb->CDB16.OperationCode == SCSIOP_SEND_KEY)
294*3088717bSVictor Perevertkin         {
295*3088717bSVictor Perevertkin             if (cdb->SEND_KEY.KeyFormat == DvdSetRpcKey)
296*3088717bSVictor Perevertkin             {
297*3088717bSVictor Perevertkin                 if (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_NO_MEDIA_IN_DEVICE)
298*3088717bSVictor Perevertkin                 {
299*3088717bSVictor Perevertkin                     // media of appropriate region required
300*3088717bSVictor Perevertkin                     *Status = STATUS_NO_MEDIA_IN_DEVICE;
301*3088717bSVictor Perevertkin                     *Retry = FALSE;
302*3088717bSVictor Perevertkin                 }
303*3088717bSVictor Perevertkin                 else if ((senseBuffer->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST) &&
304*3088717bSVictor Perevertkin                            (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_COPY_PROTECTION_FAILURE) &&
305*3088717bSVictor Perevertkin                            (senseBuffer->AdditionalSenseCodeQualifier == SCSI_SENSEQ_MEDIA_CODE_MISMATCHED_TO_LOGICAL_UNIT))
306*3088717bSVictor Perevertkin                 {
307*3088717bSVictor Perevertkin                     // media of appropriate region required
308*3088717bSVictor Perevertkin                     *Status = STATUS_CSS_REGION_MISMATCH;
309*3088717bSVictor Perevertkin                     *Retry = FALSE;
310*3088717bSVictor Perevertkin                 }
311*3088717bSVictor Perevertkin                 else if ((senseBuffer->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST) &&
312*3088717bSVictor Perevertkin                            (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_INVALID_MEDIA) &&
313*3088717bSVictor Perevertkin                            (senseBuffer->AdditionalSenseCodeQualifier == SCSI_SENSEQ_INCOMPATIBLE_FORMAT))
314*3088717bSVictor Perevertkin                 {
315*3088717bSVictor Perevertkin                     // media of appropriate region required
316*3088717bSVictor Perevertkin                     *Status = STATUS_CSS_REGION_MISMATCH;
317*3088717bSVictor Perevertkin                     *Retry = FALSE;
318*3088717bSVictor Perevertkin                 }
319*3088717bSVictor Perevertkin             }
320*3088717bSVictor Perevertkin         }
321*3088717bSVictor Perevertkin     } // end of SRB_STATUS_AUTOSENSE_VALID
322*3088717bSVictor Perevertkin 
323*3088717bSVictor Perevertkin     // On media change, if device speed should be reset to default then
324*3088717bSVictor Perevertkin     // queue a workitem to send the commands to the device. Do this on
325*3088717bSVictor Perevertkin     // media arrival as some device will fail this command if no media
326*3088717bSVictor Perevertkin     // is present. Ignore the fake media change from classpnp driver.
327*3088717bSVictor Perevertkin     if ((mediaChange == TRUE) && (*Status != STATUS_MEDIA_CHANGED))
328*3088717bSVictor Perevertkin     {
329*3088717bSVictor Perevertkin         if (DeviceExtension->DeviceAdditionalData.RestoreDefaults == TRUE)
330*3088717bSVictor Perevertkin         {
331*3088717bSVictor Perevertkin             NTSTATUS                status = STATUS_SUCCESS;
332*3088717bSVictor Perevertkin             WDF_OBJECT_ATTRIBUTES   attributes;
333*3088717bSVictor Perevertkin             WDF_WORKITEM_CONFIG     workitemConfig;
334*3088717bSVictor Perevertkin             WDFWORKITEM             workItem;
335*3088717bSVictor Perevertkin 
336*3088717bSVictor Perevertkin             WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
337*3088717bSVictor Perevertkin             attributes.ParentObject = DeviceExtension->Device;
338*3088717bSVictor Perevertkin 
339*3088717bSVictor Perevertkin             WDF_WORKITEM_CONFIG_INIT(&workitemConfig,
340*3088717bSVictor Perevertkin                                      DeviceRestoreDefaultSpeed);
341*3088717bSVictor Perevertkin 
342*3088717bSVictor Perevertkin             status = WdfWorkItemCreate(&workitemConfig,
343*3088717bSVictor Perevertkin                                        &attributes,
344*3088717bSVictor Perevertkin                                        &workItem);
345*3088717bSVictor Perevertkin             if (!NT_SUCCESS(status))
346*3088717bSVictor Perevertkin             {
347*3088717bSVictor Perevertkin                 return STATUS_SUCCESS;
348*3088717bSVictor Perevertkin             }
349*3088717bSVictor Perevertkin 
350*3088717bSVictor Perevertkin             WdfWorkItemEnqueue(workItem);
351*3088717bSVictor Perevertkin 
352*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
353*3088717bSVictor Perevertkin                         "DeviceErrorHandlerForMmc: Restore device default speed for %p\n",
354*3088717bSVictor Perevertkin                         DeviceExtension->DeviceObject));
355*3088717bSVictor Perevertkin         }
356*3088717bSVictor Perevertkin     }
357*3088717bSVictor Perevertkin     return STATUS_SUCCESS;
358*3088717bSVictor Perevertkin }
359*3088717bSVictor Perevertkin 
360*3088717bSVictor Perevertkin NTSTATUS
DeviceErrorHandlerForHitachiGD2000(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension,_In_ PSCSI_REQUEST_BLOCK Srb,_Inout_ PNTSTATUS Status,_Inout_ PBOOLEAN Retry)361*3088717bSVictor Perevertkin DeviceErrorHandlerForHitachiGD2000(
362*3088717bSVictor Perevertkin     _In_ PCDROM_DEVICE_EXTENSION  DeviceExtension,
363*3088717bSVictor Perevertkin     _In_ PSCSI_REQUEST_BLOCK      Srb,
364*3088717bSVictor Perevertkin     _Inout_ PNTSTATUS             Status,
365*3088717bSVictor Perevertkin     _Inout_ PBOOLEAN              Retry
366*3088717bSVictor Perevertkin     )
367*3088717bSVictor Perevertkin /*++
368*3088717bSVictor Perevertkin 
369*3088717bSVictor Perevertkin Routine Description:
370*3088717bSVictor Perevertkin 
371*3088717bSVictor Perevertkin    error handler for HITACHI CDR-1750S, CDR-3650/1650S
372*3088717bSVictor Perevertkin 
373*3088717bSVictor Perevertkin    This routine checks the type of error.  If the error suggests that the
374*3088717bSVictor Perevertkin    drive has spun down and cannot reinitialize itself, send a
375*3088717bSVictor Perevertkin    START_UNIT or READ to the device.  This will force the drive to spin
376*3088717bSVictor Perevertkin    up.  This drive also loses the AGIDs it has granted when it spins down,
377*3088717bSVictor Perevertkin    which may result in playback failure the first time around.
378*3088717bSVictor Perevertkin 
379*3088717bSVictor Perevertkin Arguments:
380*3088717bSVictor Perevertkin 
381*3088717bSVictor Perevertkin     DeviceExtension - the device object.
382*3088717bSVictor Perevertkin 
383*3088717bSVictor Perevertkin     Srb - Supplies a pointer to the failing Srb.
384*3088717bSVictor Perevertkin 
385*3088717bSVictor Perevertkin     Status - return the final status for this command?
386*3088717bSVictor Perevertkin 
387*3088717bSVictor Perevertkin     Retry - return if the command should be retried.
388*3088717bSVictor Perevertkin 
389*3088717bSVictor Perevertkin Return Value:
390*3088717bSVictor Perevertkin 
391*3088717bSVictor Perevertkin     None.
392*3088717bSVictor Perevertkin 
393*3088717bSVictor Perevertkin --*/
394*3088717bSVictor Perevertkin {
395*3088717bSVictor Perevertkin     PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
396*3088717bSVictor Perevertkin 
397*3088717bSVictor Perevertkin     if (!TEST_FLAG(Srb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID))
398*3088717bSVictor Perevertkin     {
399*3088717bSVictor Perevertkin         return STATUS_SUCCESS; //nobody cares about this return value yet.
400*3088717bSVictor Perevertkin     }
401*3088717bSVictor Perevertkin 
402*3088717bSVictor Perevertkin     if (((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_HARDWARE_ERROR) &&
403*3088717bSVictor Perevertkin         (senseBuffer->AdditionalSenseCode == 0x44))
404*3088717bSVictor Perevertkin     {
405*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
406*3088717bSVictor Perevertkin                     "DeviceErrorHandlerForHitachiGD2000 (%p) => Internal Target "
407*3088717bSVictor Perevertkin                     "Failure Detected -- spinning up drive\n", DeviceExtension->Device));
408*3088717bSVictor Perevertkin 
409*3088717bSVictor Perevertkin         // the request should be retried because the device isn't ready
410*3088717bSVictor Perevertkin         *Retry = TRUE;
411*3088717bSVictor Perevertkin         *Status = STATUS_DEVICE_NOT_READY;
412*3088717bSVictor Perevertkin 
413*3088717bSVictor Perevertkin         // send a START_STOP unit to spin up the drive
414*3088717bSVictor Perevertkin         // NOTE: this temporarily violates the StartIo serialization
415*3088717bSVictor Perevertkin         //       mechanism, but the completion routine on this will NOT
416*3088717bSVictor Perevertkin         //       call StartNextPacket(), so it's a temporary disruption
417*3088717bSVictor Perevertkin         //       of the serialization only.
418*3088717bSVictor Perevertkin         DeviceSendStartUnit(DeviceExtension->Device);
419*3088717bSVictor Perevertkin     }
420*3088717bSVictor Perevertkin 
421*3088717bSVictor Perevertkin     return STATUS_SUCCESS;
422*3088717bSVictor Perevertkin }
423*3088717bSVictor Perevertkin 
424*3088717bSVictor Perevertkin 
425*3088717bSVictor Perevertkin VOID
SenseInfoRequestGetInformation(_In_ WDFREQUEST Request,_Out_ UCHAR * MajorFunctionCode,_Out_ ULONG * IoControlCode,_Out_ BOOLEAN * OverrideVerifyVolume,_Out_ ULONGLONG * Total100nsSinceFirstSend)426*3088717bSVictor Perevertkin SenseInfoRequestGetInformation(
427*3088717bSVictor Perevertkin     _In_  WDFREQUEST  Request,
428*3088717bSVictor Perevertkin     _Out_ UCHAR*      MajorFunctionCode,
429*3088717bSVictor Perevertkin     _Out_ ULONG*      IoControlCode,
430*3088717bSVictor Perevertkin     _Out_ BOOLEAN*    OverrideVerifyVolume,
431*3088717bSVictor Perevertkin     _Out_ ULONGLONG*  Total100nsSinceFirstSend
432*3088717bSVictor Perevertkin     )
433*3088717bSVictor Perevertkin {
434*3088717bSVictor Perevertkin     PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request);
435*3088717bSVictor Perevertkin 
436*3088717bSVictor Perevertkin     *MajorFunctionCode = 0;
437*3088717bSVictor Perevertkin     *IoControlCode = 0;
438*3088717bSVictor Perevertkin     *OverrideVerifyVolume = FALSE;
439*3088717bSVictor Perevertkin     *Total100nsSinceFirstSend = 0;
440*3088717bSVictor Perevertkin 
441*3088717bSVictor Perevertkin     if (requestContext->OriginalRequest != NULL)
442*3088717bSVictor Perevertkin     {
443*3088717bSVictor Perevertkin         PIO_STACK_LOCATION originalIrpStack = NULL;
444*3088717bSVictor Perevertkin 
445*3088717bSVictor Perevertkin         PIRP originalIrp = WdfRequestWdmGetIrp(requestContext->OriginalRequest);
446*3088717bSVictor Perevertkin 
447*3088717bSVictor Perevertkin         if (originalIrp != NULL)
448*3088717bSVictor Perevertkin         {
449*3088717bSVictor Perevertkin             originalIrpStack = IoGetCurrentIrpStackLocation(originalIrp);
450*3088717bSVictor Perevertkin         }
451*3088717bSVictor Perevertkin 
452*3088717bSVictor Perevertkin         if (originalIrpStack != NULL)
453*3088717bSVictor Perevertkin         {
454*3088717bSVictor Perevertkin             *MajorFunctionCode = originalIrpStack->MajorFunction;
455*3088717bSVictor Perevertkin 
456*3088717bSVictor Perevertkin             if (*MajorFunctionCode == IRP_MJ_DEVICE_CONTROL)
457*3088717bSVictor Perevertkin             {
458*3088717bSVictor Perevertkin                 *IoControlCode = originalIrpStack->Parameters.DeviceIoControl.IoControlCode;
459*3088717bSVictor Perevertkin             }
460*3088717bSVictor Perevertkin 
461*3088717bSVictor Perevertkin             *OverrideVerifyVolume = TEST_FLAG(originalIrpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME);
462*3088717bSVictor Perevertkin         }
463*3088717bSVictor Perevertkin     }
464*3088717bSVictor Perevertkin 
465*3088717bSVictor Perevertkin     // Calculate time past since the request was first time sent.
466*3088717bSVictor Perevertkin     if (requestContext->TimeSentDownFirstTime.QuadPart > 0)
467*3088717bSVictor Perevertkin     {
468*3088717bSVictor Perevertkin         LARGE_INTEGER tmp;
469*3088717bSVictor Perevertkin         KeQueryTickCount(&tmp);
470*3088717bSVictor Perevertkin         tmp.QuadPart -= requestContext->TimeSentDownFirstTime.QuadPart;
471*3088717bSVictor Perevertkin         tmp.QuadPart *= KeQueryTimeIncrement();
472*3088717bSVictor Perevertkin         *Total100nsSinceFirstSend = tmp.QuadPart;
473*3088717bSVictor Perevertkin     }
474*3088717bSVictor Perevertkin     else
475*3088717bSVictor Perevertkin     {
476*3088717bSVictor Perevertkin         // set to -1 if field TimeSentDownFirstTime not set.
477*3088717bSVictor Perevertkin         *Total100nsSinceFirstSend = (ULONGLONG) -1;
478*3088717bSVictor Perevertkin     }
479*3088717bSVictor Perevertkin 
480*3088717bSVictor Perevertkin     return;
481*3088717bSVictor Perevertkin }
482*3088717bSVictor Perevertkin 
483*3088717bSVictor Perevertkin BOOLEAN
484*3088717bSVictor Perevertkin SenseInfoInterpretByAdditionalSenseCode(
485*3088717bSVictor Perevertkin     _In_      PCDROM_DEVICE_EXTENSION   DeviceExtension,
486*3088717bSVictor Perevertkin     _In_      PSCSI_REQUEST_BLOCK       Srb,
487*3088717bSVictor Perevertkin     _In_      UCHAR                     AdditionalSenseCode,
488*3088717bSVictor Perevertkin     _In_      UCHAR                     AdditionalSenseCodeQual,
489*3088717bSVictor Perevertkin     _Inout_   NTSTATUS*                 Status,
490*3088717bSVictor Perevertkin     _Inout_   BOOLEAN*                  Retry,
491*3088717bSVictor Perevertkin     _Out_ _Deref_out_range_(0,100) ULONG*         RetryIntervalInSeconds,
492*3088717bSVictor Perevertkin     _Inout_   PERROR_LOG_CONTEXT        LogContext
493*3088717bSVictor Perevertkin     )
494*3088717bSVictor Perevertkin /*
495*3088717bSVictor Perevertkin     This function will interpret error based on ASC/ASCQ.
496*3088717bSVictor Perevertkin 
497*3088717bSVictor Perevertkin     If the error code is not processed in this function, e.g. return value is TRUE,
498*3088717bSVictor Perevertkin     caller needs to call SenseInfoInterpretBySenseKey() for further interpret.
499*3088717bSVictor Perevertkin */
500*3088717bSVictor Perevertkin {
501*3088717bSVictor Perevertkin     BOOLEAN     needFurtherInterpret = TRUE;
502*3088717bSVictor Perevertkin     PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
503*3088717bSVictor Perevertkin 
504*3088717bSVictor Perevertkin     // set default values for retry fields.
505*3088717bSVictor Perevertkin     *Status = STATUS_IO_DEVICE_ERROR;
506*3088717bSVictor Perevertkin     *Retry = TRUE;
507*3088717bSVictor Perevertkin     *RetryIntervalInSeconds = 0;
508*3088717bSVictor Perevertkin 
509*3088717bSVictor Perevertkin     switch (AdditionalSenseCode)
510*3088717bSVictor Perevertkin     {
511*3088717bSVictor Perevertkin     case SCSI_ADSENSE_LUN_NOT_READY:
512*3088717bSVictor Perevertkin         {
513*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL,
514*3088717bSVictor Perevertkin                         "SenseInfoInterpretByAdditionalSenseCode: Lun not ready\n"));
515*3088717bSVictor Perevertkin 
516*3088717bSVictor Perevertkin             //
517*3088717bSVictor Perevertkin             //  Many non-WHQL certified drives (mostly CD-RW) return
518*3088717bSVictor Perevertkin             //  2/4/0 when they have no media instead of the obvious choice of:
519*3088717bSVictor Perevertkin             //
520*3088717bSVictor Perevertkin             //      SCSI_SENSE_NOT_READY/SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
521*3088717bSVictor Perevertkin             //
522*3088717bSVictor Perevertkin             //  These drives should not pass WHQL certification due to this discrepency.
523*3088717bSVictor Perevertkin             //
524*3088717bSVictor Perevertkin             //  However, we have to retry on 2/4/0 (Not ready, LUN not ready, no info)
525*3088717bSVictor Perevertkin             //  and also 3/2/0 (no seek complete).
526*3088717bSVictor Perevertkin             //
527*3088717bSVictor Perevertkin             //  These conditions occur when the shell tries to examine an
528*3088717bSVictor Perevertkin             //  injected CD (e.g. for autoplay) before the CD is spun up.
529*3088717bSVictor Perevertkin             //
530*3088717bSVictor Perevertkin             //  The drive should be returning an ASCQ of SCSI_SENSEQ_BECOMING_READY
531*3088717bSVictor Perevertkin             //  (0x01) in order to comply with WHQL standards.
532*3088717bSVictor Perevertkin             //
533*3088717bSVictor Perevertkin             //  The default retry timeout of one second is acceptable to balance
534*3088717bSVictor Perevertkin             //  these discrepencies.  don't modify the status, though....
535*3088717bSVictor Perevertkin             //
536*3088717bSVictor Perevertkin 
537*3088717bSVictor Perevertkin             switch (AdditionalSenseCodeQual)
538*3088717bSVictor Perevertkin             {
539*3088717bSVictor Perevertkin             case SCSI_SENSEQ_OPERATION_IN_PROGRESS:
540*3088717bSVictor Perevertkin                 {
541*3088717bSVictor Perevertkin                     DEVICE_EVENT_BECOMING_READY notReady = {0};
542*3088717bSVictor Perevertkin 
543*3088717bSVictor Perevertkin                     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
544*3088717bSVictor Perevertkin                                 "SenseInfoInterpretByAdditionalSenseCode: Operation In Progress\n"));
545*3088717bSVictor Perevertkin 
546*3088717bSVictor Perevertkin                     needFurtherInterpret = FALSE;
547*3088717bSVictor Perevertkin 
548*3088717bSVictor Perevertkin                     *Retry = TRUE;
549*3088717bSVictor Perevertkin                     *RetryIntervalInSeconds = NOT_READY_RETRY_INTERVAL;
550*3088717bSVictor Perevertkin                     *Status = STATUS_DEVICE_NOT_READY;
551*3088717bSVictor Perevertkin 
552*3088717bSVictor Perevertkin                     notReady.Version = 1;
553*3088717bSVictor Perevertkin                     notReady.Reason = 2;
554*3088717bSVictor Perevertkin                     notReady.Estimated100msToReady = *RetryIntervalInSeconds * 10;
555*3088717bSVictor Perevertkin                     DeviceSendNotification(DeviceExtension,
556*3088717bSVictor Perevertkin                                            &GUID_IO_DEVICE_BECOMING_READY,
557*3088717bSVictor Perevertkin                                            sizeof(DEVICE_EVENT_BECOMING_READY),
558*3088717bSVictor Perevertkin                                            &notReady);
559*3088717bSVictor Perevertkin 
560*3088717bSVictor Perevertkin                     break;
561*3088717bSVictor Perevertkin                 }
562*3088717bSVictor Perevertkin 
563*3088717bSVictor Perevertkin             case SCSI_SENSEQ_BECOMING_READY:
564*3088717bSVictor Perevertkin                 {
565*3088717bSVictor Perevertkin                     DEVICE_EVENT_BECOMING_READY notReady = {0};
566*3088717bSVictor Perevertkin 
567*3088717bSVictor Perevertkin                     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
568*3088717bSVictor Perevertkin                                 "SenseInfoInterpretByAdditionalSenseCode: In process of becoming ready\n"));
569*3088717bSVictor Perevertkin 
570*3088717bSVictor Perevertkin                     needFurtherInterpret = FALSE;
571*3088717bSVictor Perevertkin 
572*3088717bSVictor Perevertkin                     *Retry = TRUE;
573*3088717bSVictor Perevertkin                     *RetryIntervalInSeconds = NOT_READY_RETRY_INTERVAL;
574*3088717bSVictor Perevertkin                     *Status = STATUS_DEVICE_NOT_READY;
575*3088717bSVictor Perevertkin 
576*3088717bSVictor Perevertkin                     notReady.Version = 1;
577*3088717bSVictor Perevertkin                     notReady.Reason = 1;
578*3088717bSVictor Perevertkin                     notReady.Estimated100msToReady = *RetryIntervalInSeconds * 10;
579*3088717bSVictor Perevertkin                     DeviceSendNotification(DeviceExtension,
580*3088717bSVictor Perevertkin                                            &GUID_IO_DEVICE_BECOMING_READY,
581*3088717bSVictor Perevertkin                                            sizeof(DEVICE_EVENT_BECOMING_READY),
582*3088717bSVictor Perevertkin                                            &notReady);
583*3088717bSVictor Perevertkin 
584*3088717bSVictor Perevertkin                     break;
585*3088717bSVictor Perevertkin                 }
586*3088717bSVictor Perevertkin 
587*3088717bSVictor Perevertkin             case SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS:
588*3088717bSVictor Perevertkin                 {
589*3088717bSVictor Perevertkin                     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
590*3088717bSVictor Perevertkin                                 "SenseInfoInterpretByAdditionalSenseCode: Long write in progress\n"));
591*3088717bSVictor Perevertkin 
592*3088717bSVictor Perevertkin                     needFurtherInterpret = FALSE;
593*3088717bSVictor Perevertkin 
594*3088717bSVictor Perevertkin                     // This has been seen as a transcient failure on some drives
595*3088717bSVictor Perevertkin                     *Status = STATUS_DEVICE_NOT_READY;
596*3088717bSVictor Perevertkin                     *Retry = TRUE;
597*3088717bSVictor Perevertkin                     // Set retry interval to be 0 as the drive can be ready at anytime.
598*3088717bSVictor Perevertkin                     *RetryIntervalInSeconds = 0;
599*3088717bSVictor Perevertkin 
600*3088717bSVictor Perevertkin                     break;
601*3088717bSVictor Perevertkin                 }
602*3088717bSVictor Perevertkin 
603*3088717bSVictor Perevertkin             case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED:
604*3088717bSVictor Perevertkin                 {
605*3088717bSVictor Perevertkin                     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
606*3088717bSVictor Perevertkin                                 "SenseInfoInterpretByAdditionalSenseCode: Manual intervention required\n"));
607*3088717bSVictor Perevertkin 
608*3088717bSVictor Perevertkin                     needFurtherInterpret = FALSE;
609*3088717bSVictor Perevertkin 
610*3088717bSVictor Perevertkin                     *Status = STATUS_NO_MEDIA_IN_DEVICE;
611*3088717bSVictor Perevertkin                     *Retry = FALSE;
612*3088717bSVictor Perevertkin                     *RetryIntervalInSeconds = NOT_READY_RETRY_INTERVAL;
613*3088717bSVictor Perevertkin 
614*3088717bSVictor Perevertkin                     break;
615*3088717bSVictor Perevertkin                 }
616*3088717bSVictor Perevertkin 
617*3088717bSVictor Perevertkin             case SCSI_SENSEQ_FORMAT_IN_PROGRESS:
618*3088717bSVictor Perevertkin                 {
619*3088717bSVictor Perevertkin                     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
620*3088717bSVictor Perevertkin                                 "SenseInfoInterpretByAdditionalSenseCode: Format in progress\n"));
621*3088717bSVictor Perevertkin 
622*3088717bSVictor Perevertkin                     needFurtherInterpret = FALSE;
623*3088717bSVictor Perevertkin 
624*3088717bSVictor Perevertkin                     *Status = STATUS_DEVICE_NOT_READY;
625*3088717bSVictor Perevertkin                     *Retry = FALSE;
626*3088717bSVictor Perevertkin                     *RetryIntervalInSeconds = NOT_READY_RETRY_INTERVAL;
627*3088717bSVictor Perevertkin 
628*3088717bSVictor Perevertkin                     break;
629*3088717bSVictor Perevertkin                 }
630*3088717bSVictor Perevertkin 
631*3088717bSVictor Perevertkin             case SCSI_SENSEQ_CAUSE_NOT_REPORTABLE:
632*3088717bSVictor Perevertkin             case SCSI_SENSEQ_INIT_COMMAND_REQUIRED:
633*3088717bSVictor Perevertkin             default:
634*3088717bSVictor Perevertkin                 {
635*3088717bSVictor Perevertkin                     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
636*3088717bSVictor Perevertkin                                 "SenseInfoInterpretByAdditionalSenseCode: Initializing command required\n"));
637*3088717bSVictor Perevertkin 
638*3088717bSVictor Perevertkin                     needFurtherInterpret = FALSE;
639*3088717bSVictor Perevertkin 
640*3088717bSVictor Perevertkin                     *Status = STATUS_DEVICE_NOT_READY;
641*3088717bSVictor Perevertkin                     *Retry = TRUE;
642*3088717bSVictor Perevertkin                     *RetryIntervalInSeconds = 0;
643*3088717bSVictor Perevertkin 
644*3088717bSVictor Perevertkin                     // This sense code/additional sense code combination may indicate
645*3088717bSVictor Perevertkin                     // that the device needs to be started.
646*3088717bSVictor Perevertkin                     if (TEST_FLAG(DeviceExtension->DeviceFlags, DEV_SAFE_START_UNIT) &&
647*3088717bSVictor Perevertkin                         !TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_LOW_PRIORITY))
648*3088717bSVictor Perevertkin                     {
649*3088717bSVictor Perevertkin                         DeviceSendStartUnit(DeviceExtension->Device);
650*3088717bSVictor Perevertkin                     }
651*3088717bSVictor Perevertkin 
652*3088717bSVictor Perevertkin                     break;
653*3088717bSVictor Perevertkin                 }
654*3088717bSVictor Perevertkin             } // end switch (AdditionalSenseCodeQual)
655*3088717bSVictor Perevertkin             break;
656*3088717bSVictor Perevertkin 
657*3088717bSVictor Perevertkin         } // end case (SCSI_ADSENSE_LUN_NOT_READY)
658*3088717bSVictor Perevertkin 
659*3088717bSVictor Perevertkin     case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE:
660*3088717bSVictor Perevertkin         {
661*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL,
662*3088717bSVictor Perevertkin                         "SenseInfoInterpretByAdditionalSenseCode: No Media in device.\n"));
663*3088717bSVictor Perevertkin 
664*3088717bSVictor Perevertkin             needFurtherInterpret = FALSE;
665*3088717bSVictor Perevertkin 
666*3088717bSVictor Perevertkin             *Status = STATUS_NO_MEDIA_IN_DEVICE;
667*3088717bSVictor Perevertkin             *Retry = FALSE;
668*3088717bSVictor Perevertkin 
669*3088717bSVictor Perevertkin             if (AdditionalSenseCodeQual == 0xCC)
670*3088717bSVictor Perevertkin             {
671*3088717bSVictor Perevertkin                 //  The IMAPIv1 filter returns this ASCQ value while it is burning CD media, and we want
672*3088717bSVictor Perevertkin                 //  to preserve this functionality for compatibility reasons.
673*3088717bSVictor Perevertkin                 //  We want to indicate that the media is not present to most applications;
674*3088717bSVictor Perevertkin                 //  but RSM has to know that the media is still in the drive (i.e. the drive is not free).
675*3088717bSVictor Perevertkin                 DeviceSetMediaChangeStateEx(DeviceExtension, MediaUnavailable, NULL);
676*3088717bSVictor Perevertkin             }
677*3088717bSVictor Perevertkin             else
678*3088717bSVictor Perevertkin             {
679*3088717bSVictor Perevertkin                 DeviceSetMediaChangeStateEx(DeviceExtension, MediaNotPresent, NULL);
680*3088717bSVictor Perevertkin             }
681*3088717bSVictor Perevertkin 
682*3088717bSVictor Perevertkin             break;
683*3088717bSVictor Perevertkin         } // end case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
684*3088717bSVictor Perevertkin 
685*3088717bSVictor Perevertkin     case SCSI_ADSENSE_INVALID_MEDIA:
686*3088717bSVictor Perevertkin         {
687*3088717bSVictor Perevertkin         switch (AdditionalSenseCodeQual)
688*3088717bSVictor Perevertkin         {
689*3088717bSVictor Perevertkin 
690*3088717bSVictor Perevertkin         case SCSI_SENSEQ_UNKNOWN_FORMAT:
691*3088717bSVictor Perevertkin             {
692*3088717bSVictor Perevertkin                 needFurtherInterpret = FALSE;
693*3088717bSVictor Perevertkin 
694*3088717bSVictor Perevertkin                 // Log error only if this is a paging request
695*3088717bSVictor Perevertkin                 *Status = STATUS_UNRECOGNIZED_MEDIA;
696*3088717bSVictor Perevertkin                 *Retry = FALSE;
697*3088717bSVictor Perevertkin 
698*3088717bSVictor Perevertkin                 LogContext->LogError = TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_PAGING);
699*3088717bSVictor Perevertkin                 LogContext->UniqueErrorValue = 256;
700*3088717bSVictor Perevertkin                 LogContext->ErrorCode = IO_ERR_BAD_BLOCK;
701*3088717bSVictor Perevertkin 
702*3088717bSVictor Perevertkin                 break;
703*3088717bSVictor Perevertkin             }
704*3088717bSVictor Perevertkin 
705*3088717bSVictor Perevertkin         case SCSI_SENSEQ_INCOMPATIBLE_FORMAT:
706*3088717bSVictor Perevertkin             {
707*3088717bSVictor Perevertkin                 needFurtherInterpret = FALSE;
708*3088717bSVictor Perevertkin 
709*3088717bSVictor Perevertkin                 *Status = STATUS_UNRECOGNIZED_MEDIA;
710*3088717bSVictor Perevertkin                 *Retry = FALSE;
711*3088717bSVictor Perevertkin 
712*3088717bSVictor Perevertkin                 LogContext->LogError = FALSE;
713*3088717bSVictor Perevertkin 
714*3088717bSVictor Perevertkin                 break;
715*3088717bSVictor Perevertkin             }
716*3088717bSVictor Perevertkin 
717*3088717bSVictor Perevertkin         case SCSI_SENSEQ_CLEANING_CARTRIDGE_INSTALLED:
718*3088717bSVictor Perevertkin             {
719*3088717bSVictor Perevertkin                 needFurtherInterpret = FALSE;
720*3088717bSVictor Perevertkin 
721*3088717bSVictor Perevertkin                 *Status = STATUS_CLEANER_CARTRIDGE_INSTALLED;
722*3088717bSVictor Perevertkin                 *Retry = FALSE;
723*3088717bSVictor Perevertkin 
724*3088717bSVictor Perevertkin                 LogContext->LogError = FALSE;
725*3088717bSVictor Perevertkin                 LogContext->UniqueErrorValue = 256;
726*3088717bSVictor Perevertkin                 LogContext->ErrorCode = IO_ERR_BAD_BLOCK;
727*3088717bSVictor Perevertkin                 break;
728*3088717bSVictor Perevertkin             }
729*3088717bSVictor Perevertkin 
730*3088717bSVictor Perevertkin         default:
731*3088717bSVictor Perevertkin             {
732*3088717bSVictor Perevertkin                 needFurtherInterpret = TRUE;
733*3088717bSVictor Perevertkin                 break;
734*3088717bSVictor Perevertkin             }
735*3088717bSVictor Perevertkin         } // end case AdditionalSenseCodeQual
736*3088717bSVictor Perevertkin 
737*3088717bSVictor Perevertkin         break;
738*3088717bSVictor Perevertkin         } // end case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
739*3088717bSVictor Perevertkin 
740*3088717bSVictor Perevertkin     case SCSI_ADSENSE_NO_SEEK_COMPLETE:
741*3088717bSVictor Perevertkin         {
742*3088717bSVictor Perevertkin         switch (AdditionalSenseCodeQual)
743*3088717bSVictor Perevertkin         {
744*3088717bSVictor Perevertkin 
745*3088717bSVictor Perevertkin         case 0x00:
746*3088717bSVictor Perevertkin             {
747*3088717bSVictor Perevertkin                 needFurtherInterpret = FALSE;
748*3088717bSVictor Perevertkin 
749*3088717bSVictor Perevertkin                 *Status = STATUS_DEVICE_DATA_ERROR;
750*3088717bSVictor Perevertkin                 *Retry = TRUE;
751*3088717bSVictor Perevertkin                 *RetryIntervalInSeconds = 0;
752*3088717bSVictor Perevertkin                 LogContext->LogError = TRUE;
753*3088717bSVictor Perevertkin                 LogContext->UniqueErrorValue = 256;
754*3088717bSVictor Perevertkin                 LogContext->ErrorCode = IO_ERR_BAD_BLOCK;
755*3088717bSVictor Perevertkin                 break;
756*3088717bSVictor Perevertkin             }
757*3088717bSVictor Perevertkin 
758*3088717bSVictor Perevertkin         default:
759*3088717bSVictor Perevertkin             {
760*3088717bSVictor Perevertkin                 needFurtherInterpret = TRUE;
761*3088717bSVictor Perevertkin                 break;
762*3088717bSVictor Perevertkin             }
763*3088717bSVictor Perevertkin         }
764*3088717bSVictor Perevertkin 
765*3088717bSVictor Perevertkin         break;
766*3088717bSVictor Perevertkin         } // end case SCSI_ADSENSE_NO_SEEK_COMPLETE
767*3088717bSVictor Perevertkin 
768*3088717bSVictor Perevertkin     case SCSI_ADSENSE_LUN_COMMUNICATION:
769*3088717bSVictor Perevertkin         {
770*3088717bSVictor Perevertkin         switch (AdditionalSenseCodeQual)
771*3088717bSVictor Perevertkin         {
772*3088717bSVictor Perevertkin 
773*3088717bSVictor Perevertkin         case SCSI_SESNEQ_COMM_CRC_ERROR:
774*3088717bSVictor Perevertkin             {
775*3088717bSVictor Perevertkin                 needFurtherInterpret = FALSE;
776*3088717bSVictor Perevertkin 
777*3088717bSVictor Perevertkin                 *Status = STATUS_IO_DEVICE_ERROR;
778*3088717bSVictor Perevertkin                 *Retry = TRUE;
779*3088717bSVictor Perevertkin                 *RetryIntervalInSeconds = 1;
780*3088717bSVictor Perevertkin                 LogContext->LogError = TRUE;
781*3088717bSVictor Perevertkin                 LogContext->UniqueErrorValue = 257;
782*3088717bSVictor Perevertkin                 LogContext->ErrorCode = IO_ERR_CONTROLLER_ERROR;
783*3088717bSVictor Perevertkin                 break;
784*3088717bSVictor Perevertkin             }
785*3088717bSVictor Perevertkin 
786*3088717bSVictor Perevertkin         default:
787*3088717bSVictor Perevertkin             {
788*3088717bSVictor Perevertkin                 needFurtherInterpret = TRUE;
789*3088717bSVictor Perevertkin                 break;
790*3088717bSVictor Perevertkin             }
791*3088717bSVictor Perevertkin         }
792*3088717bSVictor Perevertkin 
793*3088717bSVictor Perevertkin         break;
794*3088717bSVictor Perevertkin         } // end case SCSI_ADSENSE_LUN_COMMUNICATION
795*3088717bSVictor Perevertkin 
796*3088717bSVictor Perevertkin     case SCSI_ADSENSE_ILLEGAL_BLOCK:
797*3088717bSVictor Perevertkin         {
798*3088717bSVictor Perevertkin             needFurtherInterpret = FALSE;
799*3088717bSVictor Perevertkin 
800*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
801*3088717bSVictor Perevertkin                         "SenseInfoInterpretByAdditionalSenseCode: Illegal block address\n"));
802*3088717bSVictor Perevertkin             *Status = STATUS_NONEXISTENT_SECTOR;
803*3088717bSVictor Perevertkin             *Retry = FALSE;
804*3088717bSVictor Perevertkin             break;
805*3088717bSVictor Perevertkin         }
806*3088717bSVictor Perevertkin 
807*3088717bSVictor Perevertkin     case SCSI_ADSENSE_INVALID_LUN:
808*3088717bSVictor Perevertkin         {
809*3088717bSVictor Perevertkin             needFurtherInterpret = FALSE;
810*3088717bSVictor Perevertkin 
811*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
812*3088717bSVictor Perevertkin                         "SenseInfoInterpretByAdditionalSenseCode: Invalid LUN\n"));
813*3088717bSVictor Perevertkin             *Status = STATUS_NO_SUCH_DEVICE;
814*3088717bSVictor Perevertkin             *Retry = FALSE;
815*3088717bSVictor Perevertkin             break;
816*3088717bSVictor Perevertkin         }
817*3088717bSVictor Perevertkin 
818*3088717bSVictor Perevertkin     case SCSI_ADSENSE_COPY_PROTECTION_FAILURE:
819*3088717bSVictor Perevertkin         {
820*3088717bSVictor Perevertkin             needFurtherInterpret = FALSE;
821*3088717bSVictor Perevertkin 
822*3088717bSVictor Perevertkin             *Retry = FALSE;
823*3088717bSVictor Perevertkin 
824*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
825*3088717bSVictor Perevertkin                         "SenseInfoInterpretByAdditionalSenseCode: Key - Copy protection failure\n"));
826*3088717bSVictor Perevertkin 
827*3088717bSVictor Perevertkin             switch (AdditionalSenseCodeQual)
828*3088717bSVictor Perevertkin             {
829*3088717bSVictor Perevertkin             case SCSI_SENSEQ_AUTHENTICATION_FAILURE:
830*3088717bSVictor Perevertkin                 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
831*3088717bSVictor Perevertkin                             "SenseInfoInterpretByAdditionalSenseCode: Authentication failure\n"));
832*3088717bSVictor Perevertkin                 *Status = STATUS_CSS_AUTHENTICATION_FAILURE;
833*3088717bSVictor Perevertkin                 break;
834*3088717bSVictor Perevertkin             case SCSI_SENSEQ_KEY_NOT_PRESENT:
835*3088717bSVictor Perevertkin                 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
836*3088717bSVictor Perevertkin                             "SenseInfoInterpretByAdditionalSenseCode: Key not present\n"));
837*3088717bSVictor Perevertkin                 *Status = STATUS_CSS_KEY_NOT_PRESENT;
838*3088717bSVictor Perevertkin                 break;
839*3088717bSVictor Perevertkin             case SCSI_SENSEQ_KEY_NOT_ESTABLISHED:
840*3088717bSVictor Perevertkin                 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
841*3088717bSVictor Perevertkin                             "SenseInfoInterpretByAdditionalSenseCode: Key not established\n"));
842*3088717bSVictor Perevertkin                 *Status = STATUS_CSS_KEY_NOT_ESTABLISHED;
843*3088717bSVictor Perevertkin                 break;
844*3088717bSVictor Perevertkin             case SCSI_SENSEQ_READ_OF_SCRAMBLED_SECTOR_WITHOUT_AUTHENTICATION:
845*3088717bSVictor Perevertkin                 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
846*3088717bSVictor Perevertkin                             "SenseInfoInterpretByAdditionalSenseCode: Read of scrambled sector w/o authentication\n"));
847*3088717bSVictor Perevertkin                 *Status = STATUS_CSS_SCRAMBLED_SECTOR;
848*3088717bSVictor Perevertkin                 break;
849*3088717bSVictor Perevertkin             case SCSI_SENSEQ_MEDIA_CODE_MISMATCHED_TO_LOGICAL_UNIT:
850*3088717bSVictor Perevertkin                 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
851*3088717bSVictor Perevertkin                             "SenseInfoInterpretByAdditionalSenseCode: Media region does not logical unit region\n"));
852*3088717bSVictor Perevertkin                 *Status = STATUS_CSS_REGION_MISMATCH;
853*3088717bSVictor Perevertkin                 break;
854*3088717bSVictor Perevertkin             case SCSI_SENSEQ_LOGICAL_UNIT_RESET_COUNT_ERROR:
855*3088717bSVictor Perevertkin                 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
856*3088717bSVictor Perevertkin                             "SenseInfoInterpretByAdditionalSenseCode: Region set error -- region may be permanent\n"));
857*3088717bSVictor Perevertkin                 *Status = STATUS_CSS_RESETS_EXHAUSTED;
858*3088717bSVictor Perevertkin                 break;
859*3088717bSVictor Perevertkin 
860*3088717bSVictor Perevertkin             default:
861*3088717bSVictor Perevertkin                 *Status = STATUS_COPY_PROTECTION_FAILURE;
862*3088717bSVictor Perevertkin                 break;
863*3088717bSVictor Perevertkin             } // end switch of ASCQ for COPY_PROTECTION_FAILURE
864*3088717bSVictor Perevertkin 
865*3088717bSVictor Perevertkin             break;
866*3088717bSVictor Perevertkin         }
867*3088717bSVictor Perevertkin 
868*3088717bSVictor Perevertkin     case SCSI_ADSENSE_INVALID_CDB:
869*3088717bSVictor Perevertkin         {
870*3088717bSVictor Perevertkin             needFurtherInterpret = FALSE;
871*3088717bSVictor Perevertkin 
872*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
873*3088717bSVictor Perevertkin                         "SenseInfoInterpretByAdditionalSenseCode: Key - Invalid CDB\n"));
874*3088717bSVictor Perevertkin 
875*3088717bSVictor Perevertkin             *Status = STATUS_INVALID_DEVICE_REQUEST;
876*3088717bSVictor Perevertkin             *Retry = FALSE;
877*3088717bSVictor Perevertkin 
878*3088717bSVictor Perevertkin             // Note: the retry interval is not typically used.
879*3088717bSVictor Perevertkin             // it is set here only because a ClassErrorHandler
880*3088717bSVictor Perevertkin             // cannot set the RetryIntervalInSeconds, and the error may
881*3088717bSVictor Perevertkin             // require a few commands to be sent to clear whatever
882*3088717bSVictor Perevertkin             // caused this condition (i.e. disk clears the write
883*3088717bSVictor Perevertkin             // cache, requiring at least two commands)
884*3088717bSVictor Perevertkin             //
885*3088717bSVictor Perevertkin             // hopefully, this shortcoming can be changed for blackcomb.
886*3088717bSVictor Perevertkin             *RetryIntervalInSeconds = 3;
887*3088717bSVictor Perevertkin 
888*3088717bSVictor Perevertkin             break;
889*3088717bSVictor Perevertkin         }
890*3088717bSVictor Perevertkin 
891*3088717bSVictor Perevertkin     case SCSI_ADSENSE_MEDIUM_CHANGED:
892*3088717bSVictor Perevertkin         {
893*3088717bSVictor Perevertkin             needFurtherInterpret = FALSE;
894*3088717bSVictor Perevertkin             *RetryIntervalInSeconds = 0;
895*3088717bSVictor Perevertkin 
896*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
897*3088717bSVictor Perevertkin                         "SenseInfoInterpretByAdditionalSenseCode: Media changed\n"));
898*3088717bSVictor Perevertkin 
899*3088717bSVictor Perevertkin             DeviceSetMediaChangeStateEx(DeviceExtension, MediaPresent, NULL);
900*3088717bSVictor Perevertkin 
901*3088717bSVictor Perevertkin             // special process for Media Change
902*3088717bSVictor Perevertkin             if (IsVolumeMounted(DeviceExtension->DeviceObject))
903*3088717bSVictor Perevertkin             {
904*3088717bSVictor Perevertkin                 // Set bit to indicate that media may have changed and volume needs verification.
905*3088717bSVictor Perevertkin                 SET_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME);
906*3088717bSVictor Perevertkin 
907*3088717bSVictor Perevertkin                 *Status = STATUS_VERIFY_REQUIRED;
908*3088717bSVictor Perevertkin                 *Retry = FALSE;
909*3088717bSVictor Perevertkin             }
910*3088717bSVictor Perevertkin             else
911*3088717bSVictor Perevertkin             {
912*3088717bSVictor Perevertkin                 *Status = STATUS_IO_DEVICE_ERROR;
913*3088717bSVictor Perevertkin                 *Retry = TRUE;
914*3088717bSVictor Perevertkin             }
915*3088717bSVictor Perevertkin             break;
916*3088717bSVictor Perevertkin         }
917*3088717bSVictor Perevertkin 
918*3088717bSVictor Perevertkin     case SCSI_ADSENSE_OPERATOR_REQUEST:
919*3088717bSVictor Perevertkin         {
920*3088717bSVictor Perevertkin             switch (AdditionalSenseCodeQual)
921*3088717bSVictor Perevertkin             {
922*3088717bSVictor Perevertkin             case SCSI_SENSEQ_MEDIUM_REMOVAL:
923*3088717bSVictor Perevertkin                 {
924*3088717bSVictor Perevertkin                     needFurtherInterpret = FALSE;
925*3088717bSVictor Perevertkin                     *RetryIntervalInSeconds = 0;
926*3088717bSVictor Perevertkin 
927*3088717bSVictor Perevertkin                     InterlockedIncrement((PLONG)&DeviceExtension->MediaChangeCount);
928*3088717bSVictor Perevertkin 
929*3088717bSVictor Perevertkin                     TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
930*3088717bSVictor Perevertkin                         "SenseInfoInterpretByAdditionalSenseCode: Ejection request received!\n"));
931*3088717bSVictor Perevertkin                     //Send eject notification.
932*3088717bSVictor Perevertkin                     DeviceSendNotification(DeviceExtension,
933*3088717bSVictor Perevertkin                                            &GUID_IO_MEDIA_EJECT_REQUEST,
934*3088717bSVictor Perevertkin                                            0,
935*3088717bSVictor Perevertkin                                            NULL);
936*3088717bSVictor Perevertkin                     // special process for Media Change
937*3088717bSVictor Perevertkin                     if (IsVolumeMounted(DeviceExtension->DeviceObject))
938*3088717bSVictor Perevertkin                     {
939*3088717bSVictor Perevertkin                         // Set bit to indicate that media may have changed and volume needs verification.
940*3088717bSVictor Perevertkin                         SET_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME);
941*3088717bSVictor Perevertkin 
942*3088717bSVictor Perevertkin                         *Status = STATUS_VERIFY_REQUIRED;
943*3088717bSVictor Perevertkin                         *Retry = FALSE;
944*3088717bSVictor Perevertkin                     }
945*3088717bSVictor Perevertkin                     else
946*3088717bSVictor Perevertkin                     {
947*3088717bSVictor Perevertkin                         *Status = STATUS_IO_DEVICE_ERROR;
948*3088717bSVictor Perevertkin                         *Retry = TRUE;
949*3088717bSVictor Perevertkin                     }
950*3088717bSVictor Perevertkin                     break;
951*3088717bSVictor Perevertkin                 }
952*3088717bSVictor Perevertkin             default:
953*3088717bSVictor Perevertkin                 {
954*3088717bSVictor Perevertkin                     needFurtherInterpret = TRUE;
955*3088717bSVictor Perevertkin                     break;
956*3088717bSVictor Perevertkin                 }
957*3088717bSVictor Perevertkin             }
958*3088717bSVictor Perevertkin             break;
959*3088717bSVictor Perevertkin         }
960*3088717bSVictor Perevertkin 
961*3088717bSVictor Perevertkin     case SCSI_ADSENSE_OPERATING_CONDITIONS_CHANGED:
962*3088717bSVictor Perevertkin         {
963*3088717bSVictor Perevertkin             needFurtherInterpret = FALSE;
964*3088717bSVictor Perevertkin             *RetryIntervalInSeconds = 5;
965*3088717bSVictor Perevertkin 
966*3088717bSVictor Perevertkin             InterlockedIncrement((PLONG)&DeviceExtension->MediaChangeCount);
967*3088717bSVictor Perevertkin 
968*3088717bSVictor Perevertkin             // Device information has changed, we need to rescan the
969*3088717bSVictor Perevertkin             // bus for changed information such as the capacity.
970*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
971*3088717bSVictor Perevertkin                         "SenseInfoInterpretByAdditionalSenseCode: Device information changed. Invalidate the bus\n"));
972*3088717bSVictor Perevertkin 
973*3088717bSVictor Perevertkin             IoInvalidateDeviceRelations(DeviceExtension->LowerPdo, BusRelations);
974*3088717bSVictor Perevertkin 
975*3088717bSVictor Perevertkin             // special process for Media Change
976*3088717bSVictor Perevertkin             if (IsVolumeMounted(DeviceExtension->DeviceObject))
977*3088717bSVictor Perevertkin             {
978*3088717bSVictor Perevertkin                 // Set bit to indicate that media may have changed and volume needs verification.
979*3088717bSVictor Perevertkin                 SET_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME);
980*3088717bSVictor Perevertkin 
981*3088717bSVictor Perevertkin                 *Status = STATUS_VERIFY_REQUIRED;
982*3088717bSVictor Perevertkin                 *Retry = FALSE;
983*3088717bSVictor Perevertkin             }
984*3088717bSVictor Perevertkin             else
985*3088717bSVictor Perevertkin             {
986*3088717bSVictor Perevertkin                 *Status = STATUS_IO_DEVICE_ERROR;
987*3088717bSVictor Perevertkin                 *Retry = TRUE;
988*3088717bSVictor Perevertkin             }
989*3088717bSVictor Perevertkin             break;
990*3088717bSVictor Perevertkin         } //end Case SCSI_ADSENSE_OPERATING_CONDITIONS_CHANGED
991*3088717bSVictor Perevertkin 
992*3088717bSVictor Perevertkin 
993*3088717bSVictor Perevertkin     case SCSI_ADSENSE_REC_DATA_NOECC:
994*3088717bSVictor Perevertkin     case SCSI_ADSENSE_REC_DATA_ECC:
995*3088717bSVictor Perevertkin         {
996*3088717bSVictor Perevertkin             needFurtherInterpret = FALSE;
997*3088717bSVictor Perevertkin 
998*3088717bSVictor Perevertkin             *Status = STATUS_SUCCESS;
999*3088717bSVictor Perevertkin             *Retry = FALSE;
1000*3088717bSVictor Perevertkin             LogContext->LogError = TRUE;
1001*3088717bSVictor Perevertkin             LogContext->UniqueErrorValue = 258;
1002*3088717bSVictor Perevertkin             LogContext->ErrorCode = IO_RECOVERED_VIA_ECC;
1003*3088717bSVictor Perevertkin 
1004*3088717bSVictor Perevertkin             if (senseBuffer->IncorrectLength)
1005*3088717bSVictor Perevertkin             {
1006*3088717bSVictor Perevertkin                 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
1007*3088717bSVictor Perevertkin                             "SenseInfoInterpretByAdditionalSenseCode: Incorrect length detected.\n"));
1008*3088717bSVictor Perevertkin                 *Status = STATUS_INVALID_BLOCK_LENGTH ;
1009*3088717bSVictor Perevertkin             }
1010*3088717bSVictor Perevertkin             break;
1011*3088717bSVictor Perevertkin         }
1012*3088717bSVictor Perevertkin 
1013*3088717bSVictor Perevertkin     case SCSI_ADSENSE_FAILURE_PREDICTION_THRESHOLD_EXCEEDED:
1014*3088717bSVictor Perevertkin         {
1015*3088717bSVictor Perevertkin             UCHAR wmiEventData[sizeof(ULONG)+sizeof(UCHAR)] = {0};
1016*3088717bSVictor Perevertkin 
1017*3088717bSVictor Perevertkin             *((PULONG)wmiEventData) = sizeof(UCHAR);
1018*3088717bSVictor Perevertkin             wmiEventData[sizeof(ULONG)] = AdditionalSenseCodeQual;
1019*3088717bSVictor Perevertkin 
1020*3088717bSVictor Perevertkin             needFurtherInterpret = FALSE;
1021*3088717bSVictor Perevertkin 
1022*3088717bSVictor Perevertkin             // Don't log another eventlog if we have already logged once
1023*3088717bSVictor Perevertkin             // NOTE: this should have been interlocked, but the structure
1024*3088717bSVictor Perevertkin             //       was publicly defined to use a BOOLEAN (char).  Since
1025*3088717bSVictor Perevertkin             //       media only reports these errors once per X minutes,
1026*3088717bSVictor Perevertkin             //       the potential race condition is nearly non-existant.
1027*3088717bSVictor Perevertkin             //       the worst case is duplicate log entries, so ignore.
1028*3088717bSVictor Perevertkin 
1029*3088717bSVictor Perevertkin             *Status = STATUS_SUCCESS;
1030*3088717bSVictor Perevertkin             *Retry = FALSE;
1031*3088717bSVictor Perevertkin             LogContext->UniqueErrorValue = 258;
1032*3088717bSVictor Perevertkin             LogContext->LogError = TRUE;
1033*3088717bSVictor Perevertkin             LogContext->ErrorCode = IO_WRN_FAILURE_PREDICTED;
1034*3088717bSVictor Perevertkin 
1035*3088717bSVictor Perevertkin             if (senseBuffer->IncorrectLength)
1036*3088717bSVictor Perevertkin             {
1037*3088717bSVictor Perevertkin                 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
1038*3088717bSVictor Perevertkin                             "SenseInfoInterpretByAdditionalSenseCode: Incorrect length detected.\n"));
1039*3088717bSVictor Perevertkin                 *Status = STATUS_INVALID_BLOCK_LENGTH ;
1040*3088717bSVictor Perevertkin             }
1041*3088717bSVictor Perevertkin             break;
1042*3088717bSVictor Perevertkin         }
1043*3088717bSVictor Perevertkin 
1044*3088717bSVictor Perevertkin     case 0x57:
1045*3088717bSVictor Perevertkin         {
1046*3088717bSVictor Perevertkin             // UNABLE_TO_RECOVER_TABLE_OF_CONTENTS
1047*3088717bSVictor Perevertkin             // the Matshita CR-585 returns this for all read commands
1048*3088717bSVictor Perevertkin             // on blank CD-R and CD-RW media, and we need to handle
1049*3088717bSVictor Perevertkin             // this for READ_CD detection ability.
1050*3088717bSVictor Perevertkin             switch (AdditionalSenseCodeQual)
1051*3088717bSVictor Perevertkin             {
1052*3088717bSVictor Perevertkin             case 0x00:
1053*3088717bSVictor Perevertkin                 {
1054*3088717bSVictor Perevertkin                     needFurtherInterpret = FALSE;
1055*3088717bSVictor Perevertkin 
1056*3088717bSVictor Perevertkin                     *Status = STATUS_UNRECOGNIZED_MEDIA;
1057*3088717bSVictor Perevertkin                     *Retry = FALSE;
1058*3088717bSVictor Perevertkin                     break;
1059*3088717bSVictor Perevertkin                 }
1060*3088717bSVictor Perevertkin             default:
1061*3088717bSVictor Perevertkin                 {
1062*3088717bSVictor Perevertkin                     needFurtherInterpret = TRUE;
1063*3088717bSVictor Perevertkin                     break;
1064*3088717bSVictor Perevertkin                 }
1065*3088717bSVictor Perevertkin             }
1066*3088717bSVictor Perevertkin             break;
1067*3088717bSVictor Perevertkin         }   //end case Matshita specific error 0x57
1068*3088717bSVictor Perevertkin 
1069*3088717bSVictor Perevertkin     default:
1070*3088717bSVictor Perevertkin         {
1071*3088717bSVictor Perevertkin             needFurtherInterpret = TRUE;
1072*3088717bSVictor Perevertkin             break;
1073*3088717bSVictor Perevertkin         }
1074*3088717bSVictor Perevertkin     }
1075*3088717bSVictor Perevertkin 
1076*3088717bSVictor Perevertkin     return needFurtherInterpret;
1077*3088717bSVictor Perevertkin }
1078*3088717bSVictor Perevertkin 
1079*3088717bSVictor Perevertkin VOID
1080*3088717bSVictor Perevertkin SenseInfoInterpretBySenseKey(
1081*3088717bSVictor Perevertkin     _In_      PCDROM_DEVICE_EXTENSION   DeviceExtension,
1082*3088717bSVictor Perevertkin     _In_      PSENSE_DATA               SenseData,
1083*3088717bSVictor Perevertkin     _In_      UCHAR                     SenseKey,
1084*3088717bSVictor Perevertkin     _Inout_   NTSTATUS*                 Status,
1085*3088717bSVictor Perevertkin     _Inout_   BOOLEAN*                  Retry,
1086*3088717bSVictor Perevertkin     _Out_ _Deref_out_range_(0,100) ULONG*         RetryIntervalInSeconds,
1087*3088717bSVictor Perevertkin     _Inout_   PERROR_LOG_CONTEXT        LogContext
1088*3088717bSVictor Perevertkin     )
1089*3088717bSVictor Perevertkin {
1090*3088717bSVictor Perevertkin     // set default values for retry fields.
1091*3088717bSVictor Perevertkin     *Status = STATUS_IO_DEVICE_ERROR;
1092*3088717bSVictor Perevertkin     *Retry = TRUE;
1093*3088717bSVictor Perevertkin     *RetryIntervalInSeconds = 0;
1094*3088717bSVictor Perevertkin 
1095*3088717bSVictor Perevertkin     switch (SenseKey)
1096*3088717bSVictor Perevertkin     {
1097*3088717bSVictor Perevertkin     case SCSI_SENSE_NOT_READY:
1098*3088717bSVictor Perevertkin         {
1099*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
1100*3088717bSVictor Perevertkin                         "SenseInfoInterpretBySenseKey: Key - Not Ready (bad block)\n"));
1101*3088717bSVictor Perevertkin 
1102*3088717bSVictor Perevertkin             *Status = STATUS_DEVICE_NOT_READY;
1103*3088717bSVictor Perevertkin             *Retry = TRUE;
1104*3088717bSVictor Perevertkin 
1105*3088717bSVictor Perevertkin             // for unprocessed "not ready" codes, retry the command immediately.
1106*3088717bSVictor Perevertkin             *RetryIntervalInSeconds = 0;
1107*3088717bSVictor Perevertkin             break;
1108*3088717bSVictor Perevertkin         }
1109*3088717bSVictor Perevertkin 
1110*3088717bSVictor Perevertkin     case SCSI_SENSE_DATA_PROTECT:
1111*3088717bSVictor Perevertkin         {
1112*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL,
1113*3088717bSVictor Perevertkin                         "SenseInfoInterpretBySenseKey: Key - Media write protected\n"));
1114*3088717bSVictor Perevertkin             *Status = STATUS_MEDIA_WRITE_PROTECTED;
1115*3088717bSVictor Perevertkin             *Retry = FALSE;
1116*3088717bSVictor Perevertkin             break;
1117*3088717bSVictor Perevertkin         }
1118*3088717bSVictor Perevertkin 
1119*3088717bSVictor Perevertkin     case SCSI_SENSE_MEDIUM_ERROR:
1120*3088717bSVictor Perevertkin         {
1121*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
1122*3088717bSVictor Perevertkin                         "SenseInfoInterpretBySenseKey: Key - Medium Error (bad block)\n"));
1123*3088717bSVictor Perevertkin 
1124*3088717bSVictor Perevertkin             *Status = STATUS_DEVICE_DATA_ERROR;
1125*3088717bSVictor Perevertkin             *Retry = FALSE;
1126*3088717bSVictor Perevertkin             LogContext->LogError = TRUE;
1127*3088717bSVictor Perevertkin             LogContext->UniqueErrorValue = 256;
1128*3088717bSVictor Perevertkin             LogContext->ErrorCode = IO_ERR_BAD_BLOCK;
1129*3088717bSVictor Perevertkin 
1130*3088717bSVictor Perevertkin             break;
1131*3088717bSVictor Perevertkin         } // end SCSI_SENSE_MEDIUM_ERROR
1132*3088717bSVictor Perevertkin 
1133*3088717bSVictor Perevertkin     case SCSI_SENSE_HARDWARE_ERROR:
1134*3088717bSVictor Perevertkin         {
1135*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
1136*3088717bSVictor Perevertkin                         "SenseInfoInterpretBySenseKey: Key - Hardware error\n"));
1137*3088717bSVictor Perevertkin 
1138*3088717bSVictor Perevertkin             *Status = STATUS_IO_DEVICE_ERROR;
1139*3088717bSVictor Perevertkin             *Retry = TRUE;
1140*3088717bSVictor Perevertkin             LogContext->LogError = TRUE;
1141*3088717bSVictor Perevertkin             LogContext->UniqueErrorValue = 257;
1142*3088717bSVictor Perevertkin             LogContext->ErrorCode = IO_ERR_CONTROLLER_ERROR;
1143*3088717bSVictor Perevertkin 
1144*3088717bSVictor Perevertkin             break;
1145*3088717bSVictor Perevertkin         } // end SCSI_SENSE_HARDWARE_ERROR
1146*3088717bSVictor Perevertkin 
1147*3088717bSVictor Perevertkin     case SCSI_SENSE_ILLEGAL_REQUEST:
1148*3088717bSVictor Perevertkin         {
1149*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
1150*3088717bSVictor Perevertkin                         "SenseInfoInterpretBySenseKey: Key - Illegal SCSI request\n"));
1151*3088717bSVictor Perevertkin             *Status = STATUS_INVALID_DEVICE_REQUEST;
1152*3088717bSVictor Perevertkin             *Retry = FALSE;
1153*3088717bSVictor Perevertkin 
1154*3088717bSVictor Perevertkin             break;
1155*3088717bSVictor Perevertkin         } // end SCSI_SENSE_ILLEGAL_REQUEST
1156*3088717bSVictor Perevertkin 
1157*3088717bSVictor Perevertkin     case SCSI_SENSE_UNIT_ATTENTION:
1158*3088717bSVictor Perevertkin         {
1159*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
1160*3088717bSVictor Perevertkin                         "SenseInfoInterpretBySenseKey: Key - Unit Attention\n"));
1161*3088717bSVictor Perevertkin 
1162*3088717bSVictor Perevertkin             // A media change may have occured so increment the change
1163*3088717bSVictor Perevertkin             // count for the physical device
1164*3088717bSVictor Perevertkin             InterlockedIncrement((PLONG)&DeviceExtension->MediaChangeCount);
1165*3088717bSVictor Perevertkin 
1166*3088717bSVictor Perevertkin             if (IsVolumeMounted(DeviceExtension->DeviceObject))
1167*3088717bSVictor Perevertkin             {
1168*3088717bSVictor Perevertkin                 // Set bit to indicate that media may have changed
1169*3088717bSVictor Perevertkin                 // and volume needs verification.
1170*3088717bSVictor Perevertkin                 SET_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME);
1171*3088717bSVictor Perevertkin 
1172*3088717bSVictor Perevertkin                 *Status = STATUS_VERIFY_REQUIRED;
1173*3088717bSVictor Perevertkin                 *Retry = FALSE;
1174*3088717bSVictor Perevertkin             }
1175*3088717bSVictor Perevertkin             else
1176*3088717bSVictor Perevertkin             {
1177*3088717bSVictor Perevertkin                 *Status = STATUS_IO_DEVICE_ERROR;
1178*3088717bSVictor Perevertkin                 *Retry = TRUE;
1179*3088717bSVictor Perevertkin             }
1180*3088717bSVictor Perevertkin 
1181*3088717bSVictor Perevertkin             break;
1182*3088717bSVictor Perevertkin 
1183*3088717bSVictor Perevertkin         } // end SCSI_SENSE_UNIT_ATTENTION
1184*3088717bSVictor Perevertkin 
1185*3088717bSVictor Perevertkin     case SCSI_SENSE_ABORTED_COMMAND:
1186*3088717bSVictor Perevertkin         {
1187*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
1188*3088717bSVictor Perevertkin                         "SenseInfoInterpretBySenseKey: Command aborted\n"));
1189*3088717bSVictor Perevertkin             *Status = STATUS_IO_DEVICE_ERROR;
1190*3088717bSVictor Perevertkin             *Retry = TRUE;
1191*3088717bSVictor Perevertkin             *RetryIntervalInSeconds = 1;
1192*3088717bSVictor Perevertkin             break;
1193*3088717bSVictor Perevertkin         } // end SCSI_SENSE_ABORTED_COMMAND
1194*3088717bSVictor Perevertkin 
1195*3088717bSVictor Perevertkin     case SCSI_SENSE_BLANK_CHECK:
1196*3088717bSVictor Perevertkin         {
1197*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL,
1198*3088717bSVictor Perevertkin                         "SenseInfoInterpretBySenseKey: Media blank check\n"));
1199*3088717bSVictor Perevertkin             *Retry = FALSE;
1200*3088717bSVictor Perevertkin             *Status = STATUS_NO_DATA_DETECTED;
1201*3088717bSVictor Perevertkin             break;
1202*3088717bSVictor Perevertkin         } // end SCSI_SENSE_BLANK_CHECK
1203*3088717bSVictor Perevertkin 
1204*3088717bSVictor Perevertkin     case SCSI_SENSE_RECOVERED_ERROR:
1205*3088717bSVictor Perevertkin         {
1206*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
1207*3088717bSVictor Perevertkin                         "SenseInfoInterpretBySenseKey: Recovered error\n"));
1208*3088717bSVictor Perevertkin             *Status = STATUS_SUCCESS;
1209*3088717bSVictor Perevertkin             *Retry = FALSE;
1210*3088717bSVictor Perevertkin             LogContext->LogError = TRUE;
1211*3088717bSVictor Perevertkin             LogContext->UniqueErrorValue = 258;
1212*3088717bSVictor Perevertkin             LogContext->ErrorCode = IO_ERR_CONTROLLER_ERROR;
1213*3088717bSVictor Perevertkin 
1214*3088717bSVictor Perevertkin             if (SenseData->IncorrectLength)
1215*3088717bSVictor Perevertkin             {
1216*3088717bSVictor Perevertkin                 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
1217*3088717bSVictor Perevertkin                             "SenseInfoInterpretBySenseKey: Incorrect length detected.\n"));
1218*3088717bSVictor Perevertkin                 *Status = STATUS_INVALID_BLOCK_LENGTH ;
1219*3088717bSVictor Perevertkin             }
1220*3088717bSVictor Perevertkin 
1221*3088717bSVictor Perevertkin             break;
1222*3088717bSVictor Perevertkin         } // end SCSI_SENSE_RECOVERED_ERROR
1223*3088717bSVictor Perevertkin 
1224*3088717bSVictor Perevertkin     case SCSI_SENSE_NO_SENSE:
1225*3088717bSVictor Perevertkin         {
1226*3088717bSVictor Perevertkin             // Check other indicators.
1227*3088717bSVictor Perevertkin             if (SenseData->IncorrectLength)
1228*3088717bSVictor Perevertkin             {
1229*3088717bSVictor Perevertkin                 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
1230*3088717bSVictor Perevertkin                             "SenseInfoInterpretBySenseKey: Incorrect length detected.\n"));
1231*3088717bSVictor Perevertkin                 *Status = STATUS_INVALID_BLOCK_LENGTH ;
1232*3088717bSVictor Perevertkin                 *Retry   = FALSE;
1233*3088717bSVictor Perevertkin             }
1234*3088717bSVictor Perevertkin             else
1235*3088717bSVictor Perevertkin             {
1236*3088717bSVictor Perevertkin                 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL,
1237*3088717bSVictor Perevertkin                             "SenseInfoInterpretBySenseKey: No specific sense key\n"));
1238*3088717bSVictor Perevertkin                 *Status = STATUS_IO_DEVICE_ERROR;
1239*3088717bSVictor Perevertkin                 *Retry = TRUE;
1240*3088717bSVictor Perevertkin             }
1241*3088717bSVictor Perevertkin 
1242*3088717bSVictor Perevertkin             break;
1243*3088717bSVictor Perevertkin         } // end SCSI_SENSE_NO_SENSE
1244*3088717bSVictor Perevertkin 
1245*3088717bSVictor Perevertkin     default:
1246*3088717bSVictor Perevertkin         {
1247*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
1248*3088717bSVictor Perevertkin                         "SenseInfoInterpretBySenseKey: Unrecognized sense code\n"));
1249*3088717bSVictor Perevertkin             *Status = STATUS_IO_DEVICE_ERROR;
1250*3088717bSVictor Perevertkin             *Retry = TRUE;
1251*3088717bSVictor Perevertkin             *RetryIntervalInSeconds = 0;
1252*3088717bSVictor Perevertkin 
1253*3088717bSVictor Perevertkin             break;
1254*3088717bSVictor Perevertkin         }
1255*3088717bSVictor Perevertkin 
1256*3088717bSVictor Perevertkin     } // end switch (SenseKey)
1257*3088717bSVictor Perevertkin 
1258*3088717bSVictor Perevertkin     return;
1259*3088717bSVictor Perevertkin }
1260*3088717bSVictor Perevertkin 
1261*3088717bSVictor Perevertkin VOID
1262*3088717bSVictor Perevertkin SenseInfoInterpretBySrbStatus(
1263*3088717bSVictor Perevertkin     _In_      PCDROM_DEVICE_EXTENSION   DeviceExtension,
1264*3088717bSVictor Perevertkin     _In_      PSCSI_REQUEST_BLOCK       Srb,
1265*3088717bSVictor Perevertkin     _In_ ULONG                          RetriedCount,
1266*3088717bSVictor Perevertkin     _Inout_   NTSTATUS*                 Status,
1267*3088717bSVictor Perevertkin     _Inout_   BOOLEAN*                  Retry,
1268*3088717bSVictor Perevertkin     _Out_ _Deref_out_range_(0,100) ULONG*         RetryIntervalInSeconds,
1269*3088717bSVictor Perevertkin     _Inout_   PERROR_LOG_CONTEXT        LogContext
1270*3088717bSVictor Perevertkin     )
1271*3088717bSVictor Perevertkin {
1272*3088717bSVictor Perevertkin     BOOLEAN incrementErrorCount = FALSE;
1273*3088717bSVictor Perevertkin 
1274*3088717bSVictor Perevertkin     // set default values for retry fields.
1275*3088717bSVictor Perevertkin     *Status = STATUS_IO_DEVICE_ERROR;
1276*3088717bSVictor Perevertkin     *Retry = TRUE;
1277*3088717bSVictor Perevertkin     *RetryIntervalInSeconds = 0;
1278*3088717bSVictor Perevertkin 
1279*3088717bSVictor Perevertkin     switch (SRB_STATUS(Srb->SrbStatus))
1280*3088717bSVictor Perevertkin     {
1281*3088717bSVictor Perevertkin     case SRB_STATUS_INVALID_LUN:
1282*3088717bSVictor Perevertkin     case SRB_STATUS_INVALID_TARGET_ID:
1283*3088717bSVictor Perevertkin     case SRB_STATUS_NO_DEVICE:
1284*3088717bSVictor Perevertkin     case SRB_STATUS_NO_HBA:
1285*3088717bSVictor Perevertkin     case SRB_STATUS_INVALID_PATH_ID:
1286*3088717bSVictor Perevertkin     {
1287*3088717bSVictor Perevertkin         *Status = STATUS_NO_SUCH_DEVICE;
1288*3088717bSVictor Perevertkin         *Retry = FALSE;
1289*3088717bSVictor Perevertkin         break;
1290*3088717bSVictor Perevertkin     }
1291*3088717bSVictor Perevertkin 
1292*3088717bSVictor Perevertkin     case SRB_STATUS_COMMAND_TIMEOUT:
1293*3088717bSVictor Perevertkin     case SRB_STATUS_TIMEOUT:
1294*3088717bSVictor Perevertkin     {
1295*3088717bSVictor Perevertkin         // Update the error count for the device.
1296*3088717bSVictor Perevertkin         *Status = STATUS_IO_TIMEOUT;
1297*3088717bSVictor Perevertkin         *Retry = TRUE;
1298*3088717bSVictor Perevertkin         *RetryIntervalInSeconds = 0;
1299*3088717bSVictor Perevertkin         incrementErrorCount = TRUE;
1300*3088717bSVictor Perevertkin         break;
1301*3088717bSVictor Perevertkin     }
1302*3088717bSVictor Perevertkin 
1303*3088717bSVictor Perevertkin     case SRB_STATUS_ABORTED:
1304*3088717bSVictor Perevertkin     {
1305*3088717bSVictor Perevertkin         // Update the error count for the device.
1306*3088717bSVictor Perevertkin         *Status = STATUS_IO_TIMEOUT;
1307*3088717bSVictor Perevertkin         *Retry = TRUE;
1308*3088717bSVictor Perevertkin         *RetryIntervalInSeconds = 1;
1309*3088717bSVictor Perevertkin         incrementErrorCount = TRUE;
1310*3088717bSVictor Perevertkin         break;
1311*3088717bSVictor Perevertkin     }
1312*3088717bSVictor Perevertkin 
1313*3088717bSVictor Perevertkin     case SRB_STATUS_SELECTION_TIMEOUT:
1314*3088717bSVictor Perevertkin     {
1315*3088717bSVictor Perevertkin         *Status = STATUS_DEVICE_NOT_CONNECTED;
1316*3088717bSVictor Perevertkin         *Retry = FALSE;
1317*3088717bSVictor Perevertkin         *RetryIntervalInSeconds = 2;
1318*3088717bSVictor Perevertkin         LogContext->LogError = TRUE;
1319*3088717bSVictor Perevertkin         LogContext->ErrorCode = IO_ERR_NOT_READY;
1320*3088717bSVictor Perevertkin         LogContext->UniqueErrorValue = 260;
1321*3088717bSVictor Perevertkin         break;
1322*3088717bSVictor Perevertkin     }
1323*3088717bSVictor Perevertkin 
1324*3088717bSVictor Perevertkin     case SRB_STATUS_DATA_OVERRUN:
1325*3088717bSVictor Perevertkin     {
1326*3088717bSVictor Perevertkin         *Status = STATUS_DATA_OVERRUN;
1327*3088717bSVictor Perevertkin         *Retry = FALSE;
1328*3088717bSVictor Perevertkin         break;
1329*3088717bSVictor Perevertkin     }
1330*3088717bSVictor Perevertkin 
1331*3088717bSVictor Perevertkin     case SRB_STATUS_PHASE_SEQUENCE_FAILURE:
1332*3088717bSVictor Perevertkin     {
1333*3088717bSVictor Perevertkin         // Update the error count for the device.
1334*3088717bSVictor Perevertkin         incrementErrorCount = TRUE;
1335*3088717bSVictor Perevertkin         *Status = STATUS_IO_DEVICE_ERROR;
1336*3088717bSVictor Perevertkin 
1337*3088717bSVictor Perevertkin         // If there was phase sequence error then limit the number of retries.
1338*3088717bSVictor Perevertkin         *Retry = (RetriedCount <= 1);
1339*3088717bSVictor Perevertkin 
1340*3088717bSVictor Perevertkin         break;
1341*3088717bSVictor Perevertkin     }
1342*3088717bSVictor Perevertkin 
1343*3088717bSVictor Perevertkin     case SRB_STATUS_REQUEST_FLUSHED:
1344*3088717bSVictor Perevertkin     {
1345*3088717bSVictor Perevertkin         // If the status needs verification bit is set.  Then set
1346*3088717bSVictor Perevertkin         // the status to need verification and no retry; otherwise,
1347*3088717bSVictor Perevertkin         // just retry the request.
1348*3088717bSVictor Perevertkin         if (TEST_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME))
1349*3088717bSVictor Perevertkin         {
1350*3088717bSVictor Perevertkin             *Status = STATUS_VERIFY_REQUIRED;
1351*3088717bSVictor Perevertkin             *Retry = FALSE;
1352*3088717bSVictor Perevertkin         }
1353*3088717bSVictor Perevertkin         else
1354*3088717bSVictor Perevertkin         {
1355*3088717bSVictor Perevertkin             *Status = STATUS_IO_DEVICE_ERROR;
1356*3088717bSVictor Perevertkin             *Retry = TRUE;
1357*3088717bSVictor Perevertkin         }
1358*3088717bSVictor Perevertkin 
1359*3088717bSVictor Perevertkin         break;
1360*3088717bSVictor Perevertkin     }
1361*3088717bSVictor Perevertkin 
1362*3088717bSVictor Perevertkin     case SRB_STATUS_INVALID_REQUEST:
1363*3088717bSVictor Perevertkin     {
1364*3088717bSVictor Perevertkin         *Status = STATUS_INVALID_DEVICE_REQUEST;
1365*3088717bSVictor Perevertkin         *Retry = FALSE;
1366*3088717bSVictor Perevertkin         break;
1367*3088717bSVictor Perevertkin     }
1368*3088717bSVictor Perevertkin 
1369*3088717bSVictor Perevertkin     case SRB_STATUS_UNEXPECTED_BUS_FREE:
1370*3088717bSVictor Perevertkin     case SRB_STATUS_PARITY_ERROR:
1371*3088717bSVictor Perevertkin         // Update the error count for the device and fall through to below
1372*3088717bSVictor Perevertkin         incrementErrorCount = TRUE;
1373*3088717bSVictor Perevertkin 
1374*3088717bSVictor Perevertkin     case SRB_STATUS_BUS_RESET:
1375*3088717bSVictor Perevertkin     {
1376*3088717bSVictor Perevertkin         *Status = STATUS_IO_DEVICE_ERROR;
1377*3088717bSVictor Perevertkin         *Retry = TRUE;
1378*3088717bSVictor Perevertkin         break;
1379*3088717bSVictor Perevertkin     }
1380*3088717bSVictor Perevertkin 
1381*3088717bSVictor Perevertkin     case SRB_STATUS_ERROR:
1382*3088717bSVictor Perevertkin     {
1383*3088717bSVictor Perevertkin         *Status = STATUS_IO_DEVICE_ERROR;
1384*3088717bSVictor Perevertkin         *Retry = TRUE;
1385*3088717bSVictor Perevertkin 
1386*3088717bSVictor Perevertkin         if (Srb->ScsiStatus == 0)
1387*3088717bSVictor Perevertkin         {
1388*3088717bSVictor Perevertkin             // This is some strange return code.  Update the error
1389*3088717bSVictor Perevertkin             // count for the device.
1390*3088717bSVictor Perevertkin             incrementErrorCount = TRUE;
1391*3088717bSVictor Perevertkin         }
1392*3088717bSVictor Perevertkin 
1393*3088717bSVictor Perevertkin         if (Srb->ScsiStatus == SCSISTAT_BUSY)
1394*3088717bSVictor Perevertkin         {
1395*3088717bSVictor Perevertkin             *Status = STATUS_DEVICE_NOT_READY;
1396*3088717bSVictor Perevertkin         }
1397*3088717bSVictor Perevertkin 
1398*3088717bSVictor Perevertkin         break;
1399*3088717bSVictor Perevertkin     }
1400*3088717bSVictor Perevertkin 
1401*3088717bSVictor Perevertkin     default:
1402*3088717bSVictor Perevertkin     {
1403*3088717bSVictor Perevertkin         *Status = STATUS_IO_DEVICE_ERROR;
1404*3088717bSVictor Perevertkin         *Retry = TRUE;
1405*3088717bSVictor Perevertkin         LogContext->LogError = TRUE;
1406*3088717bSVictor Perevertkin         LogContext->ErrorCode = IO_ERR_CONTROLLER_ERROR;
1407*3088717bSVictor Perevertkin         LogContext->UniqueErrorValue = 259;
1408*3088717bSVictor Perevertkin         LogContext->ErrorUnhandled = TRUE;
1409*3088717bSVictor Perevertkin         break;
1410*3088717bSVictor Perevertkin     }
1411*3088717bSVictor Perevertkin 
1412*3088717bSVictor Perevertkin     } //end of (SRB_STATUS(Srb->SrbStatus))
1413*3088717bSVictor Perevertkin 
1414*3088717bSVictor Perevertkin     if (incrementErrorCount)
1415*3088717bSVictor Perevertkin     {
1416*3088717bSVictor Perevertkin         // if any error count occurred, delay the retry of this io by
1417*3088717bSVictor Perevertkin         // at least one second, if caller supports it.
1418*3088717bSVictor Perevertkin         if (*RetryIntervalInSeconds == 0)
1419*3088717bSVictor Perevertkin         {
1420*3088717bSVictor Perevertkin             *RetryIntervalInSeconds = 1;
1421*3088717bSVictor Perevertkin         }
1422*3088717bSVictor Perevertkin 
1423*3088717bSVictor Perevertkin         DevicePerfIncrementErrorCount(DeviceExtension);
1424*3088717bSVictor Perevertkin     }
1425*3088717bSVictor Perevertkin 
1426*3088717bSVictor Perevertkin     return;
1427*3088717bSVictor Perevertkin }
1428*3088717bSVictor Perevertkin 
1429*3088717bSVictor Perevertkin VOID
SenseInfoLogError(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension,_In_ PSCSI_REQUEST_BLOCK Srb,_In_ UCHAR MajorFunctionCode,_In_ ULONG IoControlCode,_In_ ULONG RetriedCount,_In_ NTSTATUS * Status,_In_ BOOLEAN * Retry,_Inout_ PERROR_LOG_CONTEXT LogContext)1430*3088717bSVictor Perevertkin SenseInfoLogError(
1431*3088717bSVictor Perevertkin     _In_    PCDROM_DEVICE_EXTENSION DeviceExtension,
1432*3088717bSVictor Perevertkin     _In_    PSCSI_REQUEST_BLOCK     Srb,
1433*3088717bSVictor Perevertkin     _In_    UCHAR                   MajorFunctionCode,
1434*3088717bSVictor Perevertkin     _In_    ULONG                   IoControlCode,
1435*3088717bSVictor Perevertkin     _In_    ULONG                   RetriedCount,
1436*3088717bSVictor Perevertkin     _In_    NTSTATUS*               Status,
1437*3088717bSVictor Perevertkin     _In_    BOOLEAN*                Retry,
1438*3088717bSVictor Perevertkin     _Inout_ PERROR_LOG_CONTEXT      LogContext
1439*3088717bSVictor Perevertkin     )
1440*3088717bSVictor Perevertkin {
1441*3088717bSVictor Perevertkin     //      Always log the error in our internal log.
1442*3088717bSVictor Perevertkin     //      If logError is set, also log the error in the system log.
1443*3088717bSVictor Perevertkin     PSENSE_DATA          senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
1444*3088717bSVictor Perevertkin     ULONG                totalSize = 0;
1445*3088717bSVictor Perevertkin     ULONG                senseBufferSize = 0;
1446*3088717bSVictor Perevertkin     IO_ERROR_LOG_PACKET  staticErrLogEntry = {0};
1447*3088717bSVictor Perevertkin     CDROM_ERROR_LOG_DATA staticErrLogData = {0};
1448*3088717bSVictor Perevertkin 
1449*3088717bSVictor Perevertkin     // Calculate the total size of the error log entry.
1450*3088717bSVictor Perevertkin     // add to totalSize in the order that they are used.
1451*3088717bSVictor Perevertkin     // the advantage to calculating all the sizes here is
1452*3088717bSVictor Perevertkin     // that we don't have to do a bunch of extraneous checks
1453*3088717bSVictor Perevertkin     // later on in this code path.
1454*3088717bSVictor Perevertkin     totalSize = sizeof(IO_ERROR_LOG_PACKET)     // required
1455*3088717bSVictor Perevertkin               + sizeof(CDROM_ERROR_LOG_DATA);   // struct for ease
1456*3088717bSVictor Perevertkin 
1457*3088717bSVictor Perevertkin     // also save any available extra sense data, up to the maximum errlog
1458*3088717bSVictor Perevertkin     // packet size .  WMI should be used for real-time analysis.
1459*3088717bSVictor Perevertkin     // the event log should only be used for post-mortem debugging.
1460*3088717bSVictor Perevertkin     if (TEST_FLAG(Srb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID))
1461*3088717bSVictor Perevertkin     {
1462*3088717bSVictor Perevertkin         ULONG       validSenseBytes;
1463*3088717bSVictor Perevertkin         BOOLEAN     validSense;
1464*3088717bSVictor Perevertkin 
1465*3088717bSVictor Perevertkin         // make sure we can at least access the AdditionalSenseLength field
1466*3088717bSVictor Perevertkin         validSense = RTL_CONTAINS_FIELD(senseBuffer,
1467*3088717bSVictor Perevertkin                                         Srb->SenseInfoBufferLength,
1468*3088717bSVictor Perevertkin                                         AdditionalSenseLength);
1469*3088717bSVictor Perevertkin         if (validSense)
1470*3088717bSVictor Perevertkin         {
1471*3088717bSVictor Perevertkin             // if extra info exists, copy the maximum amount of available
1472*3088717bSVictor Perevertkin             // sense data that is safe into the the errlog.
1473*3088717bSVictor Perevertkin             validSenseBytes = senseBuffer->AdditionalSenseLength
1474*3088717bSVictor Perevertkin                                 + offsetof(SENSE_DATA, AdditionalSenseLength);
1475*3088717bSVictor Perevertkin 
1476*3088717bSVictor Perevertkin             // this is invalid because it causes overflow!
1477*3088717bSVictor Perevertkin             // whoever sent this type of request would cause
1478*3088717bSVictor Perevertkin             // a system crash.
1479*3088717bSVictor Perevertkin             NT_ASSERT(validSenseBytes < MAX_ADDITIONAL_SENSE_BYTES);
1480*3088717bSVictor Perevertkin 
1481*3088717bSVictor Perevertkin             // set to save the most sense buffer possible
1482*3088717bSVictor Perevertkin             senseBufferSize = max(validSenseBytes, sizeof(SENSE_DATA));
1483*3088717bSVictor Perevertkin             senseBufferSize = min(senseBufferSize, Srb->SenseInfoBufferLength);
1484*3088717bSVictor Perevertkin         }
1485*3088717bSVictor Perevertkin         else
1486*3088717bSVictor Perevertkin         {
1487*3088717bSVictor Perevertkin             // it's smaller than required to read the total number of
1488*3088717bSVictor Perevertkin             // valid bytes, so just use the SenseInfoBufferLength field.
1489*3088717bSVictor Perevertkin             senseBufferSize = Srb->SenseInfoBufferLength;
1490*3088717bSVictor Perevertkin         }
1491*3088717bSVictor Perevertkin 
1492*3088717bSVictor Perevertkin         //  Bump totalSize by the number of extra senseBuffer bytes
1493*3088717bSVictor Perevertkin         //  (beyond the default sense buffer within CDROM_ERROR_LOG_DATA).
1494*3088717bSVictor Perevertkin         //  Make sure to never allocate more than ERROR_LOG_MAXIMUM_SIZE.
1495*3088717bSVictor Perevertkin         if (senseBufferSize > sizeof(SENSE_DATA))
1496*3088717bSVictor Perevertkin         {
1497*3088717bSVictor Perevertkin             totalSize += senseBufferSize-sizeof(SENSE_DATA);
1498*3088717bSVictor Perevertkin             if (totalSize > ERROR_LOG_MAXIMUM_SIZE)
1499*3088717bSVictor Perevertkin             {
1500*3088717bSVictor Perevertkin                 senseBufferSize -= totalSize-ERROR_LOG_MAXIMUM_SIZE;
1501*3088717bSVictor Perevertkin                 totalSize = ERROR_LOG_MAXIMUM_SIZE;
1502*3088717bSVictor Perevertkin             }
1503*3088717bSVictor Perevertkin         }
1504*3088717bSVictor Perevertkin     }
1505*3088717bSVictor Perevertkin 
1506*3088717bSVictor Perevertkin     // If we've used up all of our retry attempts, set the final status to
1507*3088717bSVictor Perevertkin     // reflect the appropriate result.
1508*3088717bSVictor Perevertkin     //
1509*3088717bSVictor Perevertkin     // ISSUE: the test below should also check RetriedCount to determine if we will actually retry,
1510*3088717bSVictor Perevertkin     //            but there is no easy test because we'd have to consider the original retry count
1511*3088717bSVictor Perevertkin     //            for the op; besides, InterpretTransferPacketError sometimes ignores the retry
1512*3088717bSVictor Perevertkin     //            decision returned by this function.  So just ErrorRetried to be true in the majority case.
1513*3088717bSVictor Perevertkin     //
1514*3088717bSVictor Perevertkin     if (*Retry)
1515*3088717bSVictor Perevertkin     {
1516*3088717bSVictor Perevertkin         staticErrLogEntry.FinalStatus = STATUS_SUCCESS;
1517*3088717bSVictor Perevertkin         staticErrLogData.ErrorRetried = TRUE;
1518*3088717bSVictor Perevertkin     }
1519*3088717bSVictor Perevertkin     else
1520*3088717bSVictor Perevertkin     {
1521*3088717bSVictor Perevertkin         staticErrLogEntry.FinalStatus = *Status;
1522*3088717bSVictor Perevertkin     }
1523*3088717bSVictor Perevertkin 
1524*3088717bSVictor Perevertkin     // Don't log generic IO_WARNING_PAGING_FAILURE message if either the
1525*3088717bSVictor Perevertkin     // I/O is retried, or it completed successfully.
1526*3088717bSVictor Perevertkin     if ((LogContext->ErrorCode == IO_WARNING_PAGING_FAILURE) &&
1527*3088717bSVictor Perevertkin         (*Retry || NT_SUCCESS(*Status)) )
1528*3088717bSVictor Perevertkin     {
1529*3088717bSVictor Perevertkin         LogContext->LogError = FALSE;
1530*3088717bSVictor Perevertkin     }
1531*3088717bSVictor Perevertkin 
1532*3088717bSVictor Perevertkin     if (TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_PAGING))
1533*3088717bSVictor Perevertkin     {
1534*3088717bSVictor Perevertkin         staticErrLogData.ErrorPaging = TRUE;
1535*3088717bSVictor Perevertkin     }
1536*3088717bSVictor Perevertkin 
1537*3088717bSVictor Perevertkin     staticErrLogData.ErrorUnhandled = LogContext->ErrorUnhandled;
1538*3088717bSVictor Perevertkin 
1539*3088717bSVictor Perevertkin     // Calculate the device offset if there is a geometry.
1540*3088717bSVictor Perevertkin     staticErrLogEntry.DeviceOffset.QuadPart = (LONGLONG)LogContext->BadSector;
1541*3088717bSVictor Perevertkin     staticErrLogEntry.DeviceOffset.QuadPart *= (LONGLONG)DeviceExtension->DiskGeometry.BytesPerSector;
1542*3088717bSVictor Perevertkin 
1543*3088717bSVictor Perevertkin     if (LogContext->ErrorCode == -1)
1544*3088717bSVictor Perevertkin     {
1545*3088717bSVictor Perevertkin         staticErrLogEntry.ErrorCode = STATUS_IO_DEVICE_ERROR;
1546*3088717bSVictor Perevertkin     }
1547*3088717bSVictor Perevertkin     else
1548*3088717bSVictor Perevertkin     {
1549*3088717bSVictor Perevertkin         staticErrLogEntry.ErrorCode = LogContext->ErrorCode;
1550*3088717bSVictor Perevertkin     }
1551*3088717bSVictor Perevertkin 
1552*3088717bSVictor Perevertkin     //  The dump data follows the IO_ERROR_LOG_PACKET
1553*3088717bSVictor Perevertkin     staticErrLogEntry.DumpDataSize = (USHORT)totalSize - sizeof(IO_ERROR_LOG_PACKET);
1554*3088717bSVictor Perevertkin 
1555*3088717bSVictor Perevertkin     staticErrLogEntry.SequenceNumber = 0;
1556*3088717bSVictor Perevertkin     staticErrLogEntry.MajorFunctionCode = MajorFunctionCode;
1557*3088717bSVictor Perevertkin     staticErrLogEntry.IoControlCode = IoControlCode;
1558*3088717bSVictor Perevertkin     staticErrLogEntry.RetryCount = (UCHAR)RetriedCount;
1559*3088717bSVictor Perevertkin     staticErrLogEntry.UniqueErrorValue = LogContext->UniqueErrorValue;
1560*3088717bSVictor Perevertkin 
1561*3088717bSVictor Perevertkin     KeQueryTickCount(&staticErrLogData.TickCount);
1562*3088717bSVictor Perevertkin     staticErrLogData.PortNumber = (ULONG)-1;
1563*3088717bSVictor Perevertkin 
1564*3088717bSVictor Perevertkin     //  Save the entire contents of the SRB.
1565*3088717bSVictor Perevertkin     staticErrLogData.Srb = *Srb;
1566*3088717bSVictor Perevertkin 
1567*3088717bSVictor Perevertkin     //  For our private log, save just the default length of the SENSE_DATA.
1568*3088717bSVictor Perevertkin     if (senseBufferSize != 0)
1569*3088717bSVictor Perevertkin     {
1570*3088717bSVictor Perevertkin         RtlCopyMemory(&staticErrLogData.SenseData, senseBuffer, min(senseBufferSize, sizeof(SENSE_DATA)));
1571*3088717bSVictor Perevertkin     }
1572*3088717bSVictor Perevertkin 
1573*3088717bSVictor Perevertkin     // Save the error log in our context.
1574*3088717bSVictor Perevertkin     // We only save the default sense buffer length.
1575*3088717bSVictor Perevertkin     {
1576*3088717bSVictor Perevertkin         KIRQL                oldIrql;
1577*3088717bSVictor Perevertkin         KeAcquireSpinLock(&DeviceExtension->PrivateFdoData->SpinLock, &oldIrql);
1578*3088717bSVictor Perevertkin         DeviceExtension->PrivateFdoData->ErrorLogs[DeviceExtension->PrivateFdoData->ErrorLogNextIndex] = staticErrLogData;
1579*3088717bSVictor Perevertkin         DeviceExtension->PrivateFdoData->ErrorLogNextIndex++;
1580*3088717bSVictor Perevertkin         DeviceExtension->PrivateFdoData->ErrorLogNextIndex %= NUM_ERROR_LOG_ENTRIES;
1581*3088717bSVictor Perevertkin         KeReleaseSpinLock(&DeviceExtension->PrivateFdoData->SpinLock, oldIrql);
1582*3088717bSVictor Perevertkin     }
1583*3088717bSVictor Perevertkin 
1584*3088717bSVictor Perevertkin     //  If logError is set, also save this log in the system's error log.
1585*3088717bSVictor Perevertkin     //  But make sure we don't log TUR failures over and over
1586*3088717bSVictor Perevertkin     //  (e.g. if an external drive was switched off and we're still sending TUR's to it every second).
1587*3088717bSVictor Perevertkin     if (LogContext->LogError)
1588*3088717bSVictor Perevertkin     {
1589*3088717bSVictor Perevertkin         // We do not want to log certain system events repetitively
1590*3088717bSVictor Perevertkin         switch (((PCDB)Srb->Cdb)->CDB10.OperationCode)
1591*3088717bSVictor Perevertkin         {
1592*3088717bSVictor Perevertkin             case SCSIOP_TEST_UNIT_READY:
1593*3088717bSVictor Perevertkin             {
1594*3088717bSVictor Perevertkin                 if (DeviceExtension->PrivateFdoData->LoggedTURFailureSinceLastIO)
1595*3088717bSVictor Perevertkin                 {
1596*3088717bSVictor Perevertkin                     LogContext->LogError = FALSE;
1597*3088717bSVictor Perevertkin                 }
1598*3088717bSVictor Perevertkin                 else
1599*3088717bSVictor Perevertkin                 {
1600*3088717bSVictor Perevertkin                     DeviceExtension->PrivateFdoData->LoggedTURFailureSinceLastIO = TRUE;
1601*3088717bSVictor Perevertkin                 }
1602*3088717bSVictor Perevertkin 
1603*3088717bSVictor Perevertkin                 break;
1604*3088717bSVictor Perevertkin             }
1605*3088717bSVictor Perevertkin 
1606*3088717bSVictor Perevertkin             case SCSIOP_SYNCHRONIZE_CACHE:
1607*3088717bSVictor Perevertkin             {
1608*3088717bSVictor Perevertkin                 if (DeviceExtension->PrivateFdoData->LoggedSYNCFailure)
1609*3088717bSVictor Perevertkin                 {
1610*3088717bSVictor Perevertkin                     LogContext->LogError = FALSE;
1611*3088717bSVictor Perevertkin                 }
1612*3088717bSVictor Perevertkin                 else
1613*3088717bSVictor Perevertkin                 {
1614*3088717bSVictor Perevertkin                     DeviceExtension->PrivateFdoData->LoggedSYNCFailure = TRUE;
1615*3088717bSVictor Perevertkin                 }
1616*3088717bSVictor Perevertkin 
1617*3088717bSVictor Perevertkin                 break;
1618*3088717bSVictor Perevertkin             }
1619*3088717bSVictor Perevertkin         }
1620*3088717bSVictor Perevertkin 
1621*3088717bSVictor Perevertkin         // Do not log 5/21/00 LOGICAL BLOCK ADDRESS OUT OF RANGE if the disc is blank,
1622*3088717bSVictor Perevertkin         // it is known to litter the Event Log with repetitive errors
1623*3088717bSVictor Perevertkin         // Do not log this error for READ, as it's known that File System mount process reads different sectors from media.
1624*3088717bSVictor Perevertkin         if (senseBufferSize > RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseCodeQualifier) &&
1625*3088717bSVictor Perevertkin             senseBuffer->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST &&
1626*3088717bSVictor Perevertkin             senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_ILLEGAL_BLOCK &&
1627*3088717bSVictor Perevertkin             senseBuffer->AdditionalSenseCodeQualifier == 0 &&
1628*3088717bSVictor Perevertkin             IS_SCSIOP_READ(((PCDB)Srb->Cdb)->CDB10.OperationCode))
1629*3088717bSVictor Perevertkin         {
1630*3088717bSVictor Perevertkin             LogContext->LogError = FALSE;
1631*3088717bSVictor Perevertkin         }
1632*3088717bSVictor Perevertkin     }
1633*3088717bSVictor Perevertkin 
1634*3088717bSVictor Perevertkin     //  Write the error log packet to the system error logging thread.
1635*3088717bSVictor Perevertkin     if (LogContext->LogError)
1636*3088717bSVictor Perevertkin     {
1637*3088717bSVictor Perevertkin         PIO_ERROR_LOG_PACKET    errorLogEntry;
1638*3088717bSVictor Perevertkin         PCDROM_ERROR_LOG_DATA   errlogData;
1639*3088717bSVictor Perevertkin 
1640*3088717bSVictor Perevertkin         errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(DeviceExtension->DeviceObject, (UCHAR)totalSize);
1641*3088717bSVictor Perevertkin         if (errorLogEntry)
1642*3088717bSVictor Perevertkin         {
1643*3088717bSVictor Perevertkin             errlogData = (PCDROM_ERROR_LOG_DATA)errorLogEntry->DumpData;
1644*3088717bSVictor Perevertkin 
1645*3088717bSVictor Perevertkin             *errorLogEntry = staticErrLogEntry;
1646*3088717bSVictor Perevertkin             *errlogData = staticErrLogData;
1647*3088717bSVictor Perevertkin 
1648*3088717bSVictor Perevertkin             //  For the system log, copy as much of the sense buffer as possible.
1649*3088717bSVictor Perevertkin             if (senseBufferSize != 0)
1650*3088717bSVictor Perevertkin             {
1651*3088717bSVictor Perevertkin                 RtlCopyMemory(&errlogData->SenseData, senseBuffer, senseBufferSize);
1652*3088717bSVictor Perevertkin             }
1653*3088717bSVictor Perevertkin 
1654*3088717bSVictor Perevertkin             //  errorLogEntry - It will be freed by the kernel.
1655*3088717bSVictor Perevertkin             IoWriteErrorLogEntry(errorLogEntry);
1656*3088717bSVictor Perevertkin         }
1657*3088717bSVictor Perevertkin     }
1658*3088717bSVictor Perevertkin 
1659*3088717bSVictor Perevertkin     return;
1660*3088717bSVictor Perevertkin }
1661*3088717bSVictor Perevertkin 
1662*3088717bSVictor Perevertkin VOID
1663*3088717bSVictor Perevertkin SenseInfoInterpretRefineByScsiCommand(
1664*3088717bSVictor Perevertkin     _In_      PCDROM_DEVICE_EXTENSION   DeviceExtension,
1665*3088717bSVictor Perevertkin     _In_      PSCSI_REQUEST_BLOCK       Srb,
1666*3088717bSVictor Perevertkin     _In_      ULONG                     RetriedCount,
1667*3088717bSVictor Perevertkin     _In_      LONGLONG                  Total100nsSinceFirstSend,
1668*3088717bSVictor Perevertkin     _In_      BOOLEAN                   OverrideVerifyVolume,
1669*3088717bSVictor Perevertkin     _Inout_   BOOLEAN*                  Retry,
1670*3088717bSVictor Perevertkin     _Inout_   NTSTATUS*                 Status,
1671*3088717bSVictor Perevertkin     _Inout_   _Deref_out_range_(0, MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS)
1672*3088717bSVictor Perevertkin               LONGLONG*                 RetryIntervalIn100ns
1673*3088717bSVictor Perevertkin     )
1674*3088717bSVictor Perevertkin /*++
1675*3088717bSVictor Perevertkin 
1676*3088717bSVictor Perevertkin Routine Description:
1677*3088717bSVictor Perevertkin 
1678*3088717bSVictor Perevertkin     Based on SCSI command, modify the interpretion result.
1679*3088717bSVictor Perevertkin 
1680*3088717bSVictor Perevertkin Arguments:
1681*3088717bSVictor Perevertkin 
1682*3088717bSVictor Perevertkin     DeviceExtension - device extension.
1683*3088717bSVictor Perevertkin     Srb - Supplies the scsi request block which failed.
1684*3088717bSVictor Perevertkin     RetriedCount - retried count.
1685*3088717bSVictor Perevertkin     Total100nsUnitsSinceFirstSend - time spent after the request was sent down first time.
1686*3088717bSVictor Perevertkin     OverrideVerifyVolume - should override verify volume request.
1687*3088717bSVictor Perevertkin 
1688*3088717bSVictor Perevertkin Return Value:
1689*3088717bSVictor Perevertkin 
1690*3088717bSVictor Perevertkin     Retry - the reques should be retried or not.
1691*3088717bSVictor Perevertkin     Status - Returns the status for the request.
1692*3088717bSVictor Perevertkin     RetryInterval - waiting time (in 100ns) before the request should be retried.
1693*3088717bSVictor Perevertkin                     Zero indicates the request should be immediately retried.
1694*3088717bSVictor Perevertkin 
1695*3088717bSVictor Perevertkin --*/
1696*3088717bSVictor Perevertkin {
1697*3088717bSVictor Perevertkin     UCHAR const opCode = Srb->Cdb[0];
1698*3088717bSVictor Perevertkin     CDB const*  cdb = (CDB const*)(Srb->Cdb);
1699*3088717bSVictor Perevertkin     PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
1700*3088717bSVictor Perevertkin 
1701*3088717bSVictor Perevertkin     if (opCode == SCSIOP_MEDIUM_REMOVAL)
1702*3088717bSVictor Perevertkin     {
1703*3088717bSVictor Perevertkin         if (( cdb->AsByte[1]         == 0) &&
1704*3088717bSVictor Perevertkin             ( cdb->AsByte[2]         == 0) &&
1705*3088717bSVictor Perevertkin             ( cdb->AsByte[3]         == 0) &&
1706*3088717bSVictor Perevertkin             ((cdb->AsByte[4] & 0xFC) == 0)
1707*3088717bSVictor Perevertkin             )
1708*3088717bSVictor Perevertkin         {
1709*3088717bSVictor Perevertkin             // byte[4] == 0x3 or byte[4] == 0x1  ==  UNLOCK OF MEDIA
1710*3088717bSVictor Perevertkin             if ((cdb->AsByte[4] & 0x01) == 0)
1711*3088717bSVictor Perevertkin             {
1712*3088717bSVictor Perevertkin                 if (RetriedCount < TOTAL_COUNT_RETRY_DEFAULT)
1713*3088717bSVictor Perevertkin                 {
1714*3088717bSVictor Perevertkin                     // keep retrying unlock operation for several times
1715*3088717bSVictor Perevertkin                     *Retry = TRUE;
1716*3088717bSVictor Perevertkin                 }
1717*3088717bSVictor Perevertkin             }
1718*3088717bSVictor Perevertkin             else // LOCK REQUEST
1719*3088717bSVictor Perevertkin             {
1720*3088717bSVictor Perevertkin                 // do not retry LOCK requests more than once (per CLASSPNP code)
1721*3088717bSVictor Perevertkin                 if (RetriedCount > TOTAL_COUNT_RETRY_LOCK_MEDIA)
1722*3088717bSVictor Perevertkin                 {
1723*3088717bSVictor Perevertkin                     *Retry = FALSE;
1724*3088717bSVictor Perevertkin                 }
1725*3088717bSVictor Perevertkin             }
1726*3088717bSVictor Perevertkin         }
1727*3088717bSVictor Perevertkin 
1728*3088717bSVictor Perevertkin         // want a minimum time to retry of 2 seconds
1729*3088717bSVictor Perevertkin         if ((*Status == STATUS_DEVICE_NOT_READY) &&
1730*3088717bSVictor Perevertkin             (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY))
1731*3088717bSVictor Perevertkin         {
1732*3088717bSVictor Perevertkin             *RetryIntervalIn100ns = max(*RetryIntervalIn100ns, SECONDS_TO_100NS_UNITS(2));
1733*3088717bSVictor Perevertkin         }
1734*3088717bSVictor Perevertkin         else if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT)
1735*3088717bSVictor Perevertkin         {
1736*3088717bSVictor Perevertkin             *RetryIntervalIn100ns = max(*RetryIntervalIn100ns, SECONDS_TO_100NS_UNITS(2));
1737*3088717bSVictor Perevertkin         }
1738*3088717bSVictor Perevertkin     }
1739*3088717bSVictor Perevertkin     else if ((opCode == SCSIOP_MODE_SENSE) || (opCode == SCSIOP_MODE_SENSE10))
1740*3088717bSVictor Perevertkin     {
1741*3088717bSVictor Perevertkin         // want a minimum time to retry of 2 seconds
1742*3088717bSVictor Perevertkin         if ((*Status == STATUS_DEVICE_NOT_READY) &&
1743*3088717bSVictor Perevertkin             (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY))
1744*3088717bSVictor Perevertkin         {
1745*3088717bSVictor Perevertkin             *RetryIntervalIn100ns = max(*RetryIntervalIn100ns, SECONDS_TO_100NS_UNITS(2));
1746*3088717bSVictor Perevertkin         }
1747*3088717bSVictor Perevertkin         else if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT)
1748*3088717bSVictor Perevertkin         {
1749*3088717bSVictor Perevertkin             *RetryIntervalIn100ns = max(*RetryIntervalIn100ns, SECONDS_TO_100NS_UNITS(2));
1750*3088717bSVictor Perevertkin         }
1751*3088717bSVictor Perevertkin 
1752*3088717bSVictor Perevertkin         // Want to ignore a STATUS_VERIFY_REQUIRED error because it either
1753*3088717bSVictor Perevertkin         // doesn't make sense or is required to satisfy the VERIFY.
1754*3088717bSVictor Perevertkin         if (*Status == STATUS_VERIFY_REQUIRED)
1755*3088717bSVictor Perevertkin         {
1756*3088717bSVictor Perevertkin             *Retry = TRUE;
1757*3088717bSVictor Perevertkin         }
1758*3088717bSVictor Perevertkin         else if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN)
1759*3088717bSVictor Perevertkin         {
1760*3088717bSVictor Perevertkin             /*
1761*3088717bSVictor Perevertkin              *  This is a HACK.
1762*3088717bSVictor Perevertkin              *  Atapi returns SRB_STATUS_DATA_OVERRUN when it really means
1763*3088717bSVictor Perevertkin              *  underrun (i.e. success, and the buffer is longer than needed).
1764*3088717bSVictor Perevertkin              *  So treat this as a success.
1765*3088717bSVictor Perevertkin              *  When the caller of this function sees that the status was changed to success,
1766*3088717bSVictor Perevertkin              *  it will add the transferred length to the original irp.
1767*3088717bSVictor Perevertkin              */
1768*3088717bSVictor Perevertkin             *Status = STATUS_SUCCESS;
1769*3088717bSVictor Perevertkin             *Retry = FALSE;
1770*3088717bSVictor Perevertkin         }
1771*3088717bSVictor Perevertkin 
1772*3088717bSVictor Perevertkin         // limit the count of retries
1773*3088717bSVictor Perevertkin         if (RetriedCount > TOTAL_COUNT_RETRY_MODESENSE)
1774*3088717bSVictor Perevertkin         {
1775*3088717bSVictor Perevertkin             *Retry = FALSE;
1776*3088717bSVictor Perevertkin         }
1777*3088717bSVictor Perevertkin     }
1778*3088717bSVictor Perevertkin     else if ((opCode == SCSIOP_READ_CAPACITY) || (opCode == SCSIOP_READ_CAPACITY16))
1779*3088717bSVictor Perevertkin     {
1780*3088717bSVictor Perevertkin         // Want to ignore a STATUS_VERIFY_REQUIRED error because it either
1781*3088717bSVictor Perevertkin         // doesn't make sense or is required to satisfy the VERIFY.
1782*3088717bSVictor Perevertkin         if (*Status == STATUS_VERIFY_REQUIRED)
1783*3088717bSVictor Perevertkin         {
1784*3088717bSVictor Perevertkin             *Retry = TRUE;
1785*3088717bSVictor Perevertkin         }
1786*3088717bSVictor Perevertkin 
1787*3088717bSVictor Perevertkin         if (RetriedCount > TOTAL_COUNT_RETRY_READ_CAPACITY)
1788*3088717bSVictor Perevertkin         {
1789*3088717bSVictor Perevertkin             *Retry = FALSE;
1790*3088717bSVictor Perevertkin         }
1791*3088717bSVictor Perevertkin     }
1792*3088717bSVictor Perevertkin     else if ((opCode == SCSIOP_RESERVE_UNIT) || (opCode == SCSIOP_RELEASE_UNIT))
1793*3088717bSVictor Perevertkin     {
1794*3088717bSVictor Perevertkin         // The RESERVE(6) / RELEASE(6) commands are optional.
1795*3088717bSVictor Perevertkin         // So if they aren't supported, try the 10-byte equivalents
1796*3088717bSVictor Perevertkin         if (*Status == STATUS_INVALID_DEVICE_REQUEST)
1797*3088717bSVictor Perevertkin         {
1798*3088717bSVictor Perevertkin             PCDB tempCdb = (PCDB)Srb->Cdb;
1799*3088717bSVictor Perevertkin 
1800*3088717bSVictor Perevertkin             Srb->CdbLength = 10;
1801*3088717bSVictor Perevertkin             tempCdb->CDB10.OperationCode = (tempCdb->CDB6GENERIC.OperationCode == SCSIOP_RESERVE_UNIT)
1802*3088717bSVictor Perevertkin                                             ? SCSIOP_RESERVE_UNIT10
1803*3088717bSVictor Perevertkin                                             : SCSIOP_RELEASE_UNIT10;
1804*3088717bSVictor Perevertkin 
1805*3088717bSVictor Perevertkin             SET_FLAG(DeviceExtension->PrivateFdoData->HackFlags, FDO_HACK_NO_RESERVE6);
1806*3088717bSVictor Perevertkin             *Retry = TRUE;
1807*3088717bSVictor Perevertkin         }
1808*3088717bSVictor Perevertkin     }
1809*3088717bSVictor Perevertkin     else if (IS_SCSIOP_READWRITE(opCode))
1810*3088717bSVictor Perevertkin     {
1811*3088717bSVictor Perevertkin         // Retry if still verifying a (possibly) reloaded disk/cdrom.
1812*3088717bSVictor Perevertkin         if (OverrideVerifyVolume && (*Status == STATUS_VERIFY_REQUIRED))
1813*3088717bSVictor Perevertkin         {
1814*3088717bSVictor Perevertkin             *Status = STATUS_IO_DEVICE_ERROR;
1815*3088717bSVictor Perevertkin             *Retry = TRUE;
1816*3088717bSVictor Perevertkin         }
1817*3088717bSVictor Perevertkin 
1818*3088717bSVictor Perevertkin         // Special case for streaming READ/WRITE commands
1819*3088717bSVictor Perevertkin         if (((opCode == SCSIOP_READ12) && (cdb->READ12.Streaming == 1)) ||
1820*3088717bSVictor Perevertkin             ((opCode == SCSIOP_WRITE12) && (cdb->WRITE12.Streaming == 1)))
1821*3088717bSVictor Perevertkin         {
1822*3088717bSVictor Perevertkin             // We've got a failure while performing a streaming operation and now need to guess if
1823*3088717bSVictor Perevertkin             // it's likely to be a permanent error because the drive does not support streaming at all
1824*3088717bSVictor Perevertkin             // (in which case we're going to fall back to normal reads/writes), or a transient error
1825*3088717bSVictor Perevertkin             // (in which case we quickly fail the request but contrinue to use streaming).
1826*3088717bSVictor Perevertkin             //
1827*3088717bSVictor Perevertkin             // We analyze the sense information to make that decision. Bus resets and device timeouts
1828*3088717bSVictor Perevertkin             // are treated as permanent errors, because some non-compliant devices may even hang when
1829*3088717bSVictor Perevertkin             // they get a command that they do not expect.
1830*3088717bSVictor Perevertkin 
1831*3088717bSVictor Perevertkin             BOOLEAN     disableStreaming = FALSE;
1832*3088717bSVictor Perevertkin 
1833*3088717bSVictor Perevertkin             if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_TIMEOUT ||
1834*3088717bSVictor Perevertkin                 SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_COMMAND_TIMEOUT ||
1835*3088717bSVictor Perevertkin                 SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT ||
1836*3088717bSVictor Perevertkin                 SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_BUS_RESET)
1837*3088717bSVictor Perevertkin             {
1838*3088717bSVictor Perevertkin                 disableStreaming = TRUE;
1839*3088717bSVictor Perevertkin             }
1840*3088717bSVictor Perevertkin             else if ((senseBuffer->SenseKey &0xf) == SCSI_SENSE_UNIT_ATTENTION)
1841*3088717bSVictor Perevertkin             {
1842*3088717bSVictor Perevertkin                 if (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_BUS_RESET ||
1843*3088717bSVictor Perevertkin                     senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_INSUFFICIENT_TIME_FOR_OPERATION)
1844*3088717bSVictor Perevertkin                 {
1845*3088717bSVictor Perevertkin                     disableStreaming = TRUE;
1846*3088717bSVictor Perevertkin                 }
1847*3088717bSVictor Perevertkin             }
1848*3088717bSVictor Perevertkin             else if ((senseBuffer->SenseKey &0xf) == SCSI_SENSE_ILLEGAL_REQUEST)
1849*3088717bSVictor Perevertkin             {
1850*3088717bSVictor Perevertkin                 // LBA Out of Range is an exception, as it's more likely to be caused by
1851*3088717bSVictor Perevertkin                 // upper layers attempting to read/write a wrong LBA.
1852*3088717bSVictor Perevertkin                 if (senseBuffer->AdditionalSenseCode != SCSI_ADSENSE_ILLEGAL_BLOCK)
1853*3088717bSVictor Perevertkin                 {
1854*3088717bSVictor Perevertkin                     disableStreaming = TRUE;
1855*3088717bSVictor Perevertkin                 }
1856*3088717bSVictor Perevertkin             }
1857*3088717bSVictor Perevertkin 
1858*3088717bSVictor Perevertkin             if (disableStreaming)
1859*3088717bSVictor Perevertkin             {
1860*3088717bSVictor Perevertkin                 // if the failure looks permanent, we disable streaming for all future reads/writes
1861*3088717bSVictor Perevertkin                 // and retry the command immediately
1862*3088717bSVictor Perevertkin                 SET_FLAG(DeviceExtension->PrivateFdoData->HackFlags, FDO_HACK_NO_STREAMING);
1863*3088717bSVictor Perevertkin                 *Retry = TRUE;
1864*3088717bSVictor Perevertkin                 *RetryIntervalIn100ns = 0;
1865*3088717bSVictor Perevertkin             }
1866*3088717bSVictor Perevertkin             else
1867*3088717bSVictor Perevertkin             {
1868*3088717bSVictor Perevertkin                 // if the failure looks transient, we simply fail the current request without retries
1869*3088717bSVictor Perevertkin                 // to minimize the time of processing
1870*3088717bSVictor Perevertkin                 *Retry = FALSE;
1871*3088717bSVictor Perevertkin             }
1872*3088717bSVictor Perevertkin         }
1873*3088717bSVictor Perevertkin 
1874*3088717bSVictor Perevertkin         // Special-case handling of READ/WRITE commands.  These commands now have a 120 second timeout,
1875*3088717bSVictor Perevertkin         // but the preferred behavior (and that taken by many drives) is to immediately report 2/4/x
1876*3088717bSVictor Perevertkin         // on OPC and similar commands.  Thus, retries must occur for at least 160 seconds
1877*3088717bSVictor Perevertkin         // (120 seconds + four 10 second retries) as a conservative guess.
1878*3088717bSVictor Perevertkin         // Note: 160s retry time is also a result of discussion with OEMs for case of 2/4/7 and 2/4/8.
1879*3088717bSVictor Perevertkin         if (*Retry)
1880*3088717bSVictor Perevertkin         {
1881*3088717bSVictor Perevertkin             if ((Total100nsSinceFirstSend < 0) ||
1882*3088717bSVictor Perevertkin                 (((senseBuffer->SenseKey &0xf) == SCSI_SENSE_HARDWARE_ERROR) && (senseBuffer->AdditionalSenseCode == 0x09)))
1883*3088717bSVictor Perevertkin             {
1884*3088717bSVictor Perevertkin                 // time information is not valid. use default retry count.
1885*3088717bSVictor Perevertkin                 // or if it's SERVO FAILURE, use retry count instead of 160s retry.
1886*3088717bSVictor Perevertkin                 *Retry = (RetriedCount <= TOTAL_COUNT_RETRY_DEFAULT);
1887*3088717bSVictor Perevertkin             }
1888*3088717bSVictor Perevertkin             else if (Total100nsSinceFirstSend > SECONDS_TO_100NS_UNITS(TOTAL_SECONDS_RETRY_TIME_WRITE))
1889*3088717bSVictor Perevertkin             {
1890*3088717bSVictor Perevertkin                 *Retry = FALSE;
1891*3088717bSVictor Perevertkin             }
1892*3088717bSVictor Perevertkin 
1893*3088717bSVictor Perevertkin             // How long should we request a delay for during writing?  This depends entirely on
1894*3088717bSVictor Perevertkin             // the current write speed of the drive.  If we request retries too quickly,
1895*3088717bSVictor Perevertkin             // we can overload the processor on the drive (resulting in garbage being written),
1896*3088717bSVictor Perevertkin             // but too slowly results in lesser performance.
1897*3088717bSVictor Perevertkin             //
1898*3088717bSVictor Perevertkin             *RetryIntervalIn100ns = DeviceExtension->DeviceAdditionalData.ReadWriteRetryDelay100nsUnits;
1899*3088717bSVictor Perevertkin 
1900*3088717bSVictor Perevertkin         } // end retry for 160 seconds modification
1901*3088717bSVictor Perevertkin     }
1902*3088717bSVictor Perevertkin     else if (opCode == SCSIOP_GET_PERFORMANCE)
1903*3088717bSVictor Perevertkin     {
1904*3088717bSVictor Perevertkin         if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN)
1905*3088717bSVictor Perevertkin         {
1906*3088717bSVictor Perevertkin             //  This is a HACK.
1907*3088717bSVictor Perevertkin             //  Atapi returns SRB_STATUS_DATA_OVERRUN when it really means
1908*3088717bSVictor Perevertkin             //  underrun (i.e. success, and the buffer is longer than needed).
1909*3088717bSVictor Perevertkin             //  So treat this as a success.
1910*3088717bSVictor Perevertkin             //  When the caller of this function sees that the status was changed to success,
1911*3088717bSVictor Perevertkin             //  it will add the transferred length to the original irp.
1912*3088717bSVictor Perevertkin             *Status = STATUS_SUCCESS;
1913*3088717bSVictor Perevertkin             *Retry = FALSE;
1914*3088717bSVictor Perevertkin         }
1915*3088717bSVictor Perevertkin 
1916*3088717bSVictor Perevertkin         if ((Srb->SenseInfoBufferLength < RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA,AdditionalSenseCodeQualifier)) ||
1917*3088717bSVictor Perevertkin             !TEST_FLAG(Srb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID))
1918*3088717bSVictor Perevertkin         {
1919*3088717bSVictor Perevertkin             // If get configuration command is failing and if the request type is TYPE ONE
1920*3088717bSVictor Perevertkin             // then most likely the device does not support this request type. Set the
1921*3088717bSVictor Perevertkin             // flag so that the TYPE ONE requests will be tried as TYPE ALL requets.
1922*3088717bSVictor Perevertkin             if ((SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) &&
1923*3088717bSVictor Perevertkin                 (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_DATA_OVERRUN) &&
1924*3088717bSVictor Perevertkin                 (((PCDB)Srb->Cdb)->GET_CONFIGURATION.RequestType == SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE))
1925*3088717bSVictor Perevertkin             {
1926*3088717bSVictor Perevertkin 
1927*3088717bSVictor Perevertkin                 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL,
1928*3088717bSVictor Perevertkin                            "TYPE ONE GetConfiguration failed. Set hack flag and retry.\n"));
1929*3088717bSVictor Perevertkin                 SET_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_BAD_TYPE_ONE_GET_CONFIG);
1930*3088717bSVictor Perevertkin                 *Retry = TRUE;
1931*3088717bSVictor Perevertkin             }
1932*3088717bSVictor Perevertkin         }
1933*3088717bSVictor Perevertkin 
1934*3088717bSVictor Perevertkin         // limit retries to GET_PERFORMANCE commands to default retry count
1935*3088717bSVictor Perevertkin         if (RetriedCount > TOTAL_COUNT_RETRY_DEFAULT)
1936*3088717bSVictor Perevertkin         {
1937*3088717bSVictor Perevertkin             *Retry = FALSE;
1938*3088717bSVictor Perevertkin         }
1939*3088717bSVictor Perevertkin     }
1940*3088717bSVictor Perevertkin     else // default handler -- checks for retry count only.
1941*3088717bSVictor Perevertkin     {
1942*3088717bSVictor Perevertkin         if (RetriedCount > TOTAL_COUNT_RETRY_DEFAULT)
1943*3088717bSVictor Perevertkin         {
1944*3088717bSVictor Perevertkin             *Retry = FALSE;
1945*3088717bSVictor Perevertkin         }
1946*3088717bSVictor Perevertkin     }
1947*3088717bSVictor Perevertkin 
1948*3088717bSVictor Perevertkin     return;
1949*3088717bSVictor Perevertkin }
1950*3088717bSVictor Perevertkin 
1951*3088717bSVictor Perevertkin 
1952*3088717bSVictor Perevertkin VOID
SenseInfoInterpretRefineByIoControl(_In_ PCDROM_DEVICE_EXTENSION DeviceExtension,_In_ ULONG IoControlCode,_In_ BOOLEAN OverrideVerifyVolume,_Inout_ BOOLEAN * Retry,_Inout_ NTSTATUS * Status)1953*3088717bSVictor Perevertkin SenseInfoInterpretRefineByIoControl(
1954*3088717bSVictor Perevertkin     _In_      PCDROM_DEVICE_EXTENSION   DeviceExtension,
1955*3088717bSVictor Perevertkin     _In_      ULONG                     IoControlCode,
1956*3088717bSVictor Perevertkin     _In_      BOOLEAN                   OverrideVerifyVolume,
1957*3088717bSVictor Perevertkin     _Inout_   BOOLEAN*                  Retry,
1958*3088717bSVictor Perevertkin     _Inout_   NTSTATUS*                 Status
1959*3088717bSVictor Perevertkin     )
1960*3088717bSVictor Perevertkin /*++
1961*3088717bSVictor Perevertkin 
1962*3088717bSVictor Perevertkin Routine Description:
1963*3088717bSVictor Perevertkin 
1964*3088717bSVictor Perevertkin     Based on IOCTL code, modify the interpretion result.
1965*3088717bSVictor Perevertkin 
1966*3088717bSVictor Perevertkin Arguments:
1967*3088717bSVictor Perevertkin 
1968*3088717bSVictor Perevertkin     Device - Supplies the device object associated with this request.
1969*3088717bSVictor Perevertkin     OriginalRequest - the irp that error occurs on.
1970*3088717bSVictor Perevertkin     Srb - Supplies the scsi request block which failed.
1971*3088717bSVictor Perevertkin     MajorFunctionCode - Supplies the function code to be used for logging.
1972*3088717bSVictor Perevertkin     IoDeviceCode - Supplies the device code to be used for logging.
1973*3088717bSVictor Perevertkin     PreviousRetryCount - retried count.
1974*3088717bSVictor Perevertkin     RequestHistory_DoNotUse - the history list
1975*3088717bSVictor Perevertkin 
1976*3088717bSVictor Perevertkin Return Value:
1977*3088717bSVictor Perevertkin 
1978*3088717bSVictor Perevertkin     BOOLEAN TRUE: Drivers should retry this request.
1979*3088717bSVictor Perevertkin             FALSE: Drivers should not retry this request.
1980*3088717bSVictor Perevertkin     Status - Returns the status for the request.
1981*3088717bSVictor Perevertkin     RetryInterval - Number of seconds before the request should be retried.
1982*3088717bSVictor Perevertkin                     Zero indicates the request should be immediately retried.
1983*3088717bSVictor Perevertkin 
1984*3088717bSVictor Perevertkin --*/
1985*3088717bSVictor Perevertkin {
1986*3088717bSVictor Perevertkin     PAGED_CODE();
1987*3088717bSVictor Perevertkin 
1988*3088717bSVictor Perevertkin     if ((IoControlCode == IOCTL_CDROM_GET_LAST_SESSION) ||
1989*3088717bSVictor Perevertkin         (IoControlCode == IOCTL_CDROM_READ_TOC)         ||
1990*3088717bSVictor Perevertkin         (IoControlCode == IOCTL_CDROM_READ_TOC_EX)      ||
1991*3088717bSVictor Perevertkin         (IoControlCode == IOCTL_CDROM_GET_CONFIGURATION)||
1992*3088717bSVictor Perevertkin         (IoControlCode == IOCTL_CDROM_GET_VOLUME))
1993*3088717bSVictor Perevertkin     {
1994*3088717bSVictor Perevertkin         if (*Status == STATUS_DATA_OVERRUN)
1995*3088717bSVictor Perevertkin         {
1996*3088717bSVictor Perevertkin             *Status = STATUS_SUCCESS;
1997*3088717bSVictor Perevertkin             *Retry = FALSE;
1998*3088717bSVictor Perevertkin         }
1999*3088717bSVictor Perevertkin     }
2000*3088717bSVictor Perevertkin 
2001*3088717bSVictor Perevertkin     if (IoControlCode == IOCTL_CDROM_READ_Q_CHANNEL)
2002*3088717bSVictor Perevertkin     {
2003*3088717bSVictor Perevertkin         PLAY_ACTIVE(DeviceExtension) = FALSE;
2004*3088717bSVictor Perevertkin     }
2005*3088717bSVictor Perevertkin 
2006*3088717bSVictor Perevertkin     // If the status is verified required and the this request
2007*3088717bSVictor Perevertkin     // should bypass verify required then retry the request.
2008*3088717bSVictor Perevertkin     if (OverrideVerifyVolume && (*Status == STATUS_VERIFY_REQUIRED))
2009*3088717bSVictor Perevertkin     {
2010*3088717bSVictor Perevertkin         // note: status gets overwritten here
2011*3088717bSVictor Perevertkin         *Status = STATUS_IO_DEVICE_ERROR;
2012*3088717bSVictor Perevertkin         *Retry = TRUE;
2013*3088717bSVictor Perevertkin 
2014*3088717bSVictor Perevertkin         if ((IoControlCode == IOCTL_CDROM_CHECK_VERIFY) ||
2015*3088717bSVictor Perevertkin             (IoControlCode == IOCTL_STORAGE_CHECK_VERIFY) ||
2016*3088717bSVictor Perevertkin             (IoControlCode == IOCTL_STORAGE_CHECK_VERIFY2) ||
2017*3088717bSVictor Perevertkin             (IoControlCode == IOCTL_DISK_CHECK_VERIFY)
2018*3088717bSVictor Perevertkin            )
2019*3088717bSVictor Perevertkin         {
2020*3088717bSVictor Perevertkin             // Update the geometry information, as the media could have changed.
2021*3088717bSVictor Perevertkin             (VOID) MediaReadCapacity(DeviceExtension->Device);
2022*3088717bSVictor Perevertkin         } // end of ioctls to update capacity
2023*3088717bSVictor Perevertkin     }
2024*3088717bSVictor Perevertkin 
2025*3088717bSVictor Perevertkin     if (!NT_SUCCESS(*Status) && (IoControlCode == IOCTL_CDROM_SET_SPEED))
2026*3088717bSVictor Perevertkin     {
2027*3088717bSVictor Perevertkin         // If set speed request fails then we should disable the restore speed option.
2028*3088717bSVictor Perevertkin         // Otherwise we will try to restore to default speed on next media change,
2029*3088717bSVictor Perevertkin         // if requested by the caller.
2030*3088717bSVictor Perevertkin         DeviceExtension->DeviceAdditionalData.RestoreDefaults = FALSE;
2031*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "Disable restore default\n"));
2032*3088717bSVictor Perevertkin     }
2033*3088717bSVictor Perevertkin 
2034*3088717bSVictor Perevertkin     return;
2035*3088717bSVictor Perevertkin }
2036*3088717bSVictor Perevertkin 
2037*3088717bSVictor Perevertkin BOOLEAN
2038*3088717bSVictor Perevertkin SenseInfoInterpret(
2039*3088717bSVictor Perevertkin     _In_    PCDROM_DEVICE_EXTENSION DeviceExtension,
2040*3088717bSVictor Perevertkin     _In_    WDFREQUEST              Request,
2041*3088717bSVictor Perevertkin     _In_    PSCSI_REQUEST_BLOCK     Srb,
2042*3088717bSVictor Perevertkin     _In_    ULONG                   RetriedCount,
2043*3088717bSVictor Perevertkin     _Out_   NTSTATUS*               Status,
2044*3088717bSVictor Perevertkin     _Out_ _Deref_out_range_(0, MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS)
2045*3088717bSVictor Perevertkin               LONGLONG*             RetryIntervalIn100ns
2046*3088717bSVictor Perevertkin     )
2047*3088717bSVictor Perevertkin /*++
2048*3088717bSVictor Perevertkin 
2049*3088717bSVictor Perevertkin SenseInfoInterpret()
2050*3088717bSVictor Perevertkin 
2051*3088717bSVictor Perevertkin Routine Description:
2052*3088717bSVictor Perevertkin 
2053*3088717bSVictor Perevertkin     This routine interprets the data returned from the SCSI request sense.
2054*3088717bSVictor Perevertkin     It determines the status to return in the IRP
2055*3088717bSVictor Perevertkin     and whether this request can be retried.
2056*3088717bSVictor Perevertkin 
2057*3088717bSVictor Perevertkin Arguments:
2058*3088717bSVictor Perevertkin 
2059*3088717bSVictor Perevertkin     Device - Supplies the device object associated with this request.
2060*3088717bSVictor Perevertkin     Srb - Supplies the scsi request block which failed.
2061*3088717bSVictor Perevertkin     MajorFunctionCode - Supplies the function code to be used for logging.
2062*3088717bSVictor Perevertkin     IoDeviceCode - Supplies the device code to be used for logging.
2063*3088717bSVictor Perevertkin 
2064*3088717bSVictor Perevertkin Return Value:
2065*3088717bSVictor Perevertkin 
2066*3088717bSVictor Perevertkin     BOOLEAN TRUE: Drivers should retry this request.
2067*3088717bSVictor Perevertkin             FALSE: Drivers should not retry this request.
2068*3088717bSVictor Perevertkin     Status - Returns the status for the request.
2069*3088717bSVictor Perevertkin     RetryInterval - Number of seconds before the request should be retried.
2070*3088717bSVictor Perevertkin                     Zero indicates the request should be immediately retried.
2071*3088717bSVictor Perevertkin 
2072*3088717bSVictor Perevertkin --*/
2073*3088717bSVictor Perevertkin {
2074*3088717bSVictor Perevertkin     ULONG               retryIntervalInSeconds = 0;
2075*3088717bSVictor Perevertkin     BOOLEAN             retry = TRUE;
2076*3088717bSVictor Perevertkin     PSENSE_DATA         senseBuffer = Srb->SenseInfoBuffer;
2077*3088717bSVictor Perevertkin     ULONG               readSector = 0;
2078*3088717bSVictor Perevertkin     ERROR_LOG_CONTEXT   logContext;
2079*3088717bSVictor Perevertkin 
2080*3088717bSVictor Perevertkin     UCHAR                   majorFunctionCode = 0;
2081*3088717bSVictor Perevertkin     ULONG                   ioControlCode = 0;
2082*3088717bSVictor Perevertkin     BOOLEAN                 overrideVerifyVolume = FALSE;
2083*3088717bSVictor Perevertkin     ULONGLONG               total100nsSinceFirstSend = 0;
2084*3088717bSVictor Perevertkin     PZERO_POWER_ODD_INFO    zpoddInfo = DeviceExtension->ZeroPowerODDInfo;
2085*3088717bSVictor Perevertkin 
2086*3088717bSVictor Perevertkin     //
2087*3088717bSVictor Perevertkin     *Status = STATUS_IO_DEVICE_ERROR;
2088*3088717bSVictor Perevertkin 
2089*3088717bSVictor Perevertkin     RtlZeroMemory(&logContext, sizeof(ERROR_LOG_CONTEXT));
2090*3088717bSVictor Perevertkin     logContext.ErrorCode = -1;
2091*3088717bSVictor Perevertkin 
2092*3088717bSVictor Perevertkin     // Get Original Request related information
2093*3088717bSVictor Perevertkin     SenseInfoRequestGetInformation(Request,
2094*3088717bSVictor Perevertkin                                    &majorFunctionCode,
2095*3088717bSVictor Perevertkin                                    &ioControlCode,
2096*3088717bSVictor Perevertkin                                    &overrideVerifyVolume,
2097*3088717bSVictor Perevertkin                                    &total100nsSinceFirstSend);
2098*3088717bSVictor Perevertkin 
2099*3088717bSVictor Perevertkin     if(TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_PAGING))
2100*3088717bSVictor Perevertkin     {
2101*3088717bSVictor Perevertkin         // Log anything remotely incorrect about paging i/o
2102*3088717bSVictor Perevertkin         logContext.LogError = TRUE;
2103*3088717bSVictor Perevertkin         logContext.UniqueErrorValue = 301;
2104*3088717bSVictor Perevertkin         logContext.ErrorCode = IO_WARNING_PAGING_FAILURE;
2105*3088717bSVictor Perevertkin     }
2106*3088717bSVictor Perevertkin 
2107*3088717bSVictor Perevertkin     // must handle the SRB_STATUS_INTERNAL_ERROR case first,
2108*3088717bSVictor Perevertkin     // as it has all the flags set.
2109*3088717bSVictor Perevertkin     if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_INTERNAL_ERROR)
2110*3088717bSVictor Perevertkin     {
2111*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
2112*3088717bSVictor Perevertkin                     "SenseInfoInterpret: Internal Error code is %x\n",
2113*3088717bSVictor Perevertkin                     Srb->InternalStatus));
2114*3088717bSVictor Perevertkin 
2115*3088717bSVictor Perevertkin         retry = FALSE;
2116*3088717bSVictor Perevertkin         *Status = Srb->InternalStatus;
2117*3088717bSVictor Perevertkin     }
2118*3088717bSVictor Perevertkin     else if (Srb->ScsiStatus == SCSISTAT_RESERVATION_CONFLICT)
2119*3088717bSVictor Perevertkin     {
2120*3088717bSVictor Perevertkin         retry = FALSE;
2121*3088717bSVictor Perevertkin         *Status = STATUS_DEVICE_BUSY;
2122*3088717bSVictor Perevertkin         logContext.LogError = FALSE;
2123*3088717bSVictor Perevertkin     }
2124*3088717bSVictor Perevertkin     else if ((Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
2125*3088717bSVictor Perevertkin              (Srb->SenseInfoBufferLength >= RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseLength)))
2126*3088717bSVictor Perevertkin     {
2127*3088717bSVictor Perevertkin         UCHAR   senseKey = (UCHAR)(senseBuffer->SenseKey & 0x0f);
2128*3088717bSVictor Perevertkin         UCHAR   additionalSenseCode = 0;
2129*3088717bSVictor Perevertkin         UCHAR   additionalSenseCodeQual = 0;
2130*3088717bSVictor Perevertkin 
2131*3088717bSVictor Perevertkin         // Zero the additional sense code and additional sense code qualifier
2132*3088717bSVictor Perevertkin         // if they were not returned by the device.
2133*3088717bSVictor Perevertkin         readSector = senseBuffer->AdditionalSenseLength + offsetof(SENSE_DATA, AdditionalSenseLength);
2134*3088717bSVictor Perevertkin         if (readSector > Srb->SenseInfoBufferLength)
2135*3088717bSVictor Perevertkin         {
2136*3088717bSVictor Perevertkin             readSector = Srb->SenseInfoBufferLength;
2137*3088717bSVictor Perevertkin         }
2138*3088717bSVictor Perevertkin 
2139*3088717bSVictor Perevertkin         additionalSenseCode = (readSector >= RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseCode)) ?
2140*3088717bSVictor Perevertkin                                senseBuffer->AdditionalSenseCode : 0;
2141*3088717bSVictor Perevertkin         additionalSenseCodeQual = (readSector >= RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseCodeQualifier)) ?
2142*3088717bSVictor Perevertkin                                    senseBuffer->AdditionalSenseCodeQualifier : 0;
2143*3088717bSVictor Perevertkin 
2144*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL,
2145*3088717bSVictor Perevertkin                     "SCSI Error - \n"
2146*3088717bSVictor Perevertkin                     "\tcdb: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n"
2147*3088717bSVictor Perevertkin                     "\tsrb status: %X; sense: %02X/%02X/%02X; Retried count: %d\n\n",
2148*3088717bSVictor Perevertkin                     Srb->Cdb[0], Srb->Cdb[1], Srb->Cdb[2], Srb->Cdb[3], Srb->Cdb[4], Srb->Cdb[5],
2149*3088717bSVictor Perevertkin                     Srb->Cdb[6], Srb->Cdb[7], Srb->Cdb[8], Srb->Cdb[9], Srb->Cdb[10], Srb->Cdb[11],
2150*3088717bSVictor Perevertkin                     Srb->Cdb[12], Srb->Cdb[13], Srb->Cdb[14], Srb->Cdb[15],
2151*3088717bSVictor Perevertkin                     SRB_STATUS(Srb->SrbStatus),
2152*3088717bSVictor Perevertkin                     senseKey,
2153*3088717bSVictor Perevertkin                     additionalSenseCode,
2154*3088717bSVictor Perevertkin                     additionalSenseCodeQual,
2155*3088717bSVictor Perevertkin                     RetriedCount));
2156*3088717bSVictor Perevertkin 
2157*3088717bSVictor Perevertkin         if (senseKey == SCSI_SENSE_UNIT_ATTENTION)
2158*3088717bSVictor Perevertkin         {
2159*3088717bSVictor Perevertkin             ULONG   mediaChangeCount;
2160*3088717bSVictor Perevertkin 
2161*3088717bSVictor Perevertkin             // A media change may have occured so increment the change count for the physical device
2162*3088717bSVictor Perevertkin             mediaChangeCount = InterlockedIncrement((PLONG)&DeviceExtension->MediaChangeCount);
2163*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,
2164*3088717bSVictor Perevertkin                        "SenseInfoInterpret: Media change count for device %d incremented to %#lx\n",
2165*3088717bSVictor Perevertkin                        DeviceExtension->DeviceNumber, mediaChangeCount));
2166*3088717bSVictor Perevertkin         }
2167*3088717bSVictor Perevertkin 
2168*3088717bSVictor Perevertkin         if ((zpoddInfo != NULL) &&
2169*3088717bSVictor Perevertkin             (((PCDB)Srb->Cdb)->CDB6GENERIC.OperationCode == SCSIOP_TEST_UNIT_READY))
2170*3088717bSVictor Perevertkin         {
2171*3088717bSVictor Perevertkin             // This sense code is in response to the Test Unit Ready sent during delayed power down
2172*3088717bSVictor Perevertkin             // request. Copy the sense data into the zpoddInfo structure for later processing.
2173*3088717bSVictor Perevertkin             zpoddInfo->SenseKey = senseKey;
2174*3088717bSVictor Perevertkin             zpoddInfo->AdditionalSenseCode = additionalSenseCode;
2175*3088717bSVictor Perevertkin             zpoddInfo->AdditionalSenseCodeQualifier = additionalSenseCodeQual;
2176*3088717bSVictor Perevertkin         }
2177*3088717bSVictor Perevertkin 
2178*3088717bSVictor Perevertkin         // Interpret error by specific ASC & ASCQ first,
2179*3088717bSVictor Perevertkin         // If the error is not handled, interpret using f
2180*3088717bSVictor Perevertkin         {
2181*3088717bSVictor Perevertkin             BOOLEAN notHandled = FALSE;
2182*3088717bSVictor Perevertkin             notHandled = SenseInfoInterpretByAdditionalSenseCode(DeviceExtension,
2183*3088717bSVictor Perevertkin                                                                  Srb,
2184*3088717bSVictor Perevertkin                                                                  additionalSenseCode,
2185*3088717bSVictor Perevertkin                                                                  additionalSenseCodeQual,
2186*3088717bSVictor Perevertkin                                                                  Status,
2187*3088717bSVictor Perevertkin                                                                  &retry,
2188*3088717bSVictor Perevertkin                                                                  &retryIntervalInSeconds,
2189*3088717bSVictor Perevertkin                                                                  &logContext);
2190*3088717bSVictor Perevertkin 
2191*3088717bSVictor Perevertkin             if (notHandled)
2192*3088717bSVictor Perevertkin             {
2193*3088717bSVictor Perevertkin                 SenseInfoInterpretBySenseKey(DeviceExtension,
2194*3088717bSVictor Perevertkin                                              senseBuffer,
2195*3088717bSVictor Perevertkin                                              senseKey,
2196*3088717bSVictor Perevertkin                                              Status,
2197*3088717bSVictor Perevertkin                                              &retry,
2198*3088717bSVictor Perevertkin                                              &retryIntervalInSeconds,
2199*3088717bSVictor Perevertkin                                              &logContext);
2200*3088717bSVictor Perevertkin             }
2201*3088717bSVictor Perevertkin         }
2202*3088717bSVictor Perevertkin 
2203*3088717bSVictor Perevertkin         // Try to determine the bad sector from the inquiry data.
2204*3088717bSVictor Perevertkin         if ((IS_SCSIOP_READWRITE(((PCDB)Srb->Cdb)->CDB10.OperationCode)) ||
2205*3088717bSVictor Perevertkin             (((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_VERIFY)     ||
2206*3088717bSVictor Perevertkin             (((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_VERIFY16))
2207*3088717bSVictor Perevertkin         {
2208*3088717bSVictor Perevertkin             ULONG index;
2209*3088717bSVictor Perevertkin             readSector = 0;
2210*3088717bSVictor Perevertkin 
2211*3088717bSVictor Perevertkin             for (index = 0; index < 4; index++)
2212*3088717bSVictor Perevertkin             {
2213*3088717bSVictor Perevertkin                 logContext.BadSector = (logContext.BadSector << 8) | senseBuffer->Information[index];
2214*3088717bSVictor Perevertkin             }
2215*3088717bSVictor Perevertkin 
2216*3088717bSVictor Perevertkin             for (index = 0; index < 4; index++)
2217*3088717bSVictor Perevertkin             {
2218*3088717bSVictor Perevertkin                 readSector = (readSector << 8) | Srb->Cdb[index+2];
2219*3088717bSVictor Perevertkin             }
2220*3088717bSVictor Perevertkin 
2221*3088717bSVictor Perevertkin             index = (((PCDB)Srb->Cdb)->CDB10.TransferBlocksMsb << 8) |
2222*3088717bSVictor Perevertkin                     ((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb;
2223*3088717bSVictor Perevertkin 
2224*3088717bSVictor Perevertkin             // Make sure the bad sector is within the read sectors.
2225*3088717bSVictor Perevertkin             if (!(logContext.BadSector >= readSector && logContext.BadSector < (readSector + index)))
2226*3088717bSVictor Perevertkin             {
2227*3088717bSVictor Perevertkin                 logContext.BadSector = readSector;
2228*3088717bSVictor Perevertkin             }
2229*3088717bSVictor Perevertkin         }
2230*3088717bSVictor Perevertkin     }
2231*3088717bSVictor Perevertkin     else
2232*3088717bSVictor Perevertkin     {
2233*3088717bSVictor Perevertkin         // Request sense buffer not valid. No sense information
2234*3088717bSVictor Perevertkin         // to pinpoint the error. Return general request fail.
2235*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL,
2236*3088717bSVictor Perevertkin                     "SCSI Error - \n"
2237*3088717bSVictor Perevertkin                     "\tcdb: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n"
2238*3088717bSVictor Perevertkin                     "\tsrb status: %X; sense info not valid; Retried count: %d\n\n",
2239*3088717bSVictor Perevertkin                     Srb->Cdb[0], Srb->Cdb[1], Srb->Cdb[2], Srb->Cdb[3], Srb->Cdb[4], Srb->Cdb[5],
2240*3088717bSVictor Perevertkin                     Srb->Cdb[6], Srb->Cdb[7], Srb->Cdb[8], Srb->Cdb[9], Srb->Cdb[10], Srb->Cdb[11],
2241*3088717bSVictor Perevertkin                     Srb->Cdb[12], Srb->Cdb[13], Srb->Cdb[14], Srb->Cdb[15],
2242*3088717bSVictor Perevertkin                     SRB_STATUS(Srb->SrbStatus),
2243*3088717bSVictor Perevertkin                     RetriedCount));
2244*3088717bSVictor Perevertkin 
2245*3088717bSVictor Perevertkin         SenseInfoInterpretBySrbStatus(DeviceExtension,
2246*3088717bSVictor Perevertkin                                       Srb,
2247*3088717bSVictor Perevertkin                                       RetriedCount,
2248*3088717bSVictor Perevertkin                                       Status,
2249*3088717bSVictor Perevertkin                                       &retry,
2250*3088717bSVictor Perevertkin                                       &retryIntervalInSeconds,
2251*3088717bSVictor Perevertkin                                       &logContext);
2252*3088717bSVictor Perevertkin     }
2253*3088717bSVictor Perevertkin 
2254*3088717bSVictor Perevertkin     // all functions using unit - seconds for retry Interval already be called.
2255*3088717bSVictor Perevertkin     *RetryIntervalIn100ns = SECONDS_TO_100NS_UNITS(retryIntervalInSeconds);
2256*3088717bSVictor Perevertkin 
2257*3088717bSVictor Perevertkin     // call the device specific error handler if it has one.
2258*3088717bSVictor Perevertkin     // DeviceErrorHandlerForMmmc() for all MMC devices
2259*3088717bSVictor Perevertkin     // or DeviceErrorHandlerForHitachiGD2000() for HITACHI GD-2000, HITACHI DVD-ROM GD-2000
2260*3088717bSVictor Perevertkin     if (DeviceExtension->DeviceAdditionalData.ErrorHandler)
2261*3088717bSVictor Perevertkin     {
2262*3088717bSVictor Perevertkin         DeviceExtension->DeviceAdditionalData.ErrorHandler(DeviceExtension, Srb, Status, &retry);
2263*3088717bSVictor Perevertkin     }
2264*3088717bSVictor Perevertkin 
2265*3088717bSVictor Perevertkin     // Refine retry based on SCSI command
2266*3088717bSVictor Perevertkin     SenseInfoInterpretRefineByScsiCommand(DeviceExtension,
2267*3088717bSVictor Perevertkin                                           Srb,
2268*3088717bSVictor Perevertkin                                           RetriedCount,
2269*3088717bSVictor Perevertkin                                           total100nsSinceFirstSend,
2270*3088717bSVictor Perevertkin                                           overrideVerifyVolume,
2271*3088717bSVictor Perevertkin                                           &retry,
2272*3088717bSVictor Perevertkin                                           Status,
2273*3088717bSVictor Perevertkin                                           RetryIntervalIn100ns);
2274*3088717bSVictor Perevertkin 
2275*3088717bSVictor Perevertkin     // Refine retry based on IOCTL code.
2276*3088717bSVictor Perevertkin     if (majorFunctionCode == IRP_MJ_DEVICE_CONTROL)
2277*3088717bSVictor Perevertkin     {
2278*3088717bSVictor Perevertkin         SenseInfoInterpretRefineByIoControl(DeviceExtension,
2279*3088717bSVictor Perevertkin                                             ioControlCode,
2280*3088717bSVictor Perevertkin                                             overrideVerifyVolume,
2281*3088717bSVictor Perevertkin                                             &retry,
2282*3088717bSVictor Perevertkin                                             Status);
2283*3088717bSVictor Perevertkin     }
2284*3088717bSVictor Perevertkin 
2285*3088717bSVictor Perevertkin     // LOG the error:
2286*3088717bSVictor Perevertkin     //  Always log the error in our internal log.
2287*3088717bSVictor Perevertkin     //  If logError is set, also log the error in the system log.
2288*3088717bSVictor Perevertkin     SenseInfoLogError(DeviceExtension,
2289*3088717bSVictor Perevertkin                       Srb,
2290*3088717bSVictor Perevertkin                       majorFunctionCode,
2291*3088717bSVictor Perevertkin                       ioControlCode,
2292*3088717bSVictor Perevertkin                       RetriedCount,
2293*3088717bSVictor Perevertkin                       Status,
2294*3088717bSVictor Perevertkin                       &retry,
2295*3088717bSVictor Perevertkin                       &logContext);
2296*3088717bSVictor Perevertkin 
2297*3088717bSVictor Perevertkin     // all process about the error done. check if the irp was cancelled.
2298*3088717bSVictor Perevertkin     if ((!NT_SUCCESS(*Status)) && retry)
2299*3088717bSVictor Perevertkin     {
2300*3088717bSVictor Perevertkin         PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request);
2301*3088717bSVictor Perevertkin 
2302*3088717bSVictor Perevertkin         if ((requestContext->OriginalRequest != NULL) &&
2303*3088717bSVictor Perevertkin             WdfRequestIsCanceled(requestContext->OriginalRequest)
2304*3088717bSVictor Perevertkin             )
2305*3088717bSVictor Perevertkin         {
2306*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL,
2307*3088717bSVictor Perevertkin                        "Request %p was cancelled when it would have been retried\n",
2308*3088717bSVictor Perevertkin                        requestContext->OriginalRequest));
2309*3088717bSVictor Perevertkin 
2310*3088717bSVictor Perevertkin             *Status = STATUS_CANCELLED;
2311*3088717bSVictor Perevertkin             retry = FALSE;
2312*3088717bSVictor Perevertkin             *RetryIntervalIn100ns = 0;
2313*3088717bSVictor Perevertkin         }
2314*3088717bSVictor Perevertkin     }
2315*3088717bSVictor Perevertkin 
2316*3088717bSVictor Perevertkin     // now, all decisions are made. display trace information.
2317*3088717bSVictor Perevertkin     if (retry)
2318*3088717bSVictor Perevertkin     {
2319*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
2320*3088717bSVictor Perevertkin                    "Command shall be retried in %2I64d.%03I64d seconds\n",
2321*3088717bSVictor Perevertkin                    (*RetryIntervalIn100ns / UNIT_100NS_PER_SECOND),
2322*3088717bSVictor Perevertkin                    (*RetryIntervalIn100ns / 10000) % 1000
2323*3088717bSVictor Perevertkin                    ));
2324*3088717bSVictor Perevertkin     }
2325*3088717bSVictor Perevertkin     else
2326*3088717bSVictor Perevertkin     {
2327*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL,
2328*3088717bSVictor Perevertkin                    "Will not retry; Sense/ASC/ASCQ of %02x/%02x/%02x\n",
2329*3088717bSVictor Perevertkin                    senseBuffer->SenseKey,
2330*3088717bSVictor Perevertkin                    senseBuffer->AdditionalSenseCode,
2331*3088717bSVictor Perevertkin                    senseBuffer->AdditionalSenseCodeQualifier
2332*3088717bSVictor Perevertkin                    ));
2333*3088717bSVictor Perevertkin     }
2334*3088717bSVictor Perevertkin 
2335*3088717bSVictor Perevertkin     return retry;
2336*3088717bSVictor Perevertkin 
2337*3088717bSVictor Perevertkin } // end SenseInfoInterpret()
2338*3088717bSVictor Perevertkin 
2339*3088717bSVictor Perevertkin 
2340*3088717bSVictor Perevertkin BOOLEAN
2341*3088717bSVictor Perevertkin SenseInfoInterpretForZPODD(
2342*3088717bSVictor Perevertkin     _In_    PCDROM_DEVICE_EXTENSION DeviceExtension,
2343*3088717bSVictor Perevertkin     _In_    PSCSI_REQUEST_BLOCK     Srb,
2344*3088717bSVictor Perevertkin     _Out_   NTSTATUS*               Status,
2345*3088717bSVictor Perevertkin     _Out_ _Out_range_(0, MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS)
2346*3088717bSVictor Perevertkin               LONGLONG*             RetryIntervalIn100ns
2347*3088717bSVictor Perevertkin     )
2348*3088717bSVictor Perevertkin /*++
2349*3088717bSVictor Perevertkin 
2350*3088717bSVictor Perevertkin SenseInfoInterpretForZPODD()
2351*3088717bSVictor Perevertkin 
2352*3088717bSVictor Perevertkin Routine Description:
2353*3088717bSVictor Perevertkin 
2354*3088717bSVictor Perevertkin     This routine interprets the data returned from the SCSI request sense.
2355*3088717bSVictor Perevertkin     It determines the status to return in the IRP
2356*3088717bSVictor Perevertkin     and whether this request can be retried.
2357*3088717bSVictor Perevertkin 
2358*3088717bSVictor Perevertkin Arguments:
2359*3088717bSVictor Perevertkin 
2360*3088717bSVictor Perevertkin     Device - Supplies the device object associated with this request.
2361*3088717bSVictor Perevertkin     Srb - Supplies the scsi request block which failed.
2362*3088717bSVictor Perevertkin 
2363*3088717bSVictor Perevertkin Return Value:
2364*3088717bSVictor Perevertkin 
2365*3088717bSVictor Perevertkin     BOOLEAN TRUE: Drivers should retry this request.
2366*3088717bSVictor Perevertkin             FALSE: Drivers should not retry this request.
2367*3088717bSVictor Perevertkin     Status - Returns the status for the request.
2368*3088717bSVictor Perevertkin     RetryInterval - Number of seconds before the request should be retried.
2369*3088717bSVictor Perevertkin                     Zero indicates the request should be immediately retried.
2370*3088717bSVictor Perevertkin 
2371*3088717bSVictor Perevertkin --*/
2372*3088717bSVictor Perevertkin {
2373*3088717bSVictor Perevertkin     BOOLEAN                 retry = FALSE;
2374*3088717bSVictor Perevertkin     PSENSE_DATA             senseBuffer = Srb->SenseInfoBuffer;
2375*3088717bSVictor Perevertkin     ULONG                   readSector = 0;
2376*3088717bSVictor Perevertkin     PZERO_POWER_ODD_INFO    zpoddInfo = DeviceExtension->ZeroPowerODDInfo;
2377*3088717bSVictor Perevertkin 
2378*3088717bSVictor Perevertkin     *Status = STATUS_IO_DEVICE_ERROR;
2379*3088717bSVictor Perevertkin     *RetryIntervalIn100ns = 0;
2380*3088717bSVictor Perevertkin 
2381*3088717bSVictor Perevertkin     if (zpoddInfo->RetryFirstCommand != FALSE)
2382*3088717bSVictor Perevertkin     {
2383*3088717bSVictor Perevertkin         // The first command to the logical unit after power resumed will be terminated
2384*3088717bSVictor Perevertkin         // with CHECK CONDITION Status, 6/29/00 POWER ON, RESET, OR BUS DEVICE RESET OCCURRED
2385*3088717bSVictor Perevertkin 
2386*3088717bSVictor Perevertkin         // We have observed some devices return a different sense code, and thus as long as
2387*3088717bSVictor Perevertkin         // the first command after power resume fails, we just retry one more time.
2388*3088717bSVictor Perevertkin         zpoddInfo->RetryFirstCommand = FALSE;
2389*3088717bSVictor Perevertkin 
2390*3088717bSVictor Perevertkin         retry = TRUE;
2391*3088717bSVictor Perevertkin     }
2392*3088717bSVictor Perevertkin     else if ((Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
2393*3088717bSVictor Perevertkin              (Srb->SenseInfoBufferLength >= RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseLength)))
2394*3088717bSVictor Perevertkin     {
2395*3088717bSVictor Perevertkin         UCHAR   senseKey = (UCHAR)(senseBuffer->SenseKey & 0x0f);
2396*3088717bSVictor Perevertkin         UCHAR   additionalSenseCode = 0;
2397*3088717bSVictor Perevertkin         UCHAR   additionalSenseCodeQual = 0;
2398*3088717bSVictor Perevertkin 
2399*3088717bSVictor Perevertkin         // Zero the additional sense code and additional sense code qualifier
2400*3088717bSVictor Perevertkin         // if they were not returned by the device.
2401*3088717bSVictor Perevertkin         readSector = senseBuffer->AdditionalSenseLength + offsetof(SENSE_DATA, AdditionalSenseLength);
2402*3088717bSVictor Perevertkin         if (readSector > Srb->SenseInfoBufferLength)
2403*3088717bSVictor Perevertkin         {
2404*3088717bSVictor Perevertkin             readSector = Srb->SenseInfoBufferLength;
2405*3088717bSVictor Perevertkin         }
2406*3088717bSVictor Perevertkin 
2407*3088717bSVictor Perevertkin         additionalSenseCode = (readSector >= RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseCode)) ?
2408*3088717bSVictor Perevertkin                                senseBuffer->AdditionalSenseCode : 0;
2409*3088717bSVictor Perevertkin         additionalSenseCodeQual = (readSector >= RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseCodeQualifier)) ?
2410*3088717bSVictor Perevertkin                                    senseBuffer->AdditionalSenseCodeQualifier : 0;
2411*3088717bSVictor Perevertkin 
2412*3088717bSVictor Perevertkin         // If sense code is 2/4/1, device is becoming ready from ZPODD mode. According to Mt Fuji, device
2413*3088717bSVictor Perevertkin         // could take up to 800msec to be fully operational.
2414*3088717bSVictor Perevertkin         if ((senseKey == SCSI_SENSE_NOT_READY) &&
2415*3088717bSVictor Perevertkin             (additionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) &&
2416*3088717bSVictor Perevertkin             (additionalSenseCodeQual == SCSI_SENSEQ_BECOMING_READY))
2417*3088717bSVictor Perevertkin         {
2418*3088717bSVictor Perevertkin             TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
2419*3088717bSVictor Perevertkin                         "SenseInfoInterpretForZPODD: In process of becoming ready\n"));
2420*3088717bSVictor Perevertkin 
2421*3088717bSVictor Perevertkin             zpoddInfo->BecomingReadyRetryCount--;
2422*3088717bSVictor Perevertkin 
2423*3088717bSVictor Perevertkin             if (zpoddInfo->BecomingReadyRetryCount > 0)
2424*3088717bSVictor Perevertkin             {
2425*3088717bSVictor Perevertkin                 DEVICE_EVENT_BECOMING_READY notReady = {0};
2426*3088717bSVictor Perevertkin 
2427*3088717bSVictor Perevertkin                 retry = TRUE;
2428*3088717bSVictor Perevertkin                 *Status = STATUS_DEVICE_NOT_READY;
2429*3088717bSVictor Perevertkin                 *RetryIntervalIn100ns = BECOMING_READY_RETRY_INTERNVAL_IN_100NS;
2430*3088717bSVictor Perevertkin 
2431*3088717bSVictor Perevertkin                 notReady.Version = 1;
2432*3088717bSVictor Perevertkin                 notReady.Reason = 1;
2433*3088717bSVictor Perevertkin                 notReady.Estimated100msToReady = (ULONG) *RetryIntervalIn100ns / (1000 * 1000);
2434*3088717bSVictor Perevertkin                 DeviceSendNotification(DeviceExtension,
2435*3088717bSVictor Perevertkin                                        &GUID_IO_DEVICE_BECOMING_READY,
2436*3088717bSVictor Perevertkin                                        sizeof(DEVICE_EVENT_BECOMING_READY),
2437*3088717bSVictor Perevertkin                                        &notReady);
2438*3088717bSVictor Perevertkin             }
2439*3088717bSVictor Perevertkin         }
2440*3088717bSVictor Perevertkin     }
2441*3088717bSVictor Perevertkin 
2442*3088717bSVictor Perevertkin     // now, all decisions are made. display trace information.
2443*3088717bSVictor Perevertkin     if (retry)
2444*3088717bSVictor Perevertkin     {
2445*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
2446*3088717bSVictor Perevertkin                    "Command shall be retried in %2I64d.%03I64d seconds\n",
2447*3088717bSVictor Perevertkin                    (*RetryIntervalIn100ns / UNIT_100NS_PER_SECOND),
2448*3088717bSVictor Perevertkin                    (*RetryIntervalIn100ns / 10000) % 1000
2449*3088717bSVictor Perevertkin                    ));
2450*3088717bSVictor Perevertkin     }
2451*3088717bSVictor Perevertkin     else
2452*3088717bSVictor Perevertkin     {
2453*3088717bSVictor Perevertkin         TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL,
2454*3088717bSVictor Perevertkin                    "Will not retry; Sense/ASC/ASCQ of %02x/%02x/%02x\n",
2455*3088717bSVictor Perevertkin                    senseBuffer->SenseKey,
2456*3088717bSVictor Perevertkin                    senseBuffer->AdditionalSenseCode,
2457*3088717bSVictor Perevertkin                    senseBuffer->AdditionalSenseCodeQualifier
2458*3088717bSVictor Perevertkin                    ));
2459*3088717bSVictor Perevertkin     }
2460*3088717bSVictor Perevertkin 
2461*3088717bSVictor Perevertkin     return retry;
2462*3088717bSVictor Perevertkin 
2463*3088717bSVictor Perevertkin } // end SenseInfoInterpret()
2464*3088717bSVictor Perevertkin 
2465*3088717bSVictor Perevertkin 
2466*3088717bSVictor Perevertkin BOOLEAN
2467*3088717bSVictor Perevertkin RequestSenseInfoInterpret(
2468*3088717bSVictor Perevertkin     _In_      PCDROM_DEVICE_EXTENSION   DeviceExtension,
2469*3088717bSVictor Perevertkin     _In_      WDFREQUEST                Request,
2470*3088717bSVictor Perevertkin     _In_      PSCSI_REQUEST_BLOCK       Srb,
2471*3088717bSVictor Perevertkin     _In_      ULONG                     RetriedCount,
2472*3088717bSVictor Perevertkin     _Out_     NTSTATUS*                 Status,
2473*3088717bSVictor Perevertkin     _Out_opt_ _Deref_out_range_(0, MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS)
2474*3088717bSVictor Perevertkin               LONGLONG*                 RetryIntervalIn100ns
2475*3088717bSVictor Perevertkin     )
2476*3088717bSVictor Perevertkin /*++
2477*3088717bSVictor Perevertkin 
2478*3088717bSVictor Perevertkin Routine Description:
2479*3088717bSVictor Perevertkin 
2480*3088717bSVictor Perevertkin Interpret the error, process it.
2481*3088717bSVictor Perevertkin     1. Release device queue if it's frozen.
2482*3088717bSVictor Perevertkin     2. Interpret and process the error.
2483*3088717bSVictor Perevertkin 
2484*3088717bSVictor Perevertkin Arguments:
2485*3088717bSVictor Perevertkin 
2486*3088717bSVictor Perevertkin     DeviceExtension - Supplies the device object associated with this request.
2487*3088717bSVictor Perevertkin     Request - the Request that error occurs on.
2488*3088717bSVictor Perevertkin     Srb - Supplies the scsi request block which failed.
2489*3088717bSVictor Perevertkin     RetriedCount - retried count.
2490*3088717bSVictor Perevertkin 
2491*3088717bSVictor Perevertkin Return Value:
2492*3088717bSVictor Perevertkin 
2493*3088717bSVictor Perevertkin     BOOLEAN TRUE:  Drivers should retry this request.
2494*3088717bSVictor Perevertkin             FALSE: Drivers should not retry this request.
2495*3088717bSVictor Perevertkin     Status - Returns the status for the request.
2496*3088717bSVictor Perevertkin     RetryIntervalIn100nsUnits - Number of 100ns before the request should be retried.
2497*3088717bSVictor Perevertkin                                 Zero indicates the request should be immediately retried.
2498*3088717bSVictor Perevertkin 
2499*3088717bSVictor Perevertkin --*/
2500*3088717bSVictor Perevertkin {
2501*3088717bSVictor Perevertkin     BOOLEAN                 retry = FALSE;
2502*3088717bSVictor Perevertkin     LONGLONG                retryIntervalIn100ns = 0;
2503*3088717bSVictor Perevertkin     PZERO_POWER_ODD_INFO    zpoddInfo = DeviceExtension->ZeroPowerODDInfo;
2504*3088717bSVictor Perevertkin 
2505*3088717bSVictor Perevertkin     if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
2506*3088717bSVictor Perevertkin     {
2507*3088717bSVictor Perevertkin         // request succeeded.
2508*3088717bSVictor Perevertkin         if ((zpoddInfo != NULL) &&
2509*3088717bSVictor Perevertkin             (zpoddInfo->BecomingReadyRetryCount > 0))
2510*3088717bSVictor Perevertkin         {
2511*3088717bSVictor Perevertkin             zpoddInfo->BecomingReadyRetryCount = 0;
2512*3088717bSVictor Perevertkin         }
2513*3088717bSVictor Perevertkin 
2514*3088717bSVictor Perevertkin         *Status = STATUS_SUCCESS;
2515*3088717bSVictor Perevertkin         retry = FALSE;
2516*3088717bSVictor Perevertkin     }
2517*3088717bSVictor Perevertkin     else
2518*3088717bSVictor Perevertkin     {
2519*3088717bSVictor Perevertkin         // request failed. We need to process the error.
2520*3088717bSVictor Perevertkin 
2521*3088717bSVictor Perevertkin         // 1. Release the queue if it is frozen.
2522*3088717bSVictor Perevertkin         if (Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN)
2523*3088717bSVictor Perevertkin         {
2524*3088717bSVictor Perevertkin             DeviceReleaseQueue(DeviceExtension->Device);
2525*3088717bSVictor Perevertkin         }
2526*3088717bSVictor Perevertkin 
2527*3088717bSVictor Perevertkin         if ((zpoddInfo != NULL) &&
2528*3088717bSVictor Perevertkin             ((zpoddInfo->RetryFirstCommand != FALSE) || (zpoddInfo->BecomingReadyRetryCount > 0)))
2529*3088717bSVictor Perevertkin         {
2530*3088717bSVictor Perevertkin             retry = SenseInfoInterpretForZPODD(DeviceExtension,
2531*3088717bSVictor Perevertkin                                                Srb,
2532*3088717bSVictor Perevertkin                                                Status,
2533*3088717bSVictor Perevertkin                                                &retryIntervalIn100ns);
2534*3088717bSVictor Perevertkin         }
2535*3088717bSVictor Perevertkin 
2536*3088717bSVictor Perevertkin         if (retry == FALSE)
2537*3088717bSVictor Perevertkin         {
2538*3088717bSVictor Perevertkin             // 2. Error Processing
2539*3088717bSVictor Perevertkin             if ((zpoddInfo != NULL) &&
2540*3088717bSVictor Perevertkin                 (zpoddInfo->BecomingReadyRetryCount > 0))
2541*3088717bSVictor Perevertkin             {
2542*3088717bSVictor Perevertkin                 zpoddInfo->BecomingReadyRetryCount = 0;
2543*3088717bSVictor Perevertkin             }
2544*3088717bSVictor Perevertkin 
2545*3088717bSVictor Perevertkin             retry = SenseInfoInterpret(DeviceExtension,
2546*3088717bSVictor Perevertkin                                        Request,
2547*3088717bSVictor Perevertkin                                        Srb,
2548*3088717bSVictor Perevertkin                                        RetriedCount,
2549*3088717bSVictor Perevertkin                                        Status,
2550*3088717bSVictor Perevertkin                                        &retryIntervalIn100ns);
2551*3088717bSVictor Perevertkin         }
2552*3088717bSVictor Perevertkin     }
2553*3088717bSVictor Perevertkin 
2554*3088717bSVictor Perevertkin     if (RetryIntervalIn100ns != NULL)
2555*3088717bSVictor Perevertkin     {
2556*3088717bSVictor Perevertkin         *RetryIntervalIn100ns = retryIntervalIn100ns;
2557*3088717bSVictor Perevertkin     }
2558*3088717bSVictor Perevertkin 
2559*3088717bSVictor Perevertkin     return retry;
2560*3088717bSVictor Perevertkin }
2561*3088717bSVictor Perevertkin 
2562*3088717bSVictor Perevertkin 
2563*3088717bSVictor Perevertkin BOOLEAN
2564*3088717bSVictor Perevertkin RequestSenseInfoInterpretForScratchBuffer(
2565*3088717bSVictor Perevertkin     _In_    PCDROM_DEVICE_EXTENSION DeviceExtension,
2566*3088717bSVictor Perevertkin     _In_    ULONG                   RetriedCount,
2567*3088717bSVictor Perevertkin     _Out_   NTSTATUS*               Status,
2568*3088717bSVictor Perevertkin     _Out_ _Deref_out_range_(0, MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS)
2569*3088717bSVictor Perevertkin             LONGLONG*               RetryIntervalIn100ns
2570*3088717bSVictor Perevertkin     )
2571*3088717bSVictor Perevertkin /*++
2572*3088717bSVictor Perevertkin 
2573*3088717bSVictor Perevertkin Routine Description:
2574*3088717bSVictor Perevertkin 
2575*3088717bSVictor Perevertkin     to analyze the error occurred and set the status, retry interval and decide to retry or not.
2576*3088717bSVictor Perevertkin 
2577*3088717bSVictor Perevertkin Arguments:
2578*3088717bSVictor Perevertkin 
2579*3088717bSVictor Perevertkin     DeviceExtension - device extension
2580*3088717bSVictor Perevertkin     RetriedCount - already retried count.
2581*3088717bSVictor Perevertkin 
2582*3088717bSVictor Perevertkin Return Value:
2583*3088717bSVictor Perevertkin 
2584*3088717bSVictor Perevertkin     BOOLEAN - TRUE (should retry)
2585*3088717bSVictor Perevertkin     Status - NTSTATUS
2586*3088717bSVictor Perevertkin     RetryIntervalIn100nsUnits - retry interval
2587*3088717bSVictor Perevertkin 
2588*3088717bSVictor Perevertkin --*/
2589*3088717bSVictor Perevertkin {
2590*3088717bSVictor Perevertkin     NT_ASSERT(DeviceExtension->ScratchContext.ScratchInUse != 0);
2591*3088717bSVictor Perevertkin 
2592*3088717bSVictor Perevertkin     return RequestSenseInfoInterpret(DeviceExtension,
2593*3088717bSVictor Perevertkin                                      DeviceExtension->ScratchContext.ScratchRequest,
2594*3088717bSVictor Perevertkin                                      DeviceExtension->ScratchContext.ScratchSrb,
2595*3088717bSVictor Perevertkin                                      RetriedCount,
2596*3088717bSVictor Perevertkin                                      Status,
2597*3088717bSVictor Perevertkin                                      RetryIntervalIn100ns);
2598*3088717bSVictor Perevertkin }
2599*3088717bSVictor Perevertkin 
2600*3088717bSVictor Perevertkin 
2601