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