xref: /reactos/drivers/storage/class/sfloppy/floppy.c (revision 1734f297)
1 /*++
2 
3 Copyright (C) Microsoft Corporation, 1991 - 1999
4 
5 Module Name:
6 
7     floppy.c
8 
9 Abstract:
10 
11     SCSI floppy class driver
12 
13 Author:
14 
15     Jeff Havens (jhavens)
16 
17 Environment:
18 
19     kernel mode only
20 
21 Notes:
22 
23 Revision History:
24 02/28/96    georgioc    Merged this code with code developed by compaq in
25                         parallel with microsoft, for 120MB floppy support.
26 
27 01/17/96    georgioc    Made code PNP aware (uses the new \storage\classpnp/scsiport)
28 
29 --*/
30 
31 #if !defined(__REACTOS__) || defined(_MSC_VER)
32 #pragma warning(disable:4214) // nonstandard extension used : bit field types other than int
33 #pragma warning(disable:4201) // nonstandard extension used : nameless struct/union
34 #endif
35 
36 #include <stddef.h>
37 #include <ntddk.h>
38 #ifndef __REACTOS__
39 #include <winerror.h>
40 #endif
41 #include <scsi.h>
42 #include <classpnp.h>
43 #include <initguid.h>
44 #include <ntddstor.h>
45 
46 #include <ntstrsafe.h>
47 #include <intsafe.h>
48 
49 #ifdef __REACTOS__
50 // Downgrade unsupported NT6.2+ features.
51 #define NonPagedPoolNx NonPagedPool
52 #define NonPagedPoolNxCacheAligned NonPagedPoolCacheAligned
53 #endif
54 
55 #define MODE_DATA_SIZE      192
56 #define SCSI_FLOPPY_TIMEOUT  20
57 #define SFLOPPY_SRB_LIST_SIZE 4
58 //
59 // Define all possible drive/media combinations, given drives listed above
60 // and media types in ntdddisk.h.
61 //
62 // These values are used to index the DriveMediaConstants table.
63 //
64 
65 #define NUMBER_OF_DRIVE_TYPES              7
66 #define DRIVE_TYPE_120M                    4    //120MB Floptical
67 #define DRIVE_TYPE_NONE                    NUMBER_OF_DRIVE_TYPES
68 
69 //
70 // This array describes all media types we support.
71 // It should be arranged in the increasing order of density
72 //
73 // For a given drive, we list all the mediatypes that will
74 // work with that drive. For instance, a 120MB drive will
75 // take 720KB media, 1.44MB media, and 120MB media.
76 //
77 // Note that, DriveMediaConstants given below is grouped
78 // as drive and media combination
79 //
80 typedef enum _DRIVE_MEDIA_TYPE {
81     Drive360Media160,                      // 5.25"  360k  drive;  160k   media
82     Drive360Media180,                      // 5.25"  360k  drive;  180k   media
83     Drive360Media320,                      // 5.25"  360k  drive;  320k   media
84     Drive360Media32X,                      // 5.25"  360k  drive;  320k 1k secs
85     Drive360Media360,                      // 5.25"  360k  drive;  360k   media
86     Drive720Media720,                      // 3.5"   720k  drive;  720k   media
87     Drive120Media160,                      // 5.25" 1.2Mb  drive;  160k   media
88     Drive120Media180,                      // 5.25" 1.2Mb  drive;  180k   media
89     Drive120Media320,                      // 5.25" 1.2Mb  drive;  320k   media
90     Drive120Media32X,                      // 5.25" 1.2Mb  drive;  320k 1k secs
91     Drive120Media360,                      // 5.25" 1.2Mb  drive;  360k   media
92     Drive120Media120,                      // 5.25" 1.2Mb  drive; 1.2Mb   media
93     Drive144Media720,                      // 3.5"  1.44Mb drive;  720k   media
94     Drive144Media144,                      // 3.5"  1.44Mb drive; 1.44Mb  media
95     Drive288Media720,                      // 3.5"  2.88Mb drive;  720k   media
96     Drive288Media144,                      // 3.5"  2.88Mb drive; 1.44Mb  media
97     Drive288Media288,                      // 3.5"  2.88Mb drive; 2.88Mb  media
98     Drive2080Media720,                     // 3.5"  20.8Mb drive;  720k   media
99     Drive2080Media144,                     // 3.5"  20.8Mb drive; 1.44Mb  media
100     Drive2080Media2080,                    // 3.5"  20.8Mb drive; 20.8Mb  media
101     Drive32MMedia32M,                      // 3.5"  32Mb drive; 32MB    media
102     Drive120MMedia720,                     // 3.5"  120Mb drive; 720k  media
103     Drive120MMedia144,                     // 3.5"  120Mb drive; 1.44Mb  media
104     Drive120MMedia120M,                    // 3.5"  120Mb drive; 120Mb  media
105     Drive240MMedia144M,                    // 3.5"  240Mb drive; 1.44Mb  media
106     Drive240MMedia120M,                    // 3.5"  240Mb drive; 120Mb  media
107     Drive240MMedia240M                     // 3.5"  240Mb drive; 240Mb  media
108 } DRIVE_MEDIA_TYPE;
109 
110 //
111 // When we want to determine the media type in a drive, we will first
112 // guess that the media with highest possible density is in the drive,
113 // and keep trying lower densities until we can successfully read from
114 // the drive.
115 //
116 // These values are used to select a DRIVE_MEDIA_TYPE value.
117 //
118 // The following table defines ranges that apply to the DRIVE_MEDIA_TYPE
119 // enumerated values when trying media types for a particular drive type.
120 // Note that for this to work, the DRIVE_MEDIA_TYPE values must be sorted
121 // by ascending densities within drive types.  Also, for maximum track
122 // size to be determined properly, the drive types must be in ascending
123 // order.
124 //
125 
126 typedef struct _DRIVE_MEDIA_LIMITS {
127     DRIVE_MEDIA_TYPE HighestDriveMediaType;
128     DRIVE_MEDIA_TYPE LowestDriveMediaType;
129 } DRIVE_MEDIA_LIMITS, *PDRIVE_MEDIA_LIMITS;
130 
131 #if 0
132 DRIVE_MEDIA_LIMITS DriveMediaLimits[NUMBER_OF_DRIVE_TYPES] = {
133 
134     { Drive360Media360, Drive360Media160 }, // DRIVE_TYPE_0360
135     { Drive120Media120, Drive120Media160 }, // DRIVE_TYPE_1200
136     { Drive720Media720, Drive720Media720 }, // DRIVE_TYPE_0720
137     { Drive144Media144, Drive144Media720 }, // DRIVE_TYPE_1440
138     { Drive288Media288, Drive288Media720 }, // DRIVE_TYPE_2880
139     { Drive2080Media2080, Drive2080Media720 }
140 };
141 #else
142 DRIVE_MEDIA_LIMITS DriveMediaLimits[NUMBER_OF_DRIVE_TYPES] = {
143 
144     { Drive720Media720, Drive720Media720 }, // DRIVE_TYPE_0720
145     { Drive144Media144,  Drive144Media720}, // DRIVE_TYPE_1440
146     { Drive288Media288,  Drive288Media720}, // DRIVE_TYPE_2880
147     { Drive2080Media2080, Drive2080Media720 },
148     { Drive32MMedia32M, Drive32MMedia32M }, // DRIVE_TYPE_32M
149     { Drive120MMedia120M, Drive120MMedia720 }, // DRIVE_TYPE_120M
150     { Drive240MMedia240M, Drive240MMedia144M } // DRIVE_TYPE_240M
151 };
152 
153 #endif
154 //
155 // For each drive/media combination, define important constants.
156 //
157 
158 typedef struct _DRIVE_MEDIA_CONSTANTS {
159     MEDIA_TYPE MediaType;
160     USHORT     BytesPerSector;
161     UCHAR      SectorsPerTrack;
162     USHORT     MaximumTrack;
163     UCHAR      NumberOfHeads;
164 } DRIVE_MEDIA_CONSTANTS, *PDRIVE_MEDIA_CONSTANTS;
165 
166 //
167 // Magic value to add to the SectorLengthCode to use it as a shift value
168 // to determine the sector size.
169 //
170 
171 #define SECTORLENGTHCODE_TO_BYTESHIFT      7
172 
173 //
174 // The following values were gleaned from many different sources, which
175 // often disagreed with each other.  Where numbers were in conflict, I
176 // chose the more conservative or most-often-selected value.
177 //
178 
179 DRIVE_MEDIA_CONSTANTS DriveMediaConstants[] =
180     {
181 
182     { F5_160_512,   0x200, 0x08, 0x27, 0x1 },
183     { F5_180_512,   0x200, 0x09, 0x27, 0x1 },
184     { F5_320_1024,  0x400, 0x04, 0x27, 0x2 },
185     { F5_320_512,   0x200, 0x08, 0x27, 0x2 },
186     { F5_360_512,   0x200, 0x09, 0x27, 0x2 },
187 
188     { F3_720_512,   0x200, 0x09, 0x4f, 0x2 },
189 
190     { F5_160_512,   0x200, 0x08, 0x27, 0x1 },
191     { F5_180_512,   0x200, 0x09, 0x27, 0x1 },
192     { F5_320_1024,  0x400, 0x04, 0x27, 0x2 },
193     { F5_320_512,   0x200, 0x08, 0x27, 0x2 },
194     { F5_360_512,   0x200, 0x09, 0x27, 0x2 },
195     { F5_1Pt2_512,  0x200, 0x0f, 0x4f, 0x2 },
196 
197     { F3_720_512,   0x200, 0x09, 0x4f, 0x2 },
198     { F3_1Pt44_512, 0x200, 0x12, 0x4f, 0x2 },
199 
200     { F3_720_512,   0x200, 0x09, 0x4f, 0x2 },
201     { F3_1Pt44_512, 0x200, 0x12, 0x4f, 0x2 },
202     { F3_2Pt88_512, 0x200, 0x24, 0x4f, 0x2 },
203 
204     { F3_720_512,   0x200, 0x09, 0x4f, 0x2 },
205     { F3_1Pt44_512, 0x200, 0x12, 0x4f, 0x2 },
206     { F3_20Pt8_512, 0x200, 0x1b, 0xfa, 0x6 },
207 
208     { F3_32M_512,   0x200, 0x20, 0x3ff,0x2},
209 
210     { F3_720_512,   0x200, 0x09, 0x4f, 0x2 },
211     { F3_1Pt44_512, 0x200, 0x12, 0x4f, 0x2 },
212     { F3_120M_512,  0x200, 0x20, 0x3c2,0x8 },
213 
214     { F3_1Pt44_512, 0x200, 0x12, 0x4f, 0x2 },
215     { F3_120M_512,  0x200, 0x20, 0x3c2,0x8 },
216     { F3_240M_512,  0x200, 0x38, 0x105,0x20}
217 };
218 
219 
220 #define NUMBER_OF_DRIVE_MEDIA_COMBINATIONS sizeof(DriveMediaConstants)/sizeof(DRIVE_MEDIA_CONSTANTS)
221 
222 //
223 // floppy device data
224 //
225 
226 typedef struct _DISK_DATA {
227     ULONG DriveType;
228     BOOLEAN IsDMF;
229     // BOOLEAN EnableDMF;
230     UNICODE_STRING FloppyInterfaceString;
231 } DISK_DATA, *PDISK_DATA;
232 
233 //
234 // The FloppyCapacities and FloppyGeometries arrays are used by the
235 // USBFlopGetMediaTypes() and USBFlopFormatTracks() routines.
236 
237 // The FloppyCapacities and FloppyGeometries arrays must be kept in 1:1 sync,
238 // i.e. each FloppyGeometries[i] must correspond to each FloppyCapacities[i].
239 
240 // Also, the arrays must be kept in sorted ascending order so that they
241 // are returned in sorted ascending order by IOCTL_DISK_GET_MEDIA_TYPES.
242 //
243 
244 typedef struct _FORMATTED_CAPACITY
245 {
246     ULONG       NumberOfBlocks;
247 
248     ULONG       BlockLength;
249 
250     BOOLEAN     CanFormat;      // return for IOCTL_DISK_GET_MEDIA_TYPES ?
251 
252 } FORMATTED_CAPACITY, *PFORMATTED_CAPACITY;
253 
254 
255 FORMATTED_CAPACITY FloppyCapacities[] =
256 {
257     // Blocks  BlockLen CanFormat H   T  B/S S/T
258     {0x000500, 0x0200,  TRUE}, // 2  80  512   8   640 KB  F5_640_512
259     {0x0005A0, 0x0200,  TRUE}, // 2  80  512   9   720 KB  F3_720_512
260     {0x000960, 0x0200,  TRUE}, // 2  80  512  15  1.20 MB  F3_1Pt2_512   (Toshiba)
261     {0x0004D0, 0x0400,  TRUE}, // 2  77 1024   8  1.23 MB  F3_1Pt23_1024 (NEC)
262     {0x000B40, 0x0200,  TRUE}, // 2  80  512  18  1.44 MB  F3_1Pt44_512
263     {0x000D20, 0x0200, FALSE}, // 2  80  512  21  1.70 MB  DMF
264     {0x010000, 0x0200,  TRUE},  // 2  1024 512  32   32 MB    F3_32M_512
265     {0x03C300, 0x0200,  TRUE}, // 8 963  512  32   120 MB  F3_120M_512
266     {0x0600A4, 0x0200,  TRUE}, // 13 890  512  34   200 MB  F3_200Mb_512 (HiFD)
267     {0x072A00, 0x0200,  TRUE}  // 32 262  512  56   240 MB  F3_240M_512
268 };
269 
270 DISK_GEOMETRY FloppyGeometries[] =
271 {
272     // Cyl      MediaType       Trk/Cyl Sec/Trk Bytes/Sec
273 #ifndef __REACTOS__
274     {{80,0},    F3_640_512,     2,      8,      512},
275     {{80,0},    F3_720_512,     2,      9,      512},
276     {{80,0},    F3_1Pt2_512,    2,      15,     512},
277     {{77,0},    F3_1Pt23_1024,  2,      8,      1024},
278     {{80,0},    F3_1Pt44_512,   2,      18,     512},
279     {{80,0},    F3_1Pt44_512,   2,      21,     512},   // DMF -> F3_1Pt44_512
280     {{1024,0},  F3_32M_512,     2,      32,     512},
281     {{963,0},   F3_120M_512,    8,      32,     512},
282     {{890,0},   F3_200Mb_512,   13,     34,     512},
283     {{262,0},   F3_240M_512,    32,     56,     512}
284 #else
285     {{{80,0}},    F3_640_512,     2,      8,      512},
286     {{{80,0}},    F3_720_512,     2,      9,      512},
287     {{{80,0}},    F3_1Pt2_512,    2,      15,     512},
288     {{{77,0}},    F3_1Pt23_1024,  2,      8,      1024},
289     {{{80,0}},    F3_1Pt44_512,   2,      18,     512},
290     {{{80,0}},    F3_1Pt44_512,   2,      21,     512},   // DMF -> F3_1Pt44_512
291     {{{1024,0}},  F3_32M_512,     2,      32,     512},
292     {{{963,0}},   F3_120M_512,    8,      32,     512},
293     {{{890,0}},   F3_200Mb_512,   13,     34,     512},
294     {{{262,0}},   F3_240M_512,    32,     56,     512}
295 #endif
296 };
297 
298 #define FLOPPY_CAPACITIES (sizeof(FloppyCapacities)/sizeof(FloppyCapacities[0]))
299 
300 C_ASSERT((sizeof(FloppyGeometries)/sizeof(FloppyGeometries[0])) == FLOPPY_CAPACITIES);
301 
302 //
303 // The following structures are used by USBFlopFormatTracks()
304 //
305 
306 #pragma pack (push, 1)
307 
308 typedef struct _CDB12FORMAT
309 {
310     UCHAR   OperationCode;
311     UCHAR   DefectListFormat : 3;
312     UCHAR   CmpList : 1;
313     UCHAR   FmtData : 1;
314     UCHAR   LogicalUnitNumber : 3;
315     UCHAR   TrackNumber;
316     UCHAR   InterleaveMsb;
317     UCHAR   InterleaveLsb;
318     UCHAR   Reserved1[2];
319     UCHAR   ParameterListLengthMsb;
320     UCHAR   ParameterListLengthLsb;
321     UCHAR   Reserved2[3];
322 } CDB12FORMAT, *PCDB12FORMAT;
323 
324 
325 typedef struct _DEFECT_LIST_HEADER
326 {
327     UCHAR   Reserved1;
328     UCHAR   Side : 1;
329     UCHAR   Immediate : 1;
330     UCHAR   Reserved2 : 2;
331     UCHAR   SingleTrack : 1;
332     UCHAR   DisableCert : 1;
333     UCHAR   Reserved3 : 1;
334     UCHAR   FormatOptionsValid : 1;
335     UCHAR   DefectListLengthMsb;
336     UCHAR   DefectListLengthLsb;
337 } DEFECT_LIST_HEADER, *PDEFECT_LIST_HEADER;
338 
339 typedef struct _FORMAT_UNIT_PARAMETER_LIST
340 {
341     DEFECT_LIST_HEADER DefectListHeader;
342     FORMATTED_CAPACITY_DESCRIPTOR FormatDescriptor;
343 } FORMAT_UNIT_PARAMETER_LIST, *PFORMAT_UNIT_PARAMETER_LIST;
344 
345 #pragma pack (pop)
346 
347 DRIVER_INITIALIZE DriverEntry;
348 
349 DRIVER_UNLOAD     ScsiFlopUnload;
350 
351 DRIVER_ADD_DEVICE ScsiFlopAddDevice;
352 
353 NTSTATUS
354 #ifdef __REACTOS__
355 NTAPI
356 #endif
357 ScsiFlopInitDevice(
358     IN PDEVICE_OBJECT Fdo
359     );
360 
361 NTSTATUS
362 #ifdef __REACTOS__
363 NTAPI
364 #endif
365 ScsiFlopStartDevice(
366     IN PDEVICE_OBJECT Fdo
367     );
368 
369 NTSTATUS
370 #ifdef __REACTOS__
371 NTAPI
372 #endif
373 ScsiFlopRemoveDevice(
374     IN PDEVICE_OBJECT Fdo,
375     IN UCHAR Type
376     );
377 
378 NTSTATUS
379 #ifdef __REACTOS__
380 NTAPI
381 #endif
382 ScsiFlopStopDevice(
383     IN PDEVICE_OBJECT Fdo,
384     IN UCHAR Type
385     );
386 
387 BOOLEAN
388 FindScsiFlops(
389     IN PDRIVER_OBJECT DriverObject,
390     IN PUNICODE_STRING RegistryPath,
391     IN PCLASS_INIT_DATA InitializationData,
392     IN PDEVICE_OBJECT PortDeviceObject,
393     IN ULONG PortNumber
394     );
395 
396 NTSTATUS
397 #ifdef __REACTOS__
398 NTAPI
399 #endif
400 ScsiFlopReadWriteVerification(
401     IN PDEVICE_OBJECT DeviceObject,
402     IN PIRP Irp
403     );
404 
405 NTSTATUS
406 #ifdef __REACTOS__
407 NTAPI
408 #endif
409 ScsiFlopDeviceControl(
410     IN PDEVICE_OBJECT DeviceObject,
411     IN PIRP Irp
412     );
413 
414 BOOLEAN
415 IsFloppyDevice(
416     PDEVICE_OBJECT DeviceObject
417     );
418 
419 NTSTATUS
420 CreateFlopDeviceObject(
421     IN PDRIVER_OBJECT DriverObject,
422     IN PDEVICE_OBJECT PortDeviceObject,
423     IN ULONG DeviceCount
424     );
425 
426 NTSTATUS
427 DetermineMediaType(
428     PDEVICE_OBJECT DeviceObject
429     );
430 
431 ULONG
432 DetermineDriveType(
433     PDEVICE_OBJECT DeviceObject
434     );
435 
436 BOOLEAN
437 FlCheckFormatParameters(
438     IN PDEVICE_OBJECT DeviceObject,
439     IN PFORMAT_PARAMETERS FormatParameters
440     );
441 
442 NTSTATUS
443 FormatMedia(
444     PDEVICE_OBJECT DeviceObject,
445     MEDIA_TYPE MediaType
446     );
447 
448 NTSTATUS
449 FlopticalFormatMedia(
450     PDEVICE_OBJECT DeviceObject,
451     PFORMAT_PARAMETERS Format
452     );
453 
454 VOID
455 #ifdef __REACTOS__
456 NTAPI
457 #endif
458 ScsiFlopProcessError(
459     PDEVICE_OBJECT DeviceObject,
460     PSCSI_REQUEST_BLOCK Srb,
461     NTSTATUS *Status,
462     BOOLEAN *Retry
463     );
464 
465 NTSTATUS
466 USBFlopGetMediaTypes(
467     IN PDEVICE_OBJECT DeviceObject,
468     IN PIRP           Irp
469     );
470 
471 NTSTATUS
472 USBFlopFormatTracks(
473     IN PDEVICE_OBJECT DeviceObject,
474     IN PIRP           Irp
475     );
476 
477 #ifdef ALLOC_PRAGMA
478 #pragma alloc_text(INIT, DriverEntry)
479 
480 #pragma alloc_text(PAGE, ScsiFlopUnload)
481 #pragma alloc_text(PAGE, ScsiFlopAddDevice)
482 #pragma alloc_text(PAGE, CreateFlopDeviceObject)
483 #pragma alloc_text(PAGE, ScsiFlopStartDevice)
484 #pragma alloc_text(PAGE, ScsiFlopRemoveDevice)
485 #pragma alloc_text(PAGE, IsFloppyDevice)
486 #pragma alloc_text(PAGE, DetermineMediaType)
487 #pragma alloc_text(PAGE, DetermineDriveType)
488 #pragma alloc_text(PAGE, FlCheckFormatParameters)
489 #pragma alloc_text(PAGE, FormatMedia)
490 #pragma alloc_text(PAGE, FlopticalFormatMedia)
491 #pragma alloc_text(PAGE, USBFlopGetMediaTypes)
492 #pragma alloc_text(PAGE, USBFlopFormatTracks)
493 
494 #endif
495 
496 
497 NTSTATUS
498 #ifdef __REACTOS__
499 NTAPI
500 #endif
501 DriverEntry(
502     IN PDRIVER_OBJECT DriverObject,
503     IN PUNICODE_STRING RegistryPath
504     )
505 /*++
506 
507 Routine Description:
508 
509     This is the system initialization routine for installable drivers.
510     It calls the SCSI class driver initialization routine.
511 
512 Arguments:
513 
514     DriverObject - Pointer to driver object created by system.
515 
516 Return Value:
517 
518     NTSTATUS
519 
520 --*/
521 
522 {
523     CLASS_INIT_DATA InitializationData;
524 
525     //
526     // Zero InitData
527     //
528 
529     RtlZeroMemory (&InitializationData, sizeof(CLASS_INIT_DATA));
530 
531     //
532     // Set sizes
533     //
534 
535     InitializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
536     InitializationData.FdoData.DeviceExtensionSize =
537         sizeof(FUNCTIONAL_DEVICE_EXTENSION) + sizeof(DISK_DATA);
538 
539     InitializationData.FdoData.DeviceType = FILE_DEVICE_DISK;
540     InitializationData.FdoData.DeviceCharacteristics = FILE_REMOVABLE_MEDIA | FILE_FLOPPY_DISKETTE;
541 
542     //
543     // Set entry points
544     //
545 
546     InitializationData.FdoData.ClassInitDevice = ScsiFlopInitDevice;
547     InitializationData.FdoData.ClassStartDevice = ScsiFlopStartDevice;
548     InitializationData.FdoData.ClassStopDevice = ScsiFlopStopDevice;
549     InitializationData.FdoData.ClassRemoveDevice = ScsiFlopRemoveDevice;
550 
551     InitializationData.FdoData.ClassReadWriteVerification = ScsiFlopReadWriteVerification;
552     InitializationData.FdoData.ClassDeviceControl = ScsiFlopDeviceControl;
553 
554     InitializationData.FdoData.ClassShutdownFlush = NULL;
555     InitializationData.FdoData.ClassCreateClose = NULL;
556     InitializationData.FdoData.ClassError = ScsiFlopProcessError;
557     InitializationData.ClassStartIo = NULL;
558 
559     InitializationData.ClassAddDevice = ScsiFlopAddDevice;
560     InitializationData.ClassUnload = ScsiFlopUnload;
561     //
562     // Call the class init routine
563     //
564 
565     return ClassInitialize( DriverObject, RegistryPath, &InitializationData);
566 
567 
568 } // end DriverEntry()
569 
570 VOID
571 #ifdef __REACTOS__
572 NTAPI
573 #endif
574 ScsiFlopUnload(
575     IN PDRIVER_OBJECT DriverObject
576     )
577 {
578     PAGED_CODE();
579     UNREFERENCED_PARAMETER(DriverObject);
580     return;
581 }
582 
583 //
584 // AddDevice operation is performed in CreateFlopDeviceObject function which
585 // is called by ScsiFlopAddDevice (The AddDevice routine for sfloppy.sys).
586 // DO_DEVICE_INITIALIZING flag is cleard upon successfully processing AddDevice
587 // operation in CreateFlopDeviceObject. But PREFAST is currently unable to
588 // detect that DO_DEVICE_INITIALIZING is indeed cleard in CreateFlopDeviceObject
589 // and it raises Warning 28152 (The return from an AddDevice-like function
590 // unexpectedly did not clear DO_DEVICE_INITIALIZING). Suppress that warning
591 // using #pragma.
592 //
593 
594 #if !defined(__REACTOS__) || defined(_MSC_VER)
595 #pragma warning(push)
596 #pragma warning(disable:28152)
597 #endif
598 
599 NTSTATUS
600 #ifdef __REACTOS__
601 NTAPI
602 #endif
603 ScsiFlopAddDevice (
604     IN PDRIVER_OBJECT DriverObject,
605     IN PDEVICE_OBJECT Pdo
606     )
607 /*++
608 
609 Routine Description:
610 
611     This routine creates and initializes a new FDO for the corresponding
612     PDO.  It may perform property queries on the FDO but cannot do any
613     media access operations.
614 
615 Arguments:
616 
617     DriverObject - Scsiscan class driver object.
618 
619     Pdo - the physical device object we are being added to
620 
621 Return Value:
622 
623     status
624 
625 --*/
626 {
627     NTSTATUS status;
628     ULONG floppyCount = IoGetConfigurationInformation()->FloppyCount;
629 
630     PAGED_CODE();
631 
632     //
633     // Get the number of disks already initialized.
634     //
635 
636     status = CreateFlopDeviceObject(DriverObject, Pdo, floppyCount);
637 
638     if (NT_SUCCESS(status)) {
639 
640         //
641         // Increment system floppy device count.
642         //
643 
644         IoGetConfigurationInformation()->FloppyCount++;
645     }
646 
647     return status;
648 }
649 
650 NTSTATUS
651 CreateFlopDeviceObject(
652     IN PDRIVER_OBJECT DriverObject,
653     IN PDEVICE_OBJECT Pdo,
654     IN ULONG DeviceCount
655     )
656 
657 /*++
658 
659 Routine Description:
660 
661     This routine creates an object for the device and then calls the
662     SCSI port driver for media capacity and sector size.
663 
664 Arguments:
665 
666     DriverObject - Pointer to driver object created by system.
667     PortDeviceObject - to connect to SCSI port driver.
668     DeviceCount - Number of previously installed Floppys.
669     AdapterDescriptor - Pointer to structure returned by SCSI port
670                         driver describing adapter capabilites (and limitations).
671     DeviceDescriptor - Pointer to configuration information for this device.
672 
673 Return Value:
674 
675 --*/
676 {
677     NTSTATUS        status;
678     PDEVICE_OBJECT  deviceObject = NULL;
679     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = NULL;
680     PDISK_DATA  diskData;
681 
682     PAGED_CODE();
683 
684     DebugPrint((3,"CreateFlopDeviceObject: Enter routine\n"));
685 
686     //
687     // Try to claim the device.
688     //
689 
690     status = ClassClaimDevice(Pdo,FALSE);
691 
692     if (!NT_SUCCESS(status)) {
693         return(status);
694     }
695 
696     DeviceCount--;
697 
698     do {
699         UCHAR name[256];
700 
701         //
702         // Create device object for this device.
703         //
704 
705         DeviceCount++;
706 
707         status = RtlStringCbPrintfA((PCCHAR) name,
708                                     sizeof(name),
709                                     "\\Device\\Floppy%u",
710                                     DeviceCount);
711         if (NT_SUCCESS(status)) {
712 
713             status = ClassCreateDeviceObject(DriverObject,
714                                              (PCCHAR) name,
715                                              Pdo,
716                                              TRUE,
717                                              &deviceObject);
718         }
719     } while ((status == STATUS_OBJECT_NAME_COLLISION) ||
720              (status == STATUS_OBJECT_NAME_EXISTS));
721 
722     if (!NT_SUCCESS(status)) {
723         DebugPrint((1,"CreateFlopDeviceObjects: Can not create device\n"));
724         goto CreateFlopDeviceObjectExit;
725     }
726 
727     //
728     // Indicate that IRPs should include MDLs.
729     //
730 
731     deviceObject->Flags |= DO_DIRECT_IO;
732 
733     fdoExtension = deviceObject->DeviceExtension;
734 
735     //
736     // Back pointer to device object.
737     //
738 
739     fdoExtension->CommonExtension.DeviceObject = deviceObject;
740 
741     //
742     // This is the physical device.
743     //
744 
745     fdoExtension->CommonExtension.PartitionZeroExtension = fdoExtension;
746 
747     //
748     // Reset the drive type.
749     //
750 
751     diskData = (PDISK_DATA) fdoExtension->CommonExtension.DriverData;
752     diskData->DriveType = DRIVE_TYPE_NONE;
753     diskData->IsDMF = FALSE;
754     // diskData->EnableDMF = TRUE;
755 
756     //
757     // Initialize lock count to zero. The lock count is used to
758     // disable the ejection mechanism when media is mounted.
759     //
760 
761     fdoExtension->LockCount = 0;
762 
763     //
764     // Save system floppy number
765     //
766 
767     fdoExtension->DeviceNumber = DeviceCount;
768 
769     //
770     // Set the alignment requirements for the device based on the
771     // host adapter requirements
772     //
773 
774     if (Pdo->AlignmentRequirement > deviceObject->AlignmentRequirement) {
775         deviceObject->AlignmentRequirement = Pdo->AlignmentRequirement;
776     }
777 
778     //
779     // Clear the SrbFlags and disable synchronous transfers
780     //
781 
782     fdoExtension->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
783 
784     //
785     // Finally, attach to the PDO
786     //
787 
788     fdoExtension->LowerPdo = Pdo;
789 
790     fdoExtension->CommonExtension.LowerDeviceObject =
791         IoAttachDeviceToDeviceStack(deviceObject, Pdo);
792 
793     if(fdoExtension->CommonExtension.LowerDeviceObject == NULL) {
794 
795         status = STATUS_UNSUCCESSFUL;
796         goto CreateFlopDeviceObjectExit;
797     }
798 
799     deviceObject->StackSize++;
800 
801     //
802     // The device is initialized properly - mark it as such.
803     //
804 
805     deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
806 
807     return STATUS_SUCCESS;
808 
809 CreateFlopDeviceObjectExit:
810 
811     if (deviceObject != NULL) {
812         IoDeleteDevice(deviceObject);
813     }
814 
815     return status;
816 
817 } // end CreateFlopDeviceObject()
818 #if !defined(__REACTOS__) || defined(_MSC_VER)
819 #pragma warning(pop)
820 #endif
821 
822 NTSTATUS
823 #ifdef __REACTOS__
824 NTAPI
825 #endif
826 ScsiFlopInitDevice(
827     IN PDEVICE_OBJECT Fdo
828     )
829 {
830     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
831     PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
832     PDISK_DATA diskData = commonExtension->DriverData;
833 
834     PVOID senseData = NULL;
835     ULONG timeOut;
836 
837     NTSTATUS status = STATUS_SUCCESS;
838 
839     //
840     // Allocate request sense buffer.
841     //
842 
843     senseData = ExAllocatePool(NonPagedPoolNxCacheAligned, SENSE_BUFFER_SIZE);
844 
845     if (senseData == NULL) {
846 
847         //
848         // The buffer cannot be allocated.
849         //
850 
851         status = STATUS_INSUFFICIENT_RESOURCES;
852         return status;
853     }
854 
855     //
856     // Set the sense data pointer in the device extension.
857     //
858 
859     fdoExtension->SenseData = senseData;
860 
861     //
862     // Build the lookaside list for srb's for this device.
863     //
864 
865     ClassInitializeSrbLookasideList((PCOMMON_DEVICE_EXTENSION)fdoExtension,
866                                     SFLOPPY_SRB_LIST_SIZE);
867 
868     //
869     // Register for media change notification
870     //
871     ClassInitializeMediaChangeDetection(fdoExtension,
872                                         (PUCHAR) "SFloppy");
873 
874     //
875     // Set timeout value in seconds.
876     //
877 
878     timeOut = ClassQueryTimeOutRegistryValue(Fdo);
879     if (timeOut) {
880         fdoExtension->TimeOutValue = timeOut;
881     } else {
882         fdoExtension->TimeOutValue = SCSI_FLOPPY_TIMEOUT;
883     }
884 
885     //
886     // Floppies are not partitionable so starting offset is 0.
887     //
888 
889     fdoExtension->CommonExtension.StartingOffset.QuadPart = (LONGLONG)0;
890 
891 #if 0
892     if (!IsFloppyDevice(Fdo) ||
893         !(Fdo->Characteristics & FILE_REMOVABLE_MEDIA) ||
894         (fdoExtension->DeviceDescriptor->DeviceType != DIRECT_ACCESS_DEVICE)) {
895 
896         ExFreePool(senseData);
897         status = STATUS_NO_SUCH_DEVICE;
898         return status;
899     }
900 #endif
901 
902     RtlZeroMemory(&(fdoExtension->DiskGeometry),
903                   sizeof(DISK_GEOMETRY));
904 
905     //
906     // Determine the media type if possible. Set the current media type to
907     // Unknown so that determine media type will check the media.
908     //
909 
910     fdoExtension->DiskGeometry.MediaType = Unknown;
911 
912     //
913     // Register interfaces for this device.
914     //
915 
916     {
917         UNICODE_STRING interfaceName;
918 
919         RtlInitUnicodeString(&interfaceName, NULL);
920 
921         status = IoRegisterDeviceInterface(fdoExtension->LowerPdo,
922                                            (LPGUID) &GUID_DEVINTERFACE_FLOPPY,
923                                            NULL,
924                                            &interfaceName);
925 
926         if(NT_SUCCESS(status)) {
927             diskData->FloppyInterfaceString = interfaceName;
928         } else {
929             RtlInitUnicodeString(&(diskData->FloppyInterfaceString), NULL);
930             DebugPrint((1, "ScsiFlopStartDevice: Unable to register device "
931                            "interface for fdo %p [%08lx]\n",
932                         Fdo, status));
933         }
934     }
935 
936     return (STATUS_SUCCESS);
937 }
938 
939 #if !defined(__REACTOS__) || defined(_MSC_VER)
940 #pragma warning(suppress:6262) // This function uses 1096 bytes of stack which exceed default value of 1024 bytes used by Code Analysis for flagging as warning
941 #endif
942 #ifdef __REACTOS__
943 NTSTATUS NTAPI ScsiFlopStartDevice(
944 #else
945 NTSTATUS ScsiFlopStartDevice(
946 #endif
947     IN PDEVICE_OBJECT Fdo
948     )
949 {
950     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
951     PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
952 
953     PIRP        irp;
954     IO_STATUS_BLOCK ioStatus;
955 
956     SCSI_ADDRESS    scsiAddress;
957 
958     WCHAR   ntNameBuffer[256];
959     UNICODE_STRING  ntUnicodeString;
960 
961     WCHAR   arcNameBuffer[256];
962     UNICODE_STRING  arcUnicodeString;
963 
964     KEVENT event;
965 
966     NTSTATUS status = STATUS_SUCCESS;
967 
968     PAGED_CODE();
969 
970     KeInitializeEvent(&event,SynchronizationEvent,FALSE);
971 
972     DetermineMediaType(Fdo); // ignore unsuccessful here
973 
974     //
975     // Create device object for this device.
976     //
977 
978     RtlStringCbPrintfW(ntNameBuffer,
979                        sizeof(ntNameBuffer),
980                        L"\\Device\\Floppy%u",
981                        fdoExtension->DeviceNumber);
982 
983     //
984     // Create local copy of unicode string
985     //
986     RtlInitUnicodeString(&ntUnicodeString,ntNameBuffer);
987 
988     //
989     // Create a symbolic link from the disk name to the corresponding
990     // ARC name, to be used if we're booting off the disk.  This will
991     // fail if it's not system initialization time; that's fine.  The
992     // ARC name looks something like \ArcName\scsi(0)Flop(0)fdisk(0).
993     // In order to get the address, we need to send a IOCTL_SCSI_GET_ADDRESS...
994     //
995 
996     irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_ADDRESS,
997                                         Fdo,
998                                         NULL,
999                                         0,
1000                                         &scsiAddress,
1001                                         sizeof(scsiAddress),
1002                                         FALSE,
1003                                         &event,
1004                                         &ioStatus);
1005 
1006     if (irp == NULL) {
1007         return STATUS_INSUFFICIENT_RESOURCES;
1008     }
1009 
1010     status = IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);
1011 
1012     if (status == STATUS_PENDING) {
1013         KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
1014         status = ioStatus.Status;
1015     }
1016 
1017     //
1018     // IOCTL_SCSI_GET_ADDRESS might not be supported by the port driver and
1019     // hence may fail. But it is not a fatal error. Do not fail PnP start
1020     // if this IOCTL fails.
1021     //
1022     if (NT_SUCCESS(status)) {
1023 
1024         RtlStringCbPrintfW(arcNameBuffer,
1025                            sizeof(arcNameBuffer),
1026                            L"\\ArcName\\scsi(%u)disk(%u)fdisk(%u)",
1027                            scsiAddress.PortNumber,
1028                            scsiAddress.TargetId,
1029                            scsiAddress.Lun);
1030 
1031         RtlInitUnicodeString(&arcUnicodeString, arcNameBuffer);
1032 
1033         IoAssignArcName(&arcUnicodeString, &ntUnicodeString);
1034     }
1035 
1036     status = STATUS_SUCCESS;
1037 
1038     //
1039     // Create the multi() arc name -- Create the "fake"
1040     // name of multi(0)disk(0)fdisk(#) to handle the case where the
1041     // SCSI floppy is the only floppy in the system.  If this fails
1042     // it doesn't matter because the previous scsi() based ArcName
1043     // will work.  This name is necessary for installation.
1044     //
1045 
1046     RtlStringCbPrintfW(arcNameBuffer,
1047                        sizeof(arcNameBuffer),
1048                        L"\\ArcName\\multi(%u)disk(%u)fdisk(%u)",
1049                        0,
1050                        0,
1051                        fdoExtension->DeviceNumber);
1052 
1053     RtlInitUnicodeString(&arcUnicodeString, arcNameBuffer);
1054 
1055     IoAssignArcName(&arcUnicodeString, &ntUnicodeString);
1056 
1057     //
1058     // Set our interface state.
1059     //
1060 
1061     {
1062         PDISK_DATA diskData = commonExtension->DriverData;
1063 
1064         if(diskData->FloppyInterfaceString.Buffer != NULL) {
1065 
1066             status = IoSetDeviceInterfaceState(
1067                         &(diskData->FloppyInterfaceString),
1068                         TRUE);
1069 
1070             if(!NT_SUCCESS(status)) {
1071                 DebugPrint((1, "ScsiFlopStartDevice: Unable to set device "
1072                                "interface state to TRUE for fdo %p "
1073                                "[%08lx]\n",
1074                             Fdo, status));
1075             }
1076         }
1077     }
1078 
1079     return STATUS_SUCCESS;
1080 }
1081 
1082 
1083 NTSTATUS
1084 #ifdef __REACTOS__
1085 NTAPI
1086 #endif
1087 ScsiFlopReadWriteVerification(
1088     IN PDEVICE_OBJECT DeviceObject,
1089     IN PIRP Irp
1090     )
1091 
1092 /*++
1093 
1094 Routine Description:
1095 
1096 Arguments:
1097 
1098 Return Value:
1099 
1100     NT Status
1101 
1102 --*/
1103 
1104 {
1105     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
1106     PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
1107     NTSTATUS status = STATUS_SUCCESS;
1108 
1109     //
1110     // Make sure that the number of bytes to transfer is a multiple of the sector size
1111     //
1112     if ((irpSp->Parameters.Read.Length & (fdoExtension->DiskGeometry.BytesPerSector - 1)) != 0)
1113     {
1114         status = STATUS_INVALID_PARAMETER;
1115     }
1116 
1117     Irp->IoStatus.Status = status;
1118 
1119     return status;
1120 }
1121 
1122 
1123 NTSTATUS
1124 #ifdef __REACTOS__
1125 NTAPI
1126 #endif
1127 ScsiFlopDeviceControl(
1128     PDEVICE_OBJECT DeviceObject,
1129     PIRP Irp
1130     )
1131 
1132 /*++
1133 
1134 Routine Description:
1135 
1136 Arguments:
1137 
1138 Return Value:
1139 
1140     Status is returned.
1141 
1142 --*/
1143 
1144 {
1145     KIRQL currentIrql;
1146     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
1147     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
1148     PSCSI_REQUEST_BLOCK srb;
1149     PCDB cdb;
1150     NTSTATUS status;
1151     PDISK_GEOMETRY outputBuffer;
1152     ULONG outputBufferLength;
1153     ULONG i;
1154     DRIVE_MEDIA_TYPE lowestDriveMediaType;
1155     DRIVE_MEDIA_TYPE highestDriveMediaType;
1156     PFORMAT_PARAMETERS formatParameters;
1157     PMODE_PARAMETER_HEADER modeData;
1158     ULONG length;
1159 
1160     //
1161     // Initialize the information field
1162     //
1163     Irp->IoStatus.Information = 0;
1164 
1165     srb = ExAllocatePool(NonPagedPoolNx, SCSI_REQUEST_BLOCK_SIZE);
1166 
1167     if (srb == NULL) {
1168 
1169         Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1170         if (IoIsErrorUserInduced(Irp->IoStatus.Status)) {
1171 
1172             IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
1173         }
1174 
1175         KeRaiseIrql(DISPATCH_LEVEL, &currentIrql);
1176         ClassReleaseRemoveLock(DeviceObject, Irp);
1177         ClassCompleteRequest(DeviceObject, Irp, 0);
1178         KeLowerIrql(currentIrql);
1179 
1180         return(STATUS_INSUFFICIENT_RESOURCES);
1181     }
1182 
1183     //
1184     // Write zeros to Srb.
1185     //
1186 
1187     RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
1188 
1189     cdb = (PCDB)srb->Cdb;
1190 
1191     switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
1192 
1193 
1194     case IOCTL_DISK_VERIFY: {
1195 
1196        PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer;
1197        LARGE_INTEGER byteOffset;
1198        ULONG         sectorOffset;
1199        USHORT        sectorCount;
1200 
1201        //
1202        // Validate buffer length.
1203        //
1204 
1205        if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
1206            sizeof(VERIFY_INFORMATION)) {
1207 
1208            status = STATUS_INFO_LENGTH_MISMATCH;
1209            break;
1210        }
1211 
1212        //
1213        // Perform a bounds check on the sector range
1214        //
1215        if ((verifyInfo->StartingOffset.QuadPart > fdoExtension->CommonExtension.PartitionLength.QuadPart) ||
1216            (verifyInfo->StartingOffset.QuadPart < 0))
1217        {
1218            status = STATUS_NONEXISTENT_SECTOR;
1219            break;
1220        }
1221        else
1222        {
1223            ULONGLONG bytesRemaining = fdoExtension->CommonExtension.PartitionLength.QuadPart - verifyInfo->StartingOffset.QuadPart;
1224 
1225            if ((ULONGLONG)verifyInfo->Length > bytesRemaining)
1226            {
1227                status = STATUS_NONEXISTENT_SECTOR;
1228                break;
1229            }
1230        }
1231 
1232        //
1233        // Verify sectors
1234        //
1235 
1236        srb->CdbLength = 10;
1237 
1238        cdb->CDB10.OperationCode = SCSIOP_VERIFY;
1239 
1240        //
1241        // Add disk offset to starting sector.
1242        //
1243 
1244        byteOffset.QuadPart = fdoExtension->CommonExtension.StartingOffset.QuadPart +
1245                        verifyInfo->StartingOffset.QuadPart;
1246 
1247        //
1248        // Convert byte offset to sector offset.
1249        //
1250 
1251        sectorOffset = (ULONG)(byteOffset.QuadPart >> fdoExtension->SectorShift);
1252 
1253        //
1254        // Convert ULONG byte count to USHORT sector count.
1255        //
1256 
1257        sectorCount = (USHORT)(verifyInfo->Length >> fdoExtension->SectorShift);
1258 
1259        //
1260        // Move little endian values into CDB in big endian format.
1261        //
1262 
1263        cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&sectorOffset)->Byte3;
1264        cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&sectorOffset)->Byte2;
1265        cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&sectorOffset)->Byte1;
1266        cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&sectorOffset)->Byte0;
1267 
1268        cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&sectorCount)->Byte1;
1269        cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&sectorCount)->Byte0;
1270 
1271        //
1272        // The verify command is used by the NT FORMAT utility and
1273        // requests are sent down for 5% of the volume size. The
1274        // request timeout value is calculated based on the number of
1275        // sectors verified.
1276        //
1277 
1278        srb->TimeOutValue = ((sectorCount + 0x7F) >> 7) *
1279                              fdoExtension->TimeOutValue;
1280 
1281        status = ClassSendSrbAsynchronous(DeviceObject,
1282                                          srb,
1283                                          Irp,
1284                                          NULL,
1285                                          0,
1286                                          FALSE);
1287        return(status);
1288 
1289     }
1290 
1291     case IOCTL_DISK_GET_PARTITION_INFO: {
1292 
1293         if (fdoExtension->AdapterDescriptor->BusType == BusTypeUsb) {
1294 
1295             USBFlopGetMediaTypes(DeviceObject, NULL);
1296 
1297             // Don't need to propagate any error if one occurs
1298             //
1299             status = STATUS_SUCCESS;
1300 
1301         } else {
1302 
1303             status = DetermineMediaType(DeviceObject);
1304         }
1305 
1306         if (!NT_SUCCESS(status)) {
1307             // so will propogate error
1308             NOTHING;
1309         } else if (fdoExtension->DiskGeometry.MediaType == F3_120M_512) {
1310             //so that the format code will not try to partition it.
1311             status = STATUS_INVALID_DEVICE_REQUEST;
1312         } else {
1313            //
1314            // Free the Srb, since it is not needed.
1315            //
1316 
1317            ExFreePool(srb);
1318 
1319            //
1320            // Pass the request to the common device control routine.
1321            //
1322 
1323            return(ClassDeviceControl(DeviceObject, Irp));
1324         }
1325         break;
1326     }
1327 
1328     case IOCTL_DISK_GET_DRIVE_GEOMETRY: {
1329 
1330         DebugPrint((3,"ScsiDeviceIoControl: Get drive geometry\n"));
1331 
1332         if (fdoExtension->AdapterDescriptor->BusType == BusTypeUsb)
1333         {
1334             status = USBFlopGetMediaTypes(DeviceObject,
1335                                           Irp);
1336             break;
1337         }
1338 
1339         //
1340         // If there's not enough room to write the
1341         // data, then fail the request.
1342         //
1343 
1344         if ( irpStack->Parameters.DeviceIoControl.OutputBufferLength <
1345             sizeof( DISK_GEOMETRY ) ) {
1346 
1347             status = STATUS_INVALID_PARAMETER;
1348             break;
1349         }
1350 
1351         status = DetermineMediaType(DeviceObject);
1352 
1353         if (!NT_SUCCESS(status)) {
1354 
1355             Irp->IoStatus.Information = 0;
1356             Irp->IoStatus.Status = status;
1357 
1358         } else {
1359 
1360             //
1361             // Copy drive geometry information from device extension.
1362             //
1363 
1364             RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
1365                           &(fdoExtension->DiskGeometry),
1366                           sizeof(DISK_GEOMETRY));
1367 
1368             Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
1369             status = STATUS_SUCCESS;
1370 
1371         }
1372 
1373         break;
1374     }
1375 
1376     case IOCTL_DISK_GET_MEDIA_TYPES: {
1377 
1378         if (fdoExtension->AdapterDescriptor->BusType == BusTypeUsb)
1379         {
1380             status = USBFlopGetMediaTypes(DeviceObject,
1381                                           Irp);
1382             break;
1383         }
1384 
1385         i = DetermineDriveType(DeviceObject);
1386 
1387         if (i == DRIVE_TYPE_NONE) {
1388             status = STATUS_UNRECOGNIZED_MEDIA;
1389             break;
1390         }
1391 
1392         lowestDriveMediaType = DriveMediaLimits[i].LowestDriveMediaType;
1393         highestDriveMediaType = DriveMediaLimits[i].HighestDriveMediaType;
1394 
1395         outputBufferLength =
1396         irpStack->Parameters.DeviceIoControl.OutputBufferLength;
1397 
1398         //
1399         // Make sure that the input buffer has enough room to return
1400         // at least one descriptions of a supported media type.
1401         //
1402 
1403         if ( outputBufferLength < ( sizeof( DISK_GEOMETRY ) ) ) {
1404 
1405             status = STATUS_BUFFER_TOO_SMALL;
1406             break;
1407         }
1408 
1409         //
1410         // Assume success, although we might modify it to a buffer
1411         // overflow warning below (if the buffer isn't big enough
1412         // to hold ALL of the media descriptions).
1413         //
1414 
1415         status = STATUS_SUCCESS;
1416 
1417         if (outputBufferLength < ( sizeof( DISK_GEOMETRY ) *
1418             ( highestDriveMediaType - lowestDriveMediaType + 1 ) ) ) {
1419 
1420             //
1421             // The buffer is too small for all of the descriptions;
1422             // calculate what CAN fit in the buffer.
1423             //
1424 
1425             status = STATUS_BUFFER_OVERFLOW;
1426 
1427             highestDriveMediaType = (DRIVE_MEDIA_TYPE)( ( lowestDriveMediaType - 1 ) +
1428                 ( outputBufferLength /
1429                 sizeof( DISK_GEOMETRY ) ) );
1430         }
1431 
1432         outputBuffer = (PDISK_GEOMETRY) Irp->AssociatedIrp.SystemBuffer;
1433 
1434         for (i = (UCHAR)lowestDriveMediaType;i <= (UCHAR)highestDriveMediaType;i++ ) {
1435 
1436              outputBuffer->MediaType = DriveMediaConstants[i].MediaType;
1437              outputBuffer->Cylinders.LowPart =
1438                  DriveMediaConstants[i].MaximumTrack + 1;
1439              outputBuffer->Cylinders.HighPart = 0;
1440              outputBuffer->TracksPerCylinder =
1441                  DriveMediaConstants[i].NumberOfHeads;
1442              outputBuffer->SectorsPerTrack =
1443                  DriveMediaConstants[i].SectorsPerTrack;
1444              outputBuffer->BytesPerSector =
1445                  DriveMediaConstants[i].BytesPerSector;
1446              outputBuffer++;
1447 
1448              Irp->IoStatus.Information += sizeof( DISK_GEOMETRY );
1449         }
1450 
1451         break;
1452     }
1453 
1454     case IOCTL_DISK_FORMAT_TRACKS: {
1455 
1456         if (fdoExtension->AdapterDescriptor->BusType == BusTypeUsb)
1457         {
1458             status = USBFlopFormatTracks(DeviceObject,
1459                                          Irp);
1460             break;
1461         }
1462 
1463         //
1464         // Make sure that we got all the necessary format parameters.
1465         //
1466 
1467         if ( irpStack->Parameters.DeviceIoControl.InputBufferLength <sizeof( FORMAT_PARAMETERS ) ) {
1468 
1469             status = STATUS_INVALID_PARAMETER;
1470             break;
1471         }
1472 
1473         formatParameters = (PFORMAT_PARAMETERS) Irp->AssociatedIrp.SystemBuffer;
1474 
1475         //
1476         // Make sure the parameters we got are reasonable.
1477         //
1478 
1479         if ( !FlCheckFormatParameters(DeviceObject, formatParameters)) {
1480 
1481             status = STATUS_INVALID_PARAMETER;
1482             break;
1483         }
1484 
1485         //
1486         // If this request is for a 20.8 MB floppy then call a special
1487         // floppy format routine.
1488         //
1489 
1490         if (formatParameters->MediaType == F3_20Pt8_512) {
1491             status = FlopticalFormatMedia(DeviceObject,
1492                                           formatParameters
1493                                           );
1494 
1495             break;
1496         }
1497 
1498         //
1499         // All the work is done in the pass.  If this is not the first pass,
1500         // then complete the request and return;
1501         //
1502 
1503         if (formatParameters->StartCylinderNumber != 0 || formatParameters->StartHeadNumber != 0) {
1504 
1505             status = STATUS_SUCCESS;
1506             break;
1507         }
1508 
1509         status = FormatMedia( DeviceObject, formatParameters->MediaType);
1510         break;
1511     }
1512 
1513     case IOCTL_DISK_IS_WRITABLE: {
1514 
1515         if ((fdoExtension->DiskGeometry.MediaType) == F3_32M_512) {
1516 
1517             //
1518             // 32MB media is READ ONLY. Just return
1519             // STATUS_MEDIA_WRITE_PROTECTED
1520             //
1521 
1522             status = STATUS_MEDIA_WRITE_PROTECTED;
1523 
1524             break;
1525         }
1526 
1527         //
1528         // Determine if the device is writable.
1529         //
1530 
1531         modeData = ExAllocatePool(NonPagedPoolNxCacheAligned, MODE_DATA_SIZE);
1532 
1533         if (modeData == NULL) {
1534             status = STATUS_INSUFFICIENT_RESOURCES;
1535             break;
1536         }
1537 
1538         RtlZeroMemory(modeData, MODE_DATA_SIZE);
1539 
1540         length = ClassModeSense(DeviceObject,
1541                                 (PCHAR) modeData,
1542                                 MODE_DATA_SIZE,
1543                                 MODE_SENSE_RETURN_ALL);
1544 
1545         if (length < sizeof(MODE_PARAMETER_HEADER)) {
1546 
1547             //
1548             // Retry the request in case of a check condition.
1549             //
1550 
1551             length = ClassModeSense(DeviceObject,
1552                                     (PCHAR) modeData,
1553                                     MODE_DATA_SIZE,
1554                                     MODE_SENSE_RETURN_ALL);
1555 
1556             if (length < sizeof(MODE_PARAMETER_HEADER)) {
1557                 status = STATUS_IO_DEVICE_ERROR;
1558                 ExFreePool(modeData);
1559                 break;
1560             }
1561         }
1562 
1563         if (modeData->DeviceSpecificParameter & MODE_DSP_WRITE_PROTECT) {
1564             status = STATUS_MEDIA_WRITE_PROTECTED;
1565         } else {
1566             status = STATUS_SUCCESS;
1567         }
1568 
1569         DebugPrint((2,"IOCTL_DISK_IS_WRITABLE returns %08X\n", status));
1570 
1571         ExFreePool(modeData);
1572         break;
1573     }
1574 
1575     default: {
1576 
1577         DebugPrint((3,"ScsiIoDeviceControl: Unsupported device IOCTL\n"));
1578 
1579         //
1580         // Free the Srb, since it is not needed.
1581         //
1582 
1583         ExFreePool(srb);
1584 
1585         //
1586         // Pass the request to the common device control routine.
1587         //
1588 
1589         return(ClassDeviceControl(DeviceObject, Irp));
1590 
1591         break;
1592     }
1593 
1594     } // end switch( ...
1595 
1596     //
1597     // Check if SL_OVERRIDE_VERIFY_VOLUME flag is set in the IRP.
1598     // If so, do not return STATUS_VERIFY_REQUIRED
1599     //
1600     if ((status == STATUS_VERIFY_REQUIRED) &&
1601         (TEST_FLAG(irpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME))) {
1602 
1603         status = STATUS_IO_DEVICE_ERROR;
1604 
1605     }
1606 
1607     Irp->IoStatus.Status = status;
1608 
1609     if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
1610 
1611         IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
1612     }
1613 
1614     KeRaiseIrql(DISPATCH_LEVEL, &currentIrql);
1615     ClassReleaseRemoveLock(DeviceObject, Irp);
1616     ClassCompleteRequest(DeviceObject, Irp, 0);
1617     KeLowerIrql(currentIrql);
1618 
1619     ExFreePool(srb);
1620 
1621     return status;
1622 
1623 } // end ScsiFlopDeviceControl()
1624 
1625 #if 0
1626 
1627 BOOLEAN
1628 IsFloppyDevice(
1629     PDEVICE_OBJECT DeviceObject
1630     )
1631 /*++
1632 
1633 Routine Description:
1634 
1635     The routine performs the necessary funcitons to deterime if the device is
1636     really a floppy rather than a harddisk.  This is done by a mode sense
1637     command.  First a check is made to see if the medimum type is set.  Second
1638     a check is made for the flexible parameters mode page.
1639 
1640 Arguments:
1641 
1642     DeviceObject - Supplies the device object to be tested.
1643 
1644 Return Value:
1645 
1646     Return TRUE if the indicated device is a floppy.
1647 
1648 --*/
1649 {
1650 
1651     PVOID modeData;
1652     PUCHAR pageData;
1653     ULONG length;
1654 
1655     modeData = ExAllocatePool(NonPagedPoolNxCacheAligned, MODE_DATA_SIZE);
1656 
1657     if (modeData == NULL) {
1658         return(FALSE);
1659     }
1660 
1661     RtlZeroMemory(modeData, MODE_DATA_SIZE);
1662 
1663     length = ClassModeSense(DeviceObject, modeData, MODE_DATA_SIZE, MODE_SENSE_RETURN_ALL);
1664 
1665     if (length < sizeof(MODE_PARAMETER_HEADER)) {
1666 
1667         //
1668         // Retry the request in case of a check condition.
1669         //
1670 
1671         length = ClassModeSense(DeviceObject,
1672                     modeData,
1673                     MODE_DATA_SIZE,
1674                     MODE_SENSE_RETURN_ALL);
1675 
1676         if (length < sizeof(MODE_PARAMETER_HEADER)) {
1677 
1678             ExFreePool(modeData);
1679             return(FALSE);
1680 
1681         }
1682     }
1683 
1684 #if 0
1685     //
1686     // Some drives incorrectly report this.  In particular the SONY RMO-S350
1687     // when in disk mode.
1688     //
1689 
1690     if (((PMODE_PARAMETER_HEADER) modeData)->MediumType >= MODE_FD_SINGLE_SIDE
1691         && ((PMODE_PARAMETER_HEADER) modeData)->MediumType <= MODE_FD_MAXIMUM_TYPE) {
1692 
1693         DebugPrint((1, "ScsiFlop: MediumType value %2x, This is a floppy.\n", ((PMODE_PARAMETER_HEADER) modeData)->MediumType));
1694         ExFreePool(modeData);
1695         return(TRUE);
1696     }
1697 
1698 #endif
1699 
1700     //
1701     // If the length is greater than length indiated by the mode data reset
1702     // the data to the mode data.
1703     //
1704     if (length > (ULONG)((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) {
1705         length = (ULONG)((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1;
1706 
1707     }
1708 
1709     //
1710     // Look for the flexible disk mode page.
1711     //
1712 
1713     pageData = ClassFindModePage( modeData, length, MODE_PAGE_FLEXIBILE, TRUE);
1714 
1715     if (pageData != NULL) {
1716 
1717         DebugPrint((1, "ScsiFlop: Flexible disk page found, This is a floppy.\n"));
1718 
1719         //
1720         // As a special case for the floptical driver do a magic mode sense to
1721         // enable the drive.
1722         //
1723 
1724         ClassModeSense(DeviceObject, modeData, 0x2a, 0x2e);
1725 
1726         ExFreePool(modeData);
1727         return(TRUE);
1728 
1729     }
1730 
1731     ExFreePool(modeData);
1732     return(FALSE);
1733 
1734 }
1735 #endif
1736 
1737 
1738 NTSTATUS
1739 DetermineMediaType(
1740     PDEVICE_OBJECT DeviceObject
1741     )
1742 /*++
1743 
1744 Routine Description:
1745 
1746     This routine determines the floppy media type based on the size of the
1747     device.  The geometry information is set for the device object.
1748 
1749 Arguments:
1750 
1751     DeviceObject - Supplies the device object to be tested.
1752 
1753 Return Value:
1754 
1755     None
1756 
1757 --*/
1758 {
1759     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
1760     PDISK_GEOMETRY geometry;
1761     LONG index;
1762     NTSTATUS status;
1763 
1764     PAGED_CODE();
1765 
1766     geometry = &(fdoExtension->DiskGeometry);
1767 
1768     //
1769     // Issue ReadCapacity to update device extension
1770     // with information for current media.
1771     //
1772 
1773     status = ClassReadDriveCapacity(DeviceObject);
1774 
1775     if (!NT_SUCCESS(status)) {
1776 
1777        //
1778        // Set the media type to unknow and zero the geometry information.
1779        //
1780 
1781        geometry->MediaType = Unknown;
1782 
1783        return status;
1784 
1785     }
1786 
1787     //
1788     // Look at the capcity of disk to determine its type.
1789     //
1790 
1791     for (index = NUMBER_OF_DRIVE_MEDIA_COMBINATIONS - 1; index >= 0; index--) {
1792 
1793         //
1794         // Walk the table backward untill the drive capacity holds all of the
1795         // data and the bytes per setor are equal
1796         //
1797 
1798          if ((ULONG) (DriveMediaConstants[index].NumberOfHeads *
1799              (DriveMediaConstants[index].MaximumTrack + 1) *
1800              DriveMediaConstants[index].SectorsPerTrack *
1801              DriveMediaConstants[index].BytesPerSector) <=
1802              fdoExtension->CommonExtension.PartitionLength.LowPart &&
1803              DriveMediaConstants[index].BytesPerSector ==
1804              geometry->BytesPerSector) {
1805 
1806              geometry->MediaType = DriveMediaConstants[index].MediaType;
1807              geometry->TracksPerCylinder = DriveMediaConstants[index].NumberOfHeads;
1808              geometry->SectorsPerTrack = DriveMediaConstants[index].SectorsPerTrack;
1809              geometry->Cylinders.LowPart = DriveMediaConstants[index].MaximumTrack+1;
1810              break;
1811          }
1812     }
1813 
1814     if (index == -1) {
1815 
1816         //
1817         // Set the media type to unknow and zero the geometry information.
1818         //
1819 
1820         geometry->MediaType = Unknown;
1821 
1822 
1823     } else {
1824         //
1825         // DMF check breaks the insight SCSI floppy, so its disabled for that case
1826         //
1827         PDISK_DATA diskData = (PDISK_DATA) fdoExtension->CommonExtension.DriverData;
1828 
1829         // if (diskData->EnableDMF == TRUE) {
1830 
1831             //
1832             //check to see if DMF
1833             //
1834 
1835             PSCSI_REQUEST_BLOCK srb;
1836             PVOID               readData;
1837 
1838             //
1839             // Allocate a Srb for the read command.
1840             //
1841 
1842             readData = ExAllocatePool(NonPagedPoolNx, geometry->BytesPerSector);
1843             if (readData == NULL) {
1844                 return STATUS_NO_MEMORY;
1845             }
1846 
1847             srb = ExAllocatePool(NonPagedPoolNx, SCSI_REQUEST_BLOCK_SIZE);
1848 
1849             if (srb == NULL) {
1850 
1851                 ExFreePool(readData);
1852                 return STATUS_NO_MEMORY;
1853             }
1854 
1855             RtlZeroMemory(readData, geometry->BytesPerSector);
1856             RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
1857 
1858             srb->CdbLength = 10;
1859             srb->Cdb[0] = SCSIOP_READ;
1860             srb->Cdb[5] = 0;
1861             srb->Cdb[8] = (UCHAR) 1;
1862 
1863             //
1864             // Set timeout value.
1865             //
1866 
1867             srb->TimeOutValue = fdoExtension->TimeOutValue;
1868 
1869             //
1870             // Send the mode select data.
1871             //
1872 
1873             status = ClassSendSrbSynchronous(DeviceObject,
1874                       srb,
1875                       readData,
1876                       geometry->BytesPerSector,
1877                       FALSE
1878                       );
1879 
1880             if (NT_SUCCESS(status)) {
1881                 char *pchar = (char *)readData;
1882 
1883                 pchar += 3; //skip 3 bytes jump code
1884 
1885                 // If the MSDMF3. signature is there then mark it as DMF diskette
1886                 if (RtlCompareMemory(pchar, "MSDMF3.", 7) == 7) {
1887                     diskData->IsDMF = TRUE;
1888                 }
1889 
1890             }
1891             ExFreePool(readData);
1892             ExFreePool(srb);
1893         // }// else
1894     }
1895     return status;
1896 }
1897 
1898 ULONG
1899 DetermineDriveType(
1900     PDEVICE_OBJECT DeviceObject
1901     )
1902 /*++
1903 
1904 Routine Description:
1905 
1906     The routine determines the device type so that the supported medias can be
1907     determined.  It does a mode sense for the default parameters.  This code
1908     assumes that the returned values are for the maximum device size.
1909 
1910 Arguments:
1911 
1912     DeviceObject - Supplies the device object to be tested.
1913 
1914 Return Value:
1915 
1916     None
1917 
1918 --*/
1919 {
1920     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
1921     PVOID modeData;
1922     PDISK_DATA diskData = (PDISK_DATA) fdoExtension->CommonExtension.DriverData;
1923     PMODE_FLEXIBLE_DISK_PAGE pageData;
1924     ULONG length;
1925     LONG index;
1926     UCHAR numberOfHeads;
1927     UCHAR sectorsPerTrack;
1928     USHORT maximumTrack;
1929     BOOLEAN applyFix = FALSE;
1930 
1931     PAGED_CODE();
1932 
1933     if (diskData->DriveType != DRIVE_TYPE_NONE) {
1934         return(diskData->DriveType);
1935     }
1936 
1937     modeData = ExAllocatePool(NonPagedPoolNxCacheAligned, MODE_DATA_SIZE);
1938 
1939     if (modeData == NULL) {
1940         return(DRIVE_TYPE_NONE);
1941     }
1942 
1943     RtlZeroMemory(modeData, MODE_DATA_SIZE);
1944 
1945     length = ClassModeSense(DeviceObject,
1946                             modeData,
1947                             MODE_DATA_SIZE,
1948                             MODE_PAGE_FLEXIBILE);
1949 
1950     if (length < sizeof(MODE_PARAMETER_HEADER)) {
1951 
1952         //
1953         // Retry the request one more time
1954         // in case of a check condition.
1955         //
1956         length = ClassModeSense(DeviceObject,
1957                                 modeData,
1958                                 MODE_DATA_SIZE,
1959                                 MODE_PAGE_FLEXIBILE);
1960 
1961         if (length < sizeof(MODE_PARAMETER_HEADER)) {
1962 
1963             ExFreePool(modeData);
1964             return(DRIVE_TYPE_NONE);
1965         }
1966     }
1967 
1968     //
1969     // Look for the flexible disk mode page.
1970     //
1971 
1972     pageData = ClassFindModePage( modeData,
1973                                   length,
1974                                   MODE_PAGE_FLEXIBILE,
1975                                   TRUE);
1976 
1977     //
1978     // Make sure the page is returned and is large enough.
1979     //
1980 
1981     if ((pageData != NULL) &&
1982         (pageData->PageLength + 2 >=
1983          (UCHAR)offsetof(MODE_FLEXIBLE_DISK_PAGE, StartWritePrecom))) {
1984 
1985        //
1986        // Pull out the heads, cylinders, and sectors.
1987        //
1988 
1989        numberOfHeads = pageData->NumberOfHeads;
1990        maximumTrack = pageData->NumberOfCylinders[1];
1991        maximumTrack |= pageData->NumberOfCylinders[0] << 8;
1992        sectorsPerTrack = pageData->SectorsPerTrack;
1993 
1994 
1995        //
1996        // Convert from number of cylinders to maximum track.
1997        //
1998 
1999        maximumTrack--;
2000 
2001        //
2002        // Search for the maximum supported media. Based on the number of heads,
2003        // sectors per track and number of cylinders
2004        //
2005        for (index = 0; index < NUMBER_OF_DRIVE_MEDIA_COMBINATIONS; index++) {
2006 
2007             //
2008             // Walk the table forward until the drive capacity holds all of the
2009             // data and the bytes per setor are equal
2010             //
2011 
2012             if (DriveMediaConstants[index].NumberOfHeads == numberOfHeads &&
2013                 DriveMediaConstants[index].MaximumTrack == maximumTrack &&
2014                 DriveMediaConstants[index].SectorsPerTrack ==sectorsPerTrack) {
2015 
2016                 ExFreePool(modeData);
2017 
2018                 //
2019                 // index is now a drive media combination.  Compare this to
2020                 // the maximum drive media type in the drive media table.
2021                 //
2022 
2023                 for (length = 0; length < NUMBER_OF_DRIVE_TYPES; length++) {
2024 
2025                     if (DriveMediaLimits[length].HighestDriveMediaType == index) {
2026                         return(length);
2027                     }
2028                 }
2029                 return(DRIVE_TYPE_NONE);
2030            }
2031        }
2032 
2033        // If the maximum track is greater than 8 bits then divide the
2034        // number of tracks by 3 and multiply the number of heads by 3.
2035        // This is a special case for the 20.8 MB floppy.
2036        //
2037 
2038        if (!applyFix && maximumTrack >= 0x0100) {
2039            maximumTrack++;
2040            maximumTrack /= 3;
2041            maximumTrack--;
2042            numberOfHeads *= 3;
2043        } else {
2044            ExFreePool(modeData);
2045            return(DRIVE_TYPE_NONE);
2046        }
2047 
2048     }
2049 
2050     ExFreePool(modeData);
2051     return(DRIVE_TYPE_NONE);
2052 }
2053 
2054 
2055 BOOLEAN
2056 FlCheckFormatParameters(
2057     IN PDEVICE_OBJECT DeviceObject,
2058     IN PFORMAT_PARAMETERS FormatParameters
2059     )
2060 
2061 /*++
2062 
2063 Routine Description:
2064 
2065     This routine checks the supplied format parameters to make sure that
2066     they'll work on the drive to be formatted.
2067 
2068 Arguments:
2069 
2070     DeviceObject - Pointer to the device object to be formated.
2071 
2072     FormatParameters - a pointer to the caller's parameters for the FORMAT.
2073 
2074 Return Value:
2075 
2076     TRUE if parameters are OK.
2077     FALSE if the parameters are bad.
2078 
2079 --*/
2080 
2081 {
2082     PDRIVE_MEDIA_CONSTANTS driveMediaConstants;
2083     DRIVE_MEDIA_TYPE driveMediaType;
2084     ULONG index;
2085 
2086     PAGED_CODE();
2087 
2088     //
2089     // Get the device type.
2090     //
2091 
2092     index = DetermineDriveType(DeviceObject);
2093 
2094     if (index == DRIVE_TYPE_NONE) {
2095 
2096         //
2097         // If the determine device type failed then just use the media type
2098         // and try the parameters.
2099         //
2100 
2101         driveMediaType = Drive360Media160;
2102 
2103         while (( DriveMediaConstants[driveMediaType].MediaType !=
2104                FormatParameters->MediaType ) &&
2105                ( driveMediaType < Drive288Media288) ) {
2106 
2107                driveMediaType++;
2108         }
2109 
2110     } else {
2111 
2112         //
2113         // Figure out which entry in the DriveMediaConstants table to use.
2114         //
2115 
2116         driveMediaType =
2117             DriveMediaLimits[index].HighestDriveMediaType;
2118 
2119         while ( ( DriveMediaConstants[driveMediaType].MediaType !=
2120             FormatParameters->MediaType ) &&
2121             ( driveMediaType > DriveMediaLimits[index].
2122             LowestDriveMediaType ) ) {
2123 
2124             driveMediaType--;
2125         }
2126 
2127     }
2128 
2129 
2130      // driveMediaType is bounded below by DriveMediaLimits[].LowestDriveMediaType
2131 #if !defined(__REACTOS__) || defined(_MSC_VER)
2132 #pragma warning(push)
2133 #pragma warning(disable:33010) // 33010: Enum used as array index may be negative
2134 #endif
2135     if ( DriveMediaConstants[driveMediaType].MediaType !=
2136         FormatParameters->MediaType ) {
2137         return FALSE;
2138 
2139     } else {
2140 
2141         driveMediaConstants = &DriveMediaConstants[driveMediaType];
2142 
2143         if ( ( FormatParameters->StartHeadNumber >
2144             (ULONG)( driveMediaConstants->NumberOfHeads - 1 ) ) ||
2145             ( FormatParameters->EndHeadNumber >
2146             (ULONG)( driveMediaConstants->NumberOfHeads - 1 ) ) ||
2147             ( FormatParameters->StartCylinderNumber >
2148             driveMediaConstants->MaximumTrack ) ||
2149             ( FormatParameters->EndCylinderNumber >
2150             driveMediaConstants->MaximumTrack ) ||
2151             ( FormatParameters->EndCylinderNumber <
2152             FormatParameters->StartCylinderNumber ) ) {
2153 
2154             return FALSE;
2155 
2156         } else {
2157 
2158             return TRUE;
2159         }
2160     }
2161 #if !defined(__REACTOS__) || defined(_MSC_VER)
2162 #pragma warning(pop)
2163 #endif
2164 }
2165 
2166 NTSTATUS
2167 FormatMedia(
2168     PDEVICE_OBJECT DeviceObject,
2169     MEDIA_TYPE MediaType
2170     )
2171 /*++
2172 
2173 Routine Description:
2174 
2175     This routine formats the floppy disk.  The entire floppy is formated in
2176     one shot.
2177 
2178 Arguments:
2179 
2180     DeviceObject - Supplies the device object to be tested.
2181 
2182     Irp - Supplies a pointer to the requesting Irp.
2183 
2184     MediaType - Supplies the media type format the device for.
2185 
2186 Return Value:
2187 
2188     Returns a status for the operation.
2189 
2190 --*/
2191 {
2192     PVOID modeData;
2193     PSCSI_REQUEST_BLOCK srb;
2194     PMODE_FLEXIBLE_DISK_PAGE pageData;
2195     DRIVE_MEDIA_TYPE driveMediaType;
2196     PDRIVE_MEDIA_CONSTANTS driveMediaConstants;
2197     ULONG length;
2198     NTSTATUS status;
2199 
2200     PAGED_CODE();
2201 
2202     modeData = ExAllocatePool(NonPagedPoolNxCacheAligned, MODE_DATA_SIZE);
2203 
2204     if (modeData == NULL) {
2205         return(STATUS_INSUFFICIENT_RESOURCES);
2206     }
2207 
2208     RtlZeroMemory(modeData, MODE_DATA_SIZE);
2209 
2210     length = ClassModeSense(DeviceObject,
2211                             modeData,
2212                             MODE_DATA_SIZE,
2213                             MODE_PAGE_FLEXIBILE);
2214 
2215     if (length < sizeof(MODE_PARAMETER_HEADER)) {
2216         ExFreePool(modeData);
2217         return(STATUS_INVALID_DEVICE_REQUEST);
2218     }
2219 
2220     //
2221     // Look for the flexible disk mode page.
2222     //
2223 
2224     pageData = ClassFindModePage( modeData, length, MODE_PAGE_FLEXIBILE, TRUE);
2225 
2226     //
2227     // Make sure the page is returned and is large enough.
2228     //
2229 
2230     if ((pageData == NULL) ||
2231         (pageData->PageLength + 2 <
2232          (UCHAR)offsetof(MODE_FLEXIBLE_DISK_PAGE, StartWritePrecom))) {
2233 
2234         ExFreePool(modeData);
2235         return(STATUS_INVALID_DEVICE_REQUEST);
2236 
2237     }
2238 
2239     //
2240     // Look for a drive media type which matches the requested media type.
2241     //
2242     //
2243     //start from Drive120MMedia120M instead of Drive2080Media2080
2244     //
2245     for (driveMediaType = Drive120MMedia120M;
2246     DriveMediaConstants[driveMediaType].MediaType != MediaType;
2247     driveMediaType--) {
2248          if (driveMediaType == Drive360Media160) {
2249 
2250              ExFreePool(modeData);
2251              return(STATUS_INVALID_PARAMETER);
2252 
2253          }
2254     }
2255 
2256     driveMediaConstants = &DriveMediaConstants[driveMediaType];
2257 
2258     if ((pageData->NumberOfHeads != driveMediaConstants->NumberOfHeads) ||
2259         (pageData->SectorsPerTrack != driveMediaConstants->SectorsPerTrack) ||
2260         ((pageData->NumberOfCylinders[0] != (UCHAR)((driveMediaConstants->MaximumTrack+1) >> 8)) &&
2261          (pageData->NumberOfCylinders[1] != (UCHAR)driveMediaConstants->MaximumTrack+1)) ||
2262         (pageData->BytesPerSector[0] != driveMediaConstants->BytesPerSector >> 8 )) {
2263 
2264         //
2265         // Update the flexible parameters page with the new parameters.
2266         //
2267 
2268         pageData->NumberOfHeads = driveMediaConstants->NumberOfHeads;
2269         pageData->SectorsPerTrack = driveMediaConstants->SectorsPerTrack;
2270         pageData->NumberOfCylinders[0] = (UCHAR)((driveMediaConstants->MaximumTrack+1) >> 8);
2271         pageData->NumberOfCylinders[1] = (UCHAR)driveMediaConstants->MaximumTrack+1;
2272         pageData->BytesPerSector[0] = driveMediaConstants->BytesPerSector >> 8;
2273 
2274         //
2275         // Clear the mode parameter header.
2276         //
2277 
2278         RtlZeroMemory(modeData, sizeof(MODE_PARAMETER_HEADER));
2279 
2280         //
2281         // Set the length equal to the length returned for the flexible page.
2282         //
2283 
2284         length = pageData->PageLength + 2;
2285 
2286         //
2287         // Copy the page after the mode parameter header.
2288         //
2289 
2290         RtlMoveMemory((PCHAR) modeData + sizeof(MODE_PARAMETER_HEADER),
2291                 pageData,
2292                 length
2293                 );
2294             length += sizeof(MODE_PARAMETER_HEADER);
2295 
2296 
2297         //
2298         // Allocate a Srb for the format command.
2299         //
2300 
2301         srb = ExAllocatePool(NonPagedPoolNx, SCSI_REQUEST_BLOCK_SIZE);
2302 
2303         if (srb == NULL) {
2304 
2305             ExFreePool(modeData);
2306             return(STATUS_INSUFFICIENT_RESOURCES);
2307         }
2308 
2309         RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
2310 
2311         srb->CdbLength = 6;
2312         srb->Cdb[0] = SCSIOP_MODE_SELECT;
2313         srb->Cdb[4] = (UCHAR) length;
2314 
2315         //
2316         // Set the PF bit.
2317         //
2318 
2319         srb->Cdb[1] |= 0x10;
2320 
2321         //
2322         // Set timeout value.
2323         //
2324 
2325         srb->TimeOutValue = 2;
2326 
2327         //
2328         // Send the mode select data.
2329         //
2330 
2331         status = ClassSendSrbSynchronous(DeviceObject,
2332                   srb,
2333                   modeData,
2334                   length,
2335                   TRUE
2336                   );
2337 
2338         //
2339         // The mode data not needed any more so free it.
2340         //
2341 
2342         ExFreePool(modeData);
2343 
2344         if (!NT_SUCCESS(status)) {
2345             ExFreePool(srb);
2346             return(status);
2347         }
2348 
2349     } else {
2350 
2351         //
2352         // The mode data not needed any more so free it.
2353         //
2354 
2355         ExFreePool(modeData);
2356 
2357         //
2358         // Allocate a Srb for the format command.
2359         //
2360 
2361         srb = ExAllocatePool(NonPagedPoolNx, SCSI_REQUEST_BLOCK_SIZE);
2362 
2363         if (srb == NULL) {
2364             return(STATUS_INSUFFICIENT_RESOURCES);
2365         }
2366 
2367     }
2368 
2369     RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
2370 
2371     srb->CdbLength = 6;
2372 
2373     srb->Cdb[0] = SCSIOP_FORMAT_UNIT;
2374 
2375     //
2376     // Set timeout value.
2377     //
2378 
2379     srb->TimeOutValue = 10 * 60;
2380 
2381     status = ClassSendSrbSynchronous(DeviceObject,
2382                                      srb,
2383                                      NULL,
2384                                      0,
2385                                      FALSE
2386                                      );
2387     ExFreePool(srb);
2388 
2389     return(status);
2390 
2391 }
2392 
2393 VOID
2394 #ifdef __REACTOS__
2395 NTAPI
2396 #endif
2397 ScsiFlopProcessError(
2398     PDEVICE_OBJECT DeviceObject,
2399     PSCSI_REQUEST_BLOCK Srb,
2400     NTSTATUS *Status,
2401     BOOLEAN *Retry
2402     )
2403 /*++
2404 
2405 Routine Description:
2406 
2407    This routine checks the type of error.  If the error indicate the floppy
2408    controller needs to be reinitialize a command is made to do it.
2409 
2410 Arguments:
2411 
2412     DeviceObject - Supplies a pointer to the device object.
2413 
2414     Srb - Supplies a pointer to the failing Srb.
2415 
2416     Status - Status with which the IRP will be completed.
2417 
2418     Retry - Indication of whether the request will be retried.
2419 
2420 Return Value:
2421 
2422     None.
2423 
2424 --*/
2425 
2426 {
2427     PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
2428     PDISK_DATA diskData = (PDISK_DATA) fdoExtension->CommonExtension.DriverData;
2429     PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
2430     PIO_STACK_LOCATION irpStack;
2431     PIRP irp;
2432     PSCSI_REQUEST_BLOCK srb;
2433     LARGE_INTEGER largeInt;
2434     PCOMPLETION_CONTEXT context;
2435     PCDB cdb;
2436     ULONG_PTR alignment;
2437     ULONG majorFunction;
2438 
2439     UNREFERENCED_PARAMETER(Status);
2440     UNREFERENCED_PARAMETER(Retry);
2441 
2442     largeInt.QuadPart = 1;
2443 
2444     //
2445     // Check the status.  The initialization command only needs to be sent
2446     // if UNIT ATTENTION or LUN NOT READY is returned.
2447     //
2448 
2449     if (!(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)) {
2450 
2451         //
2452         // The drive does not require reinitialization.
2453         //
2454 
2455         return;
2456     }
2457 
2458     //
2459     // Reset the drive type.
2460     //
2461 
2462     diskData->DriveType = DRIVE_TYPE_NONE;
2463     diskData->IsDMF = FALSE;
2464 
2465     fdoExtension->DiskGeometry.MediaType = Unknown;
2466 
2467     if (fdoExtension->AdapterDescriptor->BusType == BusTypeUsb) {
2468 
2469         // FLPYDISK.SYS never returns a non-zero value for the ChangeCount
2470         // on an IOCTL_DISK_CHECK_VERIFY.  Some things seem to work better
2471         // if we do the same.  In particular, FatVerifyVolume() can exit between
2472         // the IOCTL_DISK_CHECK_VERIFY and the IOCTL_DISK_GET_DRIVE_GEOMETRY
2473         // if a non-zero ChangeCount is returned, and this appears to cause
2474         // issues formatting unformatted media in some situations.
2475         //
2476         // This is something that should probably be revisited at some point.
2477         //
2478         fdoExtension->MediaChangeCount = 0;
2479 
2480         if (((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_UNIT_ATTENTION) &&
2481             (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_MEDIUM_CHANGED)) {
2482 
2483             struct _START_STOP *startStopCdb;
2484 
2485             DebugPrint((2,"Sending SCSIOP_START_STOP_UNIT\n"));
2486 
2487             context = ExAllocatePool(NonPagedPoolNx,
2488                                      sizeof(COMPLETION_CONTEXT));
2489 
2490             if (context == NULL) {
2491 
2492                 return;
2493             }
2494 #if (NTDDI_VERSION >= NTDDI_WIN8)
2495             srb = &context->Srb.Srb;
2496 #else
2497             srb = &context->Srb;
2498 #endif
2499 
2500             RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
2501 
2502             srb->SrbFlags = SRB_FLAGS_DISABLE_AUTOSENSE;
2503 
2504             srb->CdbLength = 6;
2505 
2506             startStopCdb = (struct _START_STOP *)srb->Cdb;
2507 
2508             startStopCdb->OperationCode = SCSIOP_START_STOP_UNIT;
2509             startStopCdb->Start = 1;
2510 
2511             // A Start Stop Unit request has no transfer buffer.
2512             // Set the request to IRP_MJ_FLUSH_BUFFERS when calling
2513             // IoBuildAsynchronousFsdRequest() so that it ignores
2514             // the buffer pointer and buffer length parameters.
2515             //
2516             majorFunction = IRP_MJ_FLUSH_BUFFERS;
2517 
2518         } else if ((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_MEDIUM_ERROR) {
2519 
2520             // Return ERROR_UNRECOGNIZED_MEDIA instead of
2521             // STATUS_DEVICE_DATA_ERROR to make shell happy.
2522             //
2523             *Status = STATUS_UNRECOGNIZED_MEDIA;
2524             return;
2525 
2526         } else {
2527 
2528             return;
2529         }
2530 
2531 #ifndef __REACTOS__
2532     } else if (((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_NOT_READY) &&
2533              senseBuffer->AdditionalSenseCodeQualifier == SCSI_SENSEQ_INIT_COMMAND_REQUIRED ||
2534              (senseBuffer->SenseKey & 0xf) == SCSI_SENSE_UNIT_ATTENTION) {
2535 #else
2536     } else if ((((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_NOT_READY) &&
2537              senseBuffer->AdditionalSenseCodeQualifier == SCSI_SENSEQ_INIT_COMMAND_REQUIRED) ||
2538              (senseBuffer->SenseKey & 0xf) == SCSI_SENSE_UNIT_ATTENTION) {
2539 #endif
2540 
2541         ULONG sizeNeeded;
2542         ULONG tmpSize;
2543         BOOLEAN overFlow;
2544 
2545         DebugPrint((1, "ScsiFlopProcessError: Reinitializing the floppy.\n"));
2546 
2547         //
2548         // Send the special mode sense command to enable writes on the
2549         // floptical drive.
2550         //
2551 
2552         alignment = DeviceObject->AlignmentRequirement ?
2553             DeviceObject->AlignmentRequirement : 1;
2554 
2555         sizeNeeded = 0;
2556         overFlow = TRUE;
2557         if (SUCCEEDED(ULongAdd(sizeof(COMPLETION_CONTEXT), 0x2a, &tmpSize))) {
2558 
2559             if (SUCCEEDED(ULongAdd(tmpSize, (ULONG) alignment, &sizeNeeded))) {
2560                 overFlow = FALSE;
2561             }
2562         }
2563 
2564         context = NULL;
2565 
2566         if (!overFlow) {
2567             context = ExAllocatePool(NonPagedPoolNx, sizeNeeded);
2568         }
2569 
2570         if (context == NULL) {
2571 
2572             //
2573             // If there is not enough memory to fulfill this request,
2574             // simply return. A subsequent retry will fail and another
2575             // chance to start the unit.
2576             //
2577 
2578             return;
2579         }
2580 
2581 #if (NTDDI_VERSION >= NTDDI_WIN8)
2582         srb = &context->Srb.Srb;
2583 #else
2584         srb = &context->Srb;
2585 #endif
2586 
2587         RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
2588 
2589         //
2590         // Set the transfer length.
2591         //
2592 
2593         srb->DataTransferLength = 0x2a;
2594         srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_AUTOSENSE | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
2595 
2596         //
2597         // The data buffer must be aligned.
2598         //
2599 
2600         srb->DataBuffer = (PVOID) (((ULONG_PTR) (context + 1) + (alignment - 1)) &
2601             ~(alignment - 1));
2602 
2603 
2604         //
2605         // Build the start unit CDB.
2606         //
2607 
2608         srb->CdbLength = 6;
2609         cdb = (PCDB)srb->Cdb;
2610         cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
2611         cdb->MODE_SENSE.PageCode = 0x2e;
2612         cdb->MODE_SENSE.AllocationLength = 0x2a;
2613 
2614         majorFunction = IRP_MJ_READ;
2615 
2616     } else {
2617 
2618         return;
2619     }
2620 
2621     context->DeviceObject = DeviceObject;
2622 
2623     //
2624     // Write length to SRB.
2625     //
2626 
2627     srb->Length = SCSI_REQUEST_BLOCK_SIZE;
2628 
2629     srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
2630     srb->TimeOutValue = fdoExtension->TimeOutValue;
2631 
2632     //
2633     // Build the asynchronous request
2634     // to be sent to the port driver.
2635     //
2636 
2637     irp = IoBuildAsynchronousFsdRequest(majorFunction,
2638                        DeviceObject,
2639                        srb->DataBuffer,
2640                        srb->DataTransferLength,
2641                        &largeInt,
2642                        NULL);
2643 
2644     if(irp == NULL) {
2645         ExFreePool(context);
2646         return;
2647     }
2648 
2649 
2650     IoSetCompletionRoutine(irp,
2651            (PIO_COMPLETION_ROUTINE)ClassAsynchronousCompletion,
2652            context,
2653            TRUE,
2654            TRUE,
2655            TRUE);
2656 
2657     ClassAcquireRemoveLock(DeviceObject, irp);
2658 
2659     irpStack = IoGetNextIrpStackLocation(irp);
2660 
2661     irpStack->MajorFunction = IRP_MJ_SCSI;
2662 
2663     srb->OriginalRequest = irp;
2664 
2665     //
2666     // Save SRB address in next stack for port driver.
2667     //
2668 
2669     irpStack->Parameters.Others.Argument1 = (PVOID)srb;
2670 
2671     //
2672     // Can't release the remove lock yet - let ClassAsynchronousCompletion
2673     // take care of that for us.
2674     //
2675 
2676     (VOID)IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);
2677 
2678     return;
2679 }
2680 
2681 NTSTATUS
2682 FlopticalFormatMedia(
2683     PDEVICE_OBJECT DeviceObject,
2684     PFORMAT_PARAMETERS Format
2685     )
2686 /*++
2687 
2688 Routine Description:
2689 
2690     This routine is used to do perform a format tracks for the 20.8 MB
2691     floppy.  Because the device does not support format tracks and the full
2692     format takes a long time a write of zeros is done instead.
2693 
2694 Arguments:
2695 
2696     DeviceObject - Supplies the device object to be tested.
2697 
2698     Format - Supplies the format parameters.
2699 
2700 Return Value:
2701 
2702     Returns a status for the operation.
2703 
2704 --*/
2705 {
2706     IO_STATUS_BLOCK ioStatus;
2707     PIRP irp;
2708     KEVENT event;
2709     LARGE_INTEGER offset;
2710     ULONG length;
2711     PVOID buffer;
2712     PDRIVE_MEDIA_CONSTANTS driveMediaConstants;
2713     NTSTATUS status;
2714 
2715     PAGED_CODE();
2716 
2717     driveMediaConstants = &DriveMediaConstants[Drive2080Media2080];
2718 
2719     //
2720     // Calculate the length of the buffer.
2721     //
2722 
2723     length = ((Format->EndCylinderNumber - Format->StartCylinderNumber) *
2724         driveMediaConstants->NumberOfHeads +
2725         Format->EndHeadNumber - Format->StartHeadNumber + 1) *
2726         driveMediaConstants->SectorsPerTrack *
2727         driveMediaConstants->BytesPerSector;
2728 
2729     buffer = ExAllocatePool(NonPagedPoolNxCacheAligned, length);
2730 
2731     if (buffer == NULL) {
2732         return(STATUS_INSUFFICIENT_RESOURCES);
2733     }
2734 
2735     RtlZeroMemory(buffer, length);
2736 
2737     offset.QuadPart =
2738     (Format->StartCylinderNumber * driveMediaConstants->NumberOfHeads +
2739     Format->StartHeadNumber) * driveMediaConstants->SectorsPerTrack *
2740     driveMediaConstants->BytesPerSector;
2741 
2742     //
2743     // Set the event object to the unsignaled state.
2744     // It will be used to signal request completion.
2745     //
2746 
2747     KeInitializeEvent(&event, NotificationEvent, FALSE);
2748 
2749     //
2750     // Build the synchronous request with data transfer.
2751     //
2752 
2753     irp = IoBuildSynchronousFsdRequest(
2754        IRP_MJ_WRITE,
2755        DeviceObject,
2756        buffer,
2757        length,
2758        &offset,
2759        &event,
2760        &ioStatus);
2761 
2762     if (irp != NULL) {
2763         status = IoCallDriver(DeviceObject, irp);
2764 
2765         if (status == STATUS_PENDING) {
2766 
2767             //
2768             // Wait for the request to complete if necessary.
2769             //
2770 
2771             KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
2772         }
2773 
2774         //
2775         // If the call  driver suceeded then set the status to the status block.
2776         //
2777 
2778         if (NT_SUCCESS(status)) {
2779             status = ioStatus.Status;
2780         }
2781     } else {
2782        status = STATUS_INSUFFICIENT_RESOURCES;
2783     }
2784 
2785     ExFreePool(buffer);
2786 
2787     return(status);
2788 
2789 }
2790 
2791 
2792 NTSTATUS
2793 #ifdef __REACTOS__
2794 NTAPI
2795 #endif
2796 ScsiFlopRemoveDevice(
2797     IN PDEVICE_OBJECT DeviceObject,
2798     IN UCHAR Type
2799     )
2800 /*++
2801 
2802 Routine Description:
2803 
2804     This routine is responsible for releasing any resources in use by the
2805     sfloppy driver.  This routine is called
2806     when all outstanding requests have been completed and the driver has
2807     disappeared - no requests may be issued to the lower drivers.
2808 
2809 Arguments:
2810 
2811     DeviceObject - the device object being removed
2812 
2813     Type - the type of remove operation (QUERY, REMOVE or CANCEL)
2814 
2815 Return Value:
2816 
2817     for a query - success if the device can be removed or a failure code
2818                   indiciating why not.
2819 
2820     for a remove or cancel - STATUS_SUCCESS
2821 
2822 --*/
2823 
2824 {
2825     PFUNCTIONAL_DEVICE_EXTENSION deviceExtension =
2826         DeviceObject->DeviceExtension;
2827     PDISK_DATA diskData = deviceExtension->CommonExtension.DriverData;
2828     NTSTATUS status;
2829 
2830     PAGED_CODE();
2831 
2832     if((Type == IRP_MN_QUERY_REMOVE_DEVICE) ||
2833        (Type == IRP_MN_CANCEL_REMOVE_DEVICE)) {
2834         return STATUS_SUCCESS;
2835     }
2836 
2837     if (Type == IRP_MN_REMOVE_DEVICE){
2838         if(deviceExtension->DeviceDescriptor) {
2839             ExFreePool(deviceExtension->DeviceDescriptor);
2840             deviceExtension->DeviceDescriptor = NULL;
2841         }
2842 
2843         if(deviceExtension->AdapterDescriptor) {
2844             ExFreePool(deviceExtension->AdapterDescriptor);
2845             deviceExtension->AdapterDescriptor = NULL;
2846         }
2847 
2848         if(deviceExtension->SenseData) {
2849             ExFreePool(deviceExtension->SenseData);
2850             deviceExtension->SenseData = NULL;
2851         }
2852 
2853         ClassDeleteSrbLookasideList(&deviceExtension->CommonExtension);
2854     }
2855 
2856     if(diskData->FloppyInterfaceString.Buffer != NULL) {
2857 
2858         status = IoSetDeviceInterfaceState(
2859                    &(diskData->FloppyInterfaceString),
2860                    FALSE);
2861 
2862         if (!NT_SUCCESS(status)) {
2863             // Failed to disable device interface during removal. Not a fatal error.
2864             DebugPrint((1, "ScsiFlopRemoveDevice: Unable to set device "
2865                            "interface state to FALSE for fdo %p "
2866                            "[%08lx]\n",
2867                         DeviceObject, status));
2868         }
2869 
2870         RtlFreeUnicodeString(&(diskData->FloppyInterfaceString));
2871         RtlInitUnicodeString(&(diskData->FloppyInterfaceString), NULL);
2872     }
2873 
2874     if(Type == IRP_MN_REMOVE_DEVICE) {
2875         IoGetConfigurationInformation()->FloppyCount--;
2876     }
2877 
2878     return STATUS_SUCCESS;
2879 }
2880 
2881 
2882 NTSTATUS
2883 #ifdef __REACTOS__
2884 NTAPI
2885 #endif
2886 ScsiFlopStopDevice(
2887     IN PDEVICE_OBJECT DeviceObject,
2888     IN UCHAR Type
2889     )
2890 {
2891     UNREFERENCED_PARAMETER(DeviceObject);
2892     UNREFERENCED_PARAMETER(Type);
2893 
2894     return STATUS_SUCCESS;
2895 }
2896 
2897 
2898 NTSTATUS
2899 USBFlopGetMediaTypes(
2900     IN PDEVICE_OBJECT DeviceObject,
2901     IN PIRP           Irp
2902     )
2903 {
2904 /*++
2905 
2906 Routine Description:
2907 
2908     This routines determines the current or default geometry of the drive
2909     for IOCTL_DISK_GET_DRIVE_GEOMETRY, or all currently supported geometries
2910     of the drive (which is determined by its currently inserted media) for
2911     IOCTL_DISK_GET_MEDIA_TYPES.
2912 
2913     The returned geometries are determined by issuing a Read Format Capacities
2914     request and then matching the returned {Number of Blocks, Block Length}
2915     pairs in a table of known floppy geometries.
2916 
2917 Arguments:
2918 
2919     DeviceObject - Supplies the device object.
2920 
2921     Irp - A IOCTL_DISK_GET_DRIVE_GEOMETRY or a IOCTL_DISK_GET_MEDIA_TYPES Irp.
2922           If NULL, the device geometry is updated with the current device
2923           geometry.
2924 
2925 Return Value:
2926 
2927     Status is returned.
2928 
2929 --*/
2930     PFUNCTIONAL_DEVICE_EXTENSION    fdoExtension;
2931     PIO_STACK_LOCATION              irpStack;
2932     ULONG                           ioControlCode;
2933     PDISK_GEOMETRY                  outputBuffer;
2934     PDISK_GEOMETRY                  outputBufferEnd;
2935     ULONG                           outputBufferLength;
2936     PSCSI_REQUEST_BLOCK             srb;
2937     PVOID                           dataBuffer;
2938     ULONG                           dataTransferLength;
2939     struct _READ_FORMATTED_CAPACITIES *cdb;
2940     PFORMATTED_CAPACITY_LIST        capList;
2941     NTSTATUS                        status;
2942 
2943     PAGED_CODE();
2944 
2945     fdoExtension = DeviceObject->DeviceExtension;
2946 
2947     if (Irp != NULL) {
2948 
2949         // Get the Irp parameters
2950         //
2951         irpStack = IoGetCurrentIrpStackLocation(Irp);
2952 
2953         ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
2954 
2955         Irp->IoStatus.Information = 0;
2956 
2957         outputBuffer = (PDISK_GEOMETRY) Irp->AssociatedIrp.SystemBuffer;
2958 
2959         outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
2960 
2961         if (outputBufferLength < sizeof(DISK_GEOMETRY))
2962         {
2963             return STATUS_BUFFER_TOO_SMALL;
2964         }
2965 
2966         // Pointer arithmetic to allow multiple DISK_GEOMETRY's to be returned.
2967         // Rounds BufferEnd down to integral multiple of DISK_GEOMETRY structs.
2968         //
2969         outputBufferEnd = outputBuffer +
2970                           outputBufferLength / sizeof(DISK_GEOMETRY);
2971 
2972     } else {
2973 
2974         // No Irp to return the result in, just update the current geometry
2975         // in the device extension.
2976         //
2977         ioControlCode = IOCTL_DISK_GET_DRIVE_GEOMETRY;
2978 
2979         outputBuffer        = NULL;
2980 
2981         outputBufferEnd     = NULL;
2982 
2983         outputBufferLength  = 0;
2984     }
2985 
2986     if (ioControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY) {
2987 
2988         fdoExtension->DiskGeometry.MediaType = Unknown;
2989 
2990         status = ClassReadDriveCapacity(DeviceObject);
2991 
2992         if (!NT_SUCCESS(status))
2993         {
2994             // If the media is not recongized, we want to return the default
2995             // geometry so that the media can be formatted.  Unrecognized media
2996             // causes SCSI_SENSE_MEDIUM_ERROR, which gets reported as
2997             // STATUS_DEVICE_DATA_ERROR.  Ignore these errors, but return other
2998             // errors, such as STATUS_NO_MEDIA_IN_DEVICE.
2999             //
3000             if (status != STATUS_UNRECOGNIZED_MEDIA)
3001             {
3002                 DebugPrint((2,"IOCTL_DISK_GET_DRIVE_GEOMETRY returns %08X\n", status));
3003 
3004                 return status;
3005             }
3006         }
3007     }
3008 
3009     // Allocate an SRB for the SCSIOP_READ_FORMATTED_CAPACITY request
3010     //
3011     srb = ExAllocatePool(NonPagedPoolNx, SCSI_REQUEST_BLOCK_SIZE);
3012 
3013     if (srb == NULL)
3014     {
3015         return STATUS_INSUFFICIENT_RESOURCES;
3016     }
3017 
3018     // Allocate a transfer buffer for the SCSIOP_READ_FORMATTED_CAPACITY request
3019     // The length of the returned descriptor array is limited to a byte field
3020     // in the capacity list header.
3021     //
3022     dataTransferLength = sizeof(FORMATTED_CAPACITY_LIST) +
3023                          31 * sizeof(FORMATTED_CAPACITY_DESCRIPTOR);
3024 
3025     ASSERT(dataTransferLength < 0x100);
3026 
3027     dataBuffer = ExAllocatePool(NonPagedPoolNx, dataTransferLength);
3028 
3029     if (dataBuffer == NULL)
3030     {
3031         ExFreePool(srb);
3032         return STATUS_INSUFFICIENT_RESOURCES;
3033     }
3034 
3035     // Initialize the SRB and CDB
3036     //
3037     RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
3038 
3039     RtlZeroMemory(dataBuffer, dataTransferLength);
3040 
3041     srb->CdbLength = sizeof(struct _READ_FORMATTED_CAPACITIES);
3042 
3043     srb->TimeOutValue = fdoExtension->TimeOutValue;
3044 
3045     cdb = (struct _READ_FORMATTED_CAPACITIES *)srb->Cdb;
3046 
3047     cdb->OperationCode = SCSIOP_READ_FORMATTED_CAPACITY;
3048     cdb->AllocationLength[1] = (UCHAR)dataTransferLength;
3049 
3050     //
3051     // Send down the SCSIOP_READ_FORMATTED_CAPACITY request
3052     //
3053     status = ClassSendSrbSynchronous(DeviceObject,
3054                                      srb,
3055                                      dataBuffer,
3056                                      dataTransferLength,
3057                                      FALSE);
3058 
3059     capList = (PFORMATTED_CAPACITY_LIST)dataBuffer;
3060 
3061     // If we don't get as much data as requested, it is not an error.
3062     //
3063     if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN)
3064     {
3065         status = STATUS_SUCCESS;
3066     }
3067 
3068     if (NT_SUCCESS(status) &&
3069         srb->DataTransferLength >= sizeof(FORMATTED_CAPACITY_LIST) &&
3070         capList->CapacityListLength &&
3071         capList->CapacityListLength % sizeof(FORMATTED_CAPACITY_DESCRIPTOR) == 0)
3072     {
3073         ULONG   NumberOfBlocks;
3074         ULONG   BlockLength;
3075         ULONG   count;
3076         ULONG   i, j;
3077         LONG    currentGeometry;
3078         BOOLEAN capacityMatches[FLOPPY_CAPACITIES];
3079 
3080         // Subtract the size of the Capacity List Header to get
3081         // just the size of the Capacity List Descriptor array.
3082         //
3083         srb->DataTransferLength -= sizeof(FORMATTED_CAPACITY_LIST);
3084 
3085         // Only look at the Capacity List Descriptors that were actually
3086         // returned.
3087         //
3088         if (srb->DataTransferLength < capList->CapacityListLength)
3089         {
3090             count = srb->DataTransferLength /
3091                     sizeof(FORMATTED_CAPACITY_DESCRIPTOR);
3092         }
3093         else
3094         {
3095             count = capList->CapacityListLength /
3096                     sizeof(FORMATTED_CAPACITY_DESCRIPTOR);
3097         }
3098 
3099         // Updated only if a match is found for the first Capacity List
3100         // Descriptor returned by the device.
3101         //
3102         currentGeometry = -1;
3103 
3104         // Initialize the array of capacities that hit a match.
3105         //
3106         RtlZeroMemory(capacityMatches, sizeof(capacityMatches));
3107 
3108         // Iterate over each Capacity List Descriptor returned from the device
3109         // and record matching capacities in the capacity match array.
3110         //
3111         for (i = 0; i < count; i++)
3112         {
3113             NumberOfBlocks = (capList->Descriptors[i].NumberOfBlocks[0] << 24) +
3114                              (capList->Descriptors[i].NumberOfBlocks[1] << 16) +
3115                              (capList->Descriptors[i].NumberOfBlocks[2] <<  8) +
3116                              (capList->Descriptors[i].NumberOfBlocks[3]);
3117 
3118             BlockLength = (capList->Descriptors[i].BlockLength[0] << 16) +
3119                           (capList->Descriptors[i].BlockLength[1] <<  8) +
3120                           (capList->Descriptors[i].BlockLength[2]);
3121 
3122             // Given the {NumberOfBlocks, BlockLength} from this Capacity List
3123             // Descriptor, find a matching entry in FloppyCapacities[].
3124             //
3125             for (j = 0; j < FLOPPY_CAPACITIES; j++)
3126             {
3127                 if (NumberOfBlocks == FloppyCapacities[j].NumberOfBlocks &&
3128                     BlockLength    == FloppyCapacities[j].BlockLength)
3129                 {
3130                     // A matching capacity was found, record it.
3131                     //
3132                     capacityMatches[j] = TRUE;
3133 
3134                     // A match was found for the first Capacity List
3135                     // Descriptor returned by the device.
3136                     //
3137                     if (i == 0)
3138                     {
3139                         currentGeometry = j;
3140                     }
3141                 } else if ((capList->Descriptors[i].Valid) &&
3142                            (BlockLength == FloppyCapacities[j].BlockLength)) {
3143 
3144                     ULONG inx;
3145                     ULONG mediaInx;
3146 
3147                     //
3148                     // Check if this is 32MB media type. 32MB media
3149                     // reports variable NumberOfBlocks. So we cannot
3150                     // use that to determine the drive type
3151                     //
3152                     inx = DetermineDriveType(DeviceObject);
3153                     if (inx != DRIVE_TYPE_NONE) {
3154                         mediaInx = DriveMediaLimits[inx].HighestDriveMediaType;
3155                         if ((DriveMediaConstants[mediaInx].MediaType)
3156                              == F3_32M_512) {
3157                             capacityMatches[j] = TRUE;
3158 
3159                             if (i == 0) {
3160                                 currentGeometry = j;
3161                             }
3162                         }
3163                     }
3164                 }
3165             }
3166         }
3167 
3168         // Default status is STATUS_UNRECOGNIZED_MEDIA, unless we return
3169         // either STATUS_SUCCESS or STATUS_BUFFER_OVERFLOW.
3170         //
3171         status = STATUS_UNRECOGNIZED_MEDIA;
3172 
3173         if (ioControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY) {
3174 
3175             if (currentGeometry != -1)
3176             {
3177                 // Update the current device geometry
3178                 //
3179                 fdoExtension->DiskGeometry = FloppyGeometries[currentGeometry];
3180 
3181                 //
3182                 // Calculate sector to byte shift.
3183                 //
3184 
3185                 WHICH_BIT(fdoExtension->DiskGeometry.BytesPerSector,
3186                           fdoExtension->SectorShift);
3187 
3188                 fdoExtension->CommonExtension.PartitionLength.QuadPart =
3189                     (LONGLONG)FloppyCapacities[currentGeometry].NumberOfBlocks *
3190                     FloppyCapacities[currentGeometry].BlockLength;
3191 
3192                 DebugPrint((2,"geometry  is: %3d %2d %d %2d %4d  %2d  %08X\n",
3193                             fdoExtension->DiskGeometry.Cylinders.LowPart,
3194                             fdoExtension->DiskGeometry.MediaType,
3195                             fdoExtension->DiskGeometry.TracksPerCylinder,
3196                             fdoExtension->DiskGeometry.SectorsPerTrack,
3197                             fdoExtension->DiskGeometry.BytesPerSector,
3198                             fdoExtension->SectorShift,
3199                             fdoExtension->CommonExtension.PartitionLength.LowPart));
3200 
3201                 // Return the current device geometry
3202                 //
3203                 if (Irp != NULL)
3204                 {
3205                     *outputBuffer = FloppyGeometries[currentGeometry];
3206 
3207                     Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
3208                 }
3209 
3210                 status = STATUS_SUCCESS;
3211             }
3212 
3213         } else {
3214 
3215             // Iterate over the capacities and return the geometry
3216             // corresponding to each matching Capacity List Descriptor
3217             // returned from the device.
3218             //
3219             // The resulting list should be in sorted ascending order,
3220             // assuming that the FloppyGeometries[] array is in sorted
3221             // ascending order.
3222             //
3223             for (i = 0; i < FLOPPY_CAPACITIES; i++)
3224             {
3225                 if (capacityMatches[i] && FloppyCapacities[i].CanFormat)
3226                 {
3227                     if (outputBuffer < outputBufferEnd)
3228                     {
3229                         *outputBuffer++ = FloppyGeometries[i];
3230 
3231                         Irp->IoStatus.Information += sizeof(DISK_GEOMETRY);
3232 
3233                         DebugPrint((2,"geometry    : %3d %2d %d %2d %4d\n",
3234                                     FloppyGeometries[i].Cylinders.LowPart,
3235                                     FloppyGeometries[i].MediaType,
3236                                     FloppyGeometries[i].TracksPerCylinder,
3237                                     FloppyGeometries[i].SectorsPerTrack,
3238                                     FloppyGeometries[i].BytesPerSector));
3239 
3240                         status = STATUS_SUCCESS;
3241                     }
3242                     else
3243                     {
3244                         // We ran out of output buffer room before we ran out
3245                         // geometries to return.
3246                         //
3247                         status = STATUS_BUFFER_OVERFLOW;
3248                     }
3249                 }
3250             }
3251         }
3252     }
3253     else if (NT_SUCCESS(status))
3254     {
3255         // The SCSIOP_READ_FORMATTED_CAPACITY request was successful, but
3256         // returned data does not appear valid.
3257         //
3258         status = STATUS_UNSUCCESSFUL;
3259     }
3260 
3261     ExFreePool(dataBuffer);
3262     ExFreePool(srb);
3263 
3264     return status;
3265 }
3266 
3267 
3268 NTSTATUS
3269 USBFlopFormatTracks(
3270     IN PDEVICE_OBJECT DeviceObject,
3271     IN PIRP           Irp
3272     )
3273 {
3274 /*++
3275 
3276 Routine Description:
3277 
3278     This routines formats the specified tracks.  If multiple tracks are
3279     specified, each is formatted with a separate Format Unit request.
3280 
3281 Arguments:
3282 
3283     DeviceObject - Supplies the device object.
3284 
3285     Irp - A IOCTL_DISK_FORMAT_TRACKS Irp.
3286 
3287 Return Value:
3288 
3289     Status is returned.
3290 
3291 --*/
3292     PFUNCTIONAL_DEVICE_EXTENSION    fdoExtension;
3293     PIO_STACK_LOCATION              irpStack;
3294     PFORMAT_PARAMETERS              formatParameters;
3295     PDISK_GEOMETRY                  geometry;
3296     PFORMATTED_CAPACITY             capacity;
3297     PSCSI_REQUEST_BLOCK             srb;
3298     PFORMAT_UNIT_PARAMETER_LIST     parameterList;
3299     PCDB12FORMAT                    cdb;
3300     ULONG                           i;
3301     ULONG                           cylinder, head;
3302     NTSTATUS                        status = STATUS_SUCCESS;
3303 
3304     PAGED_CODE();
3305 
3306     fdoExtension = DeviceObject->DeviceExtension;
3307 
3308     // Get the Irp parameters
3309     //
3310     irpStack = IoGetCurrentIrpStackLocation(Irp);
3311 
3312     if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
3313         sizeof(FORMAT_PARAMETERS))
3314     {
3315         return STATUS_INVALID_PARAMETER;
3316     }
3317 
3318     formatParameters = (PFORMAT_PARAMETERS)Irp->AssociatedIrp.SystemBuffer;
3319 
3320     // Find the geometry / capacity entries corresponding to the format
3321     // parameters MediaType
3322     //
3323     geometry = NULL;
3324     capacity = NULL;
3325 
3326     for (i=0; i<FLOPPY_CAPACITIES; i++)
3327     {
3328         if (FloppyGeometries[i].MediaType == formatParameters->MediaType)
3329         {
3330             geometry = &FloppyGeometries[i];
3331             capacity = &FloppyCapacities[i];
3332 
3333             break;
3334         }
3335     }
3336 
3337     if (geometry == NULL)
3338     {
3339         return STATUS_INVALID_PARAMETER;
3340     }
3341 
3342     // Check if the format parameters are valid
3343     //
3344     if ((formatParameters->StartCylinderNumber >
3345          geometry->Cylinders.LowPart - 1)       ||
3346 
3347         (formatParameters->EndCylinderNumber >
3348          geometry->Cylinders.LowPart - 1)       ||
3349 
3350         (formatParameters->StartHeadNumber >
3351          geometry->TracksPerCylinder - 1)       ||
3352 
3353         (formatParameters->EndHeadNumber >
3354          geometry->TracksPerCylinder - 1)       ||
3355 
3356         (formatParameters->StartCylinderNumber >
3357          formatParameters->EndCylinderNumber)   ||
3358 
3359         (formatParameters->StartHeadNumber >
3360          formatParameters->EndHeadNumber))
3361     {
3362         return STATUS_INVALID_PARAMETER;
3363     }
3364 
3365     // Don't low level format LS-120 media, Imation says it's best to not
3366     // do this.
3367     //
3368     if ((formatParameters->MediaType == F3_120M_512) ||
3369         (formatParameters->MediaType == F3_240M_512) ||
3370         (formatParameters->MediaType == F3_32M_512))
3371     {
3372         return STATUS_SUCCESS;
3373     }
3374 
3375     // Allocate an SRB for the SCSIOP_FORMAT_UNIT request
3376     //
3377     srb = ExAllocatePool(NonPagedPoolNx, SCSI_REQUEST_BLOCK_SIZE);
3378 
3379     if (srb == NULL)
3380     {
3381         return STATUS_INSUFFICIENT_RESOURCES;
3382     }
3383 
3384     // Allocate a transfer buffer for the SCSIOP_FORMAT_UNIT parameter list
3385     //
3386     parameterList = ExAllocatePool(NonPagedPoolNx,
3387                                    sizeof(FORMAT_UNIT_PARAMETER_LIST));
3388 
3389     if (parameterList == NULL)
3390     {
3391         ExFreePool(srb);
3392         return STATUS_INSUFFICIENT_RESOURCES;
3393     }
3394 
3395     // Initialize the parameter list
3396     //
3397     RtlZeroMemory(parameterList, sizeof(FORMAT_UNIT_PARAMETER_LIST));
3398 
3399     parameterList->DefectListHeader.SingleTrack = 1;
3400     parameterList->DefectListHeader.DisableCert = 1;  // TEAC requires this set
3401     parameterList->DefectListHeader.FormatOptionsValid = 1;
3402     parameterList->DefectListHeader.DefectListLengthLsb = 8;
3403 
3404     parameterList->FormatDescriptor.NumberOfBlocks[0] =
3405         (UCHAR)((capacity->NumberOfBlocks >> 24) & 0xFF);
3406 
3407     parameterList->FormatDescriptor.NumberOfBlocks[1] =
3408         (UCHAR)((capacity->NumberOfBlocks >> 16) & 0xFF);
3409 
3410     parameterList->FormatDescriptor.NumberOfBlocks[2] =
3411         (UCHAR)((capacity->NumberOfBlocks >> 8) & 0xFF);
3412 
3413     parameterList->FormatDescriptor.NumberOfBlocks[3] =
3414         (UCHAR)(capacity->NumberOfBlocks & 0xFF);
3415 
3416     parameterList->FormatDescriptor.BlockLength[0] =
3417         (UCHAR)((capacity->BlockLength >> 16) & 0xFF);
3418 
3419     parameterList->FormatDescriptor.BlockLength[1] =
3420         (UCHAR)((capacity->BlockLength >> 8) & 0xFF);
3421 
3422     parameterList->FormatDescriptor.BlockLength[2] =
3423         (UCHAR)(capacity->BlockLength & 0xFF);
3424 
3425 
3426     for (cylinder =  formatParameters->StartCylinderNumber;
3427          cylinder <= formatParameters->EndCylinderNumber;
3428          cylinder++)
3429     {
3430         for (head =  formatParameters->StartHeadNumber;
3431              head <= formatParameters->EndHeadNumber;
3432              head++)
3433         {
3434             // Initialize the SRB and CDB
3435             //
3436             RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
3437 
3438             srb->CdbLength = sizeof(CDB12FORMAT);
3439 
3440             srb->TimeOutValue = fdoExtension->TimeOutValue;
3441 
3442             cdb = (PCDB12FORMAT)srb->Cdb;
3443 
3444             cdb->OperationCode = SCSIOP_FORMAT_UNIT;
3445             cdb->DefectListFormat = 7;
3446             cdb->FmtData = 1;
3447             cdb->TrackNumber = (UCHAR)cylinder;
3448             cdb->ParameterListLengthLsb = sizeof(FORMAT_UNIT_PARAMETER_LIST);
3449 
3450             parameterList->DefectListHeader.Side = (UCHAR)head;
3451 
3452             //
3453             // Send down the SCSIOP_FORMAT_UNIT request
3454             //
3455             status = ClassSendSrbSynchronous(DeviceObject,
3456                                              srb,
3457                                              parameterList,
3458                                              sizeof(FORMAT_UNIT_PARAMETER_LIST),
3459                                              TRUE);
3460 
3461             if (!NT_SUCCESS(status))
3462             {
3463                 break;
3464             }
3465         }
3466         if (!NT_SUCCESS(status))
3467         {
3468             break;
3469         }
3470     }
3471 
3472     if (NT_SUCCESS(status) && formatParameters->StartCylinderNumber == 0)
3473     {
3474         // Update the device geometry
3475         //
3476 
3477         DebugPrint((2,"geometry was: %3d %2d %d %2d %4d  %2d  %08X\n",
3478                     fdoExtension->DiskGeometry.Cylinders.LowPart,
3479                     fdoExtension->DiskGeometry.MediaType,
3480                     fdoExtension->DiskGeometry.TracksPerCylinder,
3481                     fdoExtension->DiskGeometry.SectorsPerTrack,
3482                     fdoExtension->DiskGeometry.BytesPerSector,
3483                     fdoExtension->SectorShift,
3484                     fdoExtension->CommonExtension.PartitionLength.LowPart));
3485 
3486         fdoExtension->DiskGeometry = *geometry;
3487 
3488         //
3489         // Calculate sector to byte shift.
3490         //
3491 
3492         WHICH_BIT(fdoExtension->DiskGeometry.BytesPerSector,
3493                   fdoExtension->SectorShift);
3494 
3495         fdoExtension->CommonExtension.PartitionLength.QuadPart =
3496             (LONGLONG)capacity->NumberOfBlocks *
3497             capacity->BlockLength;
3498 
3499         DebugPrint((2,"geometry  is: %3d %2d %d %2d %4d  %2d  %08X\n",
3500                     fdoExtension->DiskGeometry.Cylinders.LowPart,
3501                     fdoExtension->DiskGeometry.MediaType,
3502                     fdoExtension->DiskGeometry.TracksPerCylinder,
3503                     fdoExtension->DiskGeometry.SectorsPerTrack,
3504                     fdoExtension->DiskGeometry.BytesPerSector,
3505                     fdoExtension->SectorShift,
3506                     fdoExtension->CommonExtension.PartitionLength.LowPart));
3507     }
3508 
3509     // Free everything we allocated
3510     //
3511     ExFreePool(parameterList);
3512     ExFreePool(srb);
3513 
3514     return status;
3515 }
3516