Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenclass2.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/class2/class2.c 00005 * PURPOSE: SCSI Class driver routines 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 <include/class2.h> 00013 #include <stdio.h> 00014 00015 /* Part of the drive letter hack */ 00016 #include <ntifs.h> 00017 #include <ketypes.h> 00018 00019 //#define NDEBUG 00020 #include <debug.h> 00021 00022 #ifdef ALLOC_PRAGMA 00023 #pragma alloc_text(PAGE, ScsiClassGetInquiryData) 00024 #pragma alloc_text(PAGE, ScsiClassInitialize) 00025 #pragma alloc_text(PAGE, ScsiClassGetCapabilities) 00026 #pragma alloc_text(PAGE, ScsiClassSendSrbSynchronous) 00027 #pragma alloc_text(PAGE, ScsiClassClaimDevice) 00028 #pragma alloc_text(PAGE, ScsiClassSendSrbAsynchronous) 00029 #endif 00030 00031 00032 #define INQUIRY_DATA_SIZE 2048 00033 #define START_UNIT_TIMEOUT 30 00034 00035 /* Disk layout used by Windows NT4 and earlier versions. */ 00036 //#define DEFAULT_SECTORS_PER_TRACK 32 00037 //#define DEFAULT_TRACKS_PER_CYLINDER 64 00038 00039 /* Disk layout used by Windows 2000 and later versions. */ 00040 #define DEFAULT_SECTORS_PER_TRACK 63 00041 #define DEFAULT_TRACKS_PER_CYLINDER 255 00042 00043 NTSTATUS 00044 NTAPI 00045 ScsiClassCreateClose( 00046 IN PDEVICE_OBJECT DeviceObject, 00047 IN PIRP Irp 00048 ); 00049 00050 NTSTATUS 00051 NTAPI 00052 ScsiClassReadWrite( 00053 IN PDEVICE_OBJECT DeviceObject, 00054 IN PIRP Irp 00055 ); 00056 00057 NTSTATUS 00058 NTAPI 00059 ScsiClassDeviceControlDispatch( 00060 PDEVICE_OBJECT DeviceObject, 00061 PIRP Irp 00062 ); 00063 00064 NTSTATUS 00065 NTAPI 00066 ScsiClassDeviceControl( 00067 PDEVICE_OBJECT DeviceObject, 00068 PIRP Irp 00069 ); 00070 00071 NTSTATUS 00072 NTAPI 00073 ScsiClassInternalIoControl ( 00074 IN PDEVICE_OBJECT DeviceObject, 00075 IN PIRP Irp 00076 ); 00077 00078 NTSTATUS 00079 NTAPI 00080 ScsiClassShutdownFlush( 00081 IN PDEVICE_OBJECT DeviceObject, 00082 IN PIRP Irp 00083 ); 00084 00085 NTSTATUS 00086 NTAPI 00087 DriverEntry( 00088 IN PDRIVER_OBJECT DriverObject, 00089 IN PUNICODE_STRING RegistryPath 00090 ); 00091 00092 // 00093 // Class internal routines 00094 // 00095 00096 00097 VOID 00098 NTAPI 00099 RetryRequest( 00100 PDEVICE_OBJECT DeviceObject, 00101 PIRP Irp, 00102 PSCSI_REQUEST_BLOCK Srb, 00103 BOOLEAN Associated 00104 ); 00105 00106 VOID 00107 NTAPI 00108 StartUnit( 00109 IN PDEVICE_OBJECT DeviceObject 00110 ); 00111 00112 NTSTATUS 00113 NTAPI 00114 ClassIoCompletion( 00115 IN PDEVICE_OBJECT DeviceObject, 00116 IN PIRP Irp, 00117 IN PVOID Context 00118 ); 00119 00120 NTSTATUS 00121 NTAPI 00122 ClassCompletionRoutine(IN PDEVICE_OBJECT DeviceObject, 00123 IN PIRP Irp, 00124 IN PVOID Context); 00125 00126 00127 NTSTATUS 00128 NTAPI 00129 DriverEntry( 00130 IN PDRIVER_OBJECT DriverObject, 00131 IN PUNICODE_STRING RegistryPath 00132 ) 00133 { 00134 return STATUS_SUCCESS; 00135 } 00136 00137 /* The following hack to assign drive letters with a non-PnP storage stack */ 00138 00139 typedef struct _CLASS_DEVICE_INFO { 00140 ULONG Partitions; 00141 ULONG DeviceNumber; 00142 ULONG DriveNumber; 00143 PDEVICE_OBJECT LowerDevice; 00144 } CLASS_DEVICE_INFO, *PCLASS_DEVICE_INFO; 00145 00146 typedef struct _CLASS_DRIVER_EXTENSION { 00147 ULONG PortNumber; 00148 UNICODE_STRING RegistryPath; 00149 CLASS_INIT_DATA InitializationData; 00150 } CLASS_DRIVER_EXTENSION, *PCLASS_DRIVER_EXTENSION; 00151 00152 VOID 00153 NTAPI 00154 ScsiClassRemoveDriveLetter(PCLASS_DEVICE_INFO DeviceInfo) 00155 { 00156 WCHAR Buffer1[100]; 00157 UNICODE_STRING DriveLetterU; 00158 ULONG Index; 00159 00160 DriveLetterU.Buffer = Buffer1; 00161 DriveLetterU.MaximumLength = sizeof(Buffer1); 00162 00163 /* Delete the symbolic link to PhysicalDriveX */ 00164 DriveLetterU.Length = swprintf(DriveLetterU.Buffer, L"\\??\\PhysicalDrive%d", DeviceInfo->DriveNumber) * sizeof(WCHAR); 00165 IoDeleteSymbolicLink(&DriveLetterU); 00166 00167 DbgPrint("HACK: Deleted symbolic link %wZ\n", &DriveLetterU); 00168 00169 for (Index = 0; Index < sizeof(ULONG) * 8; Index++) 00170 { 00171 if (DeviceInfo->Partitions & (1 << Index)) 00172 { 00173 DriveLetterU.Length = swprintf(DriveLetterU.Buffer, L"\\??\\%C:", ('C' + Index)) * sizeof(WCHAR); 00174 IoDeleteSymbolicLink(&DriveLetterU); 00175 DbgPrint("HACK: Deleted symbolic link %wZ\n", &DriveLetterU); 00176 } 00177 } 00178 } 00179 00180 NTSTATUS 00181 NTAPI 00182 ScsiClassAssignDriveLetter(PCLASS_DEVICE_INFO DeviceInfo) 00183 { 00184 WCHAR Buffer1[100]; 00185 WCHAR Buffer2[100]; 00186 UNICODE_STRING DriveLetterU, PartitionU; 00187 NTSTATUS Status; 00188 ULONG Index, PartitionNumber, DeviceNumber, DriveNumber; 00189 OBJECT_ATTRIBUTES ObjectAttributes; 00190 IO_STATUS_BLOCK Iosb; 00191 HANDLE PartitionHandle; 00192 00193 /* We assume this device does not current have a drive letter */ 00194 00195 Index = 0; 00196 DeviceNumber = 0; 00197 DriveNumber = 0; 00198 PartitionNumber = 1; 00199 DriveLetterU.Buffer = Buffer1; 00200 DriveLetterU.MaximumLength = sizeof(Buffer1); 00201 PartitionU.Buffer = Buffer2; 00202 PartitionU.MaximumLength = sizeof(Buffer2); 00203 00204 /* Determine the correct disk number */ 00205 do 00206 { 00207 /* Check that the disk exists */ 00208 PartitionU.Length = swprintf(PartitionU.Buffer, L"\\Device\\HardDisk%d\\Partition0", DeviceNumber) * sizeof(WCHAR); 00209 InitializeObjectAttributes(&ObjectAttributes, 00210 &PartitionU, 00211 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 00212 NULL, 00213 NULL); 00214 Status = ZwOpenFile(&PartitionHandle, 00215 FILE_READ_ATTRIBUTES, 00216 &ObjectAttributes, 00217 &Iosb, 00218 0, 00219 0); 00220 if (!NT_SUCCESS(Status)) 00221 { 00222 /* Return the last one that worked */ 00223 DeviceNumber--; 00224 } 00225 else 00226 { 00227 ZwClose(PartitionHandle); 00228 DeviceNumber++; 00229 } 00230 } while (Status == STATUS_SUCCESS); 00231 00232 /* Determine the correct drive number */ 00233 do 00234 { 00235 /* Check that the drive exists */ 00236 PartitionU.Length = swprintf(PartitionU.Buffer, L"\\??\\PhysicalDrive%d", DriveNumber) * sizeof(WCHAR); 00237 InitializeObjectAttributes(&ObjectAttributes, 00238 &PartitionU, 00239 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 00240 NULL, 00241 NULL); 00242 Status = ZwOpenFile(&PartitionHandle, 00243 FILE_READ_ATTRIBUTES, 00244 &ObjectAttributes, 00245 &Iosb, 00246 0, 00247 0); 00248 if (NT_SUCCESS(Status)) 00249 { 00250 ZwClose(PartitionHandle); 00251 DriveNumber++; 00252 } 00253 } while (Status == STATUS_SUCCESS); 00254 00255 /* Create the symbolic link to PhysicalDriveX */ 00256 PartitionU.Length = swprintf(PartitionU.Buffer, L"\\Device\\Harddisk%d\\Partition0", DeviceNumber) * sizeof(WCHAR); 00257 DriveLetterU.Length = swprintf(DriveLetterU.Buffer, L"\\??\\PhysicalDrive%d", DriveNumber) * sizeof(WCHAR); 00258 00259 Status = IoCreateSymbolicLink(&DriveLetterU, &PartitionU); 00260 if (!NT_SUCCESS(Status)) 00261 { 00262 /* Failed to create symbolic link */ 00263 return Status; 00264 } 00265 00266 DbgPrint("HACK: Created symbolic link %wZ -> %wZ\n", &PartitionU, &DriveLetterU); 00267 00268 while (TRUE) 00269 { 00270 /* Check that the disk exists */ 00271 PartitionU.Length = swprintf(PartitionU.Buffer, L"\\Device\\Harddisk%d\\Partition%d", DeviceNumber, PartitionNumber) * sizeof(WCHAR); 00272 InitializeObjectAttributes(&ObjectAttributes, 00273 &PartitionU, 00274 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 00275 NULL, 00276 NULL); 00277 Status = ZwOpenFile(&PartitionHandle, 00278 FILE_READ_ATTRIBUTES, 00279 &ObjectAttributes, 00280 &Iosb, 00281 0, 00282 0); 00283 if (!NT_SUCCESS(Status)) 00284 break; 00285 else 00286 { 00287 ZwClose(PartitionHandle); 00288 00289 /* Assign it a drive letter */ 00290 do 00291 { 00292 DriveLetterU.Length = swprintf(DriveLetterU.Buffer, L"\\??\\%C:", ('C' + Index)) * sizeof(WCHAR); 00293 00294 Status = IoCreateSymbolicLink(&DriveLetterU, &PartitionU); 00295 00296 Index++; 00297 } while (Status != STATUS_SUCCESS); 00298 00299 DeviceInfo->Partitions |= (1 << (Index - 1)); 00300 00301 DbgPrint("HACK: Created symbolic link %wZ -> %wZ\n", &PartitionU, &DriveLetterU); 00302 PartitionNumber++; 00303 } 00304 } 00305 00306 DeviceInfo->DeviceNumber = DeviceNumber; 00307 DeviceInfo->DriveNumber = DriveNumber; 00308 00309 return STATUS_SUCCESS; 00310 } 00311 00312 NTSTATUS 00313 NTAPI 00314 ScsiClassPlugPlay( 00315 IN PDEVICE_OBJECT DeviceObject, 00316 IN PIRP Irp) 00317 { 00318 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 00319 00320 if (IrpSp->MinorFunction == IRP_MN_START_DEVICE) 00321 { 00322 IoSkipCurrentIrpStackLocation(Irp); 00323 return STATUS_SUCCESS; 00324 } 00325 else if (IrpSp->MinorFunction == IRP_MN_REMOVE_DEVICE) 00326 { 00327 PCLASS_DEVICE_INFO DeviceInfo = DeviceObject->DeviceExtension; 00328 00329 ScsiClassRemoveDriveLetter(DeviceInfo); 00330 00331 Irp->IoStatus.Status = STATUS_SUCCESS; 00332 IoCompleteRequest(Irp, IO_NO_INCREMENT); 00333 00334 IoDetachDevice(DeviceInfo->LowerDevice); 00335 IoDeleteDevice(DeviceObject); 00336 return STATUS_SUCCESS; 00337 } 00338 else 00339 { 00340 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; 00341 IoCompleteRequest(Irp, IO_NO_INCREMENT); 00342 return STATUS_NOT_SUPPORTED; 00343 } 00344 } 00345 00346 NTSTATUS 00347 NTAPI 00348 ScsiClassAddDevice( 00349 IN PDRIVER_OBJECT DriverObject, 00350 IN PDEVICE_OBJECT PhysicalDeviceObject) 00351 { 00352 PCLASS_DRIVER_EXTENSION DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject); 00353 PCLASS_DEVICE_INFO DeviceInfo; 00354 PDEVICE_OBJECT DeviceObject; 00355 NTSTATUS Status; 00356 00357 if (DriverExtension->InitializationData.ClassFindDevices(DriverObject, &DriverExtension->RegistryPath, &DriverExtension->InitializationData, 00358 PhysicalDeviceObject, DriverExtension->PortNumber)) 00359 { 00360 /* Create a device object */ 00361 Status = IoCreateDevice(DriverObject, 00362 sizeof(CLASS_DEVICE_INFO), 00363 NULL, 00364 FILE_DEVICE_DISK, 00365 0, 00366 FALSE, 00367 &DeviceObject); 00368 if (!NT_SUCCESS(Status)) 00369 { 00370 return Status; 00371 } 00372 00373 DeviceInfo = DeviceObject->DeviceExtension; 00374 RtlZeroMemory(DeviceInfo, sizeof(CLASS_DEVICE_INFO)); 00375 00376 /* Attach it to the PDO */ 00377 DeviceInfo->LowerDevice = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject); 00378 00379 /* Check that the kernel has already assigned drive letters */ 00380 if (KeLoaderBlock == NULL) 00381 { 00382 /* Assign a drive letter */ 00383 ScsiClassAssignDriveLetter(DeviceInfo); 00384 } 00385 else 00386 { 00387 /* The kernel will handle it */ 00388 } 00389 00390 /* Move to the next port number */ 00391 DriverExtension->PortNumber++; 00392 } 00393 else 00394 { 00395 /* Failed to find device */ 00396 DbgPrint("FAILED TO FIND DEVICE!\n"); 00397 } 00398 00399 return STATUS_SUCCESS; 00400 } 00401 /* ---- End hack ---- */ 00402 00403 00404 00405 ULONG 00406 NTAPI 00407 ScsiClassInitialize( 00408 IN PVOID Argument1, 00409 IN PVOID Argument2, 00410 IN PCLASS_INIT_DATA InitializationData 00411 ) 00412 00413 /*++ 00414 00415 Routine Description: 00416 00417 This routine is called by a class driver during its 00418 DriverEntry routine to initialize the driver. 00419 00420 Arguments: 00421 00422 Argument1 - Driver Object. 00423 Argument2 - Registry Path. 00424 InitializationData - Device-specific driver's initialization data. 00425 00426 Return Value: 00427 00428 A valid return code for a DriverEntry routine. 00429 00430 --*/ 00431 00432 { 00433 00434 00435 PDRIVER_OBJECT DriverObject = Argument1; 00436 PDEVICE_OBJECT portDeviceObject; 00437 NTSTATUS status; 00438 STRING deviceNameString; 00439 UNICODE_STRING unicodeDeviceName; 00440 PFILE_OBJECT fileObject; 00441 CCHAR deviceNameBuffer[256]; 00442 BOOLEAN deviceFound = FALSE; 00443 PCLASS_DRIVER_EXTENSION DriverExtension; 00444 PUNICODE_STRING RegistryPath = Argument2; 00445 00446 DebugPrint((3,"\n\nSCSI Class Driver\n")); 00447 00448 // 00449 // Validate the length of this structure. This is effectively a 00450 // version check. 00451 // 00452 00453 if (InitializationData->InitializationDataSize > sizeof(CLASS_INIT_DATA)) { 00454 00455 DebugPrint((0,"ScsiClassInitialize: Class driver wrong version\n")); 00456 return (ULONG) STATUS_REVISION_MISMATCH; 00457 } 00458 00459 // 00460 // Check that each required entry is not NULL. Note that Shutdown, Flush and Error 00461 // are not required entry points. 00462 // 00463 00464 if ((!InitializationData->ClassFindDevices) || 00465 (!InitializationData->ClassDeviceControl) || 00466 (!((InitializationData->ClassReadWriteVerification) || 00467 (InitializationData->ClassStartIo)))) { 00468 00469 DebugPrint((0, 00470 "ScsiClassInitialize: Class device-specific driver missing required entry\n")); 00471 00472 return (ULONG) STATUS_REVISION_MISMATCH; 00473 } 00474 00475 status = IoAllocateDriverObjectExtension(DriverObject, 00476 DriverObject, 00477 sizeof(CLASS_DRIVER_EXTENSION), 00478 (PVOID *)&DriverExtension); 00479 if (!NT_SUCCESS(status)) 00480 return status; 00481 00482 RtlCopyMemory(&DriverExtension->InitializationData, InitializationData, sizeof(CLASS_INIT_DATA)); 00483 DriverExtension->PortNumber = 0; 00484 00485 DriverExtension->RegistryPath.Buffer = ExAllocatePool(PagedPool, RegistryPath->MaximumLength); 00486 if (!DriverExtension->RegistryPath.Buffer) 00487 return STATUS_NO_MEMORY; 00488 00489 DriverExtension->RegistryPath.Length = RegistryPath->Length; 00490 DriverExtension->RegistryPath.MaximumLength = RegistryPath->MaximumLength; 00491 00492 RtlCopyMemory(DriverExtension->RegistryPath.Buffer, 00493 RegistryPath->Buffer, 00494 RegistryPath->Length); 00495 00496 // 00497 // Update driver object with entry points. 00498 // 00499 00500 DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiClassCreateClose; 00501 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiClassCreateClose; 00502 DriverObject->MajorFunction[IRP_MJ_READ] = ScsiClassReadWrite; 00503 DriverObject->MajorFunction[IRP_MJ_WRITE] = ScsiClassReadWrite; 00504 DriverObject->MajorFunction[IRP_MJ_PNP] = ScsiClassPlugPlay; 00505 DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiClassInternalIoControl; 00506 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiClassDeviceControlDispatch; 00507 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = ScsiClassShutdownFlush; 00508 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = ScsiClassShutdownFlush; 00509 DriverObject->DriverExtension->AddDevice = ScsiClassAddDevice; 00510 00511 if (InitializationData->ClassStartIo) { 00512 DriverObject->DriverStartIo = InitializationData->ClassStartIo; 00513 } 00514 00515 // 00516 // Open port driver controller device objects by name. 00517 // 00518 00519 do { 00520 00521 sprintf(deviceNameBuffer, "\\Device\\ScsiPort%lu", DriverExtension->PortNumber); 00522 00523 DebugPrint((2, "ScsiClassInitialize: Open Port %s\n", deviceNameBuffer)); 00524 00525 RtlInitString(&deviceNameString, deviceNameBuffer); 00526 00527 status = RtlAnsiStringToUnicodeString(&unicodeDeviceName, 00528 &deviceNameString, 00529 TRUE); 00530 00531 if (!NT_SUCCESS(status)){ 00532 break; 00533 } 00534 00535 status = IoGetDeviceObjectPointer(&unicodeDeviceName, 00536 FILE_READ_ATTRIBUTES, 00537 &fileObject, 00538 &portDeviceObject); 00539 00540 if (NT_SUCCESS(status)) { 00541 00542 // 00543 // Call the device-specific driver's FindDevice routine. 00544 // 00545 00546 if (InitializationData->ClassFindDevices(DriverObject, Argument2, InitializationData, 00547 portDeviceObject, DriverExtension->PortNumber)) { 00548 00549 deviceFound = TRUE; 00550 } 00551 } 00552 00553 // 00554 // Check next SCSI adapter. 00555 // 00556 00557 DriverExtension->PortNumber++; 00558 00559 } while(NT_SUCCESS(status)); 00560 00561 /* We don't want to fail init just because we don't have devices right now */ 00562 return STATUS_SUCCESS; /*deviceFound ? STATUS_SUCCESS : STATUS_NO_SUCH_DEVICE;*/ 00563 } 00564 00565 00566 NTSTATUS 00567 NTAPI 00568 ScsiClassCreateClose( 00569 IN PDEVICE_OBJECT DeviceObject, 00570 IN PIRP Irp 00571 ) 00572 00573 /*++ 00574 00575 Routine Description: 00576 00577 SCSI class driver create and close routine. This is called by the I/O system 00578 when the device is opened or closed. 00579 00580 Arguments: 00581 00582 DriverObject - Pointer to driver object created by system. 00583 00584 Irp - IRP involved. 00585 00586 Return Value: 00587 00588 Device-specific drivers return value or STATUS_SUCCESS. 00589 00590 --*/ 00591 00592 { 00593 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 00594 00595 // 00596 // Invoke the device-specific routine, if one exists. Otherwise complete 00597 // with SUCCESS 00598 // 00599 00600 if (deviceExtension->ClassCreateClose) { 00601 00602 return deviceExtension->ClassCreateClose(DeviceObject, Irp); 00603 00604 } else { 00605 Irp->IoStatus.Status = STATUS_SUCCESS; 00606 00607 IoCompleteRequest(Irp, IO_NO_INCREMENT); 00608 return(STATUS_SUCCESS); 00609 } 00610 } 00611 00612 00613 00614 NTSTATUS 00615 NTAPI 00616 ScsiClassReadWrite( 00617 IN PDEVICE_OBJECT DeviceObject, 00618 IN PIRP Irp 00619 ) 00620 00621 /*++ 00622 00623 Routine Description: 00624 00625 This is the system entry point for read and write requests. The device-specific handler is invoked 00626 to perform any validation necessary. The number of bytes in the request are 00627 checked against the maximum byte counts that the adapter supports and requests are broken up into 00628 smaller sizes if necessary. 00629 00630 Arguments: 00631 00632 DeviceObject 00633 Irp - IO request 00634 00635 Return Value: 00636 00637 NT Status 00638 00639 --*/ 00640 00641 { 00642 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 00643 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); 00644 ULONG transferPages; 00645 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length; 00646 ULONG maximumTransferLength = deviceExtension->PortCapabilities->MaximumTransferLength; 00647 NTSTATUS status; 00648 00649 if (DeviceObject->Flags & DO_VERIFY_VOLUME && 00650 !(currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) { 00651 00652 // 00653 // if DO_VERIFY_VOLUME bit is set 00654 // in device object flags, fail request. 00655 // 00656 00657 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject); 00658 00659 Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED; 00660 Irp->IoStatus.Information = 0; 00661 00662 IoCompleteRequest(Irp, 0); 00663 return STATUS_VERIFY_REQUIRED; 00664 } 00665 00666 // 00667 // Invoke the device specific routine to do whatever it needs to verify 00668 // this request. 00669 // 00670 00671 ASSERT(deviceExtension->ClassReadWriteVerification); 00672 00673 status = deviceExtension->ClassReadWriteVerification(DeviceObject,Irp); 00674 00675 if (!NT_SUCCESS(status)) { 00676 00677 // 00678 // It is up to the device specific driver to set the Irp status. 00679 // 00680 00681 IoCompleteRequest (Irp, IO_NO_INCREMENT); 00682 return status; 00683 } else if (status == STATUS_PENDING) { 00684 00685 IoMarkIrpPending(Irp); 00686 return STATUS_PENDING; 00687 } 00688 00689 // 00690 // Check for a zero length IO, as several macros will turn this into 00691 // seemingly a 0xffffffff length request. 00692 // 00693 00694 if (transferByteCount == 0) { 00695 Irp->IoStatus.Status = STATUS_SUCCESS; 00696 Irp->IoStatus.Information = 0; 00697 IoCompleteRequest(Irp, IO_NO_INCREMENT); 00698 return STATUS_SUCCESS; 00699 00700 } 00701 00702 if (deviceExtension->ClassStartIo) { 00703 00704 IoMarkIrpPending(Irp); 00705 00706 IoStartPacket(DeviceObject, 00707 Irp, 00708 NULL, 00709 NULL); 00710 00711 return STATUS_PENDING; 00712 } 00713 00714 // 00715 // Mark IRP with status pending. 00716 // 00717 00718 IoMarkIrpPending(Irp); 00719 00720 // 00721 // Add partition byte offset to make starting byte relative to 00722 // beginning of disk. In addition, add in skew for DM Driver, if any. 00723 // 00724 00725 currentIrpStack->Parameters.Read.ByteOffset.QuadPart += (deviceExtension->StartingOffset.QuadPart + 00726 deviceExtension->DMByteSkew); 00727 00728 // 00729 // Calculate number of pages in this transfer. 00730 // 00731 00732 transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress), 00733 currentIrpStack->Parameters.Read.Length); 00734 00735 // 00736 // Check if request length is greater than the maximum number of 00737 // bytes that the hardware can transfer. 00738 // 00739 00740 if (currentIrpStack->Parameters.Read.Length > maximumTransferLength || 00741 transferPages > deviceExtension->PortCapabilities->MaximumPhysicalPages) { 00742 00743 DebugPrint((2,"ScsiClassReadWrite: Request greater than maximum\n")); 00744 DebugPrint((2,"ScsiClassReadWrite: Maximum is %lx\n", 00745 maximumTransferLength)); 00746 DebugPrint((2,"ScsiClassReadWrite: Byte count is %lx\n", 00747 currentIrpStack->Parameters.Read.Length)); 00748 00749 transferPages = 00750 deviceExtension->PortCapabilities->MaximumPhysicalPages - 1; 00751 00752 if (maximumTransferLength > transferPages << PAGE_SHIFT ) { 00753 maximumTransferLength = transferPages << PAGE_SHIFT; 00754 } 00755 00756 // 00757 // Check that maximum transfer size is not zero. 00758 // 00759 00760 if (maximumTransferLength == 0) { 00761 maximumTransferLength = PAGE_SIZE; 00762 } 00763 00764 // 00765 // Mark IRP with status pending. 00766 // 00767 00768 IoMarkIrpPending(Irp); 00769 00770 // 00771 // Request greater than port driver maximum. 00772 // Break up into smaller routines. 00773 // 00774 00775 ScsiClassSplitRequest(DeviceObject, Irp, maximumTransferLength); 00776 00777 00778 return STATUS_PENDING; 00779 } 00780 00781 // 00782 // Build SRB and CDB for this IRP. 00783 // 00784 00785 ScsiClassBuildRequest(DeviceObject, Irp); 00786 00787 // 00788 // Return the results of the call to the port driver. 00789 // 00790 00791 return IoCallDriver(deviceExtension->PortDeviceObject, Irp); 00792 00793 } // end ScsiClassReadWrite() 00794 00795 00796 NTSTATUS 00797 NTAPI 00798 ScsiClassGetCapabilities( 00799 IN PDEVICE_OBJECT PortDeviceObject, 00800 OUT PIO_SCSI_CAPABILITIES *PortCapabilities 00801 ) 00802 00803 /*++ 00804 00805 Routine Description: 00806 00807 This routine builds and sends a request to the port driver to 00808 get a pointer to a structure that describes the adapter's 00809 capabilities/limitations. This routine is sychronous. 00810 00811 Arguments: 00812 00813 PortDeviceObject - Port driver device object representing the HBA. 00814 00815 PortCapabilities - Location to store pointer to capabilities structure. 00816 00817 Return Value: 00818 00819 Nt status indicating the results of the operation. 00820 00821 Notes: 00822 00823 This routine should only be called at initialization time. 00824 00825 --*/ 00826 00827 { 00828 PIRP irp; 00829 IO_STATUS_BLOCK ioStatus; 00830 KEVENT event; 00831 NTSTATUS status; 00832 00833 PAGED_CODE(); 00834 00835 // 00836 // Create notification event object to be used to signal the 00837 // request completion. 00838 // 00839 00840 KeInitializeEvent(&event, NotificationEvent, FALSE); 00841 00842 // 00843 // Build the synchronous request to be sent to the port driver 00844 // to perform the request. 00845 // 00846 00847 irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_CAPABILITIES, 00848 PortDeviceObject, 00849 NULL, 00850 0, 00851 PortCapabilities, 00852 sizeof(PVOID), 00853 FALSE, 00854 &event, 00855 &ioStatus); 00856 00857 if (irp == NULL) { 00858 return STATUS_INSUFFICIENT_RESOURCES; 00859 } 00860 00861 // 00862 // Pass request to port driver and wait for request to complete. 00863 // 00864 00865 status = IoCallDriver(PortDeviceObject, irp); 00866 00867 if (status == STATUS_PENDING) { 00868 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL); 00869 return(ioStatus.Status); 00870 } 00871 00872 return status; 00873 00874 } // end ScsiClassGetCapabilities() 00875 00876 00877 NTSTATUS 00878 NTAPI 00879 ScsiClassGetInquiryData( 00880 IN PDEVICE_OBJECT PortDeviceObject, 00881 OUT PSCSI_ADAPTER_BUS_INFO *ConfigInfo 00882 ) 00883 00884 /*++ 00885 00886 Routine Description: 00887 00888 This routine sends a request to a port driver to return 00889 configuration information. Space for the information is 00890 allocated by this routine. The caller is responsible for 00891 freeing the configuration information. This routine is 00892 synchronous. 00893 00894 Arguments: 00895 00896 PortDeviceObject - Port driver device object representing the HBA. 00897 00898 ConfigInfo - Returns a pointer to the configuration information. 00899 00900 Return Value: 00901 00902 Nt status indicating the results of the operation. 00903 00904 Notes: 00905 00906 This routine should be called only at initialization time. 00907 00908 --*/ 00909 00910 { 00911 PIRP irp; 00912 IO_STATUS_BLOCK ioStatus; 00913 KEVENT event; 00914 NTSTATUS status; 00915 PSCSI_ADAPTER_BUS_INFO buffer; 00916 00917 PAGED_CODE(); 00918 00919 buffer = ExAllocatePool(PagedPool, INQUIRY_DATA_SIZE); 00920 *ConfigInfo = buffer; 00921 00922 if (buffer == NULL) { 00923 return(STATUS_INSUFFICIENT_RESOURCES); 00924 } 00925 00926 // 00927 // Create notification event object to be used to signal the inquiry 00928 // request completion. 00929 // 00930 00931 KeInitializeEvent(&event, NotificationEvent, FALSE); 00932 00933 // 00934 // Build the synchronous request to be sent to the port driver 00935 // to perform the inquiries. 00936 // 00937 00938 irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA, 00939 PortDeviceObject, 00940 NULL, 00941 0, 00942 buffer, 00943 INQUIRY_DATA_SIZE, 00944 FALSE, 00945 &event, 00946 &ioStatus); 00947 00948 if (irp == NULL) { 00949 return(STATUS_INSUFFICIENT_RESOURCES); 00950 } 00951 00952 // 00953 // Pass request to port driver and wait for request to complete. 00954 // 00955 00956 status = IoCallDriver(PortDeviceObject, irp); 00957 00958 if (status == STATUS_PENDING) { 00959 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL); 00960 status = ioStatus.Status; 00961 } 00962 00963 if (!NT_SUCCESS(status)) { 00964 00965 // 00966 // Free the buffer on an error. 00967 // 00968 00969 ExFreePool(buffer); 00970 *ConfigInfo = NULL; 00971 00972 } 00973 00974 return status; 00975 00976 } // end ScsiClassGetInquiryData() 00977 00978 00979 NTSTATUS 00980 NTAPI 00981 ScsiClassReadDriveCapacity( 00982 IN PDEVICE_OBJECT DeviceObject 00983 ) 00984 00985 /*++ 00986 00987 Routine Description: 00988 00989 This routine sends a READ CAPACITY to the requested device, updates 00990 the geometry information in the device object and returns 00991 when it is complete. This routine is synchronous. 00992 00993 Arguments: 00994 00995 DeviceObject - Supplies a pointer to the device object that represents 00996 the device whose capacity is to be read. 00997 00998 Return Value: 00999 01000 Status is returned. 01001 01002 --*/ 01003 { 01004 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 01005 ULONG retries = 1; 01006 ULONG lastSector; 01007 PCDB cdb; 01008 PREAD_CAPACITY_DATA readCapacityBuffer; 01009 SCSI_REQUEST_BLOCK srb; 01010 NTSTATUS status; 01011 01012 // 01013 // Allocate read capacity buffer from nonpaged pool. 01014 // 01015 01016 readCapacityBuffer = ExAllocatePool(NonPagedPoolCacheAligned, 01017 sizeof(READ_CAPACITY_DATA)); 01018 01019 if (!readCapacityBuffer) { 01020 return(STATUS_INSUFFICIENT_RESOURCES); 01021 } 01022 01023 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); 01024 01025 // 01026 // Build the read capacity CDB. 01027 // 01028 01029 srb.CdbLength = 10; 01030 cdb = (PCDB)srb.Cdb; 01031 01032 // 01033 // Set timeout value from device extension. 01034 // 01035 01036 srb.TimeOutValue = deviceExtension->TimeOutValue; 01037 01038 cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY; 01039 01040 Retry: 01041 01042 status = ScsiClassSendSrbSynchronous(DeviceObject, 01043 &srb, 01044 readCapacityBuffer, 01045 sizeof(READ_CAPACITY_DATA), 01046 FALSE); 01047 01048 if (NT_SUCCESS(status)) { 01049 01050 // 01051 // Copy sector size from read capacity buffer to device extension 01052 // in reverse byte order. 01053 // 01054 01055 ((PFOUR_BYTE)&deviceExtension->DiskGeometry->Geometry.BytesPerSector)->Byte0 = 01056 ((PFOUR_BYTE)&readCapacityBuffer->BytesPerBlock)->Byte3; 01057 01058 ((PFOUR_BYTE)&deviceExtension->DiskGeometry->Geometry.BytesPerSector)->Byte1 = 01059 ((PFOUR_BYTE)&readCapacityBuffer->BytesPerBlock)->Byte2; 01060 01061 ((PFOUR_BYTE)&deviceExtension->DiskGeometry->Geometry.BytesPerSector)->Byte2 = 01062 ((PFOUR_BYTE)&readCapacityBuffer->BytesPerBlock)->Byte1; 01063 01064 ((PFOUR_BYTE)&deviceExtension->DiskGeometry->Geometry.BytesPerSector)->Byte3 = 01065 ((PFOUR_BYTE)&readCapacityBuffer->BytesPerBlock)->Byte0; 01066 01067 // 01068 // Copy last sector in reverse byte order. 01069 // 01070 01071 ((PFOUR_BYTE)&lastSector)->Byte0 = 01072 ((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte3; 01073 01074 ((PFOUR_BYTE)&lastSector)->Byte1 = 01075 ((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte2; 01076 01077 ((PFOUR_BYTE)&lastSector)->Byte2 = 01078 ((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte1; 01079 01080 ((PFOUR_BYTE)&lastSector)->Byte3 = 01081 ((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte0; 01082 01083 // 01084 // Calculate sector to byte shift. 01085 // 01086 01087 WHICH_BIT(deviceExtension->DiskGeometry->Geometry.BytesPerSector, deviceExtension->SectorShift); 01088 01089 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n", 01090 deviceExtension->DiskGeometry->Geometry.BytesPerSector)); 01091 01092 DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n", 01093 lastSector + 1)); 01094 01095 // 01096 // Calculate media capacity in bytes. 01097 // 01098 01099 deviceExtension->PartitionLength.QuadPart = (LONGLONG)(lastSector + 1); 01100 01101 // 01102 // Calculate number of cylinders. 01103 // 01104 01105 deviceExtension->DiskGeometry->Geometry.Cylinders.QuadPart = (LONGLONG)((lastSector + 1)/(DEFAULT_SECTORS_PER_TRACK * DEFAULT_TRACKS_PER_CYLINDER)); 01106 01107 deviceExtension->PartitionLength.QuadPart = 01108 (deviceExtension->PartitionLength.QuadPart << deviceExtension->SectorShift); 01109 01110 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) { 01111 01112 // 01113 // This device supports removable media. 01114 // 01115 01116 deviceExtension->DiskGeometry->Geometry.MediaType = RemovableMedia; 01117 01118 } else { 01119 01120 // 01121 // Assume media type is fixed disk. 01122 // 01123 01124 deviceExtension->DiskGeometry->Geometry.MediaType = FixedMedia; 01125 } 01126 01127 // 01128 // Assume sectors per track are DEFAULT_SECTORS_PER_TRACK; 01129 // 01130 01131 deviceExtension->DiskGeometry->Geometry.SectorsPerTrack = DEFAULT_SECTORS_PER_TRACK; 01132 01133 // 01134 // Assume tracks per cylinder (number of heads) is DEFAULT_TRACKS_PER_CYLINDER. 01135 // 01136 01137 deviceExtension->DiskGeometry->Geometry.TracksPerCylinder = DEFAULT_TRACKS_PER_CYLINDER; 01138 } 01139 01140 if (status == STATUS_VERIFY_REQUIRED) { 01141 01142 // 01143 // Routine ScsiClassSendSrbSynchronous does not retry 01144 // requests returned with this status. 01145 // Read Capacities should be retried 01146 // anyway. 01147 // 01148 01149 if (retries--) { 01150 01151 // 01152 // Retry request. 01153 // 01154 01155 goto Retry; 01156 } 01157 } 01158 01159 if (!NT_SUCCESS(status)) { 01160 01161 // 01162 // If the read capacity fails, set the geometry to reasonable parameter 01163 // so things don't fail at unexpected places. Zero the geometry 01164 // except for the bytes per sector and sector shift. 01165 // 01166 01167 RtlZeroMemory(deviceExtension->DiskGeometry, sizeof(DISK_GEOMETRY_EX)); 01168 deviceExtension->DiskGeometry->Geometry.BytesPerSector = 512; 01169 deviceExtension->SectorShift = 9; 01170 deviceExtension->PartitionLength.QuadPart = (LONGLONG) 0; 01171 01172 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) { 01173 01174 // 01175 // This device supports removable media. 01176 // 01177 01178 deviceExtension->DiskGeometry->Geometry.MediaType = RemovableMedia; 01179 01180 } else { 01181 01182 // 01183 // Assume media type is fixed disk. 01184 // 01185 01186 deviceExtension->DiskGeometry->Geometry.MediaType = FixedMedia; 01187 } 01188 } 01189 01190 // 01191 // Deallocate read capacity buffer. 01192 // 01193 01194 ExFreePool(readCapacityBuffer); 01195 01196 return status; 01197 01198 } // end ScsiClassReadDriveCapacity() 01199 01200 01201 VOID 01202 NTAPI 01203 ScsiClassReleaseQueue( 01204 IN PDEVICE_OBJECT DeviceObject 01205 ) 01206 01207 /*++ 01208 01209 Routine Description: 01210 01211 This routine issues an internal device control command 01212 to the port driver to release a frozen queue. The call 01213 is issued asynchronously as ScsiClassReleaseQueue will be invoked 01214 from the IO completion DPC (and will have no context to 01215 wait for a synchronous call to complete). 01216 01217 Arguments: 01218 01219 DeviceObject - The device object for the logical unit with 01220 the frozen queue. 01221 01222 Return Value: 01223 01224 None. 01225 01226 --*/ 01227 { 01228 PIO_STACK_LOCATION irpStack; 01229 PIRP irp; 01230 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 01231 PCOMPLETION_CONTEXT context; 01232 PSCSI_REQUEST_BLOCK srb; 01233 KIRQL currentIrql; 01234 01235 // 01236 // Allocate context from nonpaged pool. 01237 // 01238 01239 context = ExAllocatePool(NonPagedPoolMustSucceed, 01240 sizeof(COMPLETION_CONTEXT)); 01241 01242 // 01243 // Save the device object in the context for use by the completion 01244 // routine. 01245 // 01246 01247 context->DeviceObject = DeviceObject; 01248 srb = &context->Srb; 01249 01250 // 01251 // Zero out srb. 01252 // 01253 01254 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE); 01255 01256 // 01257 // Write length to SRB. 01258 // 01259 01260 srb->Length = SCSI_REQUEST_BLOCK_SIZE; 01261 01262 // 01263 // Set up SCSI bus address. 01264 // 01265 01266 srb->PathId = deviceExtension->PathId; 01267 srb->TargetId = deviceExtension->TargetId; 01268 srb->Lun = deviceExtension->Lun; 01269 01270 // 01271 // If this device is removable then flush the queue. This will also 01272 // release it. 01273 // 01274 01275 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) { 01276 01277 srb->Function = SRB_FUNCTION_FLUSH_QUEUE; 01278 01279 } else { 01280 01281 srb->Function = SRB_FUNCTION_RELEASE_QUEUE; 01282 01283 } 01284 01285 // 01286 // Build the asynchronous request to be sent to the port driver. 01287 // 01288 01289 irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 01290 01291 if(irp == NULL) { 01292 01293 // 01294 // We have no better way of dealing with this at the moment 01295 // 01296 01297 KeBugCheck((ULONG)0x0000002DL); 01298 01299 } 01300 01301 IoSetCompletionRoutine(irp, 01302 (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion, 01303 context, 01304 TRUE, 01305 TRUE, 01306 TRUE); 01307 01308 irpStack = IoGetNextIrpStackLocation(irp); 01309 01310 irpStack->MajorFunction = IRP_MJ_SCSI; 01311 01312 srb->OriginalRequest = irp; 01313 01314 // 01315 // Store the SRB address in next stack for port driver. 01316 // 01317 01318 irpStack->Parameters.Scsi.Srb = srb; 01319 01320 // 01321 // Since this routine can cause outstanding requests to be completed, and 01322 // calling a completion routine at < DISPATCH_LEVEL is dangerous (if they 01323 // call IoStartNextPacket we will bugcheck) raise up to dispatch level before 01324 // issuing the request 01325 // 01326 01327 currentIrql = KeGetCurrentIrql(); 01328 01329 if(currentIrql < DISPATCH_LEVEL) { 01330 KeRaiseIrql(DISPATCH_LEVEL, ¤tIrql); 01331 IoCallDriver(deviceExtension->PortDeviceObject, irp); 01332 KeLowerIrql(currentIrql); 01333 } else { 01334 IoCallDriver(deviceExtension->PortDeviceObject, irp); 01335 } 01336 01337 return; 01338 01339 } // end ScsiClassReleaseQueue() 01340 01341 01342 VOID 01343 NTAPI 01344 StartUnit( 01345 IN PDEVICE_OBJECT DeviceObject 01346 ) 01347 01348 /*++ 01349 01350 Routine Description: 01351 01352 Send command to SCSI unit to start or power up. 01353 Because this command is issued asynchronounsly, that is, without 01354 waiting on it to complete, the IMMEDIATE flag is not set. This 01355 means that the CDB will not return until the drive has powered up. 01356 This should keep subsequent requests from being submitted to the 01357 device before it has completely spun up. 01358 This routine is called from the InterpretSense routine, when a 01359 request sense returns data indicating that a drive must be 01360 powered up. 01361 01362 Arguments: 01363 01364 DeviceObject - The device object for the logical unit with 01365 the frozen queue. 01366 01367 Return Value: 01368 01369 None. 01370 01371 --*/ 01372 { 01373 PIO_STACK_LOCATION irpStack; 01374 PIRP irp; 01375 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 01376 PSCSI_REQUEST_BLOCK srb; 01377 PCOMPLETION_CONTEXT context; 01378 PCDB cdb; 01379 01380 // 01381 // Allocate Srb from nonpaged pool. 01382 // 01383 01384 context = ExAllocatePool(NonPagedPoolMustSucceed, 01385 sizeof(COMPLETION_CONTEXT)); 01386 01387 // 01388 // Save the device object in the context for use by the completion 01389 // routine. 01390 // 01391 01392 context->DeviceObject = DeviceObject; 01393 srb = &context->Srb; 01394 01395 // 01396 // Zero out srb. 01397 // 01398 01399 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE); 01400 01401 // 01402 // Write length to SRB. 01403 // 01404 01405 srb->Length = SCSI_REQUEST_BLOCK_SIZE; 01406 01407 // 01408 // Set up SCSI bus address. 01409 // 01410 01411 srb->PathId = deviceExtension->PathId; 01412 srb->TargetId = deviceExtension->TargetId; 01413 srb->Lun = deviceExtension->Lun; 01414 01415 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 01416 01417 // 01418 // Set timeout value large enough for drive to spin up. 01419 // 01420 01421 srb->TimeOutValue = START_UNIT_TIMEOUT; 01422 01423 // 01424 // Set the transfer length. 01425 // 01426 01427 srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER | SRB_FLAGS_DISABLE_AUTOSENSE | SRB_FLAGS_DISABLE_SYNCH_TRANSFER; 01428 01429 // 01430 // Build the start unit CDB. 01431 // 01432 01433 srb->CdbLength = 6; 01434 cdb = (PCDB)srb->Cdb; 01435 01436 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT; 01437 cdb->START_STOP.Start = 1; 01438 cdb->START_STOP.LogicalUnitNumber = srb->Lun; 01439 01440 // 01441 // Build the asynchronous request to be sent to the port driver. 01442 // Since this routine is called from a DPC the IRP should always be 01443 // available. 01444 // 01445 01446 irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 01447 IoSetCompletionRoutine(irp, 01448 (PIO_COMPLETION_ROUTINE)ScsiClassAsynchronousCompletion, 01449 context, 01450 TRUE, 01451 TRUE, 01452 TRUE); 01453 01454 irpStack = IoGetNextIrpStackLocation(irp); 01455 irpStack->MajorFunction = IRP_MJ_SCSI; 01456 srb->OriginalRequest = irp; 01457 01458 // 01459 // Store the SRB address in next stack for port driver. 01460 // 01461 01462 irpStack->Parameters.Scsi.Srb = srb; 01463 01464 // 01465 // Call the port driver with the IRP. 01466 // 01467 01468 IoCallDriver(deviceExtension->PortDeviceObject, irp); 01469 01470 return; 01471 01472 } // end StartUnit() 01473 01474 01475 NTSTATUS 01476 NTAPI 01477 ScsiClassAsynchronousCompletion( 01478 PDEVICE_OBJECT DeviceObject, 01479 PIRP Irp, 01480 PVOID Context 01481 ) 01482 /*++ 01483 01484 Routine Description: 01485 01486 This routine is called when an asynchronous I/O request 01487 which was issused by the class driver completes. Examples of such requests 01488 are release queue or START UNIT. This routine releases the queue if 01489 necessary. It then frees the context and the IRP. 01490 01491 Arguments: 01492 01493 DeviceObject - The device object for the logical unit; however since this 01494 is the top stack location the value is NULL. 01495 01496 Irp - Supplies a pointer to the Irp to be processed. 01497 01498 Context - Supplies the context to be used to process this request. 01499 01500 Return Value: 01501 01502 None. 01503 01504 --*/ 01505 01506 { 01507 PCOMPLETION_CONTEXT context = Context; 01508 PSCSI_REQUEST_BLOCK srb; 01509 01510 srb = &context->Srb; 01511 01512 // 01513 // If this is an execute srb, then check the return status and make sure. 01514 // the queue is not frozen. 01515 // 01516 01517 if (srb->Function == SRB_FUNCTION_EXECUTE_SCSI) { 01518 01519 // 01520 // Check for a frozen queue. 01521 // 01522 01523 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) { 01524 01525 // 01526 // Unfreeze the queue getting the device object from the context. 01527 // 01528 01529 ScsiClassReleaseQueue(context->DeviceObject); 01530 } 01531 } 01532 01533 // 01534 // Free the context and the Irp. 01535 // 01536 01537 if (Irp->MdlAddress != NULL) { 01538 MmUnlockPages(Irp->MdlAddress); 01539 IoFreeMdl(Irp->MdlAddress); 01540 01541 Irp->MdlAddress = NULL; 01542 } 01543 01544 ExFreePool(context); 01545 IoFreeIrp(Irp); 01546 01547 // 01548 // Indicate the I/O system should stop processing the Irp completion. 01549 // 01550 01551 return STATUS_MORE_PROCESSING_REQUIRED; 01552 01553 } // ScsiClassAsynchronousCompletion() 01554 01555 01556 VOID 01557 NTAPI 01558 ScsiClassSplitRequest( 01559 IN PDEVICE_OBJECT DeviceObject, 01560 IN PIRP Irp, 01561 IN ULONG MaximumBytes 01562 ) 01563 01564 /*++ 01565 01566 Routine Description: 01567 01568 Break request into smaller requests. Each new request will be the 01569 maximum transfer size that the port driver can handle or if it 01570 is the final request, it may be the residual size. 01571 01572 The number of IRPs required to process this request is written in the 01573 current stack of the original IRP. Then as each new IRP completes 01574 the count in the original IRP is decremented. When the count goes to 01575 zero, the original IRP is completed. 01576 01577 Arguments: 01578 01579 DeviceObject - Pointer to the class device object to be addressed. 01580 01581 Irp - Pointer to Irp the orginal request. 01582 01583 Return Value: 01584 01585 None. 01586 01587 --*/ 01588 01589 { 01590 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 01591 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); 01592 PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp); 01593 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length; 01594 LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset; 01595 PVOID dataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress); 01596 ULONG dataLength = MaximumBytes; 01597 ULONG irpCount = (transferByteCount + MaximumBytes - 1) / MaximumBytes; 01598 ULONG i; 01599 PSCSI_REQUEST_BLOCK srb; 01600 01601 DebugPrint((2, "ScsiClassSplitRequest: Requires %d IRPs\n", irpCount)); 01602 DebugPrint((2, "ScsiClassSplitRequest: Original IRP %lx\n", Irp)); 01603 01604 // 01605 // If all partial transfers complete successfully then the status and 01606 // bytes transferred are already set up. Failing a partial-transfer IRP 01607 // will set status to error and bytes transferred to 0 during 01608 // IoCompletion. Setting bytes transferred to 0 if an IRP fails allows 01609 // asynchronous partial transfers. This is an optimization for the 01610 // successful case. 01611 // 01612 01613 Irp->IoStatus.Status = STATUS_SUCCESS; 01614 Irp->IoStatus.Information = transferByteCount; 01615 01616 // 01617 // Save number of IRPs to complete count on current stack 01618 // of original IRP. 01619 // 01620 01621 nextIrpStack->Parameters.Others.Argument1 = (PVOID)(ULONG_PTR) irpCount; 01622 01623 for (i = 0; i < irpCount; i++) { 01624 01625 PIRP newIrp; 01626 PIO_STACK_LOCATION newIrpStack; 01627 01628 // 01629 // Allocate new IRP. 01630 // 01631 01632 newIrp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 01633 01634 if (newIrp == NULL) { 01635 01636 DebugPrint((1,"ScsiClassSplitRequest: Can't allocate Irp\n")); 01637 01638 // 01639 // If an Irp can't be allocated then the orginal request cannot 01640 // be executed. If this is the first request then just fail the 01641 // orginal request; otherwise just return. When the pending 01642 // requests complete, they will complete the original request. 01643 // In either case set the IRP status to failure. 01644 // 01645 01646 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 01647 Irp->IoStatus.Information = 0; 01648 01649 if (i == 0) { 01650 IoCompleteRequest(Irp, IO_NO_INCREMENT); 01651 } 01652 01653 return; 01654 } 01655 01656 DebugPrint((2, "ScsiClassSplitRequest: New IRP %lx\n", newIrp)); 01657 01658 // 01659 // Write MDL address to new IRP. In the port driver the SRB data 01660 // buffer field is used as an offset into the MDL, so the same MDL 01661 // can be used for each partial transfer. This saves having to build 01662 // a new MDL for each partial transfer. 01663 // 01664 01665 newIrp->MdlAddress = Irp->MdlAddress; 01666 01667 // 01668 // At this point there is no current stack. IoSetNextIrpStackLocation 01669 // will make the first stack location the current stack so that the 01670 // SRB address can be written there. 01671 // 01672 01673 IoSetNextIrpStackLocation(newIrp); 01674 newIrpStack = IoGetCurrentIrpStackLocation(newIrp); 01675 01676 newIrpStack->MajorFunction = currentIrpStack->MajorFunction; 01677 newIrpStack->Parameters.Read.Length = dataLength; 01678 newIrpStack->Parameters.Read.ByteOffset = startingOffset; 01679 newIrpStack->DeviceObject = DeviceObject; 01680 01681 // 01682 // Build SRB and CDB. 01683 // 01684 01685 ScsiClassBuildRequest(DeviceObject, newIrp); 01686 01687 // 01688 // Adjust SRB for this partial transfer. 01689 // 01690 01691 newIrpStack = IoGetNextIrpStackLocation(newIrp); 01692 01693 srb = newIrpStack->Parameters.Others.Argument1; 01694 srb->DataBuffer = dataBuffer; 01695 01696 // 01697 // Write original IRP address to new IRP. 01698 // 01699 01700 newIrp->AssociatedIrp.MasterIrp = Irp; 01701 01702 // 01703 // Set the completion routine to ScsiClassIoCompleteAssociated. 01704 // 01705 01706 IoSetCompletionRoutine(newIrp, 01707 ScsiClassIoCompleteAssociated, 01708 srb, 01709 TRUE, 01710 TRUE, 01711 TRUE); 01712 01713 // 01714 // Call port driver with new request. 01715 // 01716 01717 IoCallDriver(deviceExtension->PortDeviceObject, newIrp); 01718 01719 // 01720 // Set up for next request. 01721 // 01722 01723 dataBuffer = (PCHAR)dataBuffer + MaximumBytes; 01724 01725 transferByteCount -= MaximumBytes; 01726 01727 if (transferByteCount > MaximumBytes) { 01728 01729 dataLength = MaximumBytes; 01730 01731 } else { 01732 01733 dataLength = transferByteCount; 01734 } 01735 01736 // 01737 // Adjust disk byte offset. 01738 // 01739 01740 startingOffset.QuadPart = startingOffset.QuadPart + MaximumBytes; 01741 } 01742 01743 return; 01744 01745 } // end ScsiClassSplitRequest() 01746 01747 01748 NTSTATUS 01749 NTAPI 01750 ScsiClassIoComplete( 01751 IN PDEVICE_OBJECT DeviceObject, 01752 IN PIRP Irp, 01753 IN PVOID Context 01754 ) 01755 01756 /*++ 01757 01758 Routine Description: 01759 01760 This routine executes when the port driver has completed a request. 01761 It looks at the SRB status in the completing SRB and if not success 01762 it checks for valid request sense buffer information. If valid, the 01763 info is used to update status with more precise message of type of 01764 error. This routine deallocates the SRB. 01765 01766 Arguments: 01767 01768 DeviceObject - Supplies the device object which represents the logical 01769 unit. 01770 01771 Irp - Supplies the Irp which has completed. 01772 01773 Context - Supplies a pointer to the SRB. 01774 01775 Return Value: 01776 01777 NT status 01778 01779 --*/ 01780 01781 { 01782 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 01783 PSCSI_REQUEST_BLOCK srb = Context; 01784 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 01785 NTSTATUS status; 01786 BOOLEAN retry; 01787 01788 // 01789 // Check SRB status for success of completing request. 01790 // 01791 01792 if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) { 01793 01794 DebugPrint((2,"ScsiClassIoComplete: IRP %lx, SRB %lx\n", Irp, srb)); 01795 01796 // 01797 // Release the queue if it is frozen. 01798 // 01799 01800 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) { 01801 ScsiClassReleaseQueue(DeviceObject); 01802 } 01803 01804 retry = ScsiClassInterpretSenseInfo( 01805 DeviceObject, 01806 srb, 01807 irpStack->MajorFunction, 01808 irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ? irpStack->Parameters.DeviceIoControl.IoControlCode : 0, 01809 MAXIMUM_RETRIES - PtrToUlong(irpStack->Parameters.Others.Argument4), 01810 &status); 01811 01812 // 01813 // If the status is verified required and the this request 01814 // should bypass verify required then retry the request. 01815 // 01816 01817 if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME && 01818 status == STATUS_VERIFY_REQUIRED) { 01819 01820 status = STATUS_IO_DEVICE_ERROR; 01821 retry = TRUE; 01822 } 01823 01824 if (retry && (irpStack->Parameters.Others.Argument4 = (PVOID)((ULONG_PTR)irpStack->Parameters.Others.Argument4-1))) { 01825 01826 // 01827 // Retry request. 01828 // 01829 01830 DebugPrint((1, "Retry request %lx\n", Irp)); 01831 RetryRequest(DeviceObject, Irp, srb, FALSE); 01832 return STATUS_MORE_PROCESSING_REQUIRED; 01833 } 01834 } else { 01835 01836 // 01837 // Set status for successful request. 01838 // 01839 01840 status = STATUS_SUCCESS; 01841 01842 } // end if (SRB_STATUS(srb->SrbStatus) ... 01843 01844 // 01845 // Return SRB to list. 01846 // 01847 01848 ExFreeToNPagedLookasideList(&deviceExtension->SrbLookasideListHead, 01849 srb); 01850 01851 // 01852 // Set status in completing IRP. 01853 // 01854 01855 Irp->IoStatus.Status = status; 01856 if ((NT_SUCCESS(status)) && (Irp->Flags & IRP_PAGING_IO)) { 01857 ASSERT(Irp->IoStatus.Information); 01858 } 01859 01860 // 01861 // Set the hard error if necessary. 01862 // 01863 01864 if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) { 01865 01866 // 01867 // Store DeviceObject for filesystem, and clear 01868 // in IoStatus.Information field. 01869 // 01870 01871 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject); 01872 Irp->IoStatus.Information = 0; 01873 } 01874 01875 // 01876 // If pending has be returned for this irp then mark the current stack as 01877 // pending. 01878 // 01879 01880 if (Irp->PendingReturned) { 01881 IoMarkIrpPending(Irp); 01882 } 01883 01884 if (deviceExtension->ClassStartIo) { 01885 if (irpStack->MajorFunction != IRP_MJ_DEVICE_CONTROL) { 01886 IoStartNextPacket(DeviceObject, FALSE); 01887 } 01888 } 01889 01890 return status; 01891 01892 } // end ScsiClassIoComplete() 01893 01894 01895 NTSTATUS 01896 NTAPI 01897 ScsiClassIoCompleteAssociated( 01898 IN PDEVICE_OBJECT DeviceObject, 01899 IN PIRP Irp, 01900 IN PVOID Context 01901 ) 01902 01903 /*++ 01904 01905 Routine Description: 01906 01907 This routine executes when the port driver has completed a request. 01908 It looks at the SRB status in the completing SRB and if not success 01909 it checks for valid request sense buffer information. If valid, the 01910 info is used to update status with more precise message of type of 01911 error. This routine deallocates the SRB. This routine is used for 01912 requests which were build by split request. After it has processed 01913 the request it decrements the Irp count in the master Irp. If the 01914 count goes to zero then the master Irp is completed. 01915 01916 Arguments: 01917 01918 DeviceObject - Supplies the device object which represents the logical 01919 unit. 01920 01921 Irp - Supplies the Irp which has completed. 01922 01923 Context - Supplies a pointer to the SRB. 01924 01925 Return Value: 01926 01927 NT status 01928 01929 --*/ 01930 01931 { 01932 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 01933 PSCSI_REQUEST_BLOCK srb = Context; 01934 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 01935 PIRP originalIrp = Irp->AssociatedIrp.MasterIrp; 01936 LONG irpCount; 01937 NTSTATUS status; 01938 BOOLEAN retry; 01939 01940 // 01941 // Check SRB status for success of completing request. 01942 // 01943 01944 if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) { 01945 01946 DebugPrint((2,"ScsiClassIoCompleteAssociated: IRP %lx, SRB %lx", Irp, srb)); 01947 01948 // 01949 // Release the queue if it is frozen. 01950 // 01951 01952 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) { 01953 ScsiClassReleaseQueue(DeviceObject); 01954 } 01955 01956 retry = ScsiClassInterpretSenseInfo( 01957 DeviceObject, 01958 srb, 01959 irpStack->MajorFunction, 01960 irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ? irpStack->Parameters.DeviceIoControl.IoControlCode : 0, 01961 MAXIMUM_RETRIES - PtrToUlong(irpStack->Parameters.Others.Argument4), 01962 &status); 01963 01964 // 01965 // If the status is verified required and the this request 01966 // should bypass verify required then retry the request. 01967 // 01968 01969 if (irpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME && 01970 status == STATUS_VERIFY_REQUIRED) { 01971 01972 status = STATUS_IO_DEVICE_ERROR; 01973 retry = TRUE; 01974 } 01975 01976 if (retry && (irpStack->Parameters.Others.Argument4 = (PVOID)((ULONG_PTR)irpStack->Parameters.Others.Argument4-1))) { 01977 01978 // 01979 // Retry request. If the class driver has supplied a StartIo, 01980 // call it directly for retries. 01981 // 01982 01983 DebugPrint((1, "Retry request %lx\n", Irp)); 01984 01985 /* 01986 if (!deviceExtension->ClassStartIo) { 01987 RetryRequest(DeviceObject, Irp, srb, TRUE); 01988 } else { 01989 deviceExtension->ClassStartIo(DeviceObject, Irp); 01990 } 01991 */ 01992 01993 RetryRequest(DeviceObject, Irp, srb, TRUE); 01994 01995 return STATUS_MORE_PROCESSING_REQUIRED; 01996 } 01997 01998 01999 02000 } else { 02001 02002 // 02003 // Set status for successful request. 02004 // 02005 02006 status = STATUS_SUCCESS; 02007 02008 } // end if (SRB_STATUS(srb->SrbStatus) ... 02009 02010 // 02011 // Return SRB to list. 02012 // 02013 02014 ExFreeToNPagedLookasideList(&deviceExtension->SrbLookasideListHead, 02015 srb); 02016 02017 // 02018 // Set status in completing IRP. 02019 // 02020 02021 Irp->IoStatus.Status = status; 02022 02023 DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial xfer IRP %lx\n", Irp)); 02024 02025 // 02026 // Get next stack location. This original request is unused 02027 // except to keep track of the completing partial IRPs so the 02028 // stack location is valid. 02029 // 02030 02031 irpStack = IoGetNextIrpStackLocation(originalIrp); 02032 02033 // 02034 // Update status only if error so that if any partial transfer 02035 // completes with error, then the original IRP will return with 02036 // error. If any of the asynchronous partial transfer IRPs fail, 02037 // with an error then the original IRP will return 0 bytes transfered. 02038 // This is an optimization for successful transfers. 02039 // 02040 02041 if (!NT_SUCCESS(status)) { 02042 02043 originalIrp->IoStatus.Status = status; 02044 originalIrp->IoStatus.Information = 0; 02045 02046 // 02047 // Set the hard error if necessary. 02048 // 02049 02050 if (IoIsErrorUserInduced(status)) { 02051 02052 // 02053 // Store DeviceObject for filesystem. 02054 // 02055 02056 IoSetHardErrorOrVerifyDevice(originalIrp, DeviceObject); 02057 } 02058 } 02059 02060 // 02061 // Decrement and get the count of remaining IRPs. 02062 // 02063 02064 irpCount = InterlockedDecrement((PLONG)&irpStack->Parameters.Others.Argument1); 02065 02066 DebugPrint((2, "ScsiClassIoCompleteAssociated: Partial IRPs left %d\n", 02067 irpCount)); 02068 02069 // 02070 // Old bug could cause irp count to negative 02071 // 02072 02073 ASSERT(irpCount >= 0); 02074 02075 if (irpCount == 0) { 02076 02077 // 02078 // All partial IRPs have completed. 02079 // 02080 02081 DebugPrint((2, 02082 "ScsiClassIoCompleteAssociated: All partial IRPs complete %lx\n", 02083 originalIrp)); 02084 02085 IoCompleteRequest(originalIrp, IO_DISK_INCREMENT); 02086 02087 // 02088 // If the class driver has supplied a startio, start the 02089 // next request. 02090 // 02091 02092 if (deviceExtension->ClassStartIo) { 02093 IoStartNextPacket(DeviceObject, FALSE); 02094 } 02095 } 02096 02097 // 02098 // Deallocate IRP and indicate the I/O system should not attempt any more 02099 // processing. 02100 // 02101 02102 IoFreeIrp(Irp); 02103 return STATUS_MORE_PROCESSING_REQUIRED; 02104 02105 } // end ScsiClassIoCompleteAssociated() 02106 02107 02108 NTSTATUS 02109 NTAPI 02110 ScsiClassSendSrbSynchronous( 02111 PDEVICE_OBJECT DeviceObject, 02112 PSCSI_REQUEST_BLOCK Srb, 02113 PVOID BufferAddress, 02114 ULONG BufferLength, 02115 BOOLEAN WriteToDevice 02116 ) 02117 02118 /*++ 02119 02120 Routine Description: 02121 02122 This routine is called by SCSI device controls to complete an 02123 SRB and send it to the port driver synchronously (ie wait for 02124 completion). The CDB is already completed along with the SRB CDB 02125 size and request timeout value. 02126 02127 Arguments: 02128 02129 DeviceObject - Supplies the device object which represents the logical 02130 unit. 02131 02132 Srb - Supplies a partially initialized SRB. The SRB cannot come from zone. 02133 02134 BufferAddress - Supplies the address of the buffer. 02135 02136 BufferLength - Supplies the length in bytes of the buffer. 02137 02138 WriteToDevice - Indicates the data should be transfer to the device. 02139 02140 Return Value: 02141 02142 Nt status indicating the final results of the operation. 02143 02144 --*/ 02145 02146 { 02147 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 02148 IO_STATUS_BLOCK ioStatus; 02149 ULONG controlType, mjFunction; 02150 PIRP irp; 02151 PIO_STACK_LOCATION irpStack; 02152 KEVENT event; 02153 PUCHAR senseInfoBuffer; 02154 ULONG retryCount = MAXIMUM_RETRIES; 02155 NTSTATUS status; 02156 BOOLEAN retry; 02157 LARGE_INTEGER dummy; 02158 02159 PAGED_CODE(); 02160 02161 dummy.QuadPart = 0; 02162 02163 // 02164 // Write length to SRB. 02165 // 02166 02167 Srb->Length = SCSI_REQUEST_BLOCK_SIZE; 02168 02169 // 02170 // Set SCSI bus address. 02171 // 02172 02173 Srb->PathId = deviceExtension->PathId; 02174 Srb->TargetId = deviceExtension->TargetId; 02175 Srb->Lun = deviceExtension->Lun; 02176 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 02177 02178 // 02179 // NOTICE: The SCSI-II specification indicates that this field should be 02180 // zero; however, some target controllers ignore the logical unit number 02181 // in the INDENTIFY message and only look at the logical unit number field 02182 // in the CDB. 02183 // 02184 02185 Srb->Cdb[1] |= deviceExtension->Lun << 5; 02186 02187 // 02188 // Enable auto request sense. 02189 // 02190 02191 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE; 02192 02193 // 02194 // Sense buffer is in aligned nonpaged pool. 02195 // 02196 02197 senseInfoBuffer = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE); 02198 02199 if (senseInfoBuffer == NULL) { 02200 02201 DebugPrint((1, 02202 "ScsiClassSendSrbSynchronous: Can't allocate request sense buffer\n")); 02203 return(STATUS_INSUFFICIENT_RESOURCES); 02204 } 02205 02206 Srb->SenseInfoBuffer = senseInfoBuffer; 02207 Srb->DataBuffer = BufferAddress; 02208 02209 // 02210 // Start retries here. 02211 // 02212 02213 retry: 02214 02215 // 02216 // Set the event object to the unsignaled state. 02217 // It will be used to signal request completion. 02218 // 02219 02220 KeInitializeEvent(&event, NotificationEvent, FALSE); 02221 02222 // 02223 // Set controlType and Srb direction flags. 02224 // 02225 02226 if (BufferAddress != NULL) { 02227 02228 if (WriteToDevice) { 02229 02230 controlType = IOCTL_SCSI_EXECUTE_OUT; 02231 Srb->SrbFlags = SRB_FLAGS_DATA_OUT; 02232 mjFunction = IRP_MJ_WRITE; 02233 02234 } else { 02235 02236 controlType = IOCTL_SCSI_EXECUTE_IN; 02237 Srb->SrbFlags = SRB_FLAGS_DATA_IN; 02238 mjFunction = IRP_MJ_READ; 02239 } 02240 02241 } else { 02242 02243 BufferLength = 0; 02244 controlType = IOCTL_SCSI_EXECUTE_NONE; 02245 Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER; 02246 mjFunction = IRP_MJ_FLUSH_BUFFERS; 02247 } 02248 02249 // 02250 // Build device I/O control request with data transfer. 02251 // 02252 irp = IoBuildAsynchronousFsdRequest( 02253 mjFunction, 02254 deviceExtension->DeviceObject, 02255 BufferAddress, 02256 (BufferAddress) ? BufferLength : 0, 02257 &dummy, 02258 &ioStatus); 02259 02260 if (irp == NULL) { 02261 ExFreePool(senseInfoBuffer); 02262 DebugPrint((1, "ScsiClassSendSrbSynchronous: Can't allocate Irp\n")); 02263 return(STATUS_INSUFFICIENT_RESOURCES); 02264 } 02265 02266 // Set event field 02267 irp->UserEvent = &event; 02268 02269 // 02270 // Disable synchronous transfer for these requests. 02271 // 02272 02273 Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER; 02274 02275 // 02276 // Set the transfer length. 02277 // 02278 02279 Srb->DataTransferLength = BufferLength; 02280 02281 // 02282 // Zero out status. 02283 // 02284 02285 Srb->ScsiStatus = Srb->SrbStatus = 0; 02286 Srb->NextSrb = 0; 02287 02288 // Set completion routine 02289 IoSetCompletionRoutine( 02290 irp, 02291 ClassCompletionRoutine, 02292 NULL, 02293 TRUE, 02294 TRUE, 02295 TRUE); 02296 02297 // 02298 // Get next stack location. 02299 // 02300 02301 irpStack = IoGetNextIrpStackLocation(irp); 02302 02303 irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; 02304 irpStack->Parameters.DeviceIoControl.IoControlCode = controlType; 02305 02306 // 02307 // Set up SRB for execute scsi request. Save SRB address in next stack 02308 // for the port driver. 02309 // 02310 02311 irpStack->Parameters.Scsi.Srb = Srb; 02312 02313 // 02314 // Set up IRP Address. 02315 // 02316 02317 Srb->OriginalRequest = irp; 02318 02319 // 02320 // Call the port driver with the request and wait for it to complete. 02321 // 02322 02323 status = IoCallDriver(deviceExtension->PortDeviceObject, irp); 02324 02325 if (status == STATUS_PENDING) { 02326 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL); 02327 } 02328 02329 // 02330 // Check that request completed without error. 02331 // 02332 02333 if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) { 02334 02335 // 02336 // Release the queue if it is frozen. 02337 // 02338 02339 if (Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) { 02340 ScsiClassReleaseQueue(DeviceObject); 02341 } 02342 02343 // 02344 // Update status and determine if request should be retried. 02345 // 02346 02347 retry = ScsiClassInterpretSenseInfo(DeviceObject, 02348 Srb, 02349 IRP_MJ_SCSI, 02350 0, 02351 MAXIMUM_RETRIES - retryCount, 02352 &status); 02353 02354 if (retry) { 02355 02356 if ((status == STATUS_DEVICE_NOT_READY && ((PSENSE_DATA) senseInfoBuffer) 02357 ->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) || 02358 SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT) { 02359 02360 LARGE_INTEGER delay; 02361 02362 // 02363 // Delay for 2 seconds. 02364 // 02365 02366 delay.QuadPart = (LONGLONG)( - 10 * 1000 * 1000 * 2 ); 02367 02368 // 02369 // Stall for a while to let the controller spinup. 02370 // 02371 02372 KeDelayExecutionThread(KernelMode, 02373 FALSE, 02374 &delay); 02375 02376 } 02377 02378 // 02379 // If retries are not exhausted then retry this operation. 02380 // 02381 02382 if (retryCount--) { 02383 goto retry; 02384 } 02385 } 02386 02387 } else { 02388 02389 status = STATUS_SUCCESS; 02390 } 02391 02392 ExFreePool(senseInfoBuffer); 02393 return status; 02394 02395 } // end ScsiClassSendSrbSynchronous() 02396 02397 02398 BOOLEAN 02399 NTAPI 02400 ScsiClassInterpretSenseInfo( 02401 IN PDEVICE_OBJECT DeviceObject, 02402 IN PSCSI_REQUEST_BLOCK Srb, 02403 IN UCHAR MajorFunctionCode, 02404 IN ULONG IoDeviceCode, 02405 IN ULONG RetryCount, 02406 OUT NTSTATUS *Status 02407 ) 02408 02409 /*++ 02410 02411 Routine Description: 02412 02413 This routine interprets the data returned from the SCSI 02414 request sense. It determines the status to return in the 02415 IRP and whether this request can be retried. 02416 02417 Arguments: 02418 02419 DeviceObject - Supplies the device object associated with this request. 02420 02421 Srb - Supplies the scsi request block which failed. 02422 02423 MajorFunctionCode - Supplies the function code to be used for logging. 02424 02425 IoDeviceCode - Supplies the device code to be used for logging. 02426 02427 Status - Returns the status for the request. 02428 02429 Return Value: 02430 02431 BOOLEAN TRUE: Drivers should retry this request. 02432 FALSE: Drivers should not retry this request. 02433 02434 --*/ 02435 02436 { 02437 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 02438 PDEVICE_EXTENSION physicalExtension = deviceExtension->PhysicalDevice->DeviceExtension; 02439 PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer; 02440 BOOLEAN retry = TRUE; 02441 BOOLEAN logError = FALSE; 02442 ULONG badSector = 0; 02443 ULONG uniqueId = 0; 02444 NTSTATUS logStatus; 02445 ULONG readSector; 02446 ULONG index; 02447 PIO_ERROR_LOG_PACKET errorLogEntry; 02448 #if DBG 02449 ULONG i; 02450 #endif 02451 02452 02453 // 02454 // Check that request sense buffer is valid. 02455 // 02456 02457 #if DBG 02458 DebugPrint((3, "Opcode %x\nParameters: ",Srb->Cdb[0])); 02459 for (i = 1; i < 12; i++) { 02460 DebugPrint((3,"%x ",Srb->Cdb[i])); 02461 } 02462 DebugPrint((3,"\n")); 02463 #endif 02464 02465 if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID && 02466 Srb->SenseInfoBufferLength >= FIELD_OFFSET(SENSE_DATA, CommandSpecificInformation)) { 02467 02468 DebugPrint((1,"ScsiClassInterpretSenseInfo: Error code is %x\n", 02469 senseBuffer->ErrorCode)); 02470 DebugPrint((1,"ScsiClassInterpretSenseInfo: Sense key is %x\n", 02471 senseBuffer->SenseKey)); 02472 DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code is %x\n", 02473 senseBuffer->AdditionalSenseCode)); 02474 DebugPrint((1, "ScsiClassInterpretSenseInfo: Additional sense code qualifier is %x\n", 02475 senseBuffer->AdditionalSenseCodeQualifier)); 02476 02477 // 02478 // Zero the additional sense code and additional sense code qualifier 02479 // if they were not returned by the device. 02480 // 02481 02482 readSector = senseBuffer->AdditionalSenseLength + 02483 FIELD_OFFSET(SENSE_DATA, AdditionalSenseLength); 02484 02485 if (readSector > Srb->SenseInfoBufferLength) { 02486 readSector = Srb->SenseInfoBufferLength; 02487 } 02488 02489 if (readSector <= FIELD_OFFSET(SENSE_DATA, AdditionalSenseCode)) { 02490 senseBuffer->AdditionalSenseCode = 0; 02491 } 02492 02493 if (readSector <= FIELD_OFFSET(SENSE_DATA, AdditionalSenseCodeQualifier)) { 02494 senseBuffer->AdditionalSenseCodeQualifier = 0; 02495 } 02496 02497 switch (senseBuffer->SenseKey & 0xf) { 02498 02499 case SCSI_SENSE_NOT_READY: 02500 02501 DebugPrint((1,"ScsiClassInterpretSenseInfo: Device not ready\n")); 02502 *Status = STATUS_DEVICE_NOT_READY; 02503 02504 switch (senseBuffer->AdditionalSenseCode) { 02505 02506 case SCSI_ADSENSE_LUN_NOT_READY: 02507 02508 DebugPrint((1,"ScsiClassInterpretSenseInfo: Lun not ready\n")); 02509 02510 switch (senseBuffer->AdditionalSenseCodeQualifier) { 02511 02512 case SCSI_SENSEQ_BECOMING_READY: 02513 02514 DebugPrint((1, "ScsiClassInterpretSenseInfo:" 02515 " In process of becoming ready\n")); 02516 break; 02517 02518 case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED: 02519 02520 DebugPrint((1, "ScsiClassInterpretSenseInfo:" 02521 " Manual intervention required\n")); 02522 *Status = STATUS_NO_MEDIA_IN_DEVICE; 02523 retry = FALSE; 02524 break; 02525 02526 case SCSI_SENSEQ_FORMAT_IN_PROGRESS: 02527 02528 DebugPrint((1, "ScsiClassInterpretSenseInfo: Format in progress\n")); 02529 retry = FALSE; 02530 break; 02531 02532 case SCSI_SENSEQ_INIT_COMMAND_REQUIRED: 02533 02534 default: 02535 02536 DebugPrint((1, "ScsiClassInterpretSenseInfo:" 02537 " Initializing command required\n")); 02538 02539 // 02540 // This sense code/additional sense code 02541 // combination may indicate that the device 02542 // needs to be started. Send an start unit if this 02543 // is a disk device. 02544 // 02545 02546 if (deviceExtension->DeviceFlags & DEV_SAFE_START_UNIT) { 02547 StartUnit(DeviceObject); 02548 } 02549 02550 break; 02551 02552 } // end switch (senseBuffer->AdditionalSenseCodeQualifier) 02553 02554 break; 02555 02556 case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE: 02557 02558 DebugPrint((1, 02559 "ScsiClassInterpretSenseInfo:" 02560 " No Media in device.\n")); 02561 *Status = STATUS_NO_MEDIA_IN_DEVICE; 02562 retry = FALSE; 02563 02564 // 02565 // signal autorun that there isn't any media in the device 02566 // 02567 02568 if((deviceExtension->MediaChangeEvent != NULL)&& 02569 (!deviceExtension->MediaChangeNoMedia)) { 02570 KeSetEvent(deviceExtension->MediaChangeEvent, 02571 (KPRIORITY) 0, 02572 FALSE); 02573 DebugPrint((0, "ScsiClassInterpretSenseInfo:" 02574 "Detected No Media In Device " 02575 "[irp = 0x%lx]\n", Srb->OriginalRequest)); 02576 deviceExtension->MediaChangeNoMedia = TRUE; 02577 } 02578 02579 break; 02580 } // end switch (senseBuffer->AdditionalSenseCode) 02581 02582 break; 02583 02584 case SCSI_SENSE_DATA_PROTECT: 02585 02586 DebugPrint((1, "ScsiClassInterpretSenseInfo: Media write protected\n")); 02587 *Status = STATUS_MEDIA_WRITE_PROTECTED; 02588 retry = FALSE; 02589 break; 02590 02591 case SCSI_SENSE_MEDIUM_ERROR: 02592 02593 DebugPrint((1,"ScsiClassInterpretSenseInfo: Bad media\n")); 02594 *Status = STATUS_DEVICE_DATA_ERROR; 02595 02596 retry = FALSE; 02597 logError = TRUE; 02598 uniqueId = 256; 02599 logStatus = 0;//IO_ERR_BAD_BLOCK; 02600 break; 02601 02602 case SCSI_SENSE_HARDWARE_ERROR: 02603 02604 DebugPrint((1,"ScsiClassInterpretSenseInfo: Hardware error\n")); 02605 *Status = STATUS_IO_DEVICE_ERROR; 02606 02607 logError = TRUE; 02608 uniqueId = 257; 02609 logStatus = 0;//IO_ERR_CONTROLLER_ERROR; 02610 02611 break; 02612 02613 case SCSI_SENSE_ILLEGAL_REQUEST: 02614 02615 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal SCSI request\n")); 02616 *Status = STATUS_INVALID_DEVICE_REQUEST; 02617 02618 switch (senseBuffer->AdditionalSenseCode) { 02619 02620 case SCSI_ADSENSE_ILLEGAL_COMMAND: 02621 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal command\n")); 02622 retry = FALSE; 02623 break; 02624 02625 case SCSI_ADSENSE_ILLEGAL_BLOCK: 02626 DebugPrint((1, "ScsiClassInterpretSenseInfo: Illegal block address\n")); 02627 *Status = STATUS_NONEXISTENT_SECTOR; 02628 retry = FALSE; 02629 break; 02630 02631 case SCSI_ADSENSE_INVALID_LUN: 02632 DebugPrint((1,"ScsiClassInterpretSenseInfo: Invalid LUN\n")); 02633 *Status = STATUS_NO_SUCH_DEVICE; 02634 retry = FALSE; 02635 break; 02636 02637 case SCSI_ADSENSE_MUSIC_AREA: 02638 DebugPrint((1,"ScsiClassInterpretSenseInfo: Music area\n")); 02639 retry = FALSE; 02640 break; 02641 02642 case SCSI_ADSENSE_DATA_AREA: 02643 DebugPrint((1,"ScsiClassInterpretSenseInfo: Data area\n")); 02644 retry = FALSE; 02645 break; 02646 02647 case SCSI_ADSENSE_VOLUME_OVERFLOW: 02648 DebugPrint((1, "ScsiClassInterpretSenseInfo: Volume overflow\n")); 02649 retry = FALSE; 02650 break; 02651 02652 case SCSI_ADSENSE_INVALID_CDB: 02653 DebugPrint((1, "ScsiClassInterpretSenseInfo: Invalid CDB\n")); 02654 02655 // 02656 // Check if write cache enabled. 02657 // 02658 02659 if (deviceExtension->DeviceFlags & DEV_WRITE_CACHE) { 02660 02661 // 02662 // Assume FUA is not supported. 02663 // 02664 02665 deviceExtension->DeviceFlags &= ~DEV_WRITE_CACHE; 02666 retry = TRUE; 02667 02668 } else { 02669 retry = FALSE; 02670 } 02671 02672 break; 02673 02674 } // end switch (senseBuffer->AdditionalSenseCode) 02675 02676 break; 02677 02678 case SCSI_SENSE_UNIT_ATTENTION: 02679 02680 switch (senseBuffer->AdditionalSenseCode) { 02681 case SCSI_ADSENSE_MEDIUM_CHANGED: 02682 DebugPrint((1, "ScsiClassInterpretSenseInfo: Media changed\n")); 02683 02684 if(deviceExtension->MediaChangeEvent != NULL) { 02685 02686 KeSetEvent(deviceExtension->MediaChangeEvent, 02687 (KPRIORITY) 0, 02688 FALSE); 02689 DebugPrint((0, "ScsiClassInterpretSenseInfo:" 02690 "New Media Found - Setting MediaChanged event" 02691 " [irp = 0x%lx]\n", Srb->OriginalRequest)); 02692 deviceExtension->MediaChangeNoMedia = FALSE; 02693 02694 } 02695 break; 02696 02697 case SCSI_ADSENSE_BUS_RESET: 02698 DebugPrint((1,"ScsiClassInterpretSenseInfo: Bus reset\n")); 02699 break; 02700 02701 default: 02702 DebugPrint((1,"ScsiClassInterpretSenseInfo: Unit attention\n")); 02703 break; 02704 02705 } // end switch (senseBuffer->AdditionalSenseCode) 02706 02707 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA && 02708 DeviceObject->Vpb->Flags & VPB_MOUNTED) { 02709 02710 // 02711 // Set bit to indicate that media may have changed 02712 // and volume needs verification. 02713 // 02714 02715 DeviceObject->Flags |= DO_VERIFY_VOLUME; 02716 02717 *Status = STATUS_VERIFY_REQUIRED; 02718 retry = FALSE; 02719 02720 } else { 02721 02722 *Status = STATUS_IO_DEVICE_ERROR; 02723 02724 } 02725 02726 // 02727 // A media change may have occured so increment the change 02728 // count for the physical device 02729 // 02730 02731 physicalExtension->MediaChangeCount++; 02732 02733 DebugPrint((2, "ScsiClassInterpretSenseInfo - Media change " 02734 "count for device %d is %d\n", 02735 physicalExtension->DeviceNumber, 02736 physicalExtension->MediaChangeCount)); 02737 02738 break; 02739 02740 case SCSI_SENSE_ABORTED_COMMAND: 02741 02742 DebugPrint((1,"ScsiClassInterpretSenseInfo: Command aborted\n")); 02743 *Status = STATUS_IO_DEVICE_ERROR; 02744 break; 02745 02746 case SCSI_SENSE_RECOVERED_ERROR: 02747 02748 DebugPrint((1,"ScsiClassInterpretSenseInfo: Recovered error\n")); 02749 *Status = STATUS_SUCCESS; 02750 retry = FALSE; 02751 logError = TRUE; 02752 uniqueId = 258; 02753 02754 switch(senseBuffer->AdditionalSenseCode) { 02755 case SCSI_ADSENSE_SEEK_ERROR: 02756 case SCSI_ADSENSE_TRACK_ERROR: 02757 logStatus = 0;//IO_ERR_SEEK_ERROR; 02758 break; 02759 02760 case SCSI_ADSENSE_REC_DATA_NOECC: 02761 case SCSI_ADSENSE_REC_DATA_ECC: 02762 logStatus = 0;//IO_RECOVERED_VIA_ECC; 02763 break; 02764 02765 default: 02766 logStatus = 0;//IO_ERR_CONTROLLER_ERROR; 02767 break; 02768 02769 } // end switch(senseBuffer->AdditionalSenseCode) 02770 02771 if (senseBuffer->IncorrectLength) { 02772 02773 DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n")); 02774 *Status = STATUS_INVALID_BLOCK_LENGTH ; 02775 } 02776 02777 break; 02778 02779 case SCSI_SENSE_NO_SENSE: 02780 02781 // 02782 // Check other indicators. 02783 // 02784 02785 if (senseBuffer->IncorrectLength) { 02786 02787 DebugPrint((1, "ScsiClassInterpretSenseInfo: Incorrect length detected.\n")); 02788 *Status = STATUS_INVALID_BLOCK_LENGTH ; 02789 retry = FALSE; 02790 02791 } else { 02792 02793 DebugPrint((1, "ScsiClassInterpretSenseInfo: No specific sense key\n")); 02794 *Status = STATUS_IO_DEVICE_ERROR; 02795 retry = TRUE; 02796 } 02797 02798 break; 02799 02800 default: 02801 02802 DebugPrint((1, "ScsiClassInterpretSenseInfo: Unrecognized sense code\n")); 02803 *Status = STATUS_IO_DEVICE_ERROR; 02804 break; 02805 02806 } // end switch (senseBuffer->SenseKey & 0xf) 02807 02808 // 02809 // Try to determine the bad sector from the inquiry data. 02810 // 02811 02812 if ((((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_READ || 02813 ((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_VERIFY || 02814 ((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_WRITE)) { 02815 02816 for (index = 0; index < 4; index++) { 02817 badSector = (badSector << 8) | senseBuffer->Information[index]; 02818 } 02819 02820 readSector = 0; 02821 for (index = 0; index < 4; index++) { 02822 readSector = (readSector << 8) | Srb->Cdb[index+2]; 02823 } 02824 02825 index = (((PCDB)Srb->Cdb)->CDB10.TransferBlocksMsb << 8) | 02826 ((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb; 02827 02828 // 02829 // Make sure the bad sector is within the read sectors. 02830 // 02831 02832 if (!(badSector >= readSector && badSector < readSector + index)) { 02833 badSector = readSector; 02834 } 02835 } 02836 02837 } else { 02838 02839 // 02840 // Request sense buffer not valid. No sense information 02841 // to pinpoint the error. Return general request fail. 02842 // 02843 02844 DebugPrint((1,"ScsiClassInterpretSenseInfo: Request sense info not valid. SrbStatus %2x\n", 02845 SRB_STATUS(Srb->SrbStatus))); 02846 retry = TRUE; 02847 02848 switch (SRB_STATUS(Srb->SrbStatus)) { 02849 case SRB_STATUS_INVALID_LUN: 02850 case SRB_STATUS_INVALID_TARGET_ID: 02851 case SRB_STATUS_NO_DEVICE: 02852 case SRB_STATUS_NO_HBA: 02853 case SRB_STATUS_INVALID_PATH_ID: 02854 *Status = STATUS_NO_SUCH_DEVICE; 02855 retry = FALSE; 02856 break; 02857 02858 case SRB_STATUS_COMMAND_TIMEOUT: 02859 case SRB_STATUS_ABORTED: 02860 case SRB_STATUS_TIMEOUT: 02861 02862 // 02863 // Update the error count for the device. 02864 // 02865 02866 deviceExtension->ErrorCount++; 02867 *Status = STATUS_IO_TIMEOUT; 02868 break; 02869 02870 case SRB_STATUS_SELECTION_TIMEOUT: 02871 logError = TRUE; 02872 logStatus = 0;//IO_ERR_NOT_READY; 02873 uniqueId = 260; 02874 *Status = STATUS_DEVICE_NOT_CONNECTED; 02875 retry = FALSE; 02876 break; 02877 02878 case SRB_STATUS_DATA_OVERRUN: 02879 *Status = STATUS_DATA_OVERRUN; 02880 retry = FALSE; 02881 break; 02882 02883 case SRB_STATUS_PHASE_SEQUENCE_FAILURE: 02884 02885 // 02886 // Update the error count for the device. 02887 // 02888 02889 deviceExtension->ErrorCount++; 02890 *Status = STATUS_IO_DEVICE_ERROR; 02891 02892 // 02893 // If there was phase sequence error then limit the number of 02894 // retries. 02895 // 02896 02897 if (RetryCount > 1 ) { 02898 retry = FALSE; 02899 } 02900 02901 break; 02902 02903 case SRB_STATUS_REQUEST_FLUSHED: 02904 02905 // 02906 // If the status needs verification bit is set. Then set 02907 // the status to need verification and no retry; otherwise, 02908 // just retry the request. 02909 // 02910 02911 if (DeviceObject->Flags & DO_VERIFY_VOLUME ) { 02912 02913 *Status = STATUS_VERIFY_REQUIRED; 02914 retry = FALSE; 02915 } else { 02916 *Status = STATUS_IO_DEVICE_ERROR; 02917 } 02918 02919 break; 02920 02921 case SRB_STATUS_INVALID_REQUEST: 02922 02923 // 02924 // An invalid request was attempted. 02925 // 02926 02927 *Status = STATUS_INVALID_DEVICE_REQUEST; 02928 retry = FALSE; 02929 break; 02930 02931 case SRB_STATUS_UNEXPECTED_BUS_FREE: 02932 case SRB_STATUS_PARITY_ERROR: 02933 02934 // 02935 // Update the error count for the device. 02936 // 02937 02938 deviceExtension->ErrorCount++; 02939 02940 // 02941 // Fall through to below. 02942 // 02943 02944 case SRB_STATUS_BUS_RESET: 02945 *Status = STATUS_IO_DEVICE_ERROR; 02946 break; 02947 02948 case SRB_STATUS_ERROR: 02949 02950 *Status = STATUS_IO_DEVICE_ERROR; 02951 if (Srb->ScsiStatus == 0) { 02952 02953 // 02954 // This is some strange return code. Update the error 02955 // count for the device. 02956 // 02957 02958 deviceExtension->ErrorCount++; 02959 02960 } if (Srb->ScsiStatus == SCSISTAT_BUSY) { 02961 02962 *Status = STATUS_DEVICE_NOT_READY; 02963 02964 } if (Srb->ScsiStatus == SCSISTAT_RESERVATION_CONFLICT) { 02965 02966 *Status = STATUS_DEVICE_BUSY; 02967 retry = FALSE; 02968 02969 } 02970 02971 break; 02972 02973 default: 02974 logError = TRUE; 02975 logStatus = 0;//IO_ERR_CONTROLLER_ERROR; 02976 uniqueId = 259; 02977 *Status = STATUS_IO_DEVICE_ERROR; 02978 break; 02979 02980 } 02981 02982 // 02983 // If the error count has exceeded the error limit, then disable 02984 // any tagged queuing, multiple requests per lu queueing 02985 // and sychronous data transfers. 02986 // 02987 02988 if (deviceExtension->ErrorCount == 4) { 02989 02990 // 02991 // Clearing the no queue freeze flag prevents the port driver 02992 // from sending multiple requests per logical unit. 02993 // 02994 02995 deviceExtension->SrbFlags &= ~(SRB_FLAGS_QUEUE_ACTION_ENABLE | 02996 SRB_FLAGS_NO_QUEUE_FREEZE); 02997 02998 deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER; 02999 DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling tagged queuing and synchronous data tranfers.\n")); 03000 03001 } else if (deviceExtension->ErrorCount == 8) { 03002 03003 // 03004 // If a second threshold is reached, disable disconnects. 03005 // 03006 03007 deviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT; 03008 DebugPrint((1, "ScsiClassInterpretSenseInfo: Too many errors disabling disconnects.\n")); 03009 } 03010 } 03011 03012 // 03013 // If there is a class specific error handler call it. 03014 // 03015 03016 if (deviceExtension->ClassError != NULL) { 03017 03018 deviceExtension->ClassError(DeviceObject, 03019 Srb, 03020 Status, 03021 &retry); 03022 } 03023 03024 // 03025 // Log an error if necessary. 03026 // 03027 03028 if (logError) { 03029 03030 errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry( 03031 DeviceObject, 03032 sizeof(IO_ERROR_LOG_PACKET) + 5 * sizeof(ULONG)); 03033 03034 if (errorLogEntry == NULL) { 03035 03036 // 03037 // Return if no packet could be allocated. 03038 // 03039 03040 return retry; 03041 03042 } 03043 03044 if (retry && RetryCount < MAXIMUM_RETRIES) { 03045 errorLogEntry->FinalStatus = STATUS_SUCCESS; 03046 } else { 03047 errorLogEntry->FinalStatus = *Status; 03048 } 03049 03050 // 03051 // Calculate the device offset if there is a geometry. 03052 // 03053 03054 if (deviceExtension->DiskGeometry != NULL) { 03055 03056 errorLogEntry->DeviceOffset.QuadPart = (LONGLONG) badSector; 03057 errorLogEntry->DeviceOffset = RtlExtendedIntegerMultiply( 03058 errorLogEntry->DeviceOffset, 03059 deviceExtension->DiskGeometry->Geometry.BytesPerSector); 03060 } 03061 03062 errorLogEntry->ErrorCode = logStatus; 03063 errorLogEntry->SequenceNumber = 0; 03064 errorLogEntry->MajorFunctionCode = MajorFunctionCode; 03065 errorLogEntry->IoControlCode = IoDeviceCode; 03066 errorLogEntry->RetryCount = (UCHAR) RetryCount; 03067 errorLogEntry->UniqueErrorValue = uniqueId; 03068 errorLogEntry->DumpDataSize = 6 * sizeof(ULONG); 03069 errorLogEntry->DumpData[0] = Srb->PathId; 03070 errorLogEntry->DumpData[1] = Srb->TargetId; 03071 errorLogEntry->DumpData[2] = Srb->Lun; 03072 errorLogEntry->DumpData[3] = 0; 03073 errorLogEntry->DumpData[4] = Srb->SrbStatus << 8 | Srb->ScsiStatus; 03074 03075 if (senseBuffer != NULL) { 03076 errorLogEntry->DumpData[5] = senseBuffer->SenseKey << 16 | 03077 senseBuffer->AdditionalSenseCode << 8 | 03078 senseBuffer->AdditionalSenseCodeQualifier; 03079 03080 } 03081 03082 // 03083 // Write the error log packet. 03084 // 03085 03086 IoWriteErrorLogEntry(errorLogEntry); 03087 } 03088 03089 return retry; 03090 03091 } // end ScsiClassInterpretSenseInfo() 03092 03093 03094 VOID 03095 NTAPI 03096 RetryRequest( 03097 PDEVICE_OBJECT DeviceObject, 03098 PIRP Irp, 03099 PSCSI_REQUEST_BLOCK Srb, 03100 BOOLEAN Associated 03101 ) 03102 03103 /*++ 03104 03105 Routine Description: 03106 03107 This routine reinitalizes the necessary fields, and sends the request 03108 to the port driver. 03109 03110 Arguments: 03111 03112 DeviceObject - Supplies the device object associated with this request. 03113 03114 Irp - Supplies the request to be retried. 03115 03116 Srb - Supplies a Pointer to the SCSI request block to be retied. 03117 03118 Assocaiated - Indicates this is an assocatied Irp created by split request. 03119 03120 Return Value: 03121 03122 None 03123 03124 --*/ 03125 03126 { 03127 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 03128 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); 03129 PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp); 03130 ULONG transferByteCount; 03131 03132 // 03133 // Determine the transfer count of the request. If this is a read or a 03134 // write then the transfer count is in the Irp stack. Otherwise assume 03135 // the MDL contains the correct length. If there is no MDL then the 03136 // transfer length must be zero. 03137 // 03138 03139 if (currentIrpStack->MajorFunction == IRP_MJ_READ || 03140 currentIrpStack->MajorFunction == IRP_MJ_WRITE) { 03141 03142 transferByteCount = currentIrpStack->Parameters.Read.Length; 03143 03144 } else if (Irp->MdlAddress != NULL) { 03145 03146 // 03147 // Note this assumes that only read and write requests are spilt and 03148 // other request do not need to be. If the data buffer address in 03149 // the MDL and the SRB don't match then transfer length is most 03150 // likely incorrect. 03151 // 03152 03153 ASSERT(Srb->DataBuffer == MmGetMdlVirtualAddress(Irp->MdlAddress)); 03154 transferByteCount = Irp->MdlAddress->ByteCount; 03155 03156 } else { 03157 03158 transferByteCount = 0; 03159 } 03160 03161 // 03162 // Reset byte count of transfer in SRB Extension. 03163 // 03164 03165 Srb->DataTransferLength = transferByteCount; 03166 03167 // 03168 // Zero SRB statuses. 03169 // 03170 03171 Srb->SrbStatus = Srb->ScsiStatus = 0; 03172 03173 // 03174 // Set the no disconnect flag, disable synchronous data transfers and 03175 // disable tagged queuing. This fixes some errors. 03176 // 03177 03178 Srb->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT | 03179 SRB_FLAGS_DISABLE_SYNCH_TRANSFER; 03180 03181 Srb->SrbFlags &= ~SRB_FLAGS_QUEUE_ACTION_ENABLE; 03182 Srb->QueueTag = SP_UNTAGGED; 03183 03184 // 03185 // Set up major SCSI function. 03186 // 03187 03188 nextIrpStack->MajorFunction = IRP_MJ_SCSI; 03189 03190 // 03191 // Save SRB address in next stack for port driver. 03192 // 03193 03194 nextIrpStack->Parameters.Scsi.Srb = Srb; 03195 03196 // 03197 // Set up IoCompletion routine address. 03198 // 03199 03200 if (Associated) { 03201 03202 IoSetCompletionRoutine(Irp, ScsiClassIoCompleteAssociated, Srb, TRUE, TRUE, TRUE); 03203 03204 } else { 03205 03206 IoSetCompletionRoutine(Irp, ScsiClassIoComplete, Srb, TRUE, TRUE, TRUE); 03207 } 03208 03209 // 03210 // Pass the request to the port driver. 03211 // 03212 03213 (VOID)IoCallDriver(deviceExtension->PortDeviceObject, Irp); 03214 03215 } // end RetryRequest() 03216 03217 VOID 03218 NTAPI 03219 ScsiClassBuildRequest( 03220 PDEVICE_OBJECT DeviceObject, 03221 PIRP Irp 03222 ) 03223 03224 /*++ 03225 03226 Routine Description: 03227 03228 This routine allocates and builds an Srb for a read or write request. 03229 The block address and length are supplied by the Irp. The retry count 03230 is stored in the current stack for use by ScsiClassIoComplete which 03231 processes these requests when they complete. The Irp is ready to be 03232 passed to the port driver when this routine returns. 03233 03234 Arguments: 03235 03236 DeviceObject - Supplies the device object associated with this request. 03237 03238 Irp - Supplies the request to be retried. 03239 03240 Note: 03241 03242 If the IRP is for a disk transfer, the byteoffset field 03243 will already have been adjusted to make it relative to 03244 the beginning of the disk. 03245 03246 03247 Return Value: 03248 03249 None. 03250 03251 --*/ 03252 03253 { 03254 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 03255 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); 03256 PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp); 03257 LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset; 03258 PSCSI_REQUEST_BLOCK srb; 03259 PCDB cdb; 03260 ULONG logicalBlockAddress; 03261 USHORT transferBlocks; 03262 03263 // 03264 // Calculate relative sector address. 03265 // 03266 03267 logicalBlockAddress = (ULONG)(Int64ShrlMod32(startingOffset.QuadPart, deviceExtension->SectorShift)); 03268 03269 // 03270 // Allocate an Srb. 03271 // 03272 03273 srb = ExAllocateFromNPagedLookasideList(&deviceExtension->SrbLookasideListHead); 03274 03275 srb->SrbFlags = 0; 03276 03277 // 03278 // Write length to SRB. 03279 // 03280 03281 srb->Length = SCSI_REQUEST_BLOCK_SIZE; 03282 03283 // 03284 // Set up IRP Address. 03285 // 03286 03287 srb->OriginalRequest = Irp; 03288 03289 // 03290 // Set up target ID and logical unit number. 03291 // 03292 03293 srb->PathId = deviceExtension->PathId; 03294 srb->TargetId = deviceExtension->TargetId; 03295 srb->Lun = deviceExtension->Lun; 03296 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 03297 srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress); 03298 03299 // 03300 // Save byte count of transfer in SRB Extension. 03301 // 03302 03303 srb->DataTransferLength = currentIrpStack->Parameters.Read.Length; 03304 03305 // 03306 // Initialize the queue actions field. 03307 // 03308 03309 srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; 03310 03311 // 03312 // Queue sort key is Relative Block Address. 03313 // 03314 03315 srb->QueueSortKey = logicalBlockAddress; 03316 03317 // 03318 // Indicate auto request sense by specifying buffer and size. 03319 // 03320 03321 srb->SenseInfoBuffer = deviceExtension->SenseData; 03322 srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE; 03323 03324 // 03325 // Set timeout value of one unit per 64k bytes of data. 03326 // 03327 03328 srb->TimeOutValue = ((srb->DataTransferLength + 0xFFFF) >> 16) * 03329 deviceExtension->TimeOutValue; 03330 03331 // 03332 // Zero statuses. 03333 // 03334 03335 srb->SrbStatus = srb->ScsiStatus = 0; 03336 srb->NextSrb = 0; 03337 03338 // 03339 // Indicate that 10-byte CDB's will be used. 03340 // 03341 03342 srb->CdbLength = 10; 03343 03344 // 03345 // Fill in CDB fields. 03346 // 03347 03348 cdb = (PCDB)srb->Cdb; 03349 03350 // 03351 // Zero 12 bytes for Atapi Packets 03352 // 03353 03354 RtlZeroMemory(cdb, MAXIMUM_CDB_SIZE); 03355 03356 cdb->CDB10.LogicalUnitNumber = deviceExtension->Lun; 03357 transferBlocks = (USHORT)(currentIrpStack->Parameters.Read.Length >> deviceExtension->SectorShift); 03358 03359 // 03360 // Move little endian values into CDB in big endian format. 03361 // 03362 03363 cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte3; 03364 cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte2; 03365 cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte1; 03366 cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&logicalBlockAddress)->Byte0; 03367 03368 cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&transferBlocks)->Byte1; 03369 cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&transferBlocks)->Byte0; 03370 03371 // 03372 // Set transfer direction flag and Cdb command. 03373 // 03374 03375 if (currentIrpStack->MajorFunction == IRP_MJ_READ) { 03376 03377 DebugPrint((3, "ScsiClassBuildRequest: Read Command\n")); 03378 03379 srb->SrbFlags |= SRB_FLAGS_DATA_IN; 03380 cdb->CDB10.OperationCode = SCSIOP_READ; 03381 03382 } else { 03383 03384 DebugPrint((3, "ScsiClassBuildRequest: Write Command\n")); 03385 03386 srb->SrbFlags |= SRB_FLAGS_DATA_OUT; 03387 cdb->CDB10.OperationCode = SCSIOP_WRITE; 03388 } 03389 03390 // 03391 // If this is not a write-through request, then allow caching. 03392 // 03393 03394 if (!(currentIrpStack->Flags & SL_WRITE_THROUGH)) { 03395 03396 srb->SrbFlags |= SRB_FLAGS_ADAPTER_CACHE_ENABLE; 03397 03398 } else { 03399 03400 // 03401 // If write caching is enable then force media access in the 03402 // cdb. 03403 // 03404 03405 if (deviceExtension->DeviceFlags & DEV_WRITE_CACHE) { 03406 cdb->CDB10.ForceUnitAccess = TRUE; 03407 } 03408 } 03409 03410 // 03411 // Or in the default flags from the device object. 03412 // 03413 03414 srb->SrbFlags |= deviceExtension->SrbFlags; 03415 03416 // 03417 // Set up major SCSI function. 03418 // 03419 03420 nextIrpStack->MajorFunction = IRP_MJ_SCSI; 03421 03422 // 03423 // Save SRB address in next stack for port driver. 03424 // 03425 03426 nextIrpStack->Parameters.Scsi.Srb = srb; 03427 03428 // 03429 // Save retry count in current IRP stack. 03430 // 03431 03432 currentIrpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES; 03433 03434 // 03435 // Set up IoCompletion routine address. 03436 // 03437 03438 IoSetCompletionRoutine(Irp, ScsiClassIoComplete, srb, TRUE, TRUE, TRUE); 03439 03440 return; 03441 03442 } // end ScsiClassBuildRequest() 03443 03444 ULONG 03445 NTAPI 03446 ScsiClassModeSense( 03447 IN PDEVICE_OBJECT DeviceObject, 03448 IN PCHAR ModeSenseBuffer, 03449 IN ULONG Length, 03450 IN UCHAR PageMode 03451 ) 03452 03453 /*++ 03454 03455 Routine Description: 03456 03457 This routine sends a mode sense command to a target ID and returns 03458 when it is complete. 03459 03460 Arguments: 03461 03462 DeviceObject - Supplies the device object associated with this request. 03463 03464 ModeSenseBuffer - Supplies a buffer to store the sense data. 03465 03466 Length - Supplies the length in bytes of the mode sense buffer. 03467 03468 PageMode - Supplies the page or pages of mode sense data to be retrived. 03469 03470 Return Value: 03471 03472 Length of the transferred data is returned. 03473 03474 --*/ 03475 { 03476 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 03477 PCDB cdb; 03478 SCSI_REQUEST_BLOCK srb; 03479 ULONG retries = 1; 03480 NTSTATUS status; 03481 03482 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); 03483 03484 // 03485 // Build the MODE SENSE CDB. 03486 // 03487 03488 srb.CdbLength = 6; 03489 cdb = (PCDB)srb.Cdb; 03490 03491 // 03492 // Set timeout value from device extension. 03493 // 03494 03495 srb.TimeOutValue = deviceExtension->TimeOutValue; 03496 03497 cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE; 03498 cdb->MODE_SENSE.PageCode = PageMode; 03499 cdb->MODE_SENSE.AllocationLength = (UCHAR)Length; 03500 03501 Retry: 03502 03503 status = ScsiClassSendSrbSynchronous(DeviceObject, 03504 &srb, 03505 ModeSenseBuffer, 03506 Length, 03507 FALSE); 03508 03509 03510 if (status == STATUS_VERIFY_REQUIRED) { 03511 03512 // 03513 // Routine ScsiClassSendSrbSynchronous does not retry requests returned with 03514 // this status. MODE SENSE commands should be retried anyway. 03515 // 03516 03517 if (retries--) { 03518 03519 // 03520 // Retry request. 03521 // 03522 03523 goto Retry; 03524 } 03525 03526 } else if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) { 03527 status = STATUS_SUCCESS; 03528 } 03529 03530 if (NT_SUCCESS(status)) { 03531 return(srb.DataTransferLength); 03532 } else { 03533 return(0); 03534 } 03535 03536 } // end ScsiClassModeSense() 03537 03538 03539 PVOID 03540 NTAPI 03541 ScsiClassFindModePage( 03542 IN PCHAR ModeSenseBuffer, 03543 IN ULONG Length, 03544 IN UCHAR PageMode, 03545 IN BOOLEAN Use6Byte 03546 ) 03547 03548 /*++ 03549 03550 Routine Description: 03551 03552 This routine scans through the mode sense data and finds the requested 03553 mode sense page code. 03554 03555 Arguments: 03556 ModeSenseBuffer - Supplies a pointer to the mode sense data. 03557 03558 Length - Indicates the length of valid data. 03559 03560 PageMode - Supplies the page mode to be searched for. 03561 03562 Use6Byte - Indicates whether 6 or 10 byte mode sense was used. 03563 03564 Return Value: 03565 03566 A pointer to the the requested mode page. If the mode page was not found 03567 then NULL is return. 03568 03569 --*/ 03570 { 03571 PUCHAR limit; 03572 ULONG parameterHeaderLength; 03573 03574 limit = (PUCHAR)ModeSenseBuffer + Length; 03575 parameterHeaderLength = (Use6Byte) ? sizeof(MODE_PARAMETER_HEADER) : sizeof(MODE_PARAMETER_HEADER10); 03576 03577 03578 // 03579 // Skip the mode select header and block descriptors. 03580 // 03581 03582 if (Length < parameterHeaderLength) { 03583 return(NULL); 03584 } 03585 03586 03587 03588 ModeSenseBuffer += parameterHeaderLength + ((Use6Byte) ? ((PMODE_PARAMETER_HEADER) ModeSenseBuffer)->BlockDescriptorLength : 03589 ((PMODE_PARAMETER_HEADER10) ModeSenseBuffer)->BlockDescriptorLength[1]); 03590 03591 // 03592 // ModeSenseBuffer now points at pages. Walk the pages looking for the 03593 // requested page until the limit is reached. 03594 // 03595 03596 03597 while ((PUCHAR)ModeSenseBuffer < limit) { 03598 03599 if (((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageCode == PageMode) { 03600 return(ModeSenseBuffer); 03601 } 03602 03603 // 03604 // Advance to the next page. 03605 // 03606 03607 ModeSenseBuffer += ((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageLength + 2; 03608 } 03609 03610 return(NULL); 03611 } 03612 03613 NTSTATUS 03614 NTAPI 03615 ScsiClassSendSrbAsynchronous( 03616 PDEVICE_OBJECT DeviceObject, 03617 PSCSI_REQUEST_BLOCK Srb, 03618 PIRP Irp, 03619 PVOID BufferAddress, 03620 ULONG BufferLength, 03621 BOOLEAN WriteToDevice 03622 ) 03623 /*++ 03624 03625 Routine Description: 03626 03627 This routine takes a partially built Srb and an Irp and sends it down to 03628 the port driver. 03629 03630 Arguments: 03631 DeviceObject - Supplies the device object for the orginal request. 03632 03633 Srb - Supplies a paritally build ScsiRequestBlock. In particular, the 03634 CDB and the SRB timeout value must be filled in. The SRB must not be 03635 allocated from zone. 03636 03637 Irp - Supplies the requesting Irp. 03638 03639 BufferAddress - Supplies a pointer to the buffer to be transfered. 03640 03641 BufferLength - Supplies the length of data transfer. 03642 03643 WriteToDevice - Indicates the data transfer will be from system memory to 03644 device. 03645 03646 Return Value: 03647 03648 Returns STATUS_INSUFFICIENT_RESOURCES or the status of IoCallDriver. 03649 03650 --*/ 03651 { 03652 03653 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 03654 PIO_STACK_LOCATION irpStack; 03655 03656 PAGED_CODE(); 03657 03658 // 03659 // Write length to SRB. 03660 // 03661 03662 Srb->Length = SCSI_REQUEST_BLOCK_SIZE; 03663 03664 // 03665 // Set SCSI bus address. 03666 // 03667 03668 Srb->PathId = deviceExtension->PathId; 03669 Srb->TargetId = deviceExtension->TargetId; 03670 Srb->Lun = deviceExtension->Lun; 03671 03672 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 03673 03674 // 03675 // This is a violation of the SCSI spec but it is required for 03676 // some targets. 03677 // 03678 03679 Srb->Cdb[1] |= deviceExtension->Lun << 5; 03680 03681 // 03682 // Indicate auto request sense by specifying buffer and size. 03683 // 03684 03685 Srb->SenseInfoBuffer = deviceExtension->SenseData; 03686 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE; 03687 Srb->DataBuffer = BufferAddress; 03688 03689 if (BufferAddress != NULL) { 03690 03691 // 03692 // Build Mdl if necessary. 03693 // 03694 03695 if (Irp->MdlAddress == NULL) { 03696 03697 if (IoAllocateMdl(BufferAddress, 03698 BufferLength, 03699 FALSE, 03700 FALSE, 03701 Irp) == NULL) { 03702 03703 return(STATUS_INSUFFICIENT_RESOURCES); 03704 } 03705 03706 MmBuildMdlForNonPagedPool(Irp->MdlAddress); 03707 03708 } else { 03709 03710 // 03711 // Make sure the buffer requested matches the MDL. 03712 // 03713 03714 ASSERT(BufferAddress == MmGetMdlVirtualAddress(Irp->MdlAddress)); 03715 } 03716 03717 // 03718 // Set read flag. 03719 // 03720 03721 Srb->SrbFlags = WriteToDevice ? SRB_FLAGS_DATA_OUT : SRB_FLAGS_DATA_IN; 03722 03723 } else { 03724 03725 // 03726 // Clear flags. 03727 // 03728 03729 Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER; 03730 } 03731 03732 // 03733 // Disable synchronous transfer for these requests. 03734 // 03735 03736 Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER; 03737 03738 // 03739 // Set the transfer length. 03740 // 03741 03742 Srb->DataTransferLength = BufferLength; 03743 03744 // 03745 // Zero out status. 03746 // 03747 03748 Srb->ScsiStatus = Srb->SrbStatus = 0; 03749 03750 Srb->NextSrb = 0; 03751 03752 // 03753 // Save a few parameters in the current stack location. 03754 // 03755 03756 irpStack = IoGetCurrentIrpStackLocation(Irp); 03757 03758 // 03759 // Save retry count in current Irp stack. 03760 // 03761 03762 irpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES; 03763 03764 // 03765 // Set up IoCompletion routine address. 03766 // 03767 03768 IoSetCompletionRoutine(Irp, ScsiClassIoComplete, Srb, TRUE, TRUE, TRUE); 03769 03770 // 03771 // Get next stack location and 03772 // set major function code. 03773 // 03774 03775 irpStack = IoGetNextIrpStackLocation(Irp); 03776 03777 irpStack->MajorFunction = IRP_MJ_SCSI; 03778 03779 // 03780 // Save SRB address in next stack for port driver. 03781 // 03782 03783 irpStack->Parameters.Scsi.Srb = Srb; 03784 03785 // 03786 // Set up Irp Address. 03787 // 03788 03789 Srb->OriginalRequest = Irp; 03790 03791 // 03792 // Call the port driver to process the request. 03793 // 03794 03795 return(IoCallDriver(deviceExtension->PortDeviceObject, Irp)); 03796 03797 } 03798 03799 03800 NTSTATUS 03801 NTAPI 03802 ScsiClassDeviceControlDispatch( 03803 PDEVICE_OBJECT DeviceObject, 03804 PIRP Irp 03805 ) 03806 03807 /*++ 03808 03809 Routine Description: 03810 03811 The routine is the common class driver device control dispatch entry point. 03812 This routine is invokes the device-specific drivers DeviceControl routine, 03813 (which may call the Class driver's common DeviceControl routine). 03814 03815 Arguments: 03816 03817 DeviceObject - Supplies a pointer to the device object for this request. 03818 03819 Irp - Supplies the Irp making the request. 03820 03821 Return Value: 03822 03823 Returns the status returned from the device-specific driver. 03824 03825 --*/ 03826 03827 { 03828 03829 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 03830 03831 03832 // 03833 // Call the class specific driver DeviceControl routine. 03834 // If it doesn't handle it, it will call back into ScsiClassDeviceControl. 03835 // 03836 03837 ASSERT(deviceExtension->ClassDeviceControl); 03838 03839 return deviceExtension->ClassDeviceControl(DeviceObject,Irp); 03840 } 03841 03842 03843 NTSTATUS 03844 NTAPI 03845 ScsiClassDeviceControl( 03846 PDEVICE_OBJECT DeviceObject, 03847 PIRP Irp 03848 ) 03849 /*++ 03850 03851 Routine Description: 03852 03853 The routine is the common class driver device control dispatch function. 03854 This routine is called by a class driver when it get an unrecognized 03855 device control request. This routine will perform the correct action for 03856 common requests such as lock media. If the device request is unknown it 03857 passed down to the next level. 03858 03859 Arguments: 03860 03861 DeviceObject - Supplies a pointer to the device object for this request. 03862 03863 Irp - Supplies the Irp making the request. 03864 03865 Return Value: 03866 03867 Returns back a STATUS_PENDING or a completion status. 03868 03869 --*/ 03870 03871 { 03872 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 03873 PIO_STACK_LOCATION nextStack; 03874 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 03875 PSCSI_REQUEST_BLOCK srb; 03876 PCDB cdb; 03877 NTSTATUS status; 03878 ULONG modifiedIoControlCode; 03879 03880 if (irpStack->Parameters.DeviceIoControl.IoControlCode == 03881 IOCTL_STORAGE_RESET_DEVICE) { 03882 03883 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; 03884 IoCompleteRequest(Irp, IO_NO_INCREMENT); 03885 status = STATUS_UNSUCCESSFUL; 03886 goto SetStatusAndReturn; 03887 } 03888 03889 // 03890 // If this is a pass through I/O control, set the minor function code 03891 // and device address and pass it to the port driver. 03892 // 03893 03894 if (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH 03895 || irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT) { 03896 03897 PSCSI_PASS_THROUGH scsiPass; 03898 03899 nextStack = IoGetNextIrpStackLocation(Irp); 03900 03901 // 03902 // Validiate the user buffer. 03903 // 03904 03905 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH)){ 03906 03907 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 03908 IoCompleteRequest(Irp, IO_NO_INCREMENT); 03909 status = STATUS_INVALID_PARAMETER; 03910 goto SetStatusAndReturn; 03911 } 03912 03913 // 03914 // Force the SCSI address to the correct value. 03915 // 03916 03917 scsiPass = Irp->AssociatedIrp.SystemBuffer; 03918 scsiPass->PathId = deviceExtension->PathId; 03919 scsiPass->TargetId = deviceExtension->TargetId; 03920 scsiPass->Lun = deviceExtension->Lun; 03921 03922 // 03923 // NOTICE: The SCSI-II specificaiton indicates that this field 03924 // should be zero; however, some target controllers ignore the logical 03925 // unit number in the INDENTIFY message and only look at the logical 03926 // unit number field in the CDB. 03927 // 03928 03929 scsiPass->Cdb[1] |= deviceExtension->Lun << 5; 03930 03931 nextStack->Parameters = irpStack->Parameters; 03932 nextStack->MajorFunction = irpStack->MajorFunction; 03933 nextStack->MinorFunction = IRP_MN_SCSI_CLASS; 03934 03935 status = IoCallDriver(deviceExtension->PortDeviceObject, Irp); 03936 goto SetStatusAndReturn; 03937 } 03938 03939 if (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_GET_ADDRESS) { 03940 03941 PSCSI_ADDRESS scsiAddress = Irp->AssociatedIrp.SystemBuffer; 03942 03943 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 03944 sizeof(SCSI_ADDRESS)) { 03945 03946 // 03947 // Indicate unsuccessful status and no data transferred. 03948 // 03949 03950 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; 03951 Irp->IoStatus.Information = 0; 03952 IoCompleteRequest(Irp, IO_NO_INCREMENT); 03953 status = STATUS_BUFFER_TOO_SMALL; 03954 goto SetStatusAndReturn; 03955 03956 } 03957 03958 scsiAddress->Length = sizeof(SCSI_ADDRESS); 03959 scsiAddress->PortNumber = deviceExtension->PortNumber; 03960 scsiAddress->PathId = deviceExtension->PathId; 03961 scsiAddress->TargetId = deviceExtension->TargetId; 03962 scsiAddress->Lun = deviceExtension->Lun; 03963 Irp->IoStatus.Information = sizeof(SCSI_ADDRESS); 03964 Irp->IoStatus.Status = STATUS_SUCCESS; 03965 IoCompleteRequest(Irp, IO_NO_INCREMENT); 03966 status = STATUS_SUCCESS; 03967 goto SetStatusAndReturn; 03968 } 03969 03970 srb = ExAllocatePool(NonPagedPool, SCSI_REQUEST_BLOCK_SIZE); 03971 03972 if (srb == NULL) { 03973 03974 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 03975 IoCompleteRequest(Irp, IO_NO_INCREMENT); 03976 status = STATUS_INSUFFICIENT_RESOURCES; 03977 goto SetStatusAndReturn; 03978 } 03979 03980 // 03981 // Write zeros to Srb. 03982 // 03983 03984 RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE); 03985 03986 cdb = (PCDB)srb->Cdb; 03987 03988 // 03989 // Change the device type to disk for the switch statement. 03990 // 03991 03992 modifiedIoControlCode = (irpStack->Parameters.DeviceIoControl.IoControlCode 03993 & ~0xffff0000) | (IOCTL_DISK_BASE << 16); 03994 03995 switch (modifiedIoControlCode) { 03996 03997 case IOCTL_DISK_CHECK_VERIFY: { 03998 03999 PIRP irp2 = NULL; 04000 PIO_STACK_LOCATION newStack; 04001 04002 DebugPrint((1,"ScsiDeviceIoControl: Check verify\n")); 04003 04004 // 04005 // If a buffer for a media change count was provided, make sure it's 04006 // big enough to hold the result 04007 // 04008 04009 if(irpStack->Parameters.DeviceIoControl.OutputBufferLength) { 04010 04011 // 04012 // If the buffer is too small to hold the media change count 04013 // then return an error to the caller 04014 // 04015 04016 if(irpStack->Parameters.DeviceIoControl.OutputBufferLength < 04017 sizeof(ULONG)) { 04018 04019 DebugPrint((3,"ScsiDeviceIoControl: media count " 04020 "buffer too small\n")); 04021 04022 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; 04023 Irp->IoStatus.Information = 0; 04024 ExFreePool(srb); 04025 IoCompleteRequest(Irp, IO_NO_INCREMENT); 04026 status = STATUS_BUFFER_TOO_SMALL; 04027 goto SetStatusAndReturn; 04028 04029 } 04030 04031 // 04032 // The caller has provided a valid buffer. Allocate an additional 04033 // irp and stick the CheckVerify completion routine on it. We will 04034 // then send this down to the port driver instead of the irp the 04035 // caller sent in 04036 // 04037 04038 DebugPrint((2,"ScsiDeviceIoControl: Check verify wants " 04039 "media count\n")); 04040 04041 // 04042 // Allocate a new irp to send the TestUnitReady to the port driver 04043 // 04044 04045 irp2 = IoAllocateIrp((CCHAR) (DeviceObject->StackSize + 3), FALSE); 04046 04047 if(irp2 == NULL) { 04048 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 04049 Irp->IoStatus.Information = 0; 04050 ExFreePool(srb); 04051 IoCompleteRequest(Irp, IO_NO_INCREMENT); 04052 status = STATUS_INSUFFICIENT_RESOURCES; 04053 goto SetStatusAndReturn; 04054 04055 break; 04056 } 04057 04058 irp2->Tail.Overlay.Thread = Irp->Tail.Overlay.Thread; 04059 IoSetNextIrpStackLocation(irp2); 04060 04061 // 04062 // Set the top stack location and shove the master Irp into the 04063 // top location 04064 // 04065 04066 newStack = IoGetCurrentIrpStackLocation(irp2); 04067 newStack->Parameters.Others.Argument1 = Irp; 04068 newStack->DeviceObject = DeviceObject; 04069 04070 // 04071 // Stick the check verify completion routine onto the stack 04072 // and prepare the irp for the port driver 04073 // 04074 04075 IoSetCompletionRoutine(irp2, 04076 ScsiClassCheckVerifyComplete, 04077 NULL, 04078 TRUE, 04079 TRUE, 04080 TRUE); 04081 04082 IoSetNextIrpStackLocation(irp2); 04083 newStack = IoGetCurrentIrpStackLocation(irp2); 04084 newStack->DeviceObject = DeviceObject; 04085 04086 // 04087 // Mark the master irp as pending - whether the lower level 04088 // driver completes it immediately or not this should allow it 04089 // to go all the way back up. 04090 // 04091 04092 IoMarkIrpPending(Irp); 04093 04094 Irp = irp2; 04095 04096 } 04097 04098 // 04099 // Test Unit Ready 04100 // 04101 04102 srb->CdbLength = 6; 04103 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY; 04104 04105 // 04106 // Set timeout value. 04107 // 04108 04109 srb->TimeOutValue = deviceExtension->TimeOutValue; 04110 04111 // 04112 // Since this routine will always hand the request to the 04113 // port driver if there isn't a data transfer to be done 04114 // we don't have to worry about completing the request here 04115 // on an error 04116 // 04117 04118 status = ScsiClassSendSrbAsynchronous(DeviceObject, 04119 srb, 04120 Irp, 04121 NULL, 04122 0, 04123 FALSE); 04124 04125 break; 04126 } 04127 04128 case IOCTL_DISK_MEDIA_REMOVAL: { 04129 04130 PPREVENT_MEDIA_REMOVAL MediaRemoval = Irp->AssociatedIrp.SystemBuffer; 04131 04132 // 04133 // Prevent/Allow media removal. 04134 // 04135 04136 DebugPrint((3,"DiskIoControl: Prevent/Allow media removal\n")); 04137 04138 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 04139 sizeof(PREVENT_MEDIA_REMOVAL)) { 04140 04141 // 04142 // Indicate unsuccessful status and no data transferred. 04143 // 04144 04145 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; 04146 Irp->IoStatus.Information = 0; 04147 ExFreePool(srb); 04148 IoCompleteRequest(Irp, IO_NO_INCREMENT); 04149 status = STATUS_BUFFER_TOO_SMALL; 04150 goto SetStatusAndReturn; 04151 } 04152 04153 // 04154 // Get physical device extension. This is where the 04155 // lock count is stored. 04156 // 04157 04158 deviceExtension = deviceExtension->PhysicalDevice->DeviceExtension; 04159 04160 // 04161 // If command succeeded then increment or decrement lock counter. 04162 // 04163 04164 if (MediaRemoval->PreventMediaRemoval) { 04165 04166 // 04167 // This is a lock command. Reissue the command in case bus or device 04168 // was reset and lock cleared. 04169 // 04170 04171 InterlockedIncrement(&deviceExtension->LockCount); 04172 04173 DebugPrint((1, 04174 "ScsiClassDeviceControl: Lock media, lock count %x on disk %x\n", 04175 deviceExtension->LockCount, 04176 deviceExtension->DeviceNumber)); 04177 04178 } else { 04179 04180 // 04181 // This is an unlock command. 04182 // 04183 04184 if (!deviceExtension->LockCount || 04185 (InterlockedDecrement(&deviceExtension->LockCount) != 0)) { 04186 04187 DebugPrint((1, 04188 "ScsiClassDeviceControl: Unlock media, lock count %x on disk %x\n", 04189 deviceExtension->LockCount, 04190 deviceExtension->DeviceNumber)); 04191 04192 // 04193 // Don't unlock because someone still wants it locked. 04194 // 04195 04196 Irp->IoStatus.Status = STATUS_SUCCESS; 04197 ExFreePool(srb); 04198 IoCompleteRequest(Irp, IO_NO_INCREMENT); 04199 status = STATUS_SUCCESS; 04200 goto SetStatusAndReturn; 04201 } 04202 04203 DebugPrint((1, 04204 "ScsiClassDeviceControl: Unlock media, lock count %x on disk %x\n", 04205 deviceExtension->LockCount, 04206 deviceExtension->DeviceNumber)); 04207 } 04208 04209 srb->CdbLength = 6; 04210 04211 cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL; 04212 04213 // 04214 // TRUE - prevent media removal. 04215 // FALSE - allow media removal. 04216 // 04217 04218 cdb->MEDIA_REMOVAL.Prevent = MediaRemoval->PreventMediaRemoval; 04219 04220 // 04221 // Set timeout value. 04222 // 04223 04224 srb->TimeOutValue = deviceExtension->TimeOutValue; 04225 status = ScsiClassSendSrbAsynchronous(DeviceObject, 04226 srb, 04227 Irp, 04228 NULL, 04229 0, 04230 FALSE); 04231 04232 // 04233 // Some devices will not support lock/unlock. 04234 // Pretend that it worked. 04235 // 04236 04237 break; 04238 } 04239 04240 case IOCTL_DISK_RESERVE: { 04241 04242 // 04243 // Reserve logical unit. 04244 // 04245 04246 srb->CdbLength = 6; 04247 04248 cdb->CDB6GENERIC.OperationCode = SCSIOP_RESERVE_UNIT; 04249 04250 // 04251 // Set timeout value. 04252 // 04253 04254 srb->TimeOutValue = deviceExtension->TimeOutValue; 04255 04256 status = ScsiClassSendSrbAsynchronous(DeviceObject, 04257 srb, 04258 Irp, 04259 NULL, 04260 0, 04261 FALSE); 04262 04263 break; 04264 } 04265 04266 case IOCTL_DISK_RELEASE: { 04267 04268 // 04269 // Release logical unit. 04270 // 04271 04272 srb->CdbLength = 6; 04273 04274 cdb->CDB6GENERIC.OperationCode = SCSIOP_RELEASE_UNIT; 04275 04276 // 04277 // Set timeout value. 04278 // 04279 04280 srb->TimeOutValue = deviceExtension->TimeOutValue; 04281 04282 status = ScsiClassSendSrbAsynchronous(DeviceObject, 04283 srb, 04284 Irp, 04285 NULL, 04286 0, 04287 FALSE); 04288 04289 break; 04290 } 04291 04292 case IOCTL_DISK_EJECT_MEDIA: { 04293 04294 // 04295 // Eject media. 04296 // 04297 04298 srb->CdbLength = 6; 04299 04300 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT; 04301 cdb->START_STOP.LoadEject = 1; 04302 cdb->START_STOP.Start = 0; 04303 04304 // 04305 // Set timeout value. 04306 // 04307 04308 srb->TimeOutValue = deviceExtension->TimeOutValue; 04309 status = ScsiClassSendSrbAsynchronous(DeviceObject, 04310 srb, 04311 Irp, 04312 NULL, 04313 0, 04314 FALSE); 04315 break; 04316 } 04317 04318 case IOCTL_DISK_LOAD_MEDIA: { 04319 04320 // 04321 // Load media. 04322 // 04323 04324 DebugPrint((3,"CdRomDeviceControl: Load media\n")); 04325 04326 srb->CdbLength = 6; 04327 04328 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT; 04329 cdb->START_STOP.LoadEject = 1; 04330 cdb->START_STOP.Start = 1; 04331 04332 // 04333 // Set timeout value. 04334 // 04335 04336 srb->TimeOutValue = deviceExtension->TimeOutValue; 04337 status = ScsiClassSendSrbAsynchronous(DeviceObject, 04338 srb, 04339 Irp, 04340 NULL, 04341 0, 04342 FALSE); 04343 04344 break; 04345 } 04346 04347 case IOCTL_DISK_FIND_NEW_DEVICES: { 04348 04349 // 04350 // Search for devices that have been powered on since the last 04351 // device search or system initialization. 04352 // 04353 04354 DebugPrint((3,"CdRomDeviceControl: Find devices\n")); 04355 status = DriverEntry(DeviceObject->DriverObject, 04356 NULL); 04357 04358 Irp->IoStatus.Status = status; 04359 ExFreePool(srb); 04360 IoCompleteRequest(Irp, IO_NO_INCREMENT); 04361 04362 break; 04363 } 04364 04365 default: { 04366 04367 DebugPrint((3,"ScsiIoDeviceControl: Unsupported device IOCTL\n")); 04368 04369 // 04370 // Pass the device control to the next driver. 04371 // 04372 04373 ExFreePool(srb); 04374 04375 // 04376 // Copy the Irp stack parameters to the next stack location. 04377 // 04378 04379 nextStack = IoGetNextIrpStackLocation(Irp); 04380 nextStack->Parameters = irpStack->Parameters; 04381 nextStack->MajorFunction = irpStack->MajorFunction; 04382 nextStack->MinorFunction = irpStack->MinorFunction; 04383 04384 status = IoCallDriver(deviceExtension->PortDeviceObject, Irp); 04385 break; 04386 } 04387 04388 } // end switch( ... 04389 04390 SetStatusAndReturn: 04391 04392 return status; 04393 } 04394 04395 04396 NTSTATUS 04397 NTAPI 04398 ScsiClassShutdownFlush( 04399 IN PDEVICE_OBJECT DeviceObject, 04400 IN PIRP Irp 04401 ) 04402 04403 /*++ 04404 04405 Routine Description: 04406 04407 This routine is called for a shutdown and flush IRPs. These are sent by the 04408 system before it actually shuts down or when the file system does a flush. 04409 If it exists, the device-specific driver's routine will be invoked. If there 04410 wasn't one specified, the Irp will be completed with an Invalid device request. 04411 04412 Arguments: 04413 04414 DriverObject - Pointer to device object to being shutdown by system. 04415 04416 Irp - IRP involved. 04417 04418 Return Value: 04419 04420 NT Status 04421 04422 --*/ 04423 04424 { 04425 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 04426 04427 if (deviceExtension->ClassShutdownFlush) { 04428 04429 // 04430 // Call the device-specific driver's routine. 04431 // 04432 04433 return deviceExtension->ClassShutdownFlush(DeviceObject, Irp); 04434 } 04435 04436 // 04437 // Device-specific driver doesn't support this. 04438 // 04439 04440 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; 04441 IoCompleteRequest(Irp, IO_NO_INCREMENT); 04442 04443 return STATUS_INVALID_DEVICE_REQUEST; 04444 } 04445 04446 04447 ULONG 04448 NTAPI 04449 ScsiClassFindUnclaimedDevices( 04450 IN PCLASS_INIT_DATA InitializationData, 04451 IN PSCSI_ADAPTER_BUS_INFO AdapterInformation 04452 ) 04453 04454 { 04455 ULONG scsiBus,deviceCount = 0; 04456 PCHAR buffer = (PCHAR)AdapterInformation; 04457 PSCSI_INQUIRY_DATA lunInfo; 04458 PINQUIRYDATA inquiryData; 04459 04460 for (scsiBus=0; scsiBus < (ULONG)AdapterInformation->NumberOfBuses; scsiBus++) { 04461 04462 // 04463 // Get the SCSI bus scan data for this bus. 04464 // 04465 04466 lunInfo = (PVOID) (buffer + AdapterInformation->BusData[scsiBus].InquiryDataOffset); 04467 04468 // 04469 // Search list for unclaimed disk devices. 04470 // 04471 04472 while (AdapterInformation->BusData[scsiBus].InquiryDataOffset) { 04473 04474 inquiryData = (PVOID)lunInfo->InquiryData; 04475 04476 ASSERT(InitializationData->ClassFindDeviceCallBack); 04477 04478 if ((InitializationData->ClassFindDeviceCallBack(inquiryData)) && (!lunInfo->DeviceClaimed)) { 04479 04480 deviceCount++; 04481 } 04482 04483 if (lunInfo->NextInquiryDataOffset == 0) { 04484 break; 04485 } 04486 04487 lunInfo = (PVOID) (buffer + lunInfo->NextInquiryDataOffset); 04488 } 04489 } 04490 return deviceCount; 04491 } 04492 04493 04494 04495 NTSTATUS 04496 NTAPI 04497 ScsiClassCreateDeviceObject( 04498 IN PDRIVER_OBJECT DriverObject, 04499 IN PCCHAR ObjectNameBuffer, 04500 IN OPTIONAL PDEVICE_OBJECT PhysicalDeviceObject, 04501 IN OUT PDEVICE_OBJECT *DeviceObject, 04502 IN PCLASS_INIT_DATA InitializationData 04503 ) 04504 04505 /*++ 04506 04507 Routine Description: 04508 04509 This routine creates an object for the physical device specified and 04510 sets up the deviceExtension's function pointers for each entry point 04511 in the device-specific driver. 04512 04513 Arguments: 04514 04515 DriverObject - Pointer to driver object created by system. 04516 04517 ObjectNameBuffer - Dir. name of the object to create. 04518 04519 PhysicalDeviceObject - Pointer to the physical (class) device object for 04520 this logical unit or NULL if this is it. 04521 04522 DeviceObject - Pointer to the device object pointer we will return. 04523 04524 InitializationData - Pointer to the init data created by the device-specific driver. 04525 04526 Return Value: 04527 04528 NTSTATUS 04529 04530 --*/ 04531 04532 { 04533 STRING ntNameString; 04534 UNICODE_STRING ntUnicodeString; 04535 NTSTATUS status; 04536 PDEVICE_OBJECT deviceObject = NULL; 04537 04538 *DeviceObject = NULL; 04539 04540 DebugPrint((2, 04541 "ScsiClassCreateDeviceObject: Create device object %s\n", 04542 ObjectNameBuffer)); 04543 04544 RtlInitString(&ntNameString, 04545 ObjectNameBuffer); 04546 04547 status = RtlAnsiStringToUnicodeString(&ntUnicodeString, 04548 &ntNameString, 04549 TRUE); 04550 04551 if (!NT_SUCCESS(status)) { 04552 04553 DebugPrint((1, 04554 "CreateDiskDeviceObjects: Cannot convert string %s\n", 04555 ObjectNameBuffer)); 04556 04557 ntUnicodeString.Buffer = NULL; 04558 return status; 04559 } 04560 04561 status = IoCreateDevice(DriverObject, 04562 InitializationData->DeviceExtensionSize, 04563 &ntUnicodeString, 04564 InitializationData->DeviceType, 04565 InitializationData->DeviceCharacteristics, 04566 FALSE, 04567 &deviceObject); 04568 04569 04570 if (!NT_SUCCESS(status)) { 04571 04572 DebugPrint((1, 04573 "CreateDiskDeviceObjects: Can not create device object %s\n", 04574 ObjectNameBuffer)); 04575 04576 } else { 04577 04578 PDEVICE_EXTENSION deviceExtension = deviceObject->DeviceExtension; 04579 04580 // 04581 // Fill in entry points 04582 // 04583 04584 deviceExtension->ClassError = InitializationData->ClassError; 04585 deviceExtension->ClassReadWriteVerification = InitializationData->ClassReadWriteVerification; 04586 deviceExtension->ClassFindDevices = InitializationData->ClassFindDevices; 04587 deviceExtension->ClassDeviceControl = InitializationData->ClassDeviceControl; 04588 deviceExtension->ClassShutdownFlush = InitializationData->ClassShutdownFlush; 04589 deviceExtension->ClassCreateClose = InitializationData->ClassCreateClose; 04590 deviceExtension->ClassStartIo = InitializationData->ClassStartIo; 04591 04592 deviceExtension->MediaChangeCount = 0; 04593 04594 // 04595 // If a pointer to the physical device object was passed in then use 04596 // that. If the value was NULL, then this is the physical device so 04597 // use the pointer to the device we just created. 04598 // 04599 04600 if(ARGUMENT_PRESENT(PhysicalDeviceObject)) { 04601 deviceExtension->PhysicalDevice = PhysicalDeviceObject; 04602 } else { 04603 deviceExtension->PhysicalDevice = deviceObject; 04604 } 04605 } 04606 04607 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 04608 04609 *DeviceObject = deviceObject; 04610 04611 RtlFreeUnicodeString(&ntUnicodeString); 04612 04613 // 04614 // Indicate the ntUnicodeString is free. 04615 // 04616 04617 ntUnicodeString.Buffer = NULL; 04618 04619 return status; 04620 } 04621 04622 04623 NTSTATUS 04624 NTAPI 04625 ScsiClassClaimDevice( 04626 IN PDEVICE_OBJECT PortDeviceObject, 04627 IN PSCSI_INQUIRY_DATA LunInfo, 04628 IN BOOLEAN Release, 04629 OUT PDEVICE_OBJECT *NewPortDeviceObject OPTIONAL 04630 ) 04631 /*++ 04632 04633 Routine Description: 04634 04635 This function claims a device in the port driver. The port driver object 04636 is updated with the correct driver object if the device is successfully 04637 claimed. 04638 04639 Arguments: 04640 04641 PortDeviceObject - Supplies the base port device object. 04642 04643 LunInfo - Supplies the logical unit inforamtion of the device to be claimed. 04644 04645 Release - Indicates the logical unit should be released rather than claimed. 04646 04647 NewPortDeviceObject - Returns the updated port device object to be used 04648 for all future accesses. 04649 04650 Return Value: 04651 04652 Returns a status indicating success or failure of the operation. 04653 04654 --*/ 04655 04656 { 04657 IO_STATUS_BLOCK ioStatus; 04658 PIRP irp; 04659 PIO_STACK_LOCATION irpStack; 04660 KEVENT event; 04661 NTSTATUS status; 04662 SCSI_REQUEST_BLOCK srb; 04663 04664 PAGED_CODE(); 04665 04666 if (NewPortDeviceObject != NULL) { 04667 *NewPortDeviceObject = NULL; 04668 } 04669 04670 // 04671 // Clear the SRB fields. 04672 // 04673 04674 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); 04675 04676 // 04677 // Write length to SRB. 04678 // 04679 04680 srb.Length = SCSI_REQUEST_BLOCK_SIZE; 04681 04682 // 04683 // Set SCSI bus address. 04684 // 04685 04686 srb.PathId = LunInfo->PathId; 04687 srb.TargetId = LunInfo->TargetId; 04688 srb.Lun = LunInfo->Lun; 04689 04690 srb.Function = Release ? SRB_FUNCTION_RELEASE_DEVICE : 04691 SRB_FUNCTION_CLAIM_DEVICE; 04692 04693 // 04694 // Set the event object to the unsignaled state. 04695 // It will be used to signal request completion. 04696 // 04697 04698 KeInitializeEvent(&event, NotificationEvent, FALSE); 04699 04700 // 04701 // Build synchronous request with no transfer. 04702 // 04703 04704 irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_NONE, 04705 PortDeviceObject, 04706 NULL, 04707 0, 04708 NULL, 04709 0, 04710 TRUE, 04711 &event, 04712 &ioStatus); 04713 04714 if (irp == NULL) { 04715 04716 DebugPrint((1, "ScsiClassClaimDevice: Can't allocate Irp\n")); 04717 return STATUS_INSUFFICIENT_RESOURCES; 04718 } 04719 04720 irpStack = IoGetNextIrpStackLocation(irp); 04721 04722 // 04723 // Save SRB address in next stack for port driver. 04724 // 04725 04726 irpStack->Parameters.Scsi.Srb = &srb; 04727 04728 // 04729 // Set up IRP Address. 04730 // 04731 04732 srb.OriginalRequest = irp; 04733 04734 // 04735 // Call the port driver with the request and wait for it to complete. 04736 // 04737 04738 status = IoCallDriver(PortDeviceObject, irp); 04739 if (status == STATUS_PENDING) { 04740 04741 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL); 04742 status = ioStatus.Status; 04743 } 04744 04745 // 04746 // If this is a release request, then just decrement the reference count 04747 // and return. The status does not matter. 04748 // 04749 04750 if (Release) { 04751 04752 ObDereferenceObject(PortDeviceObject); 04753 return STATUS_SUCCESS; 04754 } 04755 04756 if (!NT_SUCCESS(status)) { 04757 return status; 04758 } 04759 04760 ASSERT(srb.DataBuffer != NULL); 04761 04762 // 04763 // Reference the new port driver object so that it will not go away while 04764 // it is being used. 04765 // 04766 04767 status = ObReferenceObjectByPointer(srb.DataBuffer, 04768 0, 04769 NULL, 04770 KernelMode ); 04771 04772 if (!NT_SUCCESS(status)) { 04773 04774 return status; 04775 } 04776 04777 // 04778 // Return the new port device object pointer. 04779 // 04780 04781 if (NewPortDeviceObject != NULL) { 04782 *NewPortDeviceObject = srb.DataBuffer; 04783 } 04784 04785 return status; 04786 } 04787 04788 04789 NTSTATUS 04790 NTAPI 04791 ScsiClassInternalIoControl ( 04792 IN PDEVICE_OBJECT DeviceObject, 04793 IN PIRP Irp 04794 ) 04795 04796 /*++ 04797 04798 Routine Description: 04799 04800 This routine passes internal device controls to the port driver. 04801 Internal device controls are used by higher level class drivers to 04802 send scsi requests to a device that are not normally sent by a generic 04803 class driver. 04804 04805 The path ID, target ID and logical unit ID are set in the srb so the 04806 higher level driver does not have to figure out what values are actually 04807 used. 04808 04809 Arguments: 04810 04811 DeviceObject - Supplies a pointer to the device object for this request. 04812 04813 Irp - Supplies the Irp making the request. 04814 04815 Return Value: 04816 04817 Returns back a STATUS_PENDING or a completion status. 04818 04819 --*/ 04820 { 04821 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 04822 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 04823 PSCSI_REQUEST_BLOCK srb; 04824 04825 // 04826 // Get a pointer to the SRB. 04827 // 04828 04829 srb = irpStack->Parameters.Scsi.Srb; 04830 04831 // 04832 // Set SCSI bus address. 04833 // 04834 04835 srb->PathId = deviceExtension->PathId; 04836 srb->TargetId = deviceExtension->TargetId; 04837 srb->Lun = deviceExtension->Lun; 04838 04839 // 04840 // NOTICE: The SCSI-II specificaiton indicates that this field should be 04841 // zero; however, some target controllers ignore the logical unit number 04842 // in the INDENTIFY message and only look at the logical unit number field 04843 // in the CDB. 04844 // 04845 04846 srb->Cdb[1] |= deviceExtension->Lun << 5; 04847 04848 // 04849 // Set the parameters in the next stack location. 04850 // 04851 04852 irpStack = IoGetNextIrpStackLocation(Irp); 04853 04854 irpStack->Parameters.Scsi.Srb = srb; 04855 irpStack->MajorFunction = IRP_MJ_SCSI; 04856 irpStack->MinorFunction = IRP_MN_SCSI_CLASS; 04857 04858 IoSetCompletionRoutine(Irp, ClassIoCompletion, NULL, TRUE, TRUE, TRUE); 04859 return IoCallDriver(deviceExtension->PortDeviceObject, Irp); 04860 } 04861 04862 NTSTATUS 04863 NTAPI 04864 ClassIoCompletion( 04865 IN PDEVICE_OBJECT DeviceObject, 04866 IN PIRP Irp, 04867 IN PVOID Context 04868 ) 04869 04870 /*++ 04871 04872 Routine Description: 04873 04874 This routine is called when an internal device control I/O request 04875 has completed. It marks the IRP pending if necessary and returns the 04876 status of the request. 04877 04878 Arguments: 04879 04880 DeviceObject - Target device object. 04881 04882 Irp - Completed request. 04883 04884 Context - not used. 04885 04886 Return Value: 04887 04888 Returns the status of the completed request. 04889 04890 --*/ 04891 04892 { 04893 UNREFERENCED_PARAMETER(Context); 04894 UNREFERENCED_PARAMETER(DeviceObject); 04895 04896 // 04897 // If pending is returned for this Irp then mark current stack 04898 // as pending 04899 // 04900 04901 if (Irp->PendingReturned) { 04902 04903 IoMarkIrpPending( Irp ); 04904 } 04905 04906 return Irp->IoStatus.Status; 04907 } 04908 04909 04910 VOID 04911 NTAPI 04912 ScsiClassInitializeSrbLookasideList( 04913 IN PDEVICE_EXTENSION DeviceExtension, 04914 IN ULONG NumberElements 04915 ) 04916 04917 /*++ 04918 04919 Routine Description: 04920 04921 This routine sets up a lookaside listhead for srbs. 04922 04923 Arguments: 04924 04925 DeviceExtension - Pointer to the deviceExtension containing the listhead. 04926 04927 NumberElements - Supplies the maximum depth of the lookaside list. 04928 04929 04930 Return Value: 04931 04932 None 04933 04934 --*/ 04935 04936 { 04937 ExInitializeNPagedLookasideList(&DeviceExtension->SrbLookasideListHead, 04938 NULL, 04939 NULL, 04940 NonPagedPoolMustSucceed, 04941 SCSI_REQUEST_BLOCK_SIZE, 04942 'ScsH', 04943 (USHORT)NumberElements); 04944 04945 } 04946 04947 04948 ULONG 04949 NTAPI 04950 ScsiClassQueryTimeOutRegistryValue( 04951 IN PUNICODE_STRING RegistryPath 04952 ) 04953 04954 /*++ 04955 04956 Routine Description: 04957 04958 This routine determines whether a reg key for a user-specified timeout value exists. 04959 04960 Arguments: 04961 04962 RegistryPath - Pointer to the hardware reg. entry describing the key. 04963 04964 Return Value: 04965 04966 New default timeout for a class of devices. 04967 04968 --*/ 04969 04970 { 04971 // 04972 // Find the appropriate reg. key 04973 // 04974 04975 PRTL_QUERY_REGISTRY_TABLE parameters = NULL; 04976 PWSTR path; 04977 NTSTATUS status; 04978 LONG timeOut = 0; 04979 ULONG zero = 0; 04980 ULONG size; 04981 04982 if (!RegistryPath) { 04983 return 0; 04984 } 04985 04986 parameters = ExAllocatePool(NonPagedPool, 04987 sizeof(RTL_QUERY_REGISTRY_TABLE)*2); 04988 04989 if (!parameters) { 04990 return 0; 04991 } 04992 04993 size = RegistryPath->MaximumLength + sizeof(WCHAR); 04994 path = ExAllocatePool(NonPagedPool, size); 04995 04996 if (!path) { 04997 ExFreePool(parameters); 04998 return 0; 04999 } 05000 05001 RtlZeroMemory(path,size); 05002 RtlCopyMemory(path, RegistryPath->Buffer, size - sizeof(WCHAR)); 05003 05004 05005 // 05006 // Check for the Timeout value. 05007 // 05008 05009 RtlZeroMemory(parameters, 05010 (sizeof(RTL_QUERY_REGISTRY_TABLE)*2)); 05011 05012 parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT; 05013 parameters[0].Name = L"TimeOutValue"; 05014 parameters[0].EntryContext = &timeOut; 05015 parameters[0].DefaultType = REG_DWORD; 05016 parameters[0].DefaultData = &zero; 05017 parameters[0].DefaultLength = sizeof(ULONG); 05018 05019 status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, 05020 path, 05021 parameters, 05022 NULL, 05023 NULL); 05024 05025 if (!(NT_SUCCESS(status))) { 05026 timeOut = 0; 05027 } 05028 05029 ExFreePool(parameters); 05030 ExFreePool(path); 05031 05032 DebugPrint((2, 05033 "ScsiClassQueryTimeOutRegistryValue: Timeout value %d\n", 05034 timeOut)); 05035 05036 05037 return timeOut; 05038 05039 } 05040 05041 NTSTATUS 05042 NTAPI 05043 ScsiClassCheckVerifyComplete( 05044 IN PDEVICE_OBJECT DeviceObject, 05045 IN PIRP Irp, 05046 IN PVOID Context 05047 ) 05048 05049 /*++ 05050 05051 Routine Description: 05052 05053 This routine executes when the port driver has completed a check verify 05054 ioctl. It will set the status of the master Irp, copy the media change 05055 count and complete the request. 05056 05057 Arguments: 05058 05059 DeviceObject - Supplies the device object which represents the logical 05060 unit. 05061 05062 Irp - Supplies the Irp which has completed. 05063 05064 Context - NULL 05065 05066 Return Value: 05067 05068 NT status 05069 05070 --*/ 05071 05072 { 05073 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 05074 PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; 05075 PDEVICE_EXTENSION physicalExtension = 05076 deviceExtension->PhysicalDevice->DeviceExtension; 05077 PIRP originalIrp; 05078 05079 originalIrp = irpStack->Parameters.Others.Argument1; 05080 05081 // 05082 // Copy the media change count and status 05083 // 05084 05085 *((PULONG) (originalIrp->AssociatedIrp.SystemBuffer)) = 05086 physicalExtension->MediaChangeCount; 05087 05088 DebugPrint((2, "ScsiClassInterpretSenseInfo - Media change count for" 05089 "device %d is %d\n", 05090 physicalExtension->DeviceNumber, 05091 physicalExtension->MediaChangeCount)); 05092 05093 originalIrp->IoStatus.Status = Irp->IoStatus.Status; 05094 originalIrp->IoStatus.Information = sizeof(ULONG); 05095 05096 IoCompleteRequest(originalIrp, IO_DISK_INCREMENT); 05097 05098 IoFreeIrp(Irp); 05099 05100 return STATUS_MORE_PROCESSING_REQUIRED; 05101 } 05102 05103 NTSTATUS 05104 NTAPI 05105 ClassCompletionRoutine(IN PDEVICE_OBJECT DeviceObject, 05106 IN PIRP Irp, 05107 IN PVOID Context) 05108 { 05109 PIO_STATUS_BLOCK IoStatusBlock = Irp->UserIosb; 05110 PKEVENT Event = Irp->UserEvent; 05111 PMDL Mdl; 05112 05113 *IoStatusBlock = Irp->IoStatus; 05114 Irp->UserIosb = NULL; 05115 Irp->UserEvent = NULL; 05116 05117 if(Irp->MdlAddress) 05118 { 05119 Mdl = Irp->MdlAddress; 05120 05121 // if necessary - unlock pages 05122 if ((Mdl->MdlFlags & MDL_PAGES_LOCKED) && 05123 !(Mdl->MdlFlags & MDL_PARTIAL_HAS_BEEN_MAPPED)) 05124 { 05125 MmUnlockPages(Mdl); 05126 } 05127 05128 // free this mdl 05129 IoFreeMdl(Mdl); 05130 } 05131 05132 // free irp and set event to unsignaled state 05133 IoFreeIrp(Irp); 05134 KeSetEvent(Event, IO_NO_INCREMENT, FALSE); 05135 05136 return STATUS_MORE_PROCESSING_REQUIRED; 05137 } Generated on Fri May 25 2012 04:26:34 for ReactOS by
1.7.6.1
|