ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

disk.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:         ReactOS Storage Stack
00003  * LICENSE:         DDK - see license.txt in the root dir
00004  * FILE:            drivers/storage/disk/disk.c
00005  * PURPOSE:         Disk class driver
00006  * PROGRAMMERS:     Based on a source code sample from Microsoft NT4 DDK
00007  */
00008 
00009 #include <ntddk.h>
00010 #include <ntdddisk.h>
00011 #include <scsi.h>
00012 #include <ntddscsi.h>
00013 #include <mountdev.h>
00014 #include <mountmgr.h>
00015 #include <include/class2.h>
00016 #include <stdio.h>
00017 
00018 #define NDEBUG
00019 #include <debug.h>
00020 
00021 #define IO_WRITE_CACHE_ENABLED  ((NTSTATUS)0x80040020L)
00022 #define IO_WRITE_CACHE_DISABLED ((NTSTATUS)0x80040022L)
00023 
00024 #ifdef POOL_TAGGING
00025 #ifdef ExAllocatePool
00026 #undef ExAllocatePool
00027 #endif
00028 #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'DscS')
00029 #endif
00030 
00031 typedef enum {
00032     NotInitialized,
00033     Initializing,
00034     Initialized
00035 } PARTITION_LIST_STATE;
00036 
00037 //
00038 // Disk device data
00039 //
00040 
00041 typedef struct _DISK_DATA {
00042 
00043     //
00044     // Partition chain
00045     //
00046 
00047     PDEVICE_EXTENSION NextPartition;
00048 
00049     //
00050     // Disk signature (from MBR)
00051     //
00052 
00053     ULONG Signature;
00054 
00055     //
00056     // MBR checksum
00057     //
00058 
00059     ULONG MbrCheckSum;
00060 
00061     //
00062     // Number of hidden sectors for BPB.
00063     //
00064 
00065     ULONG HiddenSectors;
00066 
00067     //
00068     // Partition number of this device object
00069     //
00070     // This field is set during driver initialization or when the partition
00071     // is created to identify a parition to the system.
00072     //
00073 
00074     ULONG PartitionNumber;
00075 
00076     //
00077     // This field is the ordinal of a partition as it appears on a disk.
00078     //
00079 
00080     ULONG PartitionOrdinal;
00081 
00082     //
00083     // Partition type of this device object
00084     //
00085     // This field is set by:
00086     //
00087     //     1)  Initially set according to the partition list entry partition
00088     //         type returned by IoReadPartitionTable.
00089     //
00090     //     2)  Subsequently set by the IOCTL_DISK_SET_PARTITION_INFORMATION
00091     //         I/O control function when IoSetPartitionInformation function
00092     //         successfully updates the partition type on the disk.
00093     //
00094 
00095     UCHAR PartitionType;
00096 
00097     //
00098     // Boot indicator - indicates whether this partition is a bootable (active)
00099     // partition for this device
00100     //
00101     // This field is set according to the partition list entry boot indicator
00102     // returned by IoReadPartitionTable.
00103     //
00104 
00105     BOOLEAN BootIndicator;
00106 
00107     //
00108     // DriveNotReady - inidicates that the this device is currenly not ready
00109     // because there is no media in the device.
00110     //
00111 
00112     BOOLEAN DriveNotReady;
00113 
00114     //
00115     // State of PartitionList initialization
00116     //
00117 
00118     PARTITION_LIST_STATE PartitionListState;
00119 
00120 } DISK_DATA, *PDISK_DATA;
00121 
00122 //
00123 // Define a general structure of identfing disk controllers with bad
00124 // hardware.
00125 //
00126 
00127 typedef struct _BAD_CONTROLLER_INFORMATION {
00128     PCHAR InquiryString;
00129     BOOLEAN DisableTaggedQueuing;
00130     BOOLEAN DisableSynchronousTransfers;
00131     BOOLEAN DisableDisconnects;
00132     BOOLEAN DisableWriteCache;
00133 }BAD_CONTROLLER_INFORMATION, *PBAD_CONTROLLER_INFORMATION;
00134 
00135 BAD_CONTROLLER_INFORMATION const ScsiDiskBadControllers[] = {
00136     { "TOSHIBA MK538FB         60",   TRUE,  FALSE, FALSE, FALSE },
00137     { "CONNER  CP3500",               FALSE, TRUE,  FALSE, FALSE },
00138     { "OLIVETTICP3500",               FALSE, TRUE,  FALSE, FALSE },
00139     { "SyQuest SQ5110          CHC",  TRUE,  TRUE,  FALSE, FALSE },
00140     { "SEAGATE ST41601N        0102", FALSE, TRUE,  FALSE, FALSE },
00141     { "SEAGATE ST3655N",              FALSE, FALSE, FALSE, TRUE  },
00142     { "SEAGATE ST3390N",              FALSE, FALSE, FALSE, TRUE  },
00143     { "SEAGATE ST12550N",             FALSE, FALSE, FALSE, TRUE  },
00144     { "SEAGATE ST32430N",             FALSE, FALSE, FALSE, TRUE  },
00145     { "SEAGATE ST31230N",             FALSE, FALSE, FALSE, TRUE  },
00146     { "SEAGATE ST15230N",             FALSE, FALSE, FALSE, TRUE  },
00147     { "FUJITSU M2652S-512",           TRUE,  FALSE, FALSE, FALSE },
00148     { "MAXTOR  MXT-540SL       I1.2", TRUE,  FALSE, FALSE, FALSE },
00149     { "COMPAQ  PD-1",                 FALSE, TRUE,  FALSE, FALSE }
00150 };
00151 
00152 
00153 #define NUMBER_OF_BAD_CONTROLLERS (sizeof(ScsiDiskBadControllers) / sizeof(BAD_CONTROLLER_INFORMATION))
00154 #define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) + sizeof(DISK_DATA)
00155 
00156 #define MODE_DATA_SIZE      192
00157 #define VALUE_BUFFER_SIZE  2048
00158 #define SCSI_DISK_TIMEOUT    10
00159 #define PARTITION0_LIST_SIZE  4
00160 
00161 
00162 NTSTATUS
00163 NTAPI
00164 DriverEntry(
00165     IN PDRIVER_OBJECT DriverObject,
00166     IN PUNICODE_STRING RegistryPath
00167     );
00168 
00169 BOOLEAN
00170 NTAPI
00171 ScsiDiskDeviceVerification(
00172     IN PINQUIRYDATA InquiryData
00173     );
00174 
00175 BOOLEAN
00176 NTAPI
00177 FindScsiDisks(
00178     IN PDRIVER_OBJECT DriveObject,
00179     IN PUNICODE_STRING RegistryPath,
00180     IN PCLASS_INIT_DATA InitializationData,
00181     IN PDEVICE_OBJECT PortDeviceObject,
00182     IN ULONG PortNumber
00183     );
00184 
00185 NTSTATUS
00186 NTAPI
00187 ScsiDiskCreateClose (
00188     IN PDEVICE_OBJECT DeviceObject,
00189     IN PIRP Irp
00190     );
00191 
00192 NTSTATUS
00193 NTAPI
00194 ScsiDiskReadWriteVerification(
00195     IN PDEVICE_OBJECT DeviceObject,
00196     IN PIRP Irp
00197     );
00198 
00199 NTSTATUS
00200 NTAPI
00201 ScsiDiskDeviceControl(
00202     IN PDEVICE_OBJECT DeviceObject,
00203     IN PIRP Irp
00204     );
00205 
00206 VOID
00207 NTAPI
00208 ScsiDiskProcessError(
00209     PDEVICE_OBJECT DeviceObject,
00210     PSCSI_REQUEST_BLOCK Srb,
00211     NTSTATUS *Status,
00212     BOOLEAN *Retry
00213     );
00214 
00215 NTSTATUS
00216 NTAPI
00217 ScsiDiskShutdownFlush(
00218     IN PDEVICE_OBJECT DeviceObject,
00219     IN PIRP Irp
00220     );
00221 
00222 VOID
00223 NTAPI
00224 DisableWriteCache(
00225     IN PDEVICE_OBJECT DeviceObject,
00226     IN PSCSI_INQUIRY_DATA LunInfo
00227     );
00228 
00229 BOOLEAN
00230 NTAPI
00231 ScsiDiskModeSelect(
00232     IN PDEVICE_OBJECT DeviceObject,
00233     IN PCHAR ModeSelectBuffer,
00234     IN ULONG Length,
00235     IN BOOLEAN SavePage
00236     );
00237 
00238 BOOLEAN
00239 NTAPI
00240 IsFloppyDevice(
00241     IN PDEVICE_OBJECT DeviceObject
00242     );
00243 
00244 BOOLEAN
00245 NTAPI
00246 CalculateMbrCheckSum(
00247     IN PDEVICE_EXTENSION DeviceExtension,
00248     OUT PULONG Checksum
00249     );
00250 
00251 BOOLEAN
00252 NTAPI
00253 EnumerateBusKey(
00254     IN PDEVICE_EXTENSION DeviceExtension,
00255     HANDLE BusKey,
00256     PULONG DiskNumber
00257     );
00258 
00259 VOID
00260 NTAPI
00261 UpdateGeometry(
00262     IN PDEVICE_EXTENSION DeviceExtension
00263     );
00264 
00265 NTSTATUS
00266 NTAPI
00267 UpdateRemovableGeometry (
00268     IN PDEVICE_OBJECT DeviceObject,
00269     IN PIRP Irp
00270     );
00271 
00272 NTSTATUS
00273 NTAPI
00274 CreateDiskDeviceObject(
00275     IN PDRIVER_OBJECT DriverObject,
00276     IN PUNICODE_STRING RegistryPath,
00277     IN PDEVICE_OBJECT PortDeviceObject,
00278     IN ULONG PortNumber,
00279     IN PULONG DeviceCount,
00280     IN PIO_SCSI_CAPABILITIES PortCapabilities,
00281     IN PSCSI_INQUIRY_DATA LunInfo,
00282     IN PCLASS_INIT_DATA InitData
00283     );
00284 
00285 NTSTATUS
00286 NTAPI
00287 CreatePartitionDeviceObjects(
00288     IN PDEVICE_OBJECT PhysicalDeviceObject,
00289     IN PUNICODE_STRING RegistryPath
00290     );
00291 
00292 VOID
00293 NTAPI
00294 UpdateDeviceObjects(
00295     IN PDEVICE_OBJECT DeviceObject,
00296     IN PIRP Irp
00297     );
00298 
00299 VOID
00300 NTAPI
00301 ScanForSpecial(
00302     PDEVICE_OBJECT DeviceObject,
00303     PSCSI_INQUIRY_DATA LunInfo,
00304     PIO_SCSI_CAPABILITIES PortCapabilities
00305     );
00306 
00307 VOID
00308 NTAPI
00309 ResetScsiBus(
00310     IN PDEVICE_OBJECT DeviceObject
00311     );
00312 
00313 #ifdef ALLOC_PRAGMA
00314 #pragma alloc_text(PAGE, DriverEntry)
00315 #pragma alloc_text(PAGE, FindScsiDisks)
00316 #pragma alloc_text(PAGE, CreateDiskDeviceObject)
00317 #pragma alloc_text(PAGE, CalculateMbrCheckSum)
00318 #pragma alloc_text(PAGE, EnumerateBusKey)
00319 #pragma alloc_text(PAGE, UpdateGeometry)
00320 #pragma alloc_text(PAGE, IsFloppyDevice)
00321 #pragma alloc_text(PAGE, ScanForSpecial)
00322 #pragma alloc_text(PAGE, ScsiDiskDeviceControl)
00323 #pragma alloc_text(PAGE, ScsiDiskModeSelect)
00324 #endif
00325 
00326 
00327 NTSTATUS
00328 NTAPI
00329 DriverEntry(
00330     IN PDRIVER_OBJECT DriverObject,
00331     IN PUNICODE_STRING RegistryPath
00332     )
00333 
00334 /*++
00335 
00336 Routine Description:
00337 
00338     This routine initializes the SCSI hard disk class driver.
00339 
00340 Arguments:
00341 
00342     DriverObject - Pointer to driver object created by system.
00343 
00344     RegistryPath - Pointer to the name of the services node for this driver.
00345 
00346 Return Value:
00347 
00348     The function value is the final status from the initialization operation.
00349 
00350 --*/
00351 
00352 {
00353     CLASS_INIT_DATA InitializationData;
00354 
00355     //
00356     // Zero InitData
00357     //
00358 
00359     RtlZeroMemory (&InitializationData, sizeof(CLASS_INIT_DATA));
00360 
00361     //
00362     // Set sizes
00363     //
00364 
00365     InitializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
00366     InitializationData.DeviceExtensionSize = DEVICE_EXTENSION_SIZE;
00367 
00368     InitializationData.DeviceType = FILE_DEVICE_DISK;
00369     InitializationData.DeviceCharacteristics = 0;
00370 
00371     //
00372     // Set entry points
00373     //
00374 
00375     InitializationData.ClassError = ScsiDiskProcessError;
00376     InitializationData.ClassReadWriteVerification = ScsiDiskReadWriteVerification;
00377     InitializationData.ClassFindDevices = FindScsiDisks;
00378     InitializationData.ClassFindDeviceCallBack = ScsiDiskDeviceVerification;
00379     InitializationData.ClassDeviceControl = ScsiDiskDeviceControl;
00380     InitializationData.ClassShutdownFlush = ScsiDiskShutdownFlush;
00381     InitializationData.ClassCreateClose = NULL;
00382 
00383     //
00384     // Call the class init routine
00385     //
00386 
00387     return ScsiClassInitialize( DriverObject, RegistryPath, &InitializationData);
00388 
00389 } // end DriverEntry()
00390 
00391 
00392 
00393 BOOLEAN
00394 NTAPI
00395 ScsiDiskDeviceVerification(
00396     IN PINQUIRYDATA InquiryData
00397     )
00398 
00399 /*++
00400 
00401 Routine Description:
00402 
00403     This routine checks InquiryData for the correct device type and qualifier.
00404 
00405 Arguments:
00406 
00407     InquiryData - Pointer to the inquiry data for the device in question.
00408 
00409 Return Value:
00410 
00411     True is returned if the correct device type is found.
00412 
00413 --*/
00414 {
00415 
00416     if (((InquiryData->DeviceType == DIRECT_ACCESS_DEVICE) ||
00417         (InquiryData->DeviceType == OPTICAL_DEVICE)) &&
00418         InquiryData->DeviceTypeQualifier == 0) {
00419 
00420         return TRUE;
00421 
00422     } else {
00423         return FALSE;
00424     }
00425 }
00426 
00427 
00428 BOOLEAN
00429 NTAPI
00430 FindScsiDisks(
00431     IN PDRIVER_OBJECT DriverObject,
00432     IN PUNICODE_STRING RegistryPath,
00433     IN PCLASS_INIT_DATA InitializationData,
00434     IN PDEVICE_OBJECT PortDeviceObject,
00435     IN ULONG PortNumber
00436     )
00437 
00438 /*++
00439 
00440 Routine Description:
00441 
00442     This routine gets a port drivers capabilities, obtains the
00443     inquiry data, searches the SCSI bus for the port driver and creates
00444     the device objects for the disks found.
00445 
00446 Arguments:
00447 
00448     DriverObject - Pointer to driver object created by system.
00449 
00450     PortDeviceObject - Device object use to send requests to port driver.
00451 
00452     PortNumber - Number for port driver.  Used to pass on to
00453                  CreateDiskDeviceObjects() and create device objects.
00454 
00455 Return Value:
00456 
00457     True is returned if one disk was found and successfully created.
00458 
00459 --*/
00460 
00461 {
00462     PIO_SCSI_CAPABILITIES portCapabilities;
00463     PULONG diskCount;
00464     PCONFIGURATION_INFORMATION configurationInformation;
00465     PCHAR buffer;
00466     PSCSI_INQUIRY_DATA lunInfo;
00467     PSCSI_ADAPTER_BUS_INFO  adapterInfo;
00468     PINQUIRYDATA inquiryData;
00469     ULONG scsiBus;
00470     ULONG adapterDisk;
00471     NTSTATUS status;
00472     BOOLEAN foundOne = FALSE;
00473 
00474     PAGED_CODE();
00475 
00476     //
00477     // Call port driver to get adapter capabilities.
00478     //
00479 
00480     status = ScsiClassGetCapabilities(PortDeviceObject, &portCapabilities);
00481 
00482     if (!NT_SUCCESS(status)) {
00483         DebugPrint((1,"FindScsiDevices: ScsiClassGetCapabilities failed\n"));
00484         return(FALSE);
00485     }
00486 
00487     //
00488     // Call port driver to get inquiry information to find disks.
00489     //
00490 
00491     status = ScsiClassGetInquiryData(PortDeviceObject, (PSCSI_ADAPTER_BUS_INFO *) &buffer);
00492 
00493     if (!NT_SUCCESS(status)) {
00494         DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n"));
00495         return(FALSE);
00496     }
00497 
00498     //
00499     // Do a quick scan of the devices on this adapter to determine how many
00500     // disks are on this adapter.  This is used to determine the number of
00501     // SRB zone elements to allocate.
00502     //
00503 
00504     adapterDisk = 0;
00505     adapterInfo = (PVOID) buffer;
00506 
00507     adapterDisk = ScsiClassFindUnclaimedDevices(InitializationData, adapterInfo);
00508 
00509     //
00510     // Allocate a zone of SRB for disks on this adapter.
00511     //
00512 
00513     if (adapterDisk == 0) {
00514 
00515         //
00516         // No free disks were found.
00517         //
00518 
00519         return(FALSE);
00520     }
00521 
00522     //
00523     // Get the number of disks already initialized.
00524     //
00525 
00526     configurationInformation = IoGetConfigurationInformation();
00527     diskCount = &configurationInformation->DiskCount;
00528 
00529     //
00530     // For each SCSI bus this adapter supports ...
00531     //
00532 
00533     for (scsiBus=0; scsiBus < (ULONG)adapterInfo->NumberOfBuses; scsiBus++) {
00534 
00535         //
00536         // Get the SCSI bus scan data for this bus.
00537         //
00538 
00539         lunInfo = (PVOID) (buffer + adapterInfo->BusData[scsiBus].InquiryDataOffset);
00540 
00541         //
00542         // Search list for unclaimed disk devices.
00543         //
00544 
00545         while (adapterInfo->BusData[scsiBus].InquiryDataOffset) {
00546 
00547             inquiryData = (PVOID)lunInfo->InquiryData;
00548 
00549             if (((inquiryData->DeviceType == DIRECT_ACCESS_DEVICE) ||
00550                 (inquiryData->DeviceType == OPTICAL_DEVICE)) &&
00551                 inquiryData->DeviceTypeQualifier == 0 &&
00552                 (!lunInfo->DeviceClaimed)) {
00553 
00554                 DebugPrint((1,
00555                             "FindScsiDevices: Vendor string is %.24s\n",
00556                             inquiryData->VendorId));
00557 
00558                 //
00559                 // Create device objects for disk
00560                 //
00561 
00562                 status = CreateDiskDeviceObject(DriverObject,
00563                                                 RegistryPath,
00564                                                 PortDeviceObject,
00565                                                 PortNumber,
00566                                                 diskCount,
00567                                                 portCapabilities,
00568                                                 lunInfo,
00569                                                 InitializationData);
00570 
00571                 if (NT_SUCCESS(status)) {
00572 
00573                     //
00574                     // Increment system disk device count.
00575                     //
00576 
00577                     (*diskCount)++;
00578                     foundOne = TRUE;
00579 
00580                 }
00581             }
00582 
00583             //
00584             // Get next LunInfo.
00585             //
00586 
00587             if (lunInfo->NextInquiryDataOffset == 0) {
00588                 break;
00589             }
00590 
00591             lunInfo = (PVOID) (buffer + lunInfo->NextInquiryDataOffset);
00592 
00593         }
00594     }
00595 
00596     //
00597     // Buffer is allocated by ScsiClassGetInquiryData and must be free returning.
00598     //
00599 
00600     ExFreePool(buffer);
00601 
00602     return(foundOne);
00603 
00604 } // end FindScsiDisks()
00605 
00606 
00607 NTSTATUS
00608 NTAPI
00609 CreateDiskDeviceObject(
00610     IN PDRIVER_OBJECT DriverObject,
00611     IN PUNICODE_STRING RegistryPath,
00612     IN PDEVICE_OBJECT PortDeviceObject,
00613     IN ULONG PortNumber,
00614     IN PULONG DeviceCount,
00615     IN PIO_SCSI_CAPABILITIES PortCapabilities,
00616     IN PSCSI_INQUIRY_DATA LunInfo,
00617     IN PCLASS_INIT_DATA InitData
00618     )
00619 
00620 /*++
00621 
00622 Routine Description:
00623 
00624     This routine creates an object for the physical device and then searches
00625     the device for partitions and creates an object for each partition.
00626 
00627 Arguments:
00628 
00629     DriverObject - Pointer to driver object created by system.
00630 
00631     PortDeviceObject - Miniport device object.
00632 
00633     PortNumber   - port number.  Used in creating disk objects.
00634 
00635     DeviceCount  - Number of previously installed devices.
00636 
00637     PortCapabilities - Capabilities of this SCSI port.
00638 
00639     LunInfo      - LUN specific information.
00640 
00641 Return Value:
00642 
00643     NTSTATUS
00644 
00645 --*/
00646 {
00647     CCHAR          ntNameBuffer[MAXIMUM_FILENAME_LENGTH];
00648     STRING         ntNameString;
00649     UNICODE_STRING ntUnicodeString;
00650     OBJECT_ATTRIBUTES objectAttributes;
00651     HANDLE         handle;
00652     NTSTATUS       status;
00653     PDEVICE_OBJECT deviceObject = NULL;
00654     //PDEVICE_OBJECT physicalDevice;
00655     PDISK_GEOMETRY_EX diskGeometry = NULL;
00656     PDEVICE_EXTENSION deviceExtension = NULL;
00657     //PDEVICE_EXTENSION physicalDeviceExtension;
00658     UCHAR          pathId = LunInfo->PathId;
00659     UCHAR          targetId = LunInfo->TargetId;
00660     UCHAR          lun = LunInfo->Lun;
00661     //BOOLEAN        writeCache;
00662     PVOID          senseData = NULL;
00663     //ULONG          srbFlags;
00664     ULONG          timeOut = 0;
00665     BOOLEAN        srbListInitialized = FALSE;
00666 
00667 
00668     PAGED_CODE();
00669 
00670     //
00671     // Set up an object directory to contain the objects for this
00672     // device and all its partitions.
00673     //
00674 
00675     sprintf(ntNameBuffer,
00676             "\\Device\\Harddisk%lu",
00677             *DeviceCount);
00678 
00679     RtlInitString(&ntNameString,
00680                   ntNameBuffer);
00681 
00682     status = RtlAnsiStringToUnicodeString(&ntUnicodeString,
00683                                           &ntNameString,
00684                                           TRUE);
00685 
00686     if (!NT_SUCCESS(status)) {
00687         return(status);
00688     }
00689 
00690     InitializeObjectAttributes(&objectAttributes,
00691                                &ntUnicodeString,
00692                                OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
00693                                NULL,
00694                                NULL);
00695 
00696     status = ZwCreateDirectoryObject(&handle,
00697                                      DIRECTORY_ALL_ACCESS,
00698                                      &objectAttributes);
00699 
00700     RtlFreeUnicodeString(&ntUnicodeString);
00701 
00702     if (!NT_SUCCESS(status)) {
00703 
00704         DebugPrint((1,
00705                     "CreateDiskDeviceObjects: Could not create directory %s\n",
00706                     ntNameBuffer));
00707 
00708         return(status);
00709     }
00710 
00711     //
00712     // Claim the device.
00713     //
00714 
00715     status = ScsiClassClaimDevice(PortDeviceObject,
00716                                   LunInfo,
00717                                   FALSE,
00718                                   &PortDeviceObject);
00719 
00720     if (!NT_SUCCESS(status)) {
00721         ZwMakeTemporaryObject(handle);
00722         ZwClose(handle);
00723         return status;
00724     }
00725 
00726     //
00727     // Create a device object for this device. Each physical disk will
00728     // have at least one device object. The required device object
00729     // describes the entire device. Its directory path is
00730     // \Device\HarddiskN\Partition0, where N = device number.
00731     //
00732 
00733     sprintf(ntNameBuffer,
00734             "\\Device\\Harddisk%lu\\Partition0",
00735             *DeviceCount);
00736 
00737 
00738     status = ScsiClassCreateDeviceObject(DriverObject,
00739                                          ntNameBuffer,
00740                                          NULL,
00741                                          &deviceObject,
00742                                          InitData);
00743 
00744     if (!NT_SUCCESS(status)) {
00745 
00746         DebugPrint((1,
00747                     "CreateDiskDeviceObjects: Can not create device object %s\n",
00748                     ntNameBuffer));
00749 
00750         goto CreateDiskDeviceObjectsExit;
00751     }
00752 
00753     //
00754     // Indicate that IRPs should include MDLs for data transfers.
00755     //
00756 
00757     deviceObject->Flags |= DO_DIRECT_IO;
00758 
00759     //
00760     // Check if this is during initialization. If not indicate that
00761     // system initialization already took place and this disk is ready
00762     // to be accessed.
00763     //
00764 
00765     if (!RegistryPath) {
00766         deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
00767     }
00768 
00769     //
00770     // Check for removable media support.
00771     //
00772 
00773     if (((PINQUIRYDATA)LunInfo->InquiryData)->RemovableMedia) {
00774         deviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
00775     }
00776 
00777     //
00778     // Set up required stack size in device object.
00779     //
00780 
00781     deviceObject->StackSize = (CCHAR)PortDeviceObject->StackSize + 1;
00782 
00783     deviceExtension = deviceObject->DeviceExtension;
00784 
00785     //
00786     // Allocate spinlock for split request completion.
00787     //
00788 
00789     KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock);
00790 
00791     //
00792     // Initialize lock count to zero. The lock count is used to
00793     // disable the ejection mechanism on devices that support
00794     // removable media. Only the lock count in the physical
00795     // device extension is used.
00796     //
00797 
00798     deviceExtension->LockCount = 0;
00799 
00800     //
00801     // Save system disk number.
00802     //
00803 
00804     deviceExtension->DeviceNumber = *DeviceCount;
00805 
00806     //
00807     // Copy port device object pointer to the device extension.
00808     //
00809 
00810     deviceExtension->PortDeviceObject = PortDeviceObject;
00811 
00812     //
00813     // Set the alignment requirements for the device based on the
00814     // host adapter requirements
00815     //
00816 
00817     if (PortDeviceObject->AlignmentRequirement > deviceObject->AlignmentRequirement) {
00818         deviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement;
00819     }
00820 
00821     //
00822     // This is the physical device object.
00823     //
00824 
00825     //physicalDevice = deviceObject;
00826     //physicalDeviceExtension = deviceExtension;
00827 
00828     //
00829     // Save address of port driver capabilities.
00830     //
00831 
00832     deviceExtension->PortCapabilities = PortCapabilities;
00833 
00834     //
00835     // Build the lookaside list for srb's for the physical disk. Should only
00836     // need a couple.
00837     //
00838 
00839     ScsiClassInitializeSrbLookasideList(deviceExtension,
00840                                         PARTITION0_LIST_SIZE);
00841 
00842     srbListInitialized = TRUE;
00843 
00844     //
00845     // Initialize the srb flags.
00846     //
00847 
00848     if (((PINQUIRYDATA)LunInfo->InquiryData)->CommandQueue &&
00849         PortCapabilities->TaggedQueuing) {
00850 
00851         deviceExtension->SrbFlags  = SRB_FLAGS_QUEUE_ACTION_ENABLE;
00852 
00853     } else {
00854 
00855         deviceExtension->SrbFlags  = 0;
00856 
00857     }
00858 
00859     //
00860     // Allow queued requests if this is not removable media.
00861     //
00862 
00863     if (!(deviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
00864 
00865         deviceExtension->SrbFlags |= SRB_FLAGS_NO_QUEUE_FREEZE;
00866 
00867     }
00868 
00869     //
00870     // Look for controller that require special flags.
00871     //
00872 
00873     ScanForSpecial(deviceObject,
00874                     LunInfo,
00875                     PortCapabilities);
00876 
00877     //srbFlags = deviceExtension->SrbFlags;
00878 
00879     //
00880     // Allocate buffer for drive geometry.
00881     //
00882 
00883     diskGeometry = ExAllocatePool(NonPagedPool, sizeof(DISK_GEOMETRY_EX));
00884 
00885     if (diskGeometry == NULL) {
00886 
00887         DebugPrint((1,
00888            "CreateDiskDeviceObjects: Can not allocate disk geometry buffer\n"));
00889         status = STATUS_INSUFFICIENT_RESOURCES;
00890         goto CreateDiskDeviceObjectsExit;
00891     }
00892 
00893     deviceExtension->DiskGeometry = diskGeometry;
00894 
00895     //
00896     // Allocate request sense buffer.
00897     //
00898 
00899     senseData = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
00900 
00901     if (senseData == NULL) {
00902 
00903         //
00904         // The buffer can not be allocated.
00905         //
00906 
00907         DebugPrint((1,
00908            "CreateDiskDeviceObjects: Can not allocate request sense buffer\n"));
00909 
00910         status = STATUS_INSUFFICIENT_RESOURCES;
00911         goto CreateDiskDeviceObjectsExit;
00912     }
00913 
00914     //
00915     // Set the sense data pointer in the device extension.
00916     //
00917 
00918     deviceExtension->SenseData = senseData;
00919 
00920     //
00921     // Physical device object will describe the entire
00922     // device, starting at byte offset 0.
00923     //
00924 
00925     deviceExtension->StartingOffset.QuadPart = (LONGLONG)(0);
00926 
00927     //
00928     // TargetId/LUN describes a device location on the SCSI bus.
00929     // This information comes from the inquiry buffer.
00930     //
00931 
00932     deviceExtension->PortNumber = (UCHAR)PortNumber;
00933     deviceExtension->PathId = pathId;
00934     deviceExtension->TargetId = targetId;
00935     deviceExtension->Lun = lun;
00936 
00937     //
00938     // Set timeout value in seconds.
00939     //
00940 
00941     timeOut = ScsiClassQueryTimeOutRegistryValue(RegistryPath);
00942     if (timeOut) {
00943         deviceExtension->TimeOutValue = timeOut;
00944     } else {
00945         deviceExtension->TimeOutValue = SCSI_DISK_TIMEOUT;
00946     }
00947 
00948     //
00949     // Back pointer to device object.
00950     //
00951 
00952     deviceExtension->DeviceObject = deviceObject;
00953 
00954     //
00955     // If this is a removable device, then make sure it is not a floppy.
00956     // Perform a mode sense command to determine the media type. Note
00957     // IsFloppyDevice also checks for write cache enabled.
00958     //
00959 
00960     if (IsFloppyDevice(deviceObject) && deviceObject->Characteristics & FILE_REMOVABLE_MEDIA &&
00961         (((PINQUIRYDATA)LunInfo->InquiryData)->DeviceType == DIRECT_ACCESS_DEVICE)) {
00962 
00963         status = STATUS_NO_SUCH_DEVICE;
00964         goto CreateDiskDeviceObjectsExit;
00965     }
00966 
00967     DisableWriteCache(deviceObject,LunInfo);
00968 
00969     //writeCache = deviceExtension->DeviceFlags & DEV_WRITE_CACHE;
00970 
00971     //
00972     // NOTE: At this point one device object has been successfully created.
00973     // from here on out return success.
00974     //
00975 
00976     //
00977     // Do READ CAPACITY. This SCSI command
00978     // returns the number of bytes on a device.
00979     // Device extension is updated with device size.
00980     //
00981 
00982     status = ScsiClassReadDriveCapacity(deviceObject);
00983 
00984     //
00985     // If the read capcity failed then just return, unless this is a
00986     // removable disk where a device object partition needs to be created.
00987     //
00988 
00989     if (!NT_SUCCESS(status) &&
00990         !(deviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
00991 
00992         DebugPrint((1,
00993             "CreateDiskDeviceObjects: Can't read capacity for device %s\n",
00994             ntNameBuffer));
00995 
00996         return(STATUS_SUCCESS);
00997 
00998     } else {
00999 
01000         //
01001         // Make sure the volume verification bit is off so that
01002         // IoReadPartitionTable will work.
01003         //
01004 
01005         deviceObject->Flags &= ~DO_VERIFY_VOLUME;
01006     }
01007 
01008     status = CreatePartitionDeviceObjects(deviceObject, RegistryPath);
01009 
01010     if (NT_SUCCESS(status))
01011         return STATUS_SUCCESS;
01012 
01013 
01014 CreateDiskDeviceObjectsExit:
01015 
01016     //
01017     // Release the device since an error occurred.
01018     //
01019 
01020     ScsiClassClaimDevice(PortDeviceObject,
01021                          LunInfo,
01022                          TRUE,
01023                          NULL);
01024 
01025     if (diskGeometry != NULL) {
01026         ExFreePool(diskGeometry);
01027     }
01028 
01029     if (senseData != NULL) {
01030         ExFreePool(senseData);
01031     }
01032 
01033     if (deviceObject != NULL) {
01034 
01035         if (srbListInitialized) {
01036             ExDeleteNPagedLookasideList(&deviceExtension->SrbLookasideListHead);
01037         }
01038 
01039         IoDeleteDevice(deviceObject);
01040     }
01041 
01042     //
01043     // Delete directory and return.
01044     //
01045 
01046     if (!NT_SUCCESS(status)) {
01047         ZwMakeTemporaryObject(handle);
01048     }
01049 
01050     ZwClose(handle);
01051 
01052     return(status);
01053 
01054 } // end CreateDiskDeviceObjects()
01055 
01056 
01057 NTSTATUS
01058 NTAPI
01059 CreatePartitionDeviceObjects(
01060     IN PDEVICE_OBJECT PhysicalDeviceObject,
01061     IN PUNICODE_STRING RegistryPath
01062     )
01063 {
01064     CCHAR          ntNameBuffer[MAXIMUM_FILENAME_LENGTH];
01065     ULONG          partitionNumber = 0;
01066     NTSTATUS       status;
01067     PDEVICE_OBJECT deviceObject = NULL;
01068     PDISK_GEOMETRY_EX diskGeometry = NULL;
01069     PDRIVE_LAYOUT_INFORMATION partitionList = NULL;
01070     PDEVICE_EXTENSION deviceExtension;
01071     PDEVICE_EXTENSION physicalDeviceExtension;
01072     PCLASS_INIT_DATA initData = NULL;
01073     PDISK_DATA     diskData;
01074     PDISK_DATA     physicalDiskData;
01075     ULONG          bytesPerSector;
01076     UCHAR          sectorShift;
01077     ULONG          srbFlags;
01078     ULONG          dmByteSkew = 0;
01079     PULONG         dmSkew;
01080     BOOLEAN        dmActive = FALSE;
01081     ULONG          numberListElements = 0;
01082 
01083 
01084     //
01085     // Get physical device geometry information for partition table reads.
01086     //
01087 
01088     physicalDeviceExtension = PhysicalDeviceObject->DeviceExtension;
01089     diskGeometry = physicalDeviceExtension->DiskGeometry;
01090     bytesPerSector = diskGeometry->Geometry.BytesPerSector;
01091 
01092     //
01093     // Make sure sector size is not zero.
01094     //
01095 
01096     if (bytesPerSector == 0) {
01097 
01098         //
01099         // Default sector size for disk is 512.
01100         //
01101 
01102         bytesPerSector = diskGeometry->Geometry.BytesPerSector = 512;
01103     }
01104 
01105     sectorShift = physicalDeviceExtension->SectorShift;
01106 
01107     //
01108     // Set pointer to disk data area that follows device extension.
01109     //
01110 
01111     diskData = (PDISK_DATA)(physicalDeviceExtension + 1);
01112     diskData->PartitionListState = Initializing;
01113 
01114     //
01115     // Determine is DM Driver is loaded on an IDE drive that is
01116     // under control of Atapi - this could be either a crashdump or
01117     // an Atapi device is sharing the controller with an IDE disk.
01118     //
01119 
01120     HalExamineMBR(PhysicalDeviceObject,
01121                   physicalDeviceExtension->DiskGeometry->Geometry.BytesPerSector,
01122                   (ULONG)0x54,
01123                   (PVOID)&dmSkew);
01124 
01125     if (dmSkew) {
01126 
01127         //
01128         // Update the device extension, so that the call to IoReadPartitionTable
01129         // will get the correct information. Any I/O to this disk will have
01130         // to be skewed by *dmSkew sectors aka DMByteSkew.
01131         //
01132 
01133         physicalDeviceExtension->DMSkew = *dmSkew;
01134         physicalDeviceExtension->DMActive = TRUE;
01135         physicalDeviceExtension->DMByteSkew = physicalDeviceExtension->DMSkew * bytesPerSector;
01136 
01137         //
01138         // Save away the infomation that we need, since this deviceExtension will soon be
01139         // blown away.
01140         //
01141 
01142         dmActive = TRUE;
01143         dmByteSkew = physicalDeviceExtension->DMByteSkew;
01144 
01145     }
01146 
01147     //
01148     // Create objects for all the partitions on the device.
01149     //
01150 
01151     status = IoReadPartitionTable(PhysicalDeviceObject,
01152                                   physicalDeviceExtension->DiskGeometry->Geometry.BytesPerSector,
01153                                   TRUE,
01154                                   (PVOID)&partitionList);
01155 
01156     //
01157     // If the I/O read partition table failed and this is a removable device,
01158     // then fix up the partition list to make it look like there is one
01159     // zero length partition.
01160     //
01161     DPRINT("IoReadPartitionTable() status: 0x%08X\n", status);
01162     if ((!NT_SUCCESS(status) || partitionList->PartitionCount == 0) &&
01163         PhysicalDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
01164 
01165         if (!NT_SUCCESS(status)) {
01166 
01167             //
01168             // Remember this disk is not ready.
01169             //
01170 
01171             diskData->DriveNotReady = TRUE;
01172 
01173         } else {
01174 
01175             //
01176             // Free the partition list allocated by IoReadPartitionTable.
01177             //
01178 
01179             ExFreePool(partitionList);
01180         }
01181 
01182         //
01183         // Allocate and zero a partition list.
01184         //
01185 
01186         partitionList = ExAllocatePool(NonPagedPool, sizeof(*partitionList ));
01187 
01188 
01189         if (partitionList != NULL) {
01190 
01191             RtlZeroMemory( partitionList, sizeof( *partitionList ));
01192 
01193             //
01194             // Set the partition count to one and the status to success
01195             // so one device object will be created. Set the partition type
01196             // to a bogus value.
01197             //
01198 
01199             partitionList->PartitionCount = 1;
01200 
01201             status = STATUS_SUCCESS;
01202         }
01203     }
01204 
01205     if (NT_SUCCESS(status)) {
01206 
01207         //
01208         // Record disk signature.
01209         //
01210 
01211         diskData->Signature = partitionList->Signature;
01212 
01213         //
01214         // If disk signature is zero, then calculate the MBR checksum.
01215         //
01216 
01217         if (!diskData->Signature) {
01218 
01219             if (!CalculateMbrCheckSum(physicalDeviceExtension,
01220                                       &diskData->MbrCheckSum)) {
01221 
01222                 DebugPrint((1,
01223                             "SCSIDISK: Can't calculate MBR checksum for disk %x\n",
01224                             physicalDeviceExtension->DeviceNumber));
01225             } else {
01226 
01227                 DebugPrint((2,
01228                            "SCSIDISK: MBR checksum for disk %x is %x\n",
01229                            physicalDeviceExtension->DeviceNumber,
01230                            diskData->MbrCheckSum));
01231             }
01232         }
01233 
01234         //
01235         // Check the registry and determine if the BIOS knew about this drive.  If
01236         // it did then update the geometry with the BIOS information.
01237         //
01238 
01239         UpdateGeometry(physicalDeviceExtension);
01240 
01241         srbFlags = physicalDeviceExtension->SrbFlags;
01242 
01243         initData = ExAllocatePool(NonPagedPool, sizeof(CLASS_INIT_DATA));
01244         if (!initData)
01245         {
01246             DebugPrint((1,
01247                         "Disk.CreatePartionDeviceObjects - Allocation of initData failed\n"));
01248 
01249             status = STATUS_INSUFFICIENT_RESOURCES;
01250             goto CreatePartitionDeviceObjectsExit;
01251         }
01252 
01253         RtlZeroMemory(initData, sizeof(CLASS_INIT_DATA));
01254 
01255         initData->InitializationDataSize     = sizeof(CLASS_INIT_DATA);
01256         initData->DeviceExtensionSize        = DEVICE_EXTENSION_SIZE;
01257         initData->DeviceType                 = FILE_DEVICE_DISK;
01258         initData->DeviceCharacteristics      = PhysicalDeviceObject->Characteristics;
01259         initData->ClassError                 = physicalDeviceExtension->ClassError;
01260         initData->ClassReadWriteVerification = physicalDeviceExtension->ClassReadWriteVerification;
01261         initData->ClassFindDevices           = physicalDeviceExtension->ClassFindDevices;
01262         initData->ClassDeviceControl         = physicalDeviceExtension->ClassDeviceControl;
01263         initData->ClassShutdownFlush         = physicalDeviceExtension->ClassShutdownFlush;
01264         initData->ClassCreateClose           = physicalDeviceExtension->ClassCreateClose;
01265         initData->ClassStartIo               = physicalDeviceExtension->ClassStartIo;
01266 
01267         //
01268         // Create device objects for the device partitions (if any).
01269         // PartitionCount includes physical device partition 0,
01270         // so only one partition means no objects to create.
01271         //
01272 
01273         DebugPrint((2,
01274                     "CreateDiskDeviceObjects: Number of partitions is %d\n",
01275                     partitionList->PartitionCount));
01276 
01277         for (partitionNumber = 0; partitionNumber <
01278             partitionList->PartitionCount; partitionNumber++) {
01279 
01280             //
01281             // Create partition object and set up partition parameters.
01282             //
01283 
01284             sprintf(ntNameBuffer,
01285                     "\\Device\\Harddisk%lu\\Partition%lu",
01286                     physicalDeviceExtension->DeviceNumber,
01287                     partitionNumber + 1);
01288 
01289             DebugPrint((2,
01290                         "CreateDiskDeviceObjects: Create device object %s\n",
01291                         ntNameBuffer));
01292 
01293             status = ScsiClassCreateDeviceObject(PhysicalDeviceObject->DriverObject,
01294                                                  ntNameBuffer,
01295                                                  PhysicalDeviceObject,
01296                                                  &deviceObject,
01297                                                  initData);
01298 
01299             if (!NT_SUCCESS(status)) {
01300 
01301                 DebugPrint((1, "CreateDiskDeviceObjects: Can't create device object for %s\n", ntNameBuffer));
01302 
01303                 break;
01304             }
01305 
01306             //
01307             // Set up device object fields.
01308             //
01309 
01310             deviceObject->Flags |= DO_DIRECT_IO;
01311 
01312             //
01313             // Check if this is during initialization. If not indicate that
01314             // system initialization already took place and this disk is ready
01315             // to be accessed.
01316             //
01317 
01318             if (!RegistryPath) {
01319                 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
01320             }
01321 
01322             deviceObject->StackSize = (CCHAR)physicalDeviceExtension->PortDeviceObject->StackSize + 1;
01323 
01324             //
01325             // Set up device extension fields.
01326             //
01327 
01328             deviceExtension = deviceObject->DeviceExtension;
01329 
01330             if (dmActive) {
01331 
01332                 //
01333                 // Restore any saved DM values.
01334                 //
01335 
01336                 deviceExtension->DMByteSkew = dmByteSkew;
01337                 deviceExtension->DMSkew     = *dmSkew;
01338                 deviceExtension->DMActive   = TRUE;
01339 
01340             }
01341 
01342             //
01343             // Link new device extension to previous disk data
01344             // to support dynamic partitioning.
01345             //
01346 
01347             diskData->NextPartition = deviceExtension;
01348 
01349             //
01350             // Get pointer to new disk data.
01351             //
01352 
01353             diskData = (PDISK_DATA)(deviceExtension + 1);
01354 
01355             //
01356             // Set next partition pointer to NULL in case this is the
01357             // last partition.
01358             //
01359 
01360             diskData->NextPartition = NULL;
01361 
01362             //
01363             // Allocate spinlock for zoning for split-request completion.
01364             //
01365 
01366             KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock);
01367 
01368             //
01369             // Copy port device object pointer to device extension.
01370             //
01371 
01372             deviceExtension->PortDeviceObject = physicalDeviceExtension->PortDeviceObject;
01373 
01374             //
01375             // Set the alignment requirements for the device based on the
01376             // host adapter requirements
01377             //
01378 
01379             if (physicalDeviceExtension->PortDeviceObject->AlignmentRequirement > deviceObject->AlignmentRequirement) {
01380                 deviceObject->AlignmentRequirement = physicalDeviceExtension->PortDeviceObject->AlignmentRequirement;
01381             }
01382 
01383 
01384             if (srbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) {
01385                 numberListElements = 30;
01386             } else {
01387                 numberListElements = 8;
01388             }
01389 
01390             //
01391             // Build the lookaside list for srb's for this partition based on
01392             // whether the adapter and disk can do tagged queueing.
01393             //
01394 
01395             ScsiClassInitializeSrbLookasideList(deviceExtension,
01396                                                 numberListElements);
01397 
01398             deviceExtension->SrbFlags = srbFlags;
01399 
01400             //
01401             // Set the sense-data pointer in the device extension.
01402             //
01403 
01404             deviceExtension->SenseData        = physicalDeviceExtension->SenseData;
01405             deviceExtension->PortCapabilities = physicalDeviceExtension->PortCapabilities;
01406             deviceExtension->DiskGeometry     = diskGeometry;
01407             diskData->PartitionOrdinal        = diskData->PartitionNumber = partitionNumber + 1;
01408             diskData->PartitionType           = partitionList->PartitionEntry[partitionNumber].PartitionType;
01409             diskData->BootIndicator           = partitionList->PartitionEntry[partitionNumber].BootIndicator;
01410 
01411             DebugPrint((2, "CreateDiskDeviceObjects: Partition type is %x\n",
01412                 diskData->PartitionType));
01413 
01414             deviceExtension->StartingOffset  = partitionList->PartitionEntry[partitionNumber].StartingOffset;
01415             deviceExtension->PartitionLength = partitionList->PartitionEntry[partitionNumber].PartitionLength;
01416             diskData->HiddenSectors          = partitionList->PartitionEntry[partitionNumber].HiddenSectors;
01417             deviceExtension->PortNumber      = physicalDeviceExtension->PortNumber;
01418             deviceExtension->PathId          = physicalDeviceExtension->PathId;
01419             deviceExtension->TargetId        = physicalDeviceExtension->TargetId;
01420             deviceExtension->Lun             = physicalDeviceExtension->Lun;
01421 
01422             //
01423             // Check for removable media support.
01424             //
01425 
01426             if (PhysicalDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
01427                 deviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
01428             }
01429 
01430             //
01431             // Set timeout value in seconds.
01432             //
01433 
01434             deviceExtension->TimeOutValue = physicalDeviceExtension->TimeOutValue;
01435             deviceExtension->DiskGeometry->Geometry.BytesPerSector = bytesPerSector;
01436             deviceExtension->SectorShift  = sectorShift;
01437             deviceExtension->DeviceObject = deviceObject;
01438             deviceExtension->DeviceFlags |= physicalDeviceExtension->DeviceFlags;
01439 
01440         } // end for (partitionNumber) ...
01441 
01442         //
01443         // Free the buffer allocated by reading the
01444         // partition table.
01445         //
01446 
01447         ExFreePool(partitionList);
01448 
01449     } else {
01450 
01451 CreatePartitionDeviceObjectsExit:
01452 
01453         if (partitionList) {
01454             ExFreePool(partitionList);
01455         }
01456         if (initData) {
01457             ExFreePool(initData);
01458         }
01459 
01460         return status;
01461 
01462     } // end if...else
01463 
01464 
01465     physicalDiskData = (PDISK_DATA)(physicalDeviceExtension + 1);
01466     physicalDiskData->PartitionListState = Initialized;
01467 
01468     return(STATUS_SUCCESS);
01469 
01470 
01471 } // end CreatePartitionDeviceObjects()
01472 
01473 
01474 NTSTATUS
01475 NTAPI
01476 ScsiDiskReadWriteVerification(
01477     IN PDEVICE_OBJECT DeviceObject,
01478     IN PIRP Irp
01479     )
01480 
01481 /*++
01482 
01483 Routine Description:
01484 
01485     I/O System entry for read and write requests to SCSI disks.
01486 
01487 Arguments:
01488 
01489     DeviceObject - Pointer to driver object created by system.
01490     Irp - IRP involved.
01491 
01492 Return Value:
01493 
01494     NT Status
01495 
01496 --*/
01497 
01498 {
01499     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
01500     PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
01501     ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
01502     LARGE_INTEGER startingOffset;
01503 
01504     //
01505     // Verify parameters of this request.
01506     // Check that ending sector is within partition and
01507     // that number of bytes to transfer is a multiple of
01508     // the sector size.
01509     //
01510 
01511     startingOffset.QuadPart = (currentIrpStack->Parameters.Read.ByteOffset.QuadPart +
01512                                transferByteCount);
01513 
01514     if ((startingOffset.QuadPart > deviceExtension->PartitionLength.QuadPart) ||
01515         (transferByteCount & (deviceExtension->DiskGeometry->Geometry.BytesPerSector - 1))) {
01516 
01517         //
01518         // This error maybe caused by the fact that the drive is not ready.
01519         //
01520 
01521         if (((PDISK_DATA)(deviceExtension + 1))->DriveNotReady) {
01522 
01523             //
01524             // Flag this as a user errror so that a popup is generated.
01525             //
01526 
01527             Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
01528             IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
01529 
01530         } else {
01531 
01532             //
01533             // Note fastfat depends on this parameter to determine when to
01534             // remount do to a sector size change.
01535             //
01536 
01537             Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
01538         }
01539 
01540         return STATUS_INVALID_PARAMETER;
01541     }
01542 
01543     return STATUS_SUCCESS;
01544 
01545 } // end ScsiDiskReadWrite()
01546 
01547 
01548 NTSTATUS
01549 NTAPI
01550 ScsiDiskDeviceControl(
01551     PDEVICE_OBJECT DeviceObject,
01552     PIRP Irp
01553     )
01554 
01555 /*++
01556 
01557 Routine Description:
01558 
01559     I/O system entry for device controls to SCSI disks.
01560 
01561 Arguments:
01562 
01563     DeviceObject - Pointer to driver object created by system.
01564     Irp - IRP involved.
01565 
01566 Return Value:
01567 
01568     Status is returned.
01569 
01570 --*/
01571 
01572 {
01573     PIO_STACK_LOCATION     irpStack = IoGetCurrentIrpStackLocation(Irp);
01574     PDEVICE_EXTENSION      deviceExtension = DeviceObject->DeviceExtension;
01575     PDISK_DATA             diskData = (PDISK_DATA)(deviceExtension + 1);
01576     PSCSI_REQUEST_BLOCK    srb;
01577     PCDB                   cdb;
01578     PMODE_PARAMETER_HEADER modeData;
01579     PIRP                   irp2;
01580     ULONG                  length;
01581     NTSTATUS               status;
01582     KEVENT                 event;
01583     IO_STATUS_BLOCK        ioStatus;
01584 
01585     PAGED_CODE();
01586 
01587     srb = ExAllocatePool(NonPagedPool, SCSI_REQUEST_BLOCK_SIZE);
01588 
01589     if (srb == NULL) {
01590 
01591         Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
01592         IoCompleteRequest(Irp, IO_NO_INCREMENT);
01593         return(STATUS_INSUFFICIENT_RESOURCES);
01594     }
01595 
01596     //
01597     // Write zeros to Srb.
01598     //
01599 
01600     RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
01601 
01602     cdb = (PCDB)srb->Cdb;
01603 
01604     switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
01605 
01606     case SMART_GET_VERSION: {
01607 
01608         ULONG_PTR buffer;
01609         PSRB_IO_CONTROL  srbControl;
01610         PGETVERSIONINPARAMS versionParams;
01611 
01612         if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
01613             sizeof(GETVERSIONINPARAMS)) {
01614                 status = STATUS_INVALID_PARAMETER;
01615                 break;
01616         }
01617 
01618         //
01619         // Create notification event object to be used to signal the
01620         // request completion.
01621         //
01622 
01623         KeInitializeEvent(&event, NotificationEvent, FALSE);
01624 
01625         srbControl = ExAllocatePool(NonPagedPool,
01626                                     sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS));
01627 
01628         if (!srbControl) {
01629             status =  STATUS_INSUFFICIENT_RESOURCES;
01630             break;
01631         }
01632 
01633         //
01634         // fill in srbControl fields
01635         //
01636 
01637         srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
01638         RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
01639         srbControl->Timeout = deviceExtension->TimeOutValue;
01640         srbControl->Length = sizeof(GETVERSIONINPARAMS);
01641         srbControl->ControlCode = IOCTL_SCSI_MINIPORT_SMART_VERSION;
01642 
01643         //
01644         // Point to the 'buffer' portion of the SRB_CONTROL
01645         //
01646 
01647         buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
01648 
01649         //
01650         // Ensure correct target is set in the cmd parameters.
01651         //
01652 
01653         versionParams = (PGETVERSIONINPARAMS)buffer;
01654         versionParams->bIDEDeviceMap = deviceExtension->TargetId;
01655 
01656         //
01657         // Copy the IOCTL parameters to the srb control buffer area.
01658         //
01659 
01660         RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(GETVERSIONINPARAMS));
01661 
01662 
01663         irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
01664                                             deviceExtension->PortDeviceObject,
01665                                             srbControl,
01666                                             sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS),
01667                                             srbControl,
01668                                             sizeof(SRB_IO_CONTROL) + sizeof(GETVERSIONINPARAMS),
01669                                             FALSE,
01670                                             &event,
01671                                             &ioStatus);
01672 
01673         if (irp2 == NULL) {
01674             status = STATUS_INSUFFICIENT_RESOURCES;
01675             break;
01676         }
01677 
01678         //
01679         // Call the port driver with the request and wait for it to complete.
01680         //
01681 
01682         status = IoCallDriver(deviceExtension->PortDeviceObject, irp2);
01683 
01684         if (status == STATUS_PENDING) {
01685             KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
01686             status = ioStatus.Status;
01687         }
01688 
01689         //
01690         // If successful, copy the data received into the output buffer.
01691         // This should only fail in the event that the IDE driver is older than this driver.
01692         //
01693 
01694         if (NT_SUCCESS(status)) {
01695 
01696             buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
01697 
01698             RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, sizeof(GETVERSIONINPARAMS));
01699             Irp->IoStatus.Information = sizeof(GETVERSIONINPARAMS);
01700         }
01701 
01702         ExFreePool(srbControl);
01703         break;
01704     }
01705 
01706     case SMART_RCV_DRIVE_DATA: {
01707 
01708         PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer);
01709         ULONG            controlCode = 0;
01710         PSRB_IO_CONTROL  srbControl;
01711         ULONG_PTR        buffer;
01712 
01713         if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
01714             (sizeof(SENDCMDINPARAMS) - 1)) {
01715                 status = STATUS_INVALID_PARAMETER;
01716                 break;
01717 
01718         } else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
01719             (sizeof(SENDCMDOUTPARAMS) + 512 - 1)) {
01720                 status = STATUS_INVALID_PARAMETER;
01721                 break;
01722         }
01723 
01724         //
01725         // Create notification event object to be used to signal the
01726         // request completion.
01727         //
01728 
01729         KeInitializeEvent(&event, NotificationEvent, FALSE);
01730 
01731         if (cmdInParameters->irDriveRegs.bCommandReg == ID_CMD) {
01732 
01733             length = IDENTIFY_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
01734             controlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;
01735 
01736         } else if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) {
01737             switch (cmdInParameters->irDriveRegs.bFeaturesReg) {
01738                 case READ_ATTRIBUTES:
01739                     controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS;
01740                     length = READ_ATTRIBUTE_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
01741                     break;
01742                 case READ_THRESHOLDS:
01743                     controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS;
01744                     length = READ_THRESHOLD_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS);
01745                     break;
01746                 default:
01747                     status = STATUS_INVALID_PARAMETER;
01748                     break;
01749             }
01750         } else {
01751 
01752             status = STATUS_INVALID_PARAMETER;
01753         }
01754 
01755         if (controlCode == 0) {
01756             status = STATUS_INVALID_PARAMETER;
01757             break;
01758         }
01759 
01760         srbControl = ExAllocatePool(NonPagedPool,
01761                                     sizeof(SRB_IO_CONTROL) + length);
01762 
01763         if (!srbControl) {
01764             status =  STATUS_INSUFFICIENT_RESOURCES;
01765             break;
01766         }
01767 
01768         //
01769         // fill in srbControl fields
01770         //
01771 
01772         srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
01773         RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
01774         srbControl->Timeout = deviceExtension->TimeOutValue;
01775         srbControl->Length = length;
01776         srbControl->ControlCode = controlCode;
01777 
01778         //
01779         // Point to the 'buffer' portion of the SRB_CONTROL
01780         //
01781 
01782         buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
01783 
01784         //
01785         // Ensure correct target is set in the cmd parameters.
01786         //
01787 
01788         cmdInParameters->bDriveNumber = deviceExtension->TargetId;
01789 
01790         //
01791         // Copy the IOCTL parameters to the srb control buffer area.
01792         //
01793 
01794         RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1);
01795 
01796         irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
01797                                             deviceExtension->PortDeviceObject,
01798                                             srbControl,
01799                                             sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1,
01800                                             srbControl,
01801                                             sizeof(SRB_IO_CONTROL) + length,
01802                                             FALSE,
01803                                             &event,
01804                                             &ioStatus);
01805 
01806         if (irp2 == NULL) {
01807             status = STATUS_INSUFFICIENT_RESOURCES;
01808             break;
01809         }
01810 
01811         //
01812         // Call the port driver with the request and wait for it to complete.
01813         //
01814 
01815         status = IoCallDriver(deviceExtension->PortDeviceObject, irp2);
01816 
01817         if (status == STATUS_PENDING) {
01818             KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
01819             status = ioStatus.Status;
01820         }
01821 
01822         //
01823         // If successful, copy the data received into the output buffer
01824         //
01825 
01826         buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
01827 
01828         if (NT_SUCCESS(status)) {
01829 
01830             RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, length - 1);
01831             Irp->IoStatus.Information = length - 1;
01832 
01833         } else {
01834 
01835             RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, (sizeof(SENDCMDOUTPARAMS) - 1));
01836             Irp->IoStatus.Information = sizeof(SENDCMDOUTPARAMS) - 1;
01837 
01838         }
01839 
01840         ExFreePool(srbControl);
01841         break;
01842 
01843     }
01844 
01845     case SMART_SEND_DRIVE_COMMAND: {
01846 
01847         PSENDCMDINPARAMS cmdInParameters = ((PSENDCMDINPARAMS)Irp->AssociatedIrp.SystemBuffer);
01848         PSRB_IO_CONTROL  srbControl;
01849         ULONG            controlCode = 0;
01850         ULONG_PTR        buffer;
01851 
01852         if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
01853                (sizeof(SENDCMDINPARAMS) - 1)) {
01854                 status = STATUS_INVALID_PARAMETER;
01855                 break;
01856 
01857         } else if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
01858                       (sizeof(SENDCMDOUTPARAMS) - 1)) {
01859                 status = STATUS_INVALID_PARAMETER;
01860                 break;
01861         }
01862 
01863         //
01864         // Create notification event object to be used to signal the
01865         // request completion.
01866         //
01867 
01868         KeInitializeEvent(&event, NotificationEvent, FALSE);
01869 
01870         length = 0;
01871 
01872         if (cmdInParameters->irDriveRegs.bCommandReg == SMART_CMD) {
01873             switch (cmdInParameters->irDriveRegs.bFeaturesReg) {
01874 
01875                 case ENABLE_SMART:
01876                     controlCode = IOCTL_SCSI_MINIPORT_ENABLE_SMART;
01877                     break;
01878 
01879                 case DISABLE_SMART:
01880                     controlCode = IOCTL_SCSI_MINIPORT_DISABLE_SMART;
01881                     break;
01882 
01883                 case  RETURN_SMART_STATUS:
01884 
01885                     //
01886                     // Ensure bBuffer is at least 2 bytes (to hold the values of
01887                     // cylinderLow and cylinderHigh).
01888                     //
01889 
01890                     if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
01891                         (sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS))) {
01892 
01893                         status = STATUS_INVALID_PARAMETER;
01894                         break;
01895                     }
01896 
01897                     controlCode = IOCTL_SCSI_MINIPORT_RETURN_STATUS;
01898                     length = sizeof(IDEREGS);
01899                     break;
01900 
01901                 case ENABLE_DISABLE_AUTOSAVE:
01902                     controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE;
01903                     break;
01904 
01905                 case SAVE_ATTRIBUTE_VALUES:
01906                     controlCode = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES;
01907                     break;
01908 
01909                 case EXECUTE_OFFLINE_DIAGS:
01910                     controlCode = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS;
01911                     break;
01912       
01913           default:
01914                     status = STATUS_INVALID_PARAMETER;
01915                     break;
01916             }
01917         } else {
01918 
01919             status = STATUS_INVALID_PARAMETER;
01920         }
01921 
01922         if (controlCode == 0) {
01923             status = STATUS_INVALID_PARAMETER;
01924             break;
01925         }
01926 
01927         length += (sizeof(SENDCMDOUTPARAMS) > sizeof(SENDCMDINPARAMS)) ? sizeof(SENDCMDOUTPARAMS) : sizeof(SENDCMDINPARAMS);
01928         srbControl = ExAllocatePool(NonPagedPool,
01929                                     sizeof(SRB_IO_CONTROL) + length);
01930 
01931         if (!srbControl) {
01932             status =  STATUS_INSUFFICIENT_RESOURCES;
01933             break;
01934         }
01935 
01936         //
01937         // fill in srbControl fields
01938         //
01939 
01940         srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
01941         RtlMoveMemory (srbControl->Signature, "SCSIDISK", 8);
01942         srbControl->Timeout = deviceExtension->TimeOutValue;
01943         srbControl->Length = length;
01944 
01945         //
01946         // Point to the 'buffer' portion of the SRB_CONTROL
01947         //
01948 
01949         buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
01950 
01951         //
01952         // Ensure correct target is set in the cmd parameters.
01953         //
01954 
01955         cmdInParameters->bDriveNumber = deviceExtension->TargetId;
01956 
01957         //
01958         // Copy the IOCTL parameters to the srb control buffer area.
01959         //
01960 
01961         RtlMoveMemory((PVOID)buffer, Irp->AssociatedIrp.SystemBuffer, sizeof(SENDCMDINPARAMS) - 1);
01962 
01963         srbControl->ControlCode = controlCode;
01964 
01965         irp2 = IoBuildDeviceIoControlRequest(IOCTL_SCSI_MINIPORT,
01966                                             deviceExtension->PortDeviceObject,
01967                                             srbControl,
01968                                             sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1,
01969                                             srbControl,
01970                                             sizeof(SRB_IO_CONTROL) + length,
01971                                             FALSE,
01972                                             &event,
01973                                             &ioStatus);
01974 
01975         if (irp2 == NULL) {
01976             status = STATUS_INSUFFICIENT_RESOURCES;
01977             break;
01978         }
01979 
01980         //
01981         // Call the port driver with the request and wait for it to complete.
01982         //
01983 
01984         status = IoCallDriver(deviceExtension->PortDeviceObject, irp2);
01985 
01986         if (status == STATUS_PENDING) {
01987             KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
01988             status = ioStatus.Status;
01989         }
01990 
01991         //
01992         // Copy the data received into the output buffer. Since the status buffer
01993         // contains error information also, always perform this copy. IO will will
01994         // either pass this back to the app, or zero it, in case of error.
01995         //
01996 
01997         buffer = (ULONG_PTR)srbControl + srbControl->HeaderLength;
01998 
01999         //
02000         // Update the return buffer size based on the sub-command.
02001         //
02002 
02003         if (cmdInParameters->irDriveRegs.bFeaturesReg == RETURN_SMART_STATUS) {
02004             length = sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS);
02005         } else {
02006             length = sizeof(SENDCMDOUTPARAMS) - 1;
02007         }
02008 
02009         RtlMoveMemory ( Irp->AssociatedIrp.SystemBuffer, (PVOID)buffer, length);
02010         Irp->IoStatus.Information = length;
02011 
02012         ExFreePool(srbControl);
02013         break;
02014 
02015     }
02016 
02017     case IOCTL_DISK_GET_DRIVE_GEOMETRY:
02018     case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX:
02019         {
02020 
02021         PDEVICE_EXTENSION physicalDeviceExtension;
02022         PDISK_DATA        physicalDiskData;
02023         BOOLEAN           removable = FALSE;
02024         BOOLEAN           listInitialized = FALSE;
02025 
02026         if ((irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY &&
02027              irpStack->Parameters.DeviceIoControl.OutputBufferLength <
02028             sizeof(DISK_GEOMETRY)) ||
02029              (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY_EX &&
02030              irpStack->Parameters.DeviceIoControl.OutputBufferLength <
02031             sizeof(DISK_GEOMETRY_EX))) {
02032 
02033             status = STATUS_INFO_LENGTH_MISMATCH;
02034             break;
02035         }
02036 
02037         status = STATUS_SUCCESS;
02038 
02039         physicalDeviceExtension = deviceExtension->PhysicalDevice->DeviceExtension;
02040         physicalDiskData = (PDISK_DATA)(physicalDeviceExtension + 1);
02041 
02042         removable = (BOOLEAN)DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA;
02043         listInitialized = (physicalDiskData->PartitionListState == Initialized);
02044 
02045         if (removable || (!listInitialized))
02046         {
02047             //
02048             // Issue ReadCapacity to update device extension
02049             // with information for current media.
02050             //
02051 
02052             status = ScsiClassReadDriveCapacity(deviceExtension->PhysicalDevice);
02053 
02054         }
02055 
02056         if (removable) {
02057 
02058             if (!NT_SUCCESS(status)) {
02059 
02060                 //
02061                 // Note the drive is not ready.
02062                 //
02063 
02064                 diskData->DriveNotReady = TRUE;
02065 
02066                 break;
02067             }
02068 
02069             //
02070             // Note the drive is now ready.
02071             //
02072 
02073             diskData->DriveNotReady = FALSE;
02074 
02075         } else if (NT_SUCCESS(status)) {
02076 
02077             // ReadDriveCapacity was allright, create Partition Objects
02078 
02079             if (physicalDiskData->PartitionListState == NotInitialized) {
02080                     status = CreatePartitionDeviceObjects(deviceExtension->PhysicalDevice, NULL);
02081             }
02082         }
02083 
02084         if (NT_SUCCESS(status)) {
02085 
02086             //
02087             // Copy drive geometry information from device extension.
02088             //
02089 
02090             RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
02091                           deviceExtension->DiskGeometry,
02092                           (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY) ?
02093                           sizeof(DISK_GEOMETRY) : 
02094                           sizeof(DISK_GEOMETRY_EX));
02095 
02096             status = STATUS_SUCCESS;
02097             Irp->IoStatus.Information =
02098                (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY) ?
02099                sizeof(DISK_GEOMETRY) : 
02100                sizeof(DISK_GEOMETRY_EX);
02101         }
02102 
02103         break;
02104 
02105         }
02106 
02107     case IOCTL_DISK_VERIFY:
02108 
02109         {
02110 
02111         PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer;
02112         LARGE_INTEGER byteOffset;
02113         ULONG         sectorOffset;
02114         USHORT        sectorCount;
02115 
02116         //
02117         // Validate buffer length.
02118         //
02119 
02120         if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
02121             sizeof(VERIFY_INFORMATION)) {
02122 
02123             status = STATUS_INFO_LENGTH_MISMATCH;
02124             break;
02125         }
02126 
02127         //
02128         // Verify sectors
02129         //
02130 
02131         srb->CdbLength = 10;
02132 
02133         cdb->CDB10.OperationCode = SCSIOP_VERIFY;
02134 
02135         //
02136         // Add disk offset to starting sector.
02137         //
02138 
02139         byteOffset.QuadPart = deviceExtension->StartingOffset.QuadPart +
02140                                         verifyInfo->StartingOffset.QuadPart;
02141 
02142         //
02143         // Convert byte offset to sector offset.
02144         //
02145 
02146         sectorOffset = (ULONG)(byteOffset.QuadPart >> deviceExtension->SectorShift);
02147 
02148         //
02149         // Convert ULONG byte count to USHORT sector count.
02150         //
02151 
02152         sectorCount = (USHORT)(verifyInfo->Length >> deviceExtension->SectorShift);
02153 
02154         //
02155         // Move little endian values into CDB in big endian format.
02156         //
02157 
02158         cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&sectorOffset)->Byte3;
02159         cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&sectorOffset)->Byte2;
02160         cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&sectorOffset)->Byte1;
02161         cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&sectorOffset)->Byte0;
02162 
02163         cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&sectorCount)->Byte1;
02164         cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&sectorCount)->Byte0;
02165 
02166         //
02167         // The verify command is used by the NT FORMAT utility and
02168         // requests are sent down for 5% of the volume size. The
02169         // request timeout value is calculated based on the number of
02170         // sectors verified.
02171         //
02172 
02173         srb->TimeOutValue = ((sectorCount + 0x7F) >> 7) *
02174                                               deviceExtension->TimeOutValue;
02175 
02176         status = ScsiClassSendSrbAsynchronous(DeviceObject,
02177                                               srb,
02178                                               Irp,
02179                                               NULL,
02180                                               0,
02181                                               FALSE);
02182 
02183         return(status);
02184 
02185         }
02186 
02187     case IOCTL_DISK_GET_PARTITION_INFO:
02188 
02189         //
02190         // Return the information about the partition specified by the device
02191         // object.  Note that no information is ever returned about the size
02192         // or partition type of the physical disk, as this doesn't make any
02193         // sense.
02194         //
02195 
02196         if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
02197             sizeof(PARTITION_INFORMATION)) {
02198 
02199             status = STATUS_INFO_LENGTH_MISMATCH;
02200 
02201         }
02202 #if 0 // HACK: ReactOS partition numbers must be wrong
02203         else if (diskData->PartitionNumber == 0) {
02204 
02205             //
02206             // Paritition zero is not a partition so this is not a
02207             // reasonable request.
02208             //
02209 
02210             status = STATUS_INVALID_DEVICE_REQUEST;
02211 
02212         }
02213 #endif
02214         else {
02215 
02216             PPARTITION_INFORMATION outputBuffer;
02217 
02218             //
02219             // Update the geometry in case it has changed.
02220             //
02221 
02222             status = UpdateRemovableGeometry (DeviceObject, Irp);
02223 
02224             if (!NT_SUCCESS(status)) {
02225 
02226                 //
02227                 // Note the drive is not ready.
02228                 //
02229 
02230                 diskData->DriveNotReady = TRUE;
02231                 break;
02232             }
02233 
02234             //
02235             // Note the drive is now ready.
02236             //
02237 
02238             diskData->DriveNotReady = FALSE;
02239 // HACK: ReactOS partition numbers must be wrong (>0 part)
02240             if (diskData->PartitionType == 0 && (diskData->PartitionNumber > 0)) {
02241 
02242                 status = STATUS_INVALID_DEVICE_REQUEST;
02243                 break;
02244             }
02245 
02246             outputBuffer =
02247                     (PPARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
02248 
02249             outputBuffer->PartitionType = diskData->PartitionType;
02250             outputBuffer->StartingOffset = deviceExtension->StartingOffset;
02251             outputBuffer->PartitionLength.QuadPart = (diskData->PartitionNumber) ?
02252                 deviceExtension->PartitionLength.QuadPart : 2305843009213693951LL; // HACK
02253             outputBuffer->HiddenSectors = diskData->HiddenSectors;
02254             outputBuffer->PartitionNumber = diskData->PartitionNumber;
02255             outputBuffer->BootIndicator = diskData->BootIndicator;
02256             outputBuffer->RewritePartition = FALSE;
02257             outputBuffer->RecognizedPartition =
02258                 IsRecognizedPartition(diskData->PartitionType);
02259 
02260             status = STATUS_SUCCESS;
02261             Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
02262         }
02263 
02264         break;
02265 
02266     case IOCTL_DISK_GET_PARTITION_INFO_EX:
02267 
02268         //
02269         // Return the information about the partition specified by the device
02270         // object.  Note that no information is ever returned about the size
02271         // or partition type of the physical disk, as this doesn't make any
02272         // sense.
02273         //
02274 
02275         if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
02276             sizeof(PARTITION_INFORMATION_EX)) {
02277 
02278             status = STATUS_INFO_LENGTH_MISMATCH;
02279 
02280         }
02281         else if (diskData->PartitionNumber == 0) {
02282 
02283             //
02284             // Paritition zero is not a partition so this is not a
02285             // reasonable request.
02286             //
02287 
02288             status = STATUS_INVALID_DEVICE_REQUEST;
02289 
02290         }
02291         else {
02292 
02293             PPARTITION_INFORMATION_EX outputBuffer;
02294 
02295             //
02296             // Update the geometry in case it has changed.
02297             //
02298 
02299             status = UpdateRemovableGeometry (DeviceObject, Irp);
02300 
02301             if (!NT_SUCCESS(status)) {
02302 
02303                 //
02304                 // Note the drive is not ready.
02305                 //
02306 
02307                 diskData->DriveNotReady = TRUE;
02308                 break;
02309             }
02310 
02311             //
02312             // Note the drive is now ready.
02313             //
02314 
02315             diskData->DriveNotReady = FALSE;
02316 
02317             if (diskData->PartitionType == 0 && (diskData->PartitionNumber > 0)) {
02318 
02319                 status = STATUS_INVALID_DEVICE_REQUEST;
02320                 break;
02321             }
02322 
02323             outputBuffer =
02324                     (PPARTITION_INFORMATION_EX)Irp->AssociatedIrp.SystemBuffer;
02325 
02326             //
02327             // FIXME: hack of the year, assume that partition is MBR
02328             // Thing that can obviously be wrong...
02329             //
02330 
02331             outputBuffer->PartitionStyle = PARTITION_STYLE_MBR;
02332             outputBuffer->Mbr.PartitionType = diskData->PartitionType;
02333             outputBuffer->StartingOffset = deviceExtension->StartingOffset;
02334             outputBuffer->PartitionLength.QuadPart = deviceExtension->PartitionLength.QuadPart;
02335             outputBuffer->Mbr.HiddenSectors = diskData->HiddenSectors;
02336             outputBuffer->PartitionNumber = diskData->PartitionNumber;
02337             outputBuffer->Mbr.BootIndicator = diskData->BootIndicator;
02338             outputBuffer->RewritePartition = FALSE;
02339             outputBuffer->Mbr.RecognizedPartition =
02340                 IsRecognizedPartition(diskData->PartitionType);
02341 
02342             status = STATUS_SUCCESS;
02343             Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION_EX);
02344         }
02345 
02346         break;
02347 
02348     case IOCTL_DISK_SET_PARTITION_INFO:
02349 
02350         if (diskData->PartitionNumber == 0) {
02351 
02352             status = STATUS_UNSUCCESSFUL;
02353 
02354         } else {
02355 
02356             PSET_PARTITION_INFORMATION inputBuffer =
02357                 (PSET_PARTITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
02358 
02359             //
02360             // Validate buffer length.
02361             //
02362 
02363             if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
02364                 sizeof(SET_PARTITION_INFORMATION)) {
02365 
02366                 status = STATUS_INFO_LENGTH_MISMATCH;
02367                 break;
02368             }
02369 
02370             //
02371             // The HAL routines IoGet- and IoSetPartitionInformation were
02372             // developed before support of dynamic partitioning and therefore
02373             // don't distinguish between partition ordinal (that is the order
02374             // of a partition on a disk) and the partition number. (The
02375             // partition number is assigned to a partition to identify it to
02376             // the system.) Use partition ordinals for these legacy calls.
02377             //
02378 
02379             status = IoSetPartitionInformation(
02380                           deviceExtension->PhysicalDevice,
02381                           deviceExtension->DiskGeometry->Geometry.BytesPerSector,
02382                           diskData->PartitionOrdinal,
02383                           inputBuffer->PartitionType);
02384 
02385             if (NT_SUCCESS(status)) {
02386 
02387                 diskData->PartitionType = inputBuffer->PartitionType;
02388             }
02389         }
02390 
02391         break;
02392 
02393     case IOCTL_DISK_GET_DRIVE_LAYOUT:
02394 
02395         //
02396         // Return the partition layout for the physical drive.  Note that
02397         // the layout is returned for the actual physical drive, regardless
02398         // of which partition was specified for the request.
02399         //
02400 
02401         if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
02402             sizeof(DRIVE_LAYOUT_INFORMATION)) {
02403             status = STATUS_INFO_LENGTH_MISMATCH;
02404 
02405         } else {
02406 
02407             PDRIVE_LAYOUT_INFORMATION partitionList;
02408             PDEVICE_EXTENSION         physicalExtension = deviceExtension;
02409             PPARTITION_INFORMATION    partitionEntry;
02410             PDISK_DATA                diskData;
02411             ULONG                     tempSize;
02412             ULONG                     i;
02413 
02414             //
02415             // Read partition information.
02416             //
02417 
02418             status = IoReadPartitionTable(deviceExtension->PhysicalDevice,
02419                               deviceExtension->DiskGeometry->Geometry.BytesPerSector,
02420                               FALSE,
02421                               &partitionList);
02422 
02423             if (!NT_SUCCESS(status)) {
02424                 break;
02425             }
02426 
02427             //
02428             // The disk layout has been returned in the partitionList
02429             // buffer.  Determine its size and, if the data will fit
02430             // into the intermediatery buffer, return it.
02431             //
02432 
02433             tempSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION,PartitionEntry[0]);
02434             tempSize += partitionList->PartitionCount *
02435                         sizeof(PARTITION_INFORMATION);
02436 
02437             if (tempSize >
02438                irpStack->Parameters.DeviceIoControl.OutputBufferLength) {
02439 
02440                 status = STATUS_BUFFER_TOO_SMALL;
02441                 ExFreePool(partitionList);
02442                 break;
02443             }
02444 
02445             //
02446             // Walk partition list to associate partition numbers with
02447             // partition entries.
02448             //
02449 
02450             for (i = 0; i < partitionList->PartitionCount; i++) {
02451 
02452                 //
02453                 // Walk partition chain anchored at physical disk extension.
02454                 //
02455 
02456                 deviceExtension = physicalExtension;
02457                 diskData = (PDISK_DATA)(deviceExtension + 1);
02458 
02459                 do {
02460 
02461                     deviceExtension = diskData->NextPartition;
02462 
02463                     //
02464                     // Check if this is the last partition in the chain.
02465                     //
02466 
02467                     if (!deviceExtension) {
02468                        break;
02469                     }
02470 
02471                     //
02472                     // Get the partition device extension from disk data.
02473                     //
02474 
02475                     diskData = (PDISK_DATA)(deviceExtension + 1);
02476 
02477                     //
02478                     // Check if this partition is not currently being used.
02479                     //
02480 
02481                     if (!deviceExtension->PartitionLength.QuadPart) {
02482                        continue;
02483                     }
02484 
02485                     partitionEntry = &partitionList->PartitionEntry[i];
02486 
02487                     //
02488                     // Check if empty, or describes extended partiton or hasn't changed.
02489                     //
02490 
02491                     if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
02492                         IsContainerPartition(partitionEntry->PartitionType)) {
02493                         continue;
02494                     }
02495 
02496                     //
02497                     // Check if new partition starts where this partition starts.
02498                     //
02499 
02500                     if (partitionEntry->StartingOffset.QuadPart !=
02501                               deviceExtension->StartingOffset.QuadPart) {
02502                         continue;
02503                     }
02504 
02505                     //
02506                     // Check if partition length is the same.
02507                     //
02508 
02509                     if (partitionEntry->PartitionLength.QuadPart ==
02510                               deviceExtension->PartitionLength.QuadPart) {
02511 
02512                         //
02513                         // Partitions match. Update partition number.
02514                         //
02515 
02516                         partitionEntry->PartitionNumber =
02517                             diskData->PartitionNumber;
02518                         break;
02519                     }
02520 
02521                 } while (TRUE);
02522             }
02523 
02524             //
02525             // Copy partition information to system buffer.
02526             //
02527 
02528             RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
02529                           partitionList,
02530                           tempSize);
02531             status = STATUS_SUCCESS;
02532             Irp->IoStatus.Information = tempSize;
02533 
02534             //
02535             // Finally, free the buffer allocated by reading the
02536             // partition table.
02537             //
02538 
02539             ExFreePool(partitionList);
02540         }
02541 
02542         break;
02543 
02544     case IOCTL_DISK_SET_DRIVE_LAYOUT:
02545 
02546         {
02547 
02548         //
02549         // Update the disk with new partition information.
02550         //
02551 
02552         PDRIVE_LAYOUT_INFORMATION partitionList = Irp->AssociatedIrp.SystemBuffer;
02553 
02554         //
02555         // Validate buffer length.
02556         //
02557 
02558         if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
02559             sizeof(DRIVE_LAYOUT_INFORMATION)) {
02560 
02561             status = STATUS_INFO_LENGTH_MISMATCH;
02562             break;
02563         }
02564 
02565         length = sizeof(DRIVE_LAYOUT_INFORMATION) +
02566             (partitionList->PartitionCount - 1) * sizeof(PARTITION_INFORMATION);
02567 
02568 
02569         if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
02570             length) {
02571 
02572             status = STATUS_BUFFER_TOO_SMALL;
02573             break;
02574         }
02575 
02576         //
02577         // Verify that device object is for physical disk.
02578         //
02579 
02580         if (deviceExtension->PhysicalDevice->DeviceExtension != deviceExtension) {
02581             status = STATUS_INVALID_PARAMETER;
02582             break;
02583         }
02584 
02585         //
02586         // Walk through partition table comparing partitions to
02587         // existing partitions to create, delete and change
02588         // device objects as necessary.
02589         //
02590 
02591         UpdateDeviceObjects(DeviceObject,
02592                             Irp);
02593 
02594         //
02595         // Write changes to disk.
02596         //
02597 
02598         status = IoWritePartitionTable(
02599                            deviceExtension->DeviceObject,
02600                            deviceExtension->DiskGeometry->Geometry.BytesPerSector,
02601                            deviceExtension->DiskGeometry->Geometry.SectorsPerTrack,
02602                            deviceExtension->DiskGeometry->Geometry.TracksPerCylinder,
02603                            partitionList);
02604         }
02605 
02606         //
02607         // Update IRP with bytes returned.
02608         //
02609 
02610         if (NT_SUCCESS(status)) {
02611             Irp->IoStatus.Information = length;
02612         }
02613 
02614         break;
02615 
02616     case IOCTL_DISK_REASSIGN_BLOCKS:
02617 
02618         //
02619         // Map defective blocks to new location on disk.
02620         //
02621 
02622         {
02623 
02624         PREASSIGN_BLOCKS badBlocks = Irp->AssociatedIrp.SystemBuffer;
02625         ULONG bufferSize;
02626         ULONG blockNumber;
02627         ULONG blockCount;
02628 
02629         //
02630         // Validate buffer length.
02631         //
02632 
02633         if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
02634             sizeof(REASSIGN_BLOCKS)) {
02635 
02636             status = STATUS_INFO_LENGTH_MISMATCH;
02637             break;
02638         }
02639 
02640         bufferSize = sizeof(REASSIGN_BLOCKS) +
02641             (badBlocks->Count - 1) * sizeof(ULONG);
02642 
02643         if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
02644             bufferSize) {
02645 
02646             status = STATUS_INFO_LENGTH_MISMATCH;
02647             break;
02648         }
02649 
02650         //
02651         // Build the data buffer to be transferred in the input buffer.
02652         // The format of the data to the device is:
02653         //
02654         //      2 bytes Reserved
02655         //      2 bytes Length
02656         //      x * 4 btyes Block Address
02657         //
02658         // All values are big endian.
02659         //
02660 
02661         badBlocks->Reserved = 0;
02662         blockCount = badBlocks->Count;
02663 
02664         //
02665         // Convert # of entries to # of bytes.
02666         //
02667 
02668         blockCount *= 4;
02669         badBlocks->Count = (USHORT) ((blockCount >> 8) & 0XFF);
02670         badBlocks->Count |= (USHORT) ((blockCount << 8) & 0XFF00);
02671 
02672         //
02673         // Convert back to number of entries.
02674         //
02675 
02676         blockCount /= 4;
02677 
02678         for (; blockCount > 0; blockCount--) {
02679 
02680             blockNumber = badBlocks->BlockNumber[blockCount-1];
02681 
02682             REVERSE_BYTES((PFOUR_BYTE) &badBlocks->BlockNumber[blockCount-1],
02683                           (PFOUR_BYTE) &blockNumber);
02684         }
02685 
02686         srb->CdbLength = 6;
02687 
02688         cdb->CDB6GENERIC.OperationCode = SCSIOP_REASSIGN_BLOCKS;
02689 
02690         //
02691         // Set timeout value.
02692         //
02693 
02694         srb->TimeOutValue = deviceExtension->TimeOutValue;
02695 
02696         status = ScsiClassSendSrbSynchronous(DeviceObject,
02697                                              srb,
02698                                              badBlocks,
02699                                              bufferSize,
02700                                              TRUE);
02701 
02702         Irp->IoStatus.Status = status;
02703         Irp->IoStatus.Information = 0;
02704         ExFreePool(srb);
02705         IoCompleteRequest(Irp, IO_DISK_INCREMENT);
02706         }
02707 
02708         return(status);
02709 
02710     case IOCTL_DISK_IS_WRITABLE:
02711 
02712         //
02713         // Determine if the device is writable.
02714         //
02715 
02716         modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
02717 
02718         if (modeData == NULL) {
02719             status = STATUS_INSUFFICIENT_RESOURCES;
02720             break;
02721         }
02722 
02723         RtlZeroMemory(modeData, MODE_DATA_SIZE);
02724 
02725         length = ScsiClassModeSense(DeviceObject,
02726                                     (PCHAR) modeData,
02727                                     MODE_DATA_SIZE,
02728                                     MODE_SENSE_RETURN_ALL);
02729 
02730         if (length < sizeof(MODE_PARAMETER_HEADER)) {
02731 
02732             //
02733             // Retry the request in case of a check condition.
02734             //
02735 
02736             length = ScsiClassModeSense(DeviceObject,
02737                                         (PCHAR) modeData,
02738                                         MODE_DATA_SIZE,
02739                                         MODE_SENSE_RETURN_ALL);
02740 
02741             if (length < sizeof(MODE_PARAMETER_HEADER)) {
02742                 status = STATUS_IO_DEVICE_ERROR;
02743                 ExFreePool(modeData);
02744                 break;
02745             }
02746         }
02747 
02748         if (modeData->DeviceSpecificParameter & MODE_DSP_WRITE_PROTECT) {
02749             status = STATUS_MEDIA_WRITE_PROTECTED;
02750         } else {
02751             status = STATUS_SUCCESS;
02752         }
02753 
02754         ExFreePool(modeData);
02755         break;
02756 
02757     case IOCTL_DISK_INTERNAL_SET_VERIFY:
02758 
02759         //
02760         // If the caller is kernel mode, set the verify bit.
02761         //
02762 
02763         if (Irp->RequestorMode == KernelMode) {
02764             DeviceObject->Flags |= DO_VERIFY_VOLUME;
02765         }
02766         status = STATUS_SUCCESS;
02767         break;
02768 
02769     case IOCTL_DISK_INTERNAL_CLEAR_VERIFY:
02770 
02771         //
02772         // If the caller is kernel mode, clear the verify bit.
02773         //
02774 
02775         if (Irp->RequestorMode == KernelMode) {
02776             DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
02777         }
02778         status = STATUS_SUCCESS;
02779         break;
02780 
02781     case IOCTL_DISK_FIND_NEW_DEVICES:
02782 
02783         //
02784         // Search for devices that have been powered on since the last
02785         // device search or system initialization.
02786         //
02787 
02788         DebugPrint((3,"CdRomDeviceControl: Find devices\n"));
02789         status = DriverEntry(DeviceObject->DriverObject,
02790                              NULL);
02791 
02792         Irp->IoStatus.Status = status;
02793         ExFreePool(srb);
02794         IoCompleteRequest(Irp, IO_NO_INCREMENT);
02795         return status;
02796 
02797     case IOCTL_DISK_MEDIA_REMOVAL:
02798 
02799         //
02800         // If the disk is not removable then don't allow this command.
02801         //
02802 
02803         if (!(DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
02804             status = STATUS_INVALID_DEVICE_REQUEST;
02805             break;
02806         }
02807 
02808         //
02809         // Fall through and let the class driver process the request.
02810         //
02811 
02812     case IOCTL_DISK_GET_LENGTH_INFO:
02813 
02814         //
02815         // Validate buffer length.
02816         //
02817 
02818         if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
02819             sizeof(GET_LENGTH_INFORMATION)) {
02820             status = STATUS_BUFFER_TOO_SMALL;
02821 
02822         } else {
02823 
02824             PGET_LENGTH_INFORMATION lengthInformation = Irp->AssociatedIrp.SystemBuffer;
02825 
02826             //
02827             // Update the geometry in case it has changed.
02828             //
02829 
02830             status = UpdateRemovableGeometry (DeviceObject, Irp);
02831 
02832             if (!NT_SUCCESS(status)) {
02833 
02834                 //
02835                 // Note the drive is not ready.
02836                 //
02837 
02838                 diskData->DriveNotReady = TRUE;
02839                 break;
02840             }
02841 
02842             //
02843             // Note the drive is now ready.
02844             //
02845 
02846             diskData->DriveNotReady = FALSE;
02847 
02848             //
02849             // Output data, and return
02850             //
02851 
02852             lengthInformation->Length.QuadPart = deviceExtension->PartitionLength.QuadPart;
02853             status = STATUS_SUCCESS;
02854             Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
02855         }
02856 
02857         break;
02858 
02859     default:
02860 
02861         //
02862         // Free the Srb, since it is not needed.
02863         //
02864 
02865         ExFreePool(srb);
02866 
02867         //
02868         // Pass the request to the common device control routine.
02869         //
02870 
02871         return(ScsiClassDeviceControl(DeviceObject, Irp));
02872 
02873         break;
02874 
02875     } // end switch( ...
02876 
02877     Irp->IoStatus.Status = status;
02878 
02879     if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
02880 
02881         IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
02882     }
02883 
02884     IoCompleteRequest(Irp, IO_NO_INCREMENT);
02885     ExFreePool(srb);
02886     return(status);
02887 
02888 } // end ScsiDiskDeviceControl()
02889 
02890 NTSTATUS
02891 NTAPI
02892 ScsiDiskShutdownFlush (
02893     IN PDEVICE_OBJECT DeviceObject,
02894     IN PIRP Irp
02895     )
02896 
02897 /*++
02898 
02899 Routine Description:
02900 
02901     This routine is called for a shutdown and flush IRPs.  These are sent by the
02902     system before it actually shuts down or when the file system does a flush.
02903     A synchronize cache command is sent to the device if it is write caching.
02904     If the device is removable an unlock command will be sent. This routine
02905     will sent a shutdown or flush Srb to the port driver.
02906 
02907 Arguments:
02908 
02909     DriverObject - Pointer to device object to being shutdown by system.
02910 
02911     Irp - IRP involved.
02912 
02913 Return Value:
02914 
02915     NT Status
02916 
02917 --*/
02918 
02919 {
02920     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
02921     PIO_STACK_LOCATION irpStack;
02922     PSCSI_REQUEST_BLOCK srb;
02923     NTSTATUS status;
02924     PCDB cdb;
02925 
02926     //
02927     // Allocate SCSI request block.
02928     //
02929 
02930     srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
02931 
02932     if (srb == NULL) {
02933 
02934         //
02935         // Set the status and complete the request.
02936         //
02937 
02938         Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
02939         IoCompleteRequest(Irp, IO_NO_INCREMENT);
02940         return(STATUS_INSUFFICIENT_RESOURCES);
02941     }
02942 
02943     RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
02944 
02945     //
02946     // Write length to SRB.
02947     //
02948 
02949     srb->Length = SCSI_REQUEST_BLOCK_SIZE;
02950 
02951     //
02952     // Set SCSI bus address.
02953     //
02954 
02955     srb->PathId = deviceExtension->PathId;
02956     srb->TargetId = deviceExtension->TargetId;
02957     srb->Lun = deviceExtension->Lun;
02958 
02959     //
02960     // Set timeout value and mark the request as not being a tagged request.
02961     //
02962 
02963     srb->TimeOutValue = deviceExtension->TimeOutValue * 4;
02964     srb->QueueTag = SP_UNTAGGED;
02965     srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
02966     srb->SrbFlags = deviceExtension->SrbFlags;
02967 
02968     //
02969     // If the write cache is enabled then send a synchronize cache request.
02970     //
02971 
02972     if (deviceExtension->DeviceFlags & DEV_WRITE_CACHE) {
02973 
02974         srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
02975         srb->CdbLength = 10;
02976 
02977         srb->Cdb[0] = SCSIOP_SYNCHRONIZE_CACHE;
02978 
02979         status = ScsiClassSendSrbSynchronous(DeviceObject,
02980                                              srb,
02981                                              NULL,
02982                                              0,
02983                                              TRUE);
02984 
02985         DebugPrint((1, "ScsiDiskShutdownFlush: Synchonize cache sent. Status = %lx\n", status ));
02986     }
02987 
02988     //
02989     // Unlock the device if it is removable and this is a shutdown.
02990     //
02991 
02992     irpStack = IoGetCurrentIrpStackLocation(Irp);
02993 
02994     if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA &&
02995         irpStack->MajorFunction == IRP_MJ_SHUTDOWN) {
02996 
02997         srb->CdbLength = 6;
02998         cdb = (PVOID) srb->Cdb;
02999         cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
03000         cdb->MEDIA_REMOVAL.Prevent = FALSE;
03001 
03002         //
03003         // Set timeout value.
03004         //
03005 
03006         srb->TimeOutValue = deviceExtension->TimeOutValue;
03007         status = ScsiClassSendSrbSynchronous(DeviceObject,
03008                                              srb,
03009                                              NULL,
03010                                              0,
03011                                              TRUE);
03012 
03013         DebugPrint((1, "ScsiDiskShutdownFlush: Unlock device request sent. Status = %lx\n", status ));
03014     }
03015 
03016     srb->CdbLength = 0;
03017 
03018     //
03019     // Save a few parameters in the current stack location.
03020     //
03021 
03022     srb->Function = irpStack->MajorFunction == IRP_MJ_SHUTDOWN ?
03023         SRB_FUNCTION_SHUTDOWN : SRB_FUNCTION_FLUSH;
03024 
03025     //
03026     // Set the retry count to zero.
03027     //
03028 
03029     irpStack->Parameters.Others.Argument4 = (PVOID) 0;
03030 
03031     //
03032     // Set up IoCompletion routine address.
03033     //
03034 
03035     IoSetCompletionRoutine(Irp, ScsiClassIoComplete, srb, TRUE, TRUE, TRUE);
03036 
03037     //
03038     // Get next stack location and
03039     // set major function code.
03040     //
03041 
03042     irpStack = IoGetNextIrpStackLocation(Irp);
03043 
03044     irpStack->MajorFunction = IRP_MJ_SCSI;
03045 
03046     //
03047     // Set up SRB for execute scsi request.
03048     // Save SRB address in next stack for port driver.
03049     //
03050 
03051     irpStack->Parameters.Scsi.Srb = srb;
03052 
03053     //
03054     // Set up Irp Address.
03055     //
03056 
03057     srb->OriginalRequest = Irp;
03058 
03059     //
03060     // Call the port driver to process the request.
03061     //
03062 
03063     return(IoCallDriver(deviceExtension->PortDeviceObject, Irp));
03064 
03065 } // end ScsiDiskShutdown()
03066 
03067 
03068 BOOLEAN
03069 NTAPI
03070 IsFloppyDevice(
03071     PDEVICE_OBJECT DeviceObject
03072     )
03073 /*++
03074 
03075 Routine Description:
03076 
03077     The routine performs the necessary functions to determine if a device is
03078     really a floppy rather than a harddisk.  This is done by a mode sense
03079     command.  First, a check is made to see if the medimum type is set.  Second
03080     a check is made for the flexible parameters mode page.  Also a check is
03081     made to see if the write cache is enabled.
03082 
03083 Arguments:
03084 
03085     DeviceObject - Supplies the device object to be tested.
03086 
03087 Return Value:
03088 
03089     Return TRUE if the indicated device is a floppy.
03090 
03091 --*/
03092 {
03093     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
03094     PVOID modeData;
03095     PUCHAR pageData;
03096     ULONG length;
03097 
03098     PAGED_CODE();
03099 
03100     modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
03101 
03102     if (modeData == NULL) {
03103         return(FALSE);
03104     }
03105 
03106     RtlZeroMemory(modeData, MODE_DATA_SIZE);
03107 
03108     length = ScsiClassModeSense(DeviceObject,
03109                                 modeData,
03110                                 MODE_DATA_SIZE,
03111                                 MODE_SENSE_RETURN_ALL);
03112 
03113     if (length < sizeof(MODE_PARAMETER_HEADER)) {
03114 
03115         //
03116         // Retry the request in case of a check condition.
03117         //
03118 
03119         length = ScsiClassModeSense(DeviceObject,
03120                                 modeData,
03121                                 MODE_DATA_SIZE,
03122                                 MODE_SENSE_RETURN_ALL);
03123 
03124         if (length < sizeof(MODE_PARAMETER_HEADER)) {
03125 
03126             ExFreePool(modeData);
03127             return(FALSE);
03128 
03129         }
03130     }
03131 
03132     //
03133     // If the length is greater than length indicated by the mode data reset
03134     // the data to the mode data.
03135     //
03136 
03137     if (length > (ULONG) ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) {
03138         length = ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1;
03139     }
03140 
03141     //
03142     // Look for the flexible disk mode page.
03143     //
03144 
03145     pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_FLEXIBILE, TRUE);
03146 
03147     if (pageData != NULL) {
03148 
03149         DebugPrint((1, "Scsidisk: Flexible disk page found, This is a floppy.\n"));
03150         ExFreePool(modeData);
03151         return(TRUE);
03152     }
03153 
03154     //
03155     // Check to see if the write cache is enabled.
03156     //
03157 
03158     pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_CACHING, TRUE);
03159 
03160     //
03161     // Assume that write cache is disabled or not supported.
03162     //
03163 
03164     deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
03165 
03166     //
03167     // Check if valid caching page exists.
03168     //
03169 
03170     if (pageData != NULL) {
03171 
03172         //
03173         // Check if write cache is disabled.
03174         //
03175 
03176         if (((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable) {
03177 
03178             DebugPrint((1,
03179                        "SCSIDISK: Disk write cache enabled\n"));
03180 
03181             //
03182             // Check if forced unit access (FUA) is supported.
03183             //
03184 
03185             if (((PMODE_PARAMETER_HEADER)modeData)->DeviceSpecificParameter & MODE_DSP_FUA_SUPPORTED) {
03186 
03187                 deviceExtension->DeviceFlags |= DEV_WRITE_CACHE;
03188 
03189             } else {
03190 
03191                 DebugPrint((1,
03192                            "SCSIDISK: Disk does not support FUA or DPO\n"));
03193 
03194                 //
03195                 // TODO: Log this.
03196                 //
03197 
03198             }
03199         }
03200     }
03201 
03202     ExFreePool(modeData);
03203     return(FALSE);
03204 
03205 } // end IsFloppyDevice()
03206 
03207 
03208 BOOLEAN
03209 NTAPI
03210 ScsiDiskModeSelect(
03211     IN PDEVICE_OBJECT DeviceObject,
03212     IN PCHAR ModeSelectBuffer,
03213     IN ULONG Length,
03214     IN BOOLEAN SavePage
03215     )
03216 
03217 /*++
03218 
03219 Routine Description:
03220 
03221     This routine sends a mode select command.
03222 
03223 Arguments:
03224 
03225     DeviceObject - Supplies the device object associated with this request.
03226 
03227     ModeSelectBuffer - Supplies a buffer containing the page data.
03228 
03229     Length - Supplies the length in bytes of the mode select buffer.
03230 
03231     SavePage - Indicates that parameters should be written to disk.
03232 
03233 Return Value:
03234 
03235     Length of the transferred data is returned.
03236 
03237 --*/
03238 {
03239     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
03240     PCDB cdb;
03241     SCSI_REQUEST_BLOCK srb;
03242     ULONG retries = 1;
03243     ULONG length2;
03244     NTSTATUS status;
03245     ULONG_PTR buffer;
03246     PMODE_PARAMETER_BLOCK blockDescriptor;
03247 
03248     PAGED_CODE();
03249 
03250     length2 = Length + sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_PARAMETER_BLOCK);
03251 
03252     //
03253     // Allocate buffer for mode select header, block descriptor, and mode page.
03254     //
03255 
03256     buffer = (ULONG_PTR)ExAllocatePool(NonPagedPoolCacheAligned,length2);
03257 
03258     RtlZeroMemory((PVOID)buffer, length2);
03259 
03260     //
03261     // Set length in header to size of mode page.
03262     //
03263 
03264     ((PMODE_PARAMETER_HEADER)buffer)->BlockDescriptorLength = sizeof(MODE_PARAMETER_BLOCK);
03265 
03266     blockDescriptor = (PMODE_PARAMETER_BLOCK)(buffer + 1);
03267 
03268     //
03269     // Set size
03270     //
03271 
03272     blockDescriptor->BlockLength[1]=0x02;
03273 
03274     //
03275     // Copy mode page to buffer.
03276     //
03277 
03278     RtlCopyMemory((PVOID)(buffer + 3), ModeSelectBuffer, Length);
03279 
03280     //
03281     // Zero SRB.
03282     //
03283 
03284     RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
03285 
03286     //
03287     // Build the MODE SELECT CDB.
03288     //
03289 
03290     srb.CdbLength = 6;
03291     cdb = (PCDB)srb.Cdb;
03292 
03293     //
03294     // Set timeout value from device extension.
03295     //
03296 
03297     srb.TimeOutValue = deviceExtension->TimeOutValue * 2;
03298 
03299     cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
03300     cdb->MODE_SELECT.SPBit = SavePage;
03301     cdb->MODE_SELECT.PFBit = 1;
03302     cdb->MODE_SELECT.ParameterListLength = (UCHAR)(length2);
03303 
03304 Retry:
03305 
03306     status = ScsiClassSendSrbSynchronous(DeviceObject,
03307                                          &srb,
03308                                          (PVOID)buffer,
03309                                          length2,
03310                                          TRUE);
03311 
03312 
03313     if (status == STATUS_VERIFY_REQUIRED) {
03314 
03315         //
03316         // Routine ScsiClassSendSrbSynchronous does not retry requests returned with
03317         // this status.
03318         //
03319 
03320         if (retries--) {
03321 
03322             //
03323             // Retry request.
03324             //
03325 
03326             goto Retry;
03327         }
03328 
03329     } else if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
03330         status = STATUS_SUCCESS;
03331     }
03332 
03333     ExFreePool((PVOID)buffer);
03334 
03335     if (NT_SUCCESS(status)) {
03336         return(TRUE);
03337     } else {
03338         return(FALSE);
03339     }
03340 
03341 } // end SciDiskModeSelect()
03342 
03343 
03344 VOID
03345 NTAPI
03346 DisableWriteCache(
03347     IN PDEVICE_OBJECT DeviceObject,
03348     IN PSCSI_INQUIRY_DATA LunInfo
03349     )
03350 
03351 {
03352     PDEVICE_EXTENSION          deviceExtension = DeviceObject->DeviceExtension;
03353     PINQUIRYDATA               InquiryData     = (PINQUIRYDATA)LunInfo->InquiryData;
03354     BAD_CONTROLLER_INFORMATION const *controller;
03355     ULONG                      j,length;
03356     PVOID                      modeData;
03357     PUCHAR                     pageData;
03358 
03359     for (j = 0; j <  NUMBER_OF_BAD_CONTROLLERS; j++) {
03360 
03361         controller = &ScsiDiskBadControllers[j];
03362 
03363         if (!controller->DisableWriteCache || strncmp(controller->InquiryString, (PCCHAR)InquiryData->VendorId, strlen(controller->InquiryString))) {
03364             continue;
03365         }
03366 
03367         DebugPrint((1, "ScsiDisk.DisableWriteCache, Found bad controller! %s\n", controller->InquiryString));
03368 
03369         modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
03370 
03371         if (modeData == NULL) {
03372 
03373             DebugPrint((1,
03374                         "ScsiDisk.DisableWriteCache: Check for write-cache enable failed\n"));
03375             return;
03376         }
03377 
03378         RtlZeroMemory(modeData, MODE_DATA_SIZE);
03379 
03380         length = ScsiClassModeSense(DeviceObject,
03381                                     modeData,
03382                                     MODE_DATA_SIZE,
03383                                     MODE_SENSE_RETURN_ALL);
03384 
03385         if (length < sizeof(MODE_PARAMETER_HEADER)) {
03386 
03387             //
03388             // Retry the request in case of a check condition.
03389             //
03390 
03391             length = ScsiClassModeSense(DeviceObject,
03392                                     modeData,
03393                                     MODE_DATA_SIZE,
03394                                     MODE_SENSE_RETURN_ALL);
03395 
03396             if (length < sizeof(MODE_PARAMETER_HEADER)) {
03397 
03398 
03399                 DebugPrint((1,
03400                             "ScsiDisk.DisableWriteCache: Mode Sense failed\n"));
03401 
03402                 ExFreePool(modeData);
03403                 return;
03404 
03405             }
03406         }
03407 
03408         //
03409         // If the length is greater than length indicated by the mode data reset
03410         // the data to the mode data.
03411         //
03412 
03413         if (length > (ULONG) ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) {
03414             length = ((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1;
03415         }
03416 
03417         //
03418         // Check to see if the write cache is enabled.
03419         //
03420 
03421         pageData = ScsiClassFindModePage( modeData, length, MODE_PAGE_CACHING, TRUE);
03422 
03423         //
03424         // Assume that write cache is disabled or not supported.
03425         //
03426 
03427         deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
03428 
03429         //
03430         // Check if valid caching page exists.
03431         //
03432 
03433         if (pageData != NULL) {
03434 
03435             BOOLEAN savePage = FALSE;
03436 
03437             savePage = (BOOLEAN)(((PMODE_CACHING_PAGE)pageData)->PageSavable);
03438 
03439             //
03440             // Check if write cache is disabled.
03441             //
03442 
03443             if (((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable) {
03444 
03445                 PIO_ERROR_LOG_PACKET errorLogEntry;
03446                 LONG                 errorCode;
03447 
03448 
03449                 //
03450                 // Disable write cache and ensure necessary fields are zeroed.
03451                 //
03452 
03453                 ((PMODE_CACHING_PAGE)pageData)->WriteCacheEnable = FALSE;
03454                 ((PMODE_CACHING_PAGE)pageData)->Reserved = 0;
03455                 ((PMODE_CACHING_PAGE)pageData)->PageSavable = 0;
03456                 ((PMODE_CACHING_PAGE)pageData)->Reserved2 = 0;
03457 
03458                 //
03459                 // Extract length from caching page.
03460                 //
03461 
03462                 length = ((PMODE_CACHING_PAGE)pageData)->PageLength;
03463 
03464                 //
03465                 // Compensate for page code and page length.
03466                 //
03467 
03468                 length += 2;
03469 
03470                 //
03471                 // Issue mode select to set the parameter.
03472                 //
03473 
03474                 if (ScsiDiskModeSelect(DeviceObject,
03475                                        (PCHAR)pageData,
03476                                        length,
03477                                        savePage)) {
03478 
03479                     DebugPrint((1,
03480                                "SCSIDISK: Disk write cache disabled\n"));
03481 
03482                     deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
03483                     errorCode = IO_WRITE_CACHE_DISABLED;
03484 
03485                 } else {
03486                     if (ScsiDiskModeSelect(DeviceObject,
03487                                            (PCHAR)pageData,
03488                                            length,
03489                                            savePage)) {
03490 
03491                         DebugPrint((1,
03492                                    "SCSIDISK: Disk write cache disabled\n"));
03493 
03494 
03495                         deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE;
03496                         errorCode = IO_WRITE_CACHE_DISABLED;
03497 
03498                     } else {
03499 
03500                             DebugPrint((1,
03501                                        "SCSIDISK: Mode select to disable write cache failed\n"));
03502 
03503                             deviceExtension->DeviceFlags |= DEV_WRITE_CACHE;
03504                             errorCode = IO_WRITE_CACHE_ENABLED;
03505                     }
03506                 }
03507 
03508                 //
03509                 // Log the appropriate informational or error entry.
03510                 //
03511 
03512                 errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
03513                                                          DeviceObject,
03514                                                          sizeof(IO_ERROR_LOG_PACKET) + 3
03515                                                              * sizeof(ULONG));
03516 
03517                 if (errorLogEntry != NULL) {
03518 
03519                     errorLogEntry->FinalStatus     = STATUS_SUCCESS;
03520                     errorLogEntry->ErrorCode       = errorCode;
03521                     errorLogEntry->SequenceNumber  = 0;
03522                     errorLogEntry->MajorFunctionCode = IRP_MJ_SCSI;
03523                     errorLogEntry->IoControlCode   = 0;
03524                     errorLogEntry->RetryCount      = 0;
03525                     errorLogEntry->UniqueErrorValue = 0x1;
03526                     errorLogEntry->DumpDataSize    = 3 * sizeof(ULONG);
03527                     errorLogEntry->DumpData[0]     = LunInfo->PathId;
03528                     errorLogEntry->DumpData[1]     = LunInfo->TargetId;
03529                     errorLogEntry->DumpData[2]     = LunInfo->Lun;
03530 
03531                     //
03532                     // Write the error log packet.
03533                     //
03534 
03535                     IoWriteErrorLogEntry(errorLogEntry);
03536                 }
03537             }
03538         }
03539 
03540         //
03541         // Found device so exit the loop and return.
03542         //
03543 
03544         break;
03545     }
03546 
03547     return;
03548 }
03549 
03550 
03551 BOOLEAN
03552 NTAPI
03553 CalculateMbrCheckSum(
03554     IN PDEVICE_EXTENSION DeviceExtension,
03555     OUT PULONG Checksum
03556     )
03557 
03558 /*++
03559 
03560 Routine Description:
03561 
03562     Read MBR and calculate checksum.
03563 
03564 Arguments:
03565 
03566     DeviceExtension - Supplies a pointer to the device information for disk.
03567     Checksum - Memory location to return MBR checksum.
03568 
03569 Return Value:
03570 
03571     Returns TRUE if checksum is valid.
03572 
03573 --*/
03574 {
03575     LARGE_INTEGER   sectorZero;
03576     PIRP            irp;
03577     IO_STATUS_BLOCK ioStatus;
03578     KEVENT          event;
03579     NTSTATUS        status;
03580     ULONG           sectorSize;
03581     PULONG          mbr;
03582     ULONG           i;
03583 
03584     PAGED_CODE();
03585     sectorZero.QuadPart = (LONGLONG) 0;
03586 
03587     //
03588     // Create notification event object to be used to signal the inquiry
03589     // request completion.
03590     //
03591 
03592     KeInitializeEvent(&event, NotificationEvent, FALSE);
03593 
03594     //
03595     // Get sector size.
03596     //
03597 
03598     sectorSize = DeviceExtension->DiskGeometry->Geometry.BytesPerSector;
03599 
03600     //
03601     // Make sure sector size is at least 512 bytes.
03602     //
03603 
03604     if (sectorSize < 512) {
03605         sectorSize = 512;
03606     }
03607 
03608     //
03609     // Allocate buffer for sector read.
03610     //
03611 
03612     mbr = ExAllocatePool(NonPagedPoolCacheAligned, sectorSize);
03613 
03614     if (!mbr) {
03615         return FALSE;
03616     }
03617 
03618     //
03619     // Build IRP to read MBR.
03620     //
03621 
03622     irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
03623                                        DeviceExtension->DeviceObject,
03624                                        mbr,
03625                                        sectorSize,
03626                                        &sectorZero,
03627                                        &event,
03628                                        &ioStatus );
03629 
03630     if (!irp) {
03631         ExFreePool(mbr);
03632         return FALSE;
03633     }
03634 
03635     //
03636     // Pass request to port driver and wait for request to complete.
03637     //
03638 
03639     status = IoCallDriver(DeviceExtension->DeviceObject,
03640                           irp);
03641 
03642     if (status == STATUS_PENDING) {
03643         KeWaitForSingleObject(&event,
03644                               Suspended,
03645                               KernelMode,
03646                               FALSE,
03647                               NULL);
03648         status = ioStatus.Status;
03649     }
03650 
03651     if (!NT_SUCCESS(status)) {
03652         ExFreePool(mbr);
03653         return FALSE;
03654     }
03655 
03656     //
03657     // Calculate MBR checksum.
03658     //
03659 
03660     *Checksum = 0;
03661 
03662     for (i = 0; i < 128; i++) {
03663         *Checksum += mbr[i];
03664     }
03665 
03666     *Checksum = ~*Checksum + 1;
03667 
03668     ExFreePool(mbr);
03669     return TRUE;
03670 }
03671 
03672 
03673 BOOLEAN
03674 NTAPI
03675 EnumerateBusKey(
03676     IN PDEVICE_EXTENSION DeviceExtension,
03677     HANDLE BusKey,
03678     PULONG DiskNumber
03679     )
03680 
03681 /*++
03682 
03683 Routine Description:
03684 
03685     The routine queries the registry to determine if this disk is visible to
03686     the BIOS.  If the disk is visable to the BIOS, then the geometry information
03687     is updated.
03688 
03689 Arguments:
03690 
03691     DeviceExtension - Supplies a pointer to the device information for disk.
03692     Signature - Unique identifier recorded in MBR.
03693     BusKey - Handle of bus key.
03694     DiskNumber - Returns ordinal of disk as BIOS sees it.
03695 
03696 Return Value:
03697 
03698     TRUE is disk signature matched.
03699 
03700 --*/
03701 {
03702     PDISK_DATA        diskData = (PDISK_DATA)(DeviceExtension + 1);
03703     BOOLEAN           diskFound = FALSE;
03704     OBJECT_ATTRIBUTES objectAttributes;
03705     UNICODE_STRING    unicodeString;
03706     UNICODE_STRING    identifier;
03707     ULONG             busNumber;
03708     ULONG             adapterNumber;
03709     ULONG             diskNumber;
03710     HANDLE            adapterKey;
03711     HANDLE            spareKey;
03712     HANDLE            diskKey;
03713     HANDLE            targetKey;
03714     NTSTATUS          status;
03715     STRING            string;
03716     STRING            anotherString;
03717     ULONG             length;
03718     UCHAR             buffer[20];
03719     PKEY_VALUE_FULL_INFORMATION keyData;
03720 
03721     PAGED_CODE();
03722 
03723     for (busNumber = 0; ; busNumber++) {
03724 
03725         //
03726         // Open controller name key.
03727         //
03728 
03729         sprintf((PCHAR)buffer,
03730                 "%lu",
03731                 busNumber);
03732 
03733         RtlInitString(&string,
03734                       (PCSZ)buffer);
03735 
03736         status = RtlAnsiStringToUnicodeString(&unicodeString,
03737                                               &string,
03738                                               TRUE);
03739 
03740         if (!NT_SUCCESS(status)){
03741             break;
03742         }
03743 
03744         InitializeObjectAttributes(&objectAttributes,
03745                                    &unicodeString,
03746                                    OBJ_CASE_INSENSITIVE,
03747                                    BusKey,
03748                                    (PSECURITY_DESCRIPTOR)NULL);
03749 
03750         status = ZwOpenKey(&spareKey,
03751                            KEY_READ,
03752                            &objectAttributes);
03753 
03754         RtlFreeUnicodeString(&unicodeString);
03755 
03756         if (!NT_SUCCESS(status)) {
03757             break;
03758         }
03759 
03760         //
03761         // Open up controller ordinal key.
03762         //
03763 
03764         RtlInitUnicodeString(&unicodeString, L"DiskController");
03765         InitializeObjectAttributes(&objectAttributes,
03766                                    &unicodeString,
03767                                    OBJ_CASE_INSENSITIVE,
03768                                    spareKey,
03769                                    (PSECURITY_DESCRIPTOR)NULL);
03770 
03771         status = ZwOpenKey(&adapterKey,
03772                            KEY_READ,
03773                            &objectAttributes);
03774 
03775         //
03776         // This could fail even with additional adapters of this type
03777         // to search.
03778         //
03779 
03780         if (!NT_SUCCESS(status)) {
03781             continue;
03782         }
03783 
03784         for (adapterNumber = 0; ; adapterNumber++) {
03785 
03786             //
03787             // Open disk key.
03788             //
03789 
03790             sprintf((PCHAR)buffer,
03791                     "%lu\\DiskPeripheral",
03792                     adapterNumber);
03793 
03794             RtlInitString(&string,
03795                           (PCSZ)buffer);
03796 
03797             status = RtlAnsiStringToUnicodeString(&unicodeString,
03798                                                   &string,
03799                                                   TRUE);
03800 
03801             if (!NT_SUCCESS(status)){
03802                 break;
03803             }
03804 
03805             InitializeObjectAttributes(&objectAttributes,
03806                                        &unicodeString,
03807                                        OBJ_CASE_INSENSITIVE,
03808                                        adapterKey,
03809                                        (PSECURITY_DESCRIPTOR)NULL);
03810 
03811             status = ZwOpenKey(&diskKey,
03812                                KEY_READ,
03813                                &objectAttributes);
03814 
03815             RtlFreeUnicodeString(&unicodeString);
03816 
03817             if (!NT_SUCCESS(status)) {
03818                 break;
03819             }
03820 
03821             for (diskNumber = 0; ; diskNumber++) {
03822 
03823                 sprintf((PCHAR)buffer,
03824                         "%lu",
03825                         diskNumber);
03826 
03827                 RtlInitString(&string,
03828                               (PCSZ)buffer);
03829 
03830                 status = RtlAnsiStringToUnicodeString(&unicodeString,
03831                                                       &string,
03832                                                       TRUE);
03833 
03834                 if (!NT_SUCCESS(status)){
03835                     break;
03836                 }
03837 
03838                 InitializeObjectAttributes(&objectAttributes,
03839                                            &unicodeString,
03840                                            OBJ_CASE_INSENSITIVE,
03841                                            diskKey,
03842                                            (PSECURITY_DESCRIPTOR)NULL);
03843 
03844                 status = ZwOpenKey(&targetKey,
03845                                    KEY_READ,
03846                                    &objectAttributes);
03847 
03848                 RtlFreeUnicodeString(&unicodeString);
03849 
03850                 if (!NT_SUCCESS(status)) {
03851                     break;
03852                 }
03853 
03854                 //
03855                 // Allocate buffer for registry query.
03856                 //
03857 
03858                 keyData = ExAllocatePool(PagedPool, VALUE_BUFFER_SIZE);
03859 
03860                 if (keyData == NULL) {
03861                     ZwClose(targetKey);
03862                     continue;
03863                 }
03864 
03865                 //
03866                 // Get disk peripheral identifier.
03867                 //
03868 
03869                 RtlInitUnicodeString(&unicodeString, L"Identifier");
03870                 status = ZwQueryValueKey(targetKey,
03871                                          &unicodeString,
03872                                          KeyValueFullInformation,
03873                                          keyData,
03874                                          VALUE_BUFFER_SIZE,
03875                                          &length);
03876 
03877                 ZwClose(targetKey);
03878 
03879                 if (!NT_SUCCESS(status)) {
03880                     continue;
03881                 }
03882 
03883                 //
03884                 // Complete unicode string.
03885                 //
03886 
03887                 identifier.Buffer =
03888                     (PWSTR)((PUCHAR)keyData + keyData->DataOffset);
03889                 identifier.Length = (USHORT)keyData->DataLength;
03890                 identifier.MaximumLength = (USHORT)keyData->DataLength;
03891 
03892                 //
03893                 // Convert unicode identifier to ansi string.
03894                 //
03895 
03896                 status =
03897                     RtlUnicodeStringToAnsiString(&anotherString,
03898                                                  &identifier,
03899                                                  TRUE);
03900 
03901                 if (!NT_SUCCESS(status)) {
03902                     continue;
03903                 }
03904 
03905                 //
03906                 // If checksum is zero, then the MBR is valid and
03907                 // the signature is meaningful.
03908                 //
03909 
03910                 if (diskData->MbrCheckSum) {
03911 
03912                     //
03913                     // Convert checksum to ansi string.
03914                     //
03915 
03916                     sprintf((PCHAR)buffer, "%08lx", diskData->MbrCheckSum);
03917 
03918                 } else {
03919 
03920                     //
03921                     // Convert signature to ansi string.
03922                     //
03923 
03924                     sprintf((PCHAR)buffer, "%08lx", diskData->Signature);
03925 
03926                     //
03927                     // Make string point at signature. Can't use scan
03928                     // functions because they are not exported for driver use.
03929                     //
03930 
03931                     anotherString.Buffer+=9;
03932                 }
03933 
03934                 //
03935                 // Convert to ansi string.
03936                 //
03937 
03938                 RtlInitString(&string,
03939                               (PCSZ)buffer);
03940 
03941 
03942                 //
03943                 // Make string lengths equal.
03944                 //
03945 
03946                 anotherString.Length = string.Length;
03947 
03948                 //
03949                 // Check if strings match.
03950                 //
03951 
03952                 if (RtlCompareString(&string,
03953                                      &anotherString,
03954                                      TRUE) == 0)  {
03955 
03956                     diskFound = TRUE;
03957                     *DiskNumber = diskNumber;
03958                 }
03959 
03960                 ExFreePool(keyData);
03961 
03962                 //
03963                 // Readjust indentifier string if necessary.
03964                 //
03965 
03966                 if (!diskData->MbrCheckSum) {
03967                     anotherString.Buffer-=9;
03968                 }
03969 
03970                 RtlFreeAnsiString(&anotherString);
03971 
03972                 if (diskFound) {
03973                     break;
03974                 }
03975             }
03976 
03977             ZwClose(diskKey);
03978         }
03979 
03980         ZwClose(adapterKey);
03981     }
03982 
03983     ZwClose(BusKey);
03984     return diskFound;
03985 
03986 } // end EnumerateBusKey()
03987 
03988 
03989 VOID
03990 NTAPI
03991 UpdateGeometry(
03992     IN PDEVICE_EXTENSION DeviceExtension
03993     )
03994 /*++
03995 
03996 Routine Description:
03997 
03998     The routine queries the registry to determine if this disk is visible to
03999     the BIOS.  If the disk is visable to the BIOS, then the geometry information
04000     is updated.
04001 
04002 Arguments:
04003 
04004     DeviceExtension - Supplies a pointer to the device information for disk.
04005 
04006 Return Value:
04007 
04008     None.
04009 
04010 --*/
04011 
04012 {
04013     OBJECT_ATTRIBUTES objectAttributes;
04014     UNICODE_STRING unicodeString;
04015     NTSTATUS status;
04016     HANDLE hardwareKey;
04017     HANDLE busKey;
04018     PCM_INT13_DRIVE_PARAMETER driveParameters;
04019     PCM_FULL_RESOURCE_DESCRIPTOR resourceDescriptor;
04020     PKEY_VALUE_FULL_INFORMATION keyData;
04021     ULONG diskNumber;
04022     PUCHAR buffer;
04023     ULONG length;
04024     ULONG numberOfDrives;
04025     ULONG cylinders;
04026     ULONG sectors;
04027     ULONG sectorsPerTrack;
04028     ULONG tracksPerCylinder;
04029     BOOLEAN foundEZHooker;
04030     PVOID tmpPtr;
04031 
04032     PAGED_CODE();
04033 
04034     //
04035     // Initialize the object for the key.
04036     //
04037 
04038     InitializeObjectAttributes(&objectAttributes,
04039                                DeviceExtension->DeviceObject->DriverObject->HardwareDatabase,
04040                                OBJ_CASE_INSENSITIVE,
04041                                NULL,
04042                                (PSECURITY_DESCRIPTOR) NULL);
04043 
04044     //
04045     // Create the hardware base key.
04046     //
04047 
04048     status =  ZwOpenKey(&hardwareKey,
04049                         KEY_READ,
04050                         &objectAttributes);
04051 
04052 
04053     if (!NT_SUCCESS(status)) {
04054         DebugPrint((1, "ScsiDisk UpdateParameters: Cannot open hardware data. Name: %wZ\n", DeviceExtension->DeviceObject->DriverObject->HardwareDatabase));
04055         return;
04056     }
04057 
04058 
04059     //
04060     // Get disk BIOS geometry information.
04061     //
04062 
04063     RtlInitUnicodeString(&unicodeString, L"Configuration Data");
04064 
04065     keyData = ExAllocatePool(PagedPool, VALUE_BUFFER_SIZE);
04066 
04067     if (keyData == NULL) {
04068         ZwClose(hardwareKey);
04069         return;
04070     }
04071 
04072     status = ZwQueryValueKey(hardwareKey,
04073                              &unicodeString,
04074                              KeyValueFullInformation,
04075                              keyData,
04076                              VALUE_BUFFER_SIZE,
04077                              &length);
04078 
04079     if (!NT_SUCCESS(status)) {
04080         DebugPrint((1,
04081                    "SCSIDISK: ExtractBiosGeometry: Can't query configuration data (%x)\n",
04082                    status));
04083         ExFreePool(keyData);
04084         return;
04085     }
04086 
04087     //
04088     // Open EISA bus key.
04089     //
04090 
04091     RtlInitUnicodeString(&unicodeString, L"EisaAdapter");
04092 
04093     InitializeObjectAttributes(&objectAttributes,
04094                                &unicodeString,
04095                                OBJ_CASE_INSENSITIVE,
04096                                hardwareKey,
04097                                (PSECURITY_DESCRIPTOR)NULL);
04098 
04099     status = ZwOpenKey(&busKey,
04100                        KEY_READ,
04101                        &objectAttributes);
04102 
04103     if (!NT_SUCCESS(status)) {
04104         goto openMultiKey;
04105     }
04106 
04107     DebugPrint((3,
04108                "SCSIDISK: UpdateGeometry: Opened EisaAdapter key\n"));
04109     if (EnumerateBusKey(DeviceExtension,
04110                         busKey,
04111                         &diskNumber)) {
04112 
04113         ZwClose(hardwareKey);
04114         goto diskMatched;
04115     }
04116 
04117 openMultiKey:
04118 
04119     //
04120     // Open Multifunction bus key.
04121     //
04122 
04123     RtlInitUnicodeString(&unicodeString, L"MultifunctionAdapter");
04124 
04125     InitializeObjectAttributes(&objectAttributes,
04126                                &unicodeString,
04127                                OBJ_CASE_INSENSITIVE,
04128                                hardwareKey,
04129                                (PSECURITY_DESCRIPTOR)NULL);
04130 
04131     status = ZwOpenKey(&busKey,
04132                        KEY_READ,
04133                        &objectAttributes);
04134 
04135     ZwClose(hardwareKey);
04136     if (NT_SUCCESS(status)) {
04137         DebugPrint((3,
04138                    "SCSIDISK: UpdateGeometry: Opened MultifunctionAdapter key\n"));
04139         if (EnumerateBusKey(DeviceExtension,
04140                             busKey,
04141                             &diskNumber)) {
04142 
04143             goto diskMatched;
04144         }
04145     }
04146 
04147     ExFreePool(keyData);
04148     return;
04149 
04150 diskMatched:
04151 
04152     resourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PUCHAR)keyData +
04153         keyData->DataOffset);
04154 
04155     //
04156     // Check that the data is long enough to hold a full resource descriptor,
04157     // and that the last resouce list is device-specific and long enough.
04158     //
04159 
04160     if (keyData->DataLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR) ||
04161         resourceDescriptor->PartialResourceList.Count == 0 ||
04162         resourceDescriptor->PartialResourceList.PartialDescriptors[0].Type !=
04163         CmResourceTypeDeviceSpecific ||
04164         resourceDescriptor->PartialResourceList.PartialDescriptors[0]
04165             .u.DeviceSpecificData.DataSize < sizeof(ULONG)) {
04166 
04167         DebugPrint((1, "SCSIDISK: ExtractBiosGeometry: BIOS header data too small or invalid\n"));
04168         ExFreePool(keyData);
04169         return;
04170     }
04171 
04172     length =
04173         resourceDescriptor->PartialResourceList.PartialDescriptors[0].u.DeviceSpecificData.DataSize;
04174 
04175     //
04176     // Point to the BIOS data. The BIOS data is located after the first
04177     // partial Resource list which should be device specific data.
04178     //
04179 
04180     buffer = (PUCHAR) keyData + keyData->DataOffset +
04181         sizeof(CM_FULL_RESOURCE_DESCRIPTOR);
04182 
04183 
04184     numberOfDrives = length / sizeof(CM_INT13_DRIVE_PARAMETER);
04185 
04186     //
04187     // Use the defaults if the drive number is greater than the
04188     // number of drives detected by the BIOS.
04189     //
04190 
04191     if (numberOfDrives <= diskNumber) {
04192         ExFreePool(keyData);
04193         return;
04194     }
04195 
04196     //
04197     // Point to the array of drive parameters.
04198     //
04199 
04200     driveParameters = (PCM_INT13_DRIVE_PARAMETER) buffer + diskNumber;
04201     cylinders = driveParameters->MaxCylinders + 1;
04202     sectorsPerTrack = driveParameters->SectorsPerTrack;
04203     tracksPerCylinder = driveParameters->MaxHeads +1;
04204 
04205     //
04206     // Calculate the actual number of sectors.
04207     //
04208 
04209     sectors = (ULONG)(DeviceExtension->PartitionLength.QuadPart >>
04210                                      DeviceExtension->SectorShift);
04211 
04212 #if DBG
04213     if (sectors >= cylinders * tracksPerCylinder * sectorsPerTrack) {
04214         DebugPrint((1, "ScsiDisk: UpdateGeometry: Disk smaller than BIOS indicated\n"
04215             "SCSIDISK: Sectors: %x, Cylinders: %x, Track per Cylinder: %x Sectors per track: %x\n",
04216             sectors, cylinders, tracksPerCylinder, sectorsPerTrack));
04217     }
04218 #endif
04219 
04220     //
04221     // Since the BIOS may not report the full drive, recalculate the drive
04222     // size based on the volume size and the BIOS values for tracks per
04223     // cylinder and sectors per track..
04224     //
04225 
04226     length = tracksPerCylinder * sectorsPerTrack;
04227 
04228     if (length == 0) {
04229 
04230         //
04231         // The BIOS information is bogus.
04232         //
04233 
04234         DebugPrint((1, "ScsiDisk UpdateParameters: sectorPerTrack zero\n"));
04235         ExFreePool(keyData);
04236         return;
04237     }
04238 
04239     cylinders = sectors / length;
04240 
04241     //
04242     // Update the actual geometry information.
04243     //
04244 
04245     DeviceExtension->DiskGeometry->Geometry.SectorsPerTrack = sectorsPerTrack;
04246     DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder = tracksPerCylinder;
04247     DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = (LONGLONG)cylinders;
04248     DeviceExtension->DiskGeometry->DiskSize.QuadPart = cylinders * tracksPerCylinder * sectorsPerTrack *
04249                                                        DeviceExtension->DiskGeometry->Geometry.BytesPerSector;
04250 
04251     DebugPrint((3,
04252                "SCSIDISK: UpdateGeometry: BIOS spt %x, #heads %x, #cylinders %x\n",
04253                sectorsPerTrack,
04254                tracksPerCylinder,
04255                cylinders));
04256 
04257     ExFreePool(keyData);
04258 
04259     foundEZHooker = FALSE;
04260 
04261     if (!DeviceExtension->DMActive) {
04262 
04263         HalExamineMBR(DeviceExtension->DeviceObject,
04264                       DeviceExtension->DiskGeometry->Geometry.BytesPerSector,
04265                       (ULONG)0x55,
04266                       &tmpPtr
04267                       );
04268 
04269         if (tmpPtr) {
04270 
04271             ExFreePool(tmpPtr);
04272             foundEZHooker = TRUE;
04273 
04274         }
04275 
04276     }
04277 
04278     if (DeviceExtension->DMActive || foundEZHooker) {
04279 
04280         while (cylinders > 1024) {
04281 
04282             tracksPerCylinder = tracksPerCylinder*2;
04283             cylinders = cylinders/2;
04284 
04285         }
04286 
04287         //
04288         // int 13 values are always 1 less.
04289         //
04290 
04291         tracksPerCylinder -= 1;
04292         cylinders -= 1;
04293 
04294         //
04295         // DM reserves the CE cylinder
04296         //
04297 
04298         cylinders -= 1;
04299 
04300         DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = cylinders + 1;
04301         DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder = tracksPerCylinder + 1;
04302 
04303         DeviceExtension->PartitionLength.QuadPart =
04304         DeviceExtension->DiskGeometry->DiskSize.QuadPart =
04305             DeviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart *
04306                 DeviceExtension->DiskGeometry->Geometry.SectorsPerTrack *
04307                 DeviceExtension->DiskGeometry->Geometry.BytesPerSector *
04308                 DeviceExtension->DiskGeometry->Geometry.TracksPerCylinder;
04309 
04310         if (DeviceExtension->DMActive) {
04311 
04312             DeviceExtension->DMByteSkew = DeviceExtension->DMSkew * DeviceExtension->DiskGeometry->Geometry.BytesPerSector;
04313 
04314         }
04315 
04316     } else {
04317 
04318         DeviceExtension->DMByteSkew = 0;
04319 
04320     }
04321 
04322     return;
04323 
04324 } // end UpdateGeometry()
04325 
04326 
04327 
04328 NTSTATUS
04329 NTAPI
04330 UpdateRemovableGeometry (
04331     IN PDEVICE_OBJECT DeviceObject,
04332     IN PIRP Irp
04333     )
04334 
04335 /*++
04336 
04337 Routine Description:
04338 
04339     This routines updates the size and starting offset of the device.  This is
04340     used when the media on the device may have changed thereby changing the
04341     size of the device.  If this is the physical device then a
04342     ScsiClassReadDriveCapacity is done; otherewise, a read partition table is done.
04343 
04344 Arguments:
04345 
04346     DeviceObject - Supplies the device object whos size needs to be updated.
04347 
04348     Irp - Supplies a reference where the status can be updated.
04349 
04350 Return Value:
04351 
04352     Returns the status of the opertion.
04353 
04354 --*/
04355 {
04356 
04357     PDEVICE_EXTENSION         deviceExtension = DeviceObject->DeviceExtension;
04358     PDRIVE_LAYOUT_INFORMATION partitionList;
04359     NTSTATUS                  status;
04360     PDISK_DATA                diskData;
04361     ULONG                     partitionNumber;
04362 
04363     //
04364     // Determine if the size of the partition may have changed because
04365     // the media has changed.
04366     //
04367 
04368     if (!(DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
04369 
04370         return(STATUS_SUCCESS);
04371 
04372     }
04373 
04374     //
04375     // If this request is for partition zero then do a read drive
04376     // capacity otherwise do a I/O read partition table.
04377     //
04378 
04379     diskData = (PDISK_DATA) (deviceExtension + 1);
04380 
04381     //
04382     // Read the drive capcity.  If that fails, give up.
04383     //
04384 
04385     status = ScsiClassReadDriveCapacity(deviceExtension->PhysicalDevice);
04386 
04387     if (!NT_SUCCESS(status)) {
04388         return(status);
04389     }
04390 
04391     //
04392     // Read the partition table agian.
04393     //
04394 
04395     status = IoReadPartitionTable(deviceExtension->PhysicalDevice,
04396                       deviceExtension->DiskGeometry->Geometry.BytesPerSector,
04397                       TRUE,
04398                       &partitionList);
04399 
04400 
04401     if (!NT_SUCCESS(status)) {
04402 
04403         //
04404         // Fail the request.
04405         //
04406 
04407         return(status);
04408     }
04409 
04410     if (diskData->PartitionNumber != 0 &&
04411         diskData->PartitionNumber <= partitionList->PartitionCount ) {
04412 
04413         partitionNumber = diskData->PartitionNumber - 1;
04414 
04415         //
04416         // Update the partition information for this parition.
04417         //
04418 
04419         diskData->PartitionType =
04420             partitionList->PartitionEntry[partitionNumber].PartitionType;
04421 
04422         diskData->BootIndicator =
04423             partitionList->PartitionEntry[partitionNumber].BootIndicator;
04424 
04425         deviceExtension->StartingOffset =
04426             partitionList->PartitionEntry[partitionNumber].StartingOffset;
04427 
04428         deviceExtension->PartitionLength =
04429             partitionList->PartitionEntry[partitionNumber].PartitionLength;
04430 
04431         diskData->HiddenSectors =
04432             partitionList->PartitionEntry[partitionNumber].HiddenSectors;
04433 
04434         deviceExtension->SectorShift = ((PDEVICE_EXTENSION)
04435             deviceExtension->PhysicalDevice->DeviceExtension)->SectorShift;
04436 
04437     } else if (diskData->PartitionNumber != 0) {
04438 
04439         //
04440         // The paritition does not exist.  Zero all the data.
04441         //
04442 
04443         diskData->PartitionType = 0;
04444         diskData->BootIndicator = 0;
04445         diskData->HiddenSectors = 0;
04446         deviceExtension->StartingOffset.QuadPart  = (LONGLONG)0;
04447         deviceExtension->PartitionLength.QuadPart = (LONGLONG)0;
04448     }
04449 
04450     //
04451     // Free the parition list allocate by I/O read partition table.
04452     //
04453 
04454     ExFreePool(partitionList);
04455 
04456 
04457     return(STATUS_SUCCESS);
04458 }
04459 
04460 
04461 VOID
04462 NTAPI
04463 ScsiDiskProcessError(
04464     PDEVICE_OBJECT DeviceObject,
04465     PSCSI_REQUEST_BLOCK Srb,
04466     NTSTATUS *Status,
04467     BOOLEAN *Retry
04468     )
04469 /*++
04470 
04471 Routine Description:
04472 
04473    This routine checks the type of error.  If the error indicates an underrun
04474    then indicate the request should be retried.
04475 
04476 Arguments:
04477 
04478     DeviceObject - Supplies a pointer to the device object.
04479 
04480     Srb - Supplies a pointer to the failing Srb.
04481 
04482     Status - Status with which the IRP will be completed.
04483 
04484     Retry - Indication of whether the request will be retried.
04485 
04486 Return Value:
04487 
04488     None.
04489 
04490 --*/
04491 
04492 {
04493     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
04494 
04495     if (*Status == STATUS_DATA_OVERRUN &&
04496         ( Srb->Cdb[0] == SCSIOP_WRITE || Srb->Cdb[0] == SCSIOP_READ)) {
04497 
04498             *Retry = TRUE;
04499 
04500             //
04501             // Update the error count for the device.
04502             //
04503 
04504             deviceExtension->ErrorCount++;
04505     }
04506 
04507     if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_ERROR &&
04508         Srb->ScsiStatus == SCSISTAT_BUSY) {
04509 
04510         //
04511         // The disk drive should never be busy this long. Reset the scsi bus
04512         // maybe this will clear the condition.
04513         //
04514 
04515         ResetScsiBus(DeviceObject);
04516 
04517         //
04518         // Update the error count for the device.
04519         //
04520 
04521         deviceExtension->ErrorCount++;
04522     }
04523 }
04524 
04525 VOID
04526 NTAPI
04527 ScanForSpecial(
04528     PDEVICE_OBJECT DeviceObject,
04529     PSCSI_INQUIRY_DATA LunInfo,
04530     PIO_SCSI_CAPABILITIES PortCapabilities
04531     )
04532 
04533 /*++
04534 
04535 Routine Description:
04536 
04537     This function checks to see if an SCSI logical unit requires speical
04538     flags to be set.
04539 
04540 Arguments:
04541 
04542     DeviceObject - Supplies the device object to be tested.
04543 
04544     InquiryData - Supplies the inquiry data returned by the device of interest.
04545 
04546     PortCapabilities - Supplies the capabilities of the device object.
04547 
04548 Return Value:
04549 
04550     None.
04551 
04552 --*/
04553 
04554 {
04555     PDEVICE_EXTENSION          deviceExtension = DeviceObject->DeviceExtension;
04556     PINQUIRYDATA               InquiryData     = (PINQUIRYDATA)LunInfo->InquiryData;
04557     BAD_CONTROLLER_INFORMATION const *controller;
04558     ULONG                      j;
04559 
04560     for (j = 0; j <  NUMBER_OF_BAD_CONTROLLERS; j++) {
04561 
04562         controller = &ScsiDiskBadControllers[j];
04563 
04564         if (strncmp(controller->InquiryString, (PCCHAR)InquiryData->VendorId, strlen(controller->InquiryString))) {
04565             continue;
04566         }
04567 
04568         DebugPrint((1, "ScsiDisk ScanForSpecial, Found bad controller! %s\n", controller->InquiryString));
04569 
04570         //
04571         // Found a listed controller.  Determine what must be done.
04572         //
04573 
04574         if (controller->DisableTaggedQueuing) {
04575 
04576             //
04577             // Disable tagged queuing.
04578             //
04579 
04580             deviceExtension->SrbFlags &= ~SRB_FLAGS_QUEUE_ACTION_ENABLE;
04581         }
04582 
04583         if (controller->DisableSynchronousTransfers) {
04584 
04585             //
04586             // Disable synchronous data transfers.
04587             //
04588 
04589             deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
04590 
04591         }
04592 
04593         if (controller->DisableDisconnects) {
04594 
04595             //
04596             // Disable disconnects.
04597             //
04598 
04599             deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT;
04600 
04601         }
04602 
04603         //
04604         // Found device so exit the loop and return.
04605         //
04606 
04607         break;
04608     }
04609 
04610     //
04611     // Set the StartUnit flag appropriately.
04612     //
04613 
04614     if (DeviceObject->DeviceType == FILE_DEVICE_DISK) {
04615         deviceExtension->DeviceFlags |= DEV_SAFE_START_UNIT;
04616 
04617         if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
04618             if (_strnicmp((PCCHAR)InquiryData->VendorId, "iomega", strlen("iomega"))) {
04619                 deviceExtension->DeviceFlags &= ~DEV_SAFE_START_UNIT;
04620             }
04621         }
04622     }
04623 
04624     return;
04625 }
04626 
04627 VOID
04628 NTAPI
04629 ResetScsiBus(
04630     IN PDEVICE_OBJECT DeviceObject
04631     )
04632 
04633 /*++
04634 
04635 Routine Description:
04636 
04637     This command sends a reset bus command to the SCSI port driver.
04638 
04639 Arguments:
04640 
04641     DeviceObject - The device object for the logical unit with
04642         hardware problem.
04643 
04644 Return Value:
04645 
04646     None.
04647 
04648 --*/
04649 {
04650     PIO_STACK_LOCATION irpStack;
04651     PIRP irp;
04652     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
04653     PSCSI_REQUEST_BLOCK srb;
04654     PCOMPLETION_CONTEXT context;
04655 
04656     DebugPrint((1, "ScsiDisk ResetScsiBus: Sending reset bus request to port driver.\n"));
04657 
04658     //
04659     // Allocate Srb from nonpaged pool.
04660     //
04661 
04662     context = ExAllocatePool(NonPagedPoolMustSucceed,
04663                              sizeof(COMPLETION_CONTEXT));
04664 
04665     //
04666     // Save the device object in the context for use by the completion
04667     // routine.
04668     //
04669 
04670     context->DeviceObject = DeviceObject;
04671     srb = &context->Srb;
04672 
04673     //
04674     // Zero out srb.
04675     //
04676 
04677     RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
04678 
04679     //
04680     // Write length to SRB.
04681     //
04682 
04683     srb->Length = SCSI_REQUEST_BLOCK_SIZE;
04684 
04685     //
04686     // Set up SCSI bus address.
04687     //
04688 
04689     srb->PathId = deviceExtension->PathId;
04690     srb->TargetId = deviceExtension->TargetId;
04691     srb->Lun = deviceExtension->Lun;
04692 
04693     srb->Function = SRB_FUNCTION_RESET_BUS;
04694 
04695     //
04696     // Build the asynchronous request to be sent to the port driver.
04697     // Since this routine is called from a DPC the IRP should always be
04698     // available.
04699     //
04700 
04701     irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
04702 
04703     IoSetCompletionRoutine(irp,
04704                            (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion,
04705                            context,
04706                            TRUE,
04707                            TRUE,
04708                            TRUE);
04709 
04710     irpStack = IoGetNextIrpStackLocation(irp);
04711 
04712     irpStack->MajorFunction = IRP_MJ_SCSI;
04713 
04714     srb->OriginalRequest = irp;
04715 
04716     //
04717     // Store the SRB address in next stack for port driver.
04718     //
04719 
04720     irpStack->Parameters.Scsi.Srb = srb;
04721 
04722     //
04723     // Call the port driver with the IRP.
04724     //
04725 
04726     IoCallDriver(deviceExtension->PortDeviceObject, irp);
04727 
04728     return;
04729 
04730 } // end ResetScsiBus()
04731 
04732 
04733 VOID
04734 NTAPI
04735 UpdateDeviceObjects(
04736     IN PDEVICE_OBJECT PhysicalDisk,
04737     IN PIRP Irp
04738     )
04739 
04740 /*++
04741 
04742 Routine Description:
04743 
04744     This routine creates, deletes and changes device objects when
04745     the IOCTL_SET_DRIVE_LAYOUT is called.  This routine also updates
04746     the drive layout information for the user.  It is possible to
04747     call this routine even in the GET_LAYOUT case because RewritePartition
04748     will be false.
04749 
04750 Arguments:
04751 
04752     DeviceObject - Device object for physical disk.
04753     Irp - IO Request Packet (IRP).
04754 
04755 Return Value:
04756 
04757     None.
04758 
04759 --*/
04760 {
04761     PDEVICE_EXTENSION         physicalExtension = PhysicalDisk->DeviceExtension;
04762     PDRIVE_LAYOUT_INFORMATION partitionList = Irp->AssociatedIrp.SystemBuffer;
04763     ULONG                     partition;
04764     ULONG                     partitionNumber;
04765     ULONG                     partitionCount;
04766     ULONG                     lastPartition;
04767     ULONG                     partitionOrdinal;
04768     PPARTITION_INFORMATION    partitionEntry;
04769     CCHAR                     ntNameBuffer[MAXIMUM_FILENAME_LENGTH];
04770     STRING                    ntNameString;
04771     UNICODE_STRING            ntUnicodeString;
04772     PDEVICE_OBJECT            deviceObject;
04773     PDEVICE_EXTENSION         deviceExtension;
04774     PDISK_DATA                diskData;
04775     NTSTATUS                  status;
04776     ULONG                     numberListElements;
04777     BOOLEAN                   found;
04778 
04779     partitionCount = ((partitionList->PartitionCount + 3) / 4) * 4;
04780 
04781     //
04782     // Zero all of the partition numbers.
04783     //
04784 
04785     for (partition = 0; partition < partitionCount; partition++) {
04786         partitionEntry = &partitionList->PartitionEntry[partition];
04787         partitionEntry->PartitionNumber = 0;
04788     }
04789 
04790     //
04791     // Walk through chain of partitions for this disk to determine
04792     // which existing partitions have no match.
04793     //
04794 
04795     deviceExtension = physicalExtension;
04796     diskData = (PDISK_DATA)(deviceExtension + 1);
04797     lastPartition = 0;
04798 
04799     do {
04800 
04801         deviceExtension = diskData->NextPartition;
04802 
04803         //
04804         // Check if this is the last partition in the chain.
04805         //
04806 
04807         if (!deviceExtension) {
04808            break;
04809         }
04810 
04811         //
04812         // Get the partition device extension from disk data.
04813         //
04814 
04815         diskData = (PDISK_DATA)(deviceExtension + 1);
04816 
04817         //
04818         // Check for highest partition number this far.
04819         //
04820 
04821         if (diskData->PartitionNumber > lastPartition) {
04822            lastPartition = diskData->PartitionNumber;
04823         }
04824 
04825         //
04826         // Check if this partition is not currently being used.
04827         //
04828 
04829         if (!deviceExtension->PartitionLength.QuadPart) {
04830            continue;
04831         }
04832 
04833         //
04834         // Loop through partition information to look for match.
04835         //
04836 
04837         found = FALSE;
04838         partitionOrdinal = 0;
04839 
04840         for (partition = 0; partition < partitionCount; partition++) {
04841 
04842             //
04843             // Get partition descriptor.
04844             //
04845 
04846             partitionEntry = &partitionList->PartitionEntry[partition];
04847 
04848             //
04849             // Check if empty, or describes extended partiton or hasn't changed.
04850             //
04851 
04852             if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
04853                 IsContainerPartition(partitionEntry->PartitionType)) {
04854                 continue;
04855             }
04856 
04857             //
04858             // Advance partition ordinal.
04859             //
04860 
04861             partitionOrdinal++;
04862 
04863             //
04864             // Check if new partition starts where this partition starts.
04865             //
04866 
04867             if (partitionEntry->StartingOffset.QuadPart !=
04868                       deviceExtension->StartingOffset.QuadPart) {
04869                 continue;
04870             }
04871 
04872             //
04873             // Check if partition length is the same.
04874             //
04875 
04876             if (partitionEntry->PartitionLength.QuadPart ==
04877                       deviceExtension->PartitionLength.QuadPart) {
04878 
04879                 DebugPrint((3,
04880                            "UpdateDeviceObjects: Found match for \\Harddisk%d\\Partition%d\n",
04881                            physicalExtension->DeviceNumber,
04882                            diskData->PartitionNumber));
04883 
04884                 //
04885                 // Indicate match is found and set partition number
04886                 // in user buffer.
04887                 //
04888 
04889                 found = TRUE;
04890                 partitionEntry->PartitionNumber = diskData->PartitionNumber;
04891                 break;
04892             }
04893         }
04894 
04895         if (found) {
04896 
04897             //
04898             // A match is found.
04899             //
04900 
04901             diskData = (PDISK_DATA)(deviceExtension + 1);
04902 
04903             //
04904             // If this partition is marked for update then update partition type.
04905             //
04906 
04907             if (partitionEntry->RewritePartition) {
04908                 diskData->PartitionType = partitionEntry->PartitionType;
04909             }
04910 
04911             //
04912             // Update partitional ordinal for calls to HAL routine
04913             // IoSetPartitionInformation.
04914             //
04915 
04916             diskData->PartitionOrdinal = partitionOrdinal;
04917 
04918             DebugPrint((1,
04919                        "UpdateDeviceObjects: Disk %d ordinal %d is partition %d\n",
04920                        physicalExtension->DeviceNumber,
04921                        diskData->PartitionOrdinal,
04922                        diskData->PartitionNumber));
04923 
04924         } else {
04925 
04926             //
04927             // no match was found, indicate this partition is gone.
04928             //
04929 
04930             DebugPrint((1,
04931                        "UpdateDeviceObjects: Deleting \\Device\\Harddisk%x\\Partition%x\n",
04932                        physicalExtension->DeviceNumber,
04933                        diskData->PartitionNumber));
04934 
04935             deviceExtension->PartitionLength.QuadPart = (LONGLONG) 0;
04936         }
04937 
04938     } while (TRUE);
04939 
04940     //
04941     // Walk through partition loop to find new partitions and set up
04942     // device extensions to describe them. In some cases new device
04943     // objects will be created.
04944     //
04945 
04946     partitionOrdinal = 0;
04947 
04948     for (partition = 0;
04949          partition < partitionCount;
04950          partition++) {
04951 
04952         //
04953         // Get partition descriptor.
04954         //
04955 
04956         partitionEntry = &partitionList->PartitionEntry[partition];
04957 
04958         //
04959         // Check if empty, or describes an extended partiton.
04960         //
04961 
04962         if (partitionEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
04963             IsContainerPartition(partitionEntry->PartitionType)) {
04964             continue;
04965         }
04966 
04967         //
04968         // Keep track of position on the disk for calls to IoSetPartitionInformation.
04969         //
04970 
04971         partitionOrdinal++;
04972 
04973         //
04974         // Check if this entry should be rewritten.
04975         //
04976 
04977         if (!partitionEntry->RewritePartition) {
04978             continue;
04979         }
04980 
04981         if (partitionEntry->PartitionNumber) {
04982 
04983             //
04984             // Partition is an exact match with an existing partition, but is
04985             // being written anyway.
04986             //
04987 
04988             continue;
04989         }
04990 
04991         //
04992         // Check first if existing device object is available by
04993         // walking partition extension list.
04994         //
04995 
04996         partitionNumber = 0;
04997         deviceExtension = physicalExtension;
04998         diskData = (PDISK_DATA)(deviceExtension + 1);
04999 
05000         do {
05001 
05002             //
05003             // Get next partition device extension from disk data.
05004             //
05005 
05006             deviceExtension = diskData->NextPartition;
05007 
05008             if (!deviceExtension) {
05009                break;
05010             }
05011 
05012             diskData = (PDISK_DATA)(deviceExtension + 1);
05013 
05014             //
05015             // A device object is free if the partition length is set to zero.
05016             //
05017 
05018             if (!deviceExtension->PartitionLength.QuadPart) {
05019                partitionNumber = diskData->PartitionNumber;
05020                break;
05021             }
05022 
05023         } while (TRUE);
05024 
05025         //
05026         // If partition number is still zero then a new device object
05027         // must be created.
05028         //
05029 
05030         if (partitionNumber == 0) {
05031 
05032             lastPartition++;
05033             partitionNumber = lastPartition;
05034 
05035             //
05036             // Get or create partition object and set up partition parameters.
05037             //
05038 
05039             sprintf(ntNameBuffer,
05040                     "\\Device\\Harddisk%lu\\Partition%lu",
05041                     physicalExtension->DeviceNumber,
05042                     partitionNumber);
05043 
05044             RtlInitString(&ntNameString,
05045                           ntNameBuffer);
05046 
05047             status = RtlAnsiStringToUnicodeString(&ntUnicodeString,
05048                                                   &ntNameString,
05049                                                   TRUE);
05050 
05051             if (!NT_SUCCESS(status)) {
05052                 continue;
05053             }
05054 
05055             DebugPrint((3,
05056                         "UpdateDeviceObjects: Create device object %s\n",
05057                         ntNameBuffer));
05058 
05059             //
05060             // This is a new name. Create the device object to represent it.
05061             //
05062 
05063             status = IoCreateDevice(PhysicalDisk->DriverObject,
05064                                     DEVICE_EXTENSION_SIZE,
05065                                     &ntUnicodeString,
05066                                     FILE_DEVICE_DISK,
05067                                     0,
05068                                     FALSE,
05069                                     &deviceObject);
05070 
05071             if (!NT_SUCCESS(status)) {
05072                 DebugPrint((1,
05073                             "UpdateDeviceObjects: Can't create device %s\n",
05074                             ntNameBuffer));
05075                 RtlFreeUnicodeString(&ntUnicodeString);
05076                 continue;
05077             }
05078 
05079             //
05080             // Set up device object fields.
05081             //
05082 
05083             deviceObject->Flags |= DO_DIRECT_IO;
05084             deviceObject->StackSize = PhysicalDisk->StackSize;
05085 
05086             //
05087             // Set up device extension fields.
05088             //
05089 
05090             deviceExtension = deviceObject->DeviceExtension;
05091 
05092             //
05093             // Copy physical disk extension to partition extension.
05094             //
05095 
05096             RtlMoveMemory(deviceExtension,
05097                           physicalExtension,
05098                           sizeof(DEVICE_EXTENSION));
05099 
05100             //
05101             // Initialize the new S-List.
05102             //
05103 
05104             if (deviceExtension->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) {
05105                 numberListElements = 30;
05106             } else {
05107                 numberListElements = 8;
05108             }
05109 
05110             //
05111             // Build the lookaside list for srb's for this partition based on
05112             // whether the adapter and disk can do tagged queueing.
05113             //
05114 
05115             ScsiClassInitializeSrbLookasideList(deviceExtension,
05116                                                 numberListElements);
05117 
05118             //
05119             // Allocate spinlock for zoning for split-request completion.
05120             //
05121 
05122             KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock);
05123 
05124             //
05125             // Write back partition number used in creating object name.
05126             //
05127 
05128             partitionEntry->PartitionNumber = partitionNumber;
05129 
05130             //
05131             // Clear flags initializing bit.
05132             //
05133 
05134             deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
05135 
05136             //
05137             // Point back at device object.
05138             //
05139 
05140             deviceExtension->DeviceObject = deviceObject;
05141 
05142             RtlFreeUnicodeString(&ntUnicodeString);
05143 
05144             //
05145             // Link to end of partition chain using previous disk data.
05146             //
05147 
05148             diskData->NextPartition = deviceExtension;
05149 
05150             //
05151             // Get new disk data and zero next partition pointer.
05152             //
05153 
05154             diskData = (PDISK_DATA)(deviceExtension + 1);
05155             diskData->NextPartition = NULL;
05156 
05157         } else {
05158 
05159             //
05160             // Set pointer to disk data area that follows device extension.
05161             //
05162 
05163             diskData = (PDISK_DATA)(deviceExtension + 1);
05164 
05165             DebugPrint((1,
05166                         "UpdateDeviceObjects: Used existing device object \\Device\\Harddisk%x\\Partition%x\n",
05167                         physicalExtension->DeviceNumber,
05168                         partitionNumber));
05169         }
05170 
05171         //
05172         // Update partition information in partition device extension.
05173         //
05174 
05175         diskData->PartitionNumber = partitionNumber;
05176         diskData->PartitionType = partitionEntry->PartitionType;
05177         diskData->BootIndicator = partitionEntry->BootIndicator;
05178         deviceExtension->StartingOffset = partitionEntry->StartingOffset;
05179         deviceExtension->PartitionLength = partitionEntry->PartitionLength;
05180         diskData->HiddenSectors = partitionEntry->HiddenSectors;
05181         diskData->PartitionOrdinal = partitionOrdinal;
05182 
05183         DebugPrint((1,
05184                    "UpdateDeviceObjects: Ordinal %d is partition %d\n",
05185                    diskData->PartitionOrdinal,
05186                    diskData->PartitionNumber));
05187 
05188         //
05189         // Update partition number passed in to indicate the
05190         // device name for this partition.
05191         //
05192 
05193         partitionEntry->PartitionNumber = partitionNumber;
05194     }
05195 
05196 } // end UpdateDeviceObjects()

Generated on Sat May 26 2012 04:17:54 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.