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