summaryrefslogtreecommitdiff
path: root/storage/class/cdrom/src/cdromp.h
blob: 2fdf7118c9cdb6a4738af08760d8aae72b7d2bb1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
/*++

Copyright (C) Microsoft Corporation. All rights reserved.

Module Name:

    cdromp.h 

Abstract:

    Private header file for cdrom.sys modules.  This contains private
    structure and function declarations as well as constant values which do
    not need to be exported.

Author:

Environment:

    kernel mode only

Notes:


Revision History:

--*/

#ifndef __CDROMP_H__
#define __CDROMP_H__


#include <scsi.h>
#include <storduid.h>
#include <mountdev.h>
#include <ioevent.h>
#include <ntintsafe.h>

/*
 *  IA64 requires 8-byte alignment for pointers, but the IA64 NT kernel expects 16-byte alignment
 */
#ifdef _WIN64
    #define PTRALIGN                DECLSPEC_ALIGN(16)
#else
    #define PTRALIGN
#endif

// NOTE: Start with a smaller 100 second maximum, due to current assert in CLASSPNP
//       0x0000 00C9'2A69 C000 (864,000,000,000) is 24 hours in 100ns units
//       0x0000 0000'3B9A CA00 (  1,000,000,000) is 100 seconds in 100ns units
#define MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS (0x3B9ACA00)

// structures to simplify matching devices, ids, and hacks required for
// these ids.
typedef struct _CDROM_SCAN_FOR_SPECIAL_INFO {
    //
    // * NULL pointers indicates that no match is required.
    // * empty string will only match an empty string.  non-existant strings
    //   in the device descriptor are considered empty strings for this match.
    //   (ie. "" will only match "")
    // * all other strings will do partial matches, based upon
    //   string provided (ie. "hi" will match "hitazen" and "higazui")
    // * array must end with all three PCHARs being set to NULL.
    //

    PCHAR      VendorId;
    PCHAR      ProductId;
    PCHAR      ProductRevision;

    //
    // marked as a ULONG_PTR to allow use as either a ptr to a data block
    // or 32 bits worth of flags. (64 bits on 64 bit systems)  no longer a
    // const so that it may be dynamically built.
    //

    ULONG_PTR  Data;

} CDROM_SCAN_FOR_SPECIAL_INFO, *PCDROM_SCAN_FOR_SPECIAL_INFO;

// Define the various states that media can be in for autorun.
typedef enum _MEDIA_CHANGE_DETECTION_STATE {
    MediaUnknown,
    MediaPresent,
    MediaNotPresent,
    MediaUnavailable   // e.g. cd-r media undergoing burn
} MEDIA_CHANGE_DETECTION_STATE, *PMEDIA_CHANGE_DETECTION_STATE;


/*++////////////////////////////////////////////////////////////////////////////

    This structure defines the history kept for a given transfer packet.
    It includes a srb status/sense data structure that is always either valid
    or zero-filled for the full 18 bytes, time sent/completed, and how long
    the retry delay was requested to be.
    
--*/
typedef struct _SRB_HISTORY_ITEM {
    LARGE_INTEGER TickCountSent;             //  0x00..0x07
    LARGE_INTEGER TickCountCompleted;        //  0x08..0x0F
    ULONG         MillisecondsDelayOnRetry;  //  0x10..0x13
    SENSE_DATA    NormalizedSenseData;       //  0x14..0x25 (0x12 bytes)
    UCHAR         SrbStatus;                 //  0x26
    UCHAR         ClassDriverUse;            //  0x27 -- one byte free (alignment)
} SRB_HISTORY_ITEM, *PSRB_HISTORY_ITEM;

typedef struct _SRB_HISTORY {
    ULONG_PTR        ClassDriverUse[4]; // for the class driver to use as they please
    _Field_range_(1,30000)
    ULONG            TotalHistoryCount;
    _Field_range_(0,TotalHistoryCount)
    ULONG            UsedHistoryCount;
    _Field_size_part_(TotalHistoryCount, UsedHistoryCount)
    SRB_HISTORY_ITEM History[1];
} SRB_HISTORY, *PSRB_HISTORY;

extern CDROM_SCAN_FOR_SPECIAL_INFO CdRomBadItems[];

/*++////////////////////////////////////////////////////////////////////////////*/

// legacy registry key and values.
#define CLASSP_REG_SUBKEY_NAME                  (L"Classpnp")

#define CLASSP_REG_HACK_VALUE_NAME              (L"HackMask")
#define CLASSP_REG_MMC_DETECTION_VALUE_NAME     (L"MMCDetectionState")
#define CLASSP_REG_WRITE_CACHE_VALUE_NAME       (L"WriteCacheEnableOverride")
#define CLASSP_REG_PERF_RESTORE_VALUE_NAME      (L"RestorePerfAtCount")
#define CLASSP_REG_REMOVAL_POLICY_VALUE_NAME    (L"UserRemovalPolicy")
#define WINPE_REG_KEY_NAME                      (L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\MiniNT")

#define CLASS_PERF_RESTORE_MINIMUM              (0x10)
#define CLASS_ERROR_LEVEL_1                     (0x4)
#define CLASS_ERROR_LEVEL_2                     (0x8)

#define FDO_HACK_CANNOT_LOCK_MEDIA              (0x00000001)
#define FDO_HACK_GESN_IS_BAD                    (0x00000002)
#define FDO_HACK_NO_RESERVE6                    (0x00000008)
#define FDO_HACK_GESN_IGNORE_OPCHANGE           (0x00000010)
#define FDO_HACK_NO_STREAMING                   (0x00000020)
#define FDO_HACK_NO_ASYNCHRONOUS_NOTIFICATION   (0x00000040)

#define FDO_HACK_VALID_FLAGS                    (0x0000007F)
#define FDO_HACK_INVALID_FLAGS                  (~FDO_HACK_VALID_FLAGS)

/*
 *  Lots of retries of synchronized SCSI commands that devices may not
 *  even support really slows down the system (especially while booting).
 *  (Even GetDriveCapacity may be failed on purpose if an external disk is powered off).
 *  If a disk cannot return a small initialization buffer at startup
 *  in two attempts (with delay interval) then we cannot expect it to return
 *  data consistently with four retries.
 *  So don't set the retry counts as high here as for data SRBs.
 *
 *  If we find that these requests are failing consecutively,
 *  despite the retry interval, on otherwise reliable media,
 *  then we should either increase the retry interval for
 *  that failure or (by all means) increase these retry counts as appropriate.
 */
//#define NUM_LOCKMEDIAREMOVAL_RETRIES    1
//#define NUM_MODESENSE_RETRIES           1
//#define NUM_DRIVECAPACITY_RETRIES       1

/*
 *  We retry failed I/O requests at 1-second intervals.
 *  In the case of a failure due to bus reset, we want to make sure that we retry after the allowable
 *  reset time.  For SCSI, the allowable reset time is 5 seconds.  ScsiPort queues requests during
 *  a bus reset, which should cause us to retry after the reset is over; but the requests queued in
 *  the miniport are failed all the way back to us immediately.  In any event, in order to make
 *  extra sure that our retries span the allowable reset time, we should retry more than 5 times.
 */
//#define NUM_IO_RETRIES      8

#define CDROM_VOLUME_VERIFY_CHECKED        0x34

#define CDROM_TAG_PRIVATE_DATA             'CPcS'

typedef struct _MEDIA_CHANGE_DETECTION_INFO {

    // Use AN if supported so that we don't need to poll for media change notifications.
    BOOLEAN     AsynchronousNotificationSupported;

    // If AN is turned on and we received an AN signal when the device is exclusively locked,
    // we should take a note and send down a GESN when the lock is lifted, since otherwise
    // we will lose the signal. Even worse, some ODD models will signal the event again next
    // time a SYNC CACHE is sent down, and processing the event in that arbitrary timing may
    // cause unexpected behaviors.
    BOOLEAN     ANSignalPendingDueToExclusiveLock;

    // Mutex to synchronize enable/disable requests and media state changes
    KMUTEX      MediaChangeMutex;

    // For request erialization use.
    // This irp is used in timer callback routine, will be sent to the device itself.
    // so that the sequentail queue will get request wrapped on this irp. After doing
    // the real work, this irp will be completed to indicate it's ok to send the next
    // MCN request.
    PIRP        MediaChangeSyncIrp;

    // The last known state of the media (present, not present, unknown).
    // Protected by MediaChangeMutex.
    MEDIA_CHANGE_DETECTION_STATE LastKnownMediaDetectionState;

    // The last state of the media (present, not present, unknown) reported to apps
    // via notifications. Protected by MediaChangeMutex
    MEDIA_CHANGE_DETECTION_STATE LastReportedMediaDetectionState;

    // This is a count of how many time MCD has been disabled.  if it is
    // set to zero, then we'll poll the device for MCN events with the
    // then-current method (ie. TEST UNIT READY or GESN).  this is
    // protected by MediaChangeMutex
    LONG        MediaChangeDetectionDisableCount;

    // recent changes allowed instant retries of the MCN REQUEST.  Since this
    // could cause an infinite loop, keep a count of how many times we've
    // retried immediately so that we can catch if the count exceeds an
    // arbitrary limit.
    LONG        MediaChangeRetryCount;

    // use GESN if it's available
    struct {
        BOOLEAN Supported;
        BOOLEAN HackEventMask;
        UCHAR   EventMask;
        UCHAR   NoChangeEventMask;
        PUCHAR  Buffer;
        PMDL    Mdl;
        ULONG   BufferSize;
    } Gesn;

    // If this value is one, then the REQUEST is currently in use.
    // If this value is zero, then the REQUEST is available.
    // Use InterlockedCompareExchange() to set from "available" to "in use".
    // ASSERT that InterlockedCompareExchange() showed previous value of
    //    "in use" when changing back to "available" state.
    // This also implicitly protects the MediaChangeSrb and SenseBuffer
    //
    // This protect is needed in the polling case since the timer is fired asynchronous
    // to our sequential I/O queues, and when the timer is fired, our Sync Irp could be
    // still using the MediaChangeRequest. However, if AN is used, then each interrupt
    // will cause us to queue a request, so interrupts are serialized, and within the
    // handling of each request, we already sequentially use the MediaChangeRequest if
    // we need retries. We still use it in case of AN to be consistent with polling, but
    // if in the future we remove polling altogether, then we don't need this field anymore.
    LONG                MediaChangeRequestInUse;

    // Pointer to the REQUEST to be used for media change detection.
    // protected by Interlocked MediaChangeRequestInUse
    WDFREQUEST          MediaChangeRequest;

    // The srb for the media change detection.
    // protected by Interlocked MediaChangeIrpInUse
    SCSI_REQUEST_BLOCK  MediaChangeSrb;
    PUCHAR              SenseBuffer;
    ULONG               SrbFlags;

    // Handle to the display state notification registration.
    PVOID               DisplayStateCallbackHandle;

} MEDIA_CHANGE_DETECTION_INFO, *PMEDIA_CHANGE_DETECTION_INFO;

#define DELAY_TIME_TO_ENTER_ZERO_POWER_IN_MS        (60 * 1000)
#define DELAY_TIME_TO_ENTER_AOAC_IDLE_POWER_IN_MS   (10 * 1000)
#define BECOMING_READY_RETRY_COUNT                  (15)
#define BECOMING_READY_RETRY_INTERNVAL_IN_100NS     (2 * 1000 * 1000)

typedef struct _ZERO_POWER_ODD_INFO {

    UCHAR                       LoadingMechanism;               // From Removable Medium Feature Descriptor
    UCHAR                       Load;                           // From Removable Medium Feature Descriptor

    D3COLD_SUPPORT_INTERFACE    D3ColdInterface;                // D3Cold interface from ACPI

    BOOLEAN                     Reserved;                       // Reserved
    BOOLEAN                     InZeroPowerState;               // Is device currently in Zero Power State
    BOOLEAN                     RetryFirstCommand;              // First command after power resume should be retried
    BOOLEAN                     MonitorStartStopUnit;           // If 1. drawer 2. soft eject 3. no media 4. Immed=0,
                                                                // we will not receive any GESN events, and so we should
                                                                // monitor the command to get notified
    ULONG                       BecomingReadyRetryCount;        // How many times we should retry for becoming ready

    UCHAR                       SenseKey;                       // sense code from TUR to check media & tray status
    UCHAR                       AdditionalSenseCode;            // sense code from TUR to check media & tray status
    UCHAR                       AdditionalSenseCodeQualifier;   // sense code from TUR to check media & tray status

    PGET_CONFIGURATION_HEADER   GetConfigurationBuffer;         // Cached Get Configuration response from device
    ULONG                       GetConfigurationBufferSize;     // Size of the above buffer

} ZERO_POWER_ODD_INFO, *PZERO_POWER_ODD_INFO;

typedef enum {
    SimpleMediaLock,
    SecureMediaLock,
    InternalMediaLock
} MEDIA_LOCK_TYPE, *PMEDIA_LOCK_TYPE;


typedef enum _CDROM_DETECTION_STATE {
    CdromDetectionUnknown = 0,
    CdromDetectionUnsupported = 1,
    CdromDetectionSupported = 2
} CDROM_DETECTION_STATE, *PCDROM_DETECTION_STATE;


typedef struct _CDROM_ERROR_LOG_DATA {
    LARGE_INTEGER       TickCount;          // Offset 0x00
    ULONG               PortNumber;         // Offset 0x08

    UCHAR               ErrorPaging    : 1; // Offset 0x0c
    UCHAR               ErrorRetried   : 1;
    UCHAR               ErrorUnhandled : 1;
    UCHAR               ErrorReserved  : 5;

    UCHAR               Reserved[3];

    SCSI_REQUEST_BLOCK  Srb;                // Offset 0x10

    //  We define the SenseData as the default length.
    //  Since the sense data returned by the port driver may be longer,
    //  SenseData must be at the end of this structure.
    //  For our internal error log, we only log the default length.
    SENSE_DATA          SenseData;     // Offset 0x50 for x86 (or 0x68 for ia64) (ULONG32 Alignment required!)
} CDROM_ERROR_LOG_DATA, *PCDROM_ERROR_LOG_DATA;


#define NUM_ERROR_LOG_ENTRIES       16

//
// add to the front of this structure to help prevent illegal
// snooping by other utilities.
//
typedef struct _CDROM_PRIVATE_FDO_DATA {

    // this private structure allows us to
    // dynamically re-enable the perf benefits
    // lost due to transient error conditions.
    // in w2k, a reboot was required. :(
    struct {
        ULONG      OriginalSrbFlags;
        ULONG      SuccessfulIO;
        ULONG      ReEnableThreshhold; // 0 means never
    } Perf;

    ULONG_PTR            HackFlags;

    STORAGE_HOTPLUG_INFO HotplugInfo;

    BOOLEAN              TimerStarted;
    BOOLEAN              LoggedTURFailureSinceLastIO;
    BOOLEAN              LoggedSYNCFailure;

    // not use WDFSPINLOCK to avoid exposing private object creation 
    // in initialization code. (cdrom.sys was in WDK example)
    KSPIN_LOCK           SpinLock;

    // Circular array of timestamped logs of errors that occurred on this device.
    ULONG                ErrorLogNextIndex;
    CDROM_ERROR_LOG_DATA ErrorLogs[NUM_ERROR_LOG_ENTRIES];

}CDROM_PRIVATE_FDO_DATA, *PCDROM_PRIVATE_FDO_DATA;

//
// this is a private structure, but must be kept here
// to properly compile size of FUNCTIONAL_DEVICE_EXTENSION
//
typedef struct _FILE_OBJECT_CONTEXT {
    WDFFILEOBJECT   FileObject;
    WDFDEVICE       DeviceObject;
    ULONG           LockCount;
    ULONG           McnDisableCount;
    BOOLEAN         EnforceStreamingRead;
    BOOLEAN         EnforceStreamingWrite;
} FILE_OBJECT_CONTEXT, *PFILE_OBJECT_CONTEXT;

WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FILE_OBJECT_CONTEXT, FileObjectGetContext)


#define NOT_READY_RETRY_INTERVAL    10
#define MODE_PAGE_DATA_SIZE         192

//
// per session device
//
#define INVALID_SESSION         ((ULONG)-1)

#endif // __CDROMP_H__