3226 lines
80 KiB
C
3226 lines
80 KiB
C
#if defined(JAZZ) || defined(i386) || defined(_ALPHA_)
|
||
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
scsidisk.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the hard disk boot driver for the Jazz system.
|
||
|
||
Author:
|
||
|
||
Jeff Havens (jhavens) 8-12-1991
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
|
||
#ifdef MIPS
|
||
#include "..\fw\mips\fwp.h"
|
||
#undef KeGetDcacheFillSize
|
||
#define KeGetDcacheFillSize() BlDcacheFillSize
|
||
#elif defined(_ALPHA_)
|
||
#include "..\fw\alpha\fwp.h"
|
||
#undef KeGetDcacheFillSize
|
||
#define KeGetDcacheFillSize() BlDcacheFillSize
|
||
#else
|
||
#include "bootx86.h"
|
||
#undef KeGetDcacheFillSize
|
||
#define KeGetDcacheFillSize() 4
|
||
#endif
|
||
#include "ntdddisk.h"
|
||
#include "scsi.h"
|
||
#include "scsiboot.h"
|
||
#include "stdio.h"
|
||
#include "string.h"
|
||
|
||
#if defined(SETUP) && i386
|
||
#include "spscsi.h"
|
||
#endif
|
||
|
||
|
||
|
||
//
|
||
// SCSI driver constants.
|
||
//
|
||
|
||
#define MAXIMUM_NUMBER_SECTORS 128 // maximum number of transfer sector
|
||
#define MAXIMUM_NUMBER_RETRIES 8 // maximum number of read/write retries
|
||
#define MAXIMUM_SECTOR_SIZE 2048 // define the maximum supported sector size
|
||
#define MODE_DATA_SIZE 192
|
||
#define HITACHI_MODE_DATA_SIZE 12
|
||
|
||
CHAR ScsiTempBuffer[MAXIMUM_SECTOR_SIZE + 128];
|
||
|
||
|
||
//
|
||
// Define device driver prototypes.
|
||
//
|
||
|
||
NTSTATUS
|
||
ScsiDiskBootPartitionOpen(
|
||
IN ULONG FileId,
|
||
IN UCHAR DeviceUnit,
|
||
IN UCHAR PartitionNumber
|
||
);
|
||
|
||
ARC_STATUS
|
||
ScsiDiskClose (
|
||
IN ULONG FileId
|
||
);
|
||
|
||
ARC_STATUS
|
||
ScsiDiskMount (
|
||
IN PCHAR MountPath,
|
||
IN MOUNT_OPERATION Operation
|
||
);
|
||
|
||
ARC_STATUS
|
||
ScsiDiskOpen (
|
||
IN PCHAR OpenPath,
|
||
IN OPEN_MODE OpenMode,
|
||
OUT PULONG FileId
|
||
);
|
||
|
||
ARC_STATUS
|
||
ScsiDiskRead (
|
||
IN ULONG FileId,
|
||
IN PVOID Buffer,
|
||
IN ULONG Length,
|
||
OUT PULONG Count
|
||
);
|
||
|
||
ARC_STATUS
|
||
ScsiDiskGetReadStatus (
|
||
IN ULONG FileId
|
||
);
|
||
|
||
ARC_STATUS
|
||
ScsiDiskSeek (
|
||
IN ULONG FileId,
|
||
IN PLARGE_INTEGER Offset,
|
||
IN SEEK_MODE SeekMode
|
||
);
|
||
|
||
ARC_STATUS
|
||
ScsiDiskWrite (
|
||
IN ULONG FileId,
|
||
IN PVOID Buffer,
|
||
IN ULONG Length,
|
||
OUT PULONG Count
|
||
);
|
||
|
||
ARC_STATUS
|
||
ScsiDiskGetFileInformation (
|
||
IN ULONG FileId,
|
||
OUT PFILE_INFORMATION Finfo
|
||
);
|
||
|
||
NTSTATUS
|
||
ScsiDiskBootIO (
|
||
IN PMDL MdlAddress,
|
||
IN ULONG LogicalBlock,
|
||
IN PPARTITION_CONTEXT PartitionContext,
|
||
IN BOOLEAN Operation
|
||
);
|
||
|
||
VOID
|
||
ScsiDiskBootSetup (
|
||
VOID
|
||
);
|
||
|
||
VOID
|
||
ScsiPortExecute(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
);
|
||
|
||
VOID
|
||
ScsiDiskStartUnit(
|
||
IN PPARTITION_CONTEXT PartitionContext
|
||
);
|
||
|
||
VOID
|
||
ScsiDiskStartUnit(
|
||
IN PPARTITION_CONTEXT PartitionContext
|
||
);
|
||
|
||
VOID
|
||
ScsiDiskFilterBad(
|
||
IN PPARTITION_CONTEXT PartitionContext
|
||
);
|
||
|
||
ULONG
|
||
ClassModeSense(
|
||
IN PPARTITION_CONTEXT Context,
|
||
IN PCHAR ModeSenseBuffer,
|
||
IN ULONG Length,
|
||
IN UCHAR PageMode
|
||
);
|
||
|
||
PVOID
|
||
ClassFindModePage(
|
||
IN PCHAR ModeSenseBuffer,
|
||
IN ULONG Length,
|
||
IN UCHAR PageMode
|
||
);
|
||
BOOLEAN
|
||
IsFloppyDevice(
|
||
PPARTITION_CONTEXT Context
|
||
);
|
||
|
||
BOOLEAN
|
||
CheckFileId(
|
||
ULONG FileId
|
||
);
|
||
|
||
|
||
//
|
||
// Define static data.
|
||
//
|
||
|
||
BL_DEVICE_ENTRY_TABLE ScsiDiskEntryTable = {
|
||
ScsiDiskClose,
|
||
ScsiDiskMount,
|
||
ScsiDiskOpen,
|
||
ScsiDiskRead,
|
||
ScsiDiskGetReadStatus,
|
||
ScsiDiskSeek,
|
||
ScsiDiskWrite,
|
||
ScsiDiskGetFileInformation,
|
||
(PARC_SET_FILE_INFO_ROUTINE)NULL
|
||
};
|
||
|
||
|
||
//
|
||
// Global poiter for buffers.
|
||
//
|
||
|
||
PREAD_CAPACITY_DATA ReadCapacityBuffer;
|
||
PUCHAR SenseInfoBuffer;
|
||
|
||
#define SECTORS_IN_LOGICAL_VOLUME 0x20
|
||
|
||
|
||
ARC_STATUS
|
||
ScsiDiskGetFileInformation (
|
||
IN ULONG FileId,
|
||
OUT PFILE_INFORMATION Finfo
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns information on the scsi partition.
|
||
|
||
Arguments:
|
||
|
||
FileId - Supplies the file table index.
|
||
|
||
Finfo - Supplies a pointer to where the File Informatino is stored.
|
||
|
||
Return Value:
|
||
|
||
ESUCCESS is returned.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PPARTITION_CONTEXT Context;
|
||
|
||
RtlZeroMemory(Finfo, sizeof(FILE_INFORMATION));
|
||
|
||
Context = &BlFileTable[FileId].u.PartitionContext;
|
||
|
||
Finfo->StartingAddress.QuadPart = Context->StartingSector;
|
||
Finfo->StartingAddress.QuadPart <<= Context->SectorShift;
|
||
|
||
Finfo->EndingAddress.QuadPart = Finfo->StartingAddress.QuadPart + Context->PartitionLength.QuadPart;
|
||
|
||
Finfo->Type = DiskPeripheral;
|
||
|
||
return ESUCCESS;
|
||
}
|
||
|
||
|
||
ARC_STATUS
|
||
ScsiDiskClose (
|
||
IN ULONG FileId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function closes the file table entry specified by the file id.
|
||
|
||
Arguments:
|
||
|
||
FileId - Supplies the file table index.
|
||
|
||
Return Value:
|
||
|
||
ESUCCESS is returned.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
BlFileTable[FileId].Flags.Open = 0;
|
||
return ESUCCESS;
|
||
}
|
||
|
||
ARC_STATUS
|
||
ScsiDiskMount (
|
||
IN PCHAR MountPath,
|
||
IN MOUNT_OPERATION Operation
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
return ESUCCESS;
|
||
}
|
||
|
||
ARC_STATUS
|
||
ScsiDiskOpen (
|
||
IN PCHAR OpenPath,
|
||
IN OPEN_MODE OpenMode,
|
||
OUT PULONG FileId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine fills in the file table entry. In particular the Scsi address
|
||
of the device is determined from the name. The block size of device is
|
||
queried from the target controller, and the partition information is read
|
||
from the device.
|
||
|
||
Arguments:
|
||
|
||
OpenPath - Supplies the name of the device being opened.
|
||
|
||
OpenMode - Unused.
|
||
|
||
FileId - Supplies the index to the file table entry to be initialized.
|
||
|
||
Return Value:
|
||
|
||
Retruns the arc status of the operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG Partition;
|
||
ULONG Id;
|
||
BOOLEAN IsCdRom;
|
||
BOOLEAN IsFloppy;
|
||
PPARTITION_CONTEXT Context;
|
||
|
||
Context = &BlFileTable[*FileId].u.PartitionContext;
|
||
|
||
//
|
||
// Determine the scsi port device object.
|
||
//
|
||
|
||
if (FwGetPathMnemonicKey(OpenPath, "scsi", &Id)) {
|
||
return ENODEV;
|
||
}
|
||
|
||
if (ScsiPortDeviceObject[Id] == NULL) {
|
||
return ENODEV;
|
||
}
|
||
|
||
Context->PortDeviceObject = ScsiPortDeviceObject[Id];
|
||
|
||
//
|
||
// Get the logical unit, path Id and target id from the name.
|
||
// NOTE: FwGetPathMnemonicKey returns 0 for success.
|
||
//
|
||
|
||
if (FwGetPathMnemonicKey(OpenPath, "rdisk", &Id)) {
|
||
if (FwGetPathMnemonicKey(OpenPath, "fdisk", &Id)) {
|
||
return ENODEV;
|
||
} else {
|
||
IsFloppy = TRUE;
|
||
}
|
||
} else {
|
||
IsFloppy = FALSE;
|
||
}
|
||
|
||
//
|
||
// Booting is only allowed on LUN 0 since the scsibus
|
||
// scan in the loader only searches for LUN 0.
|
||
//
|
||
|
||
if (Id != 0) {
|
||
return ENODEV;
|
||
}
|
||
|
||
Context->DiskId = (UCHAR)Id;
|
||
|
||
if (!FwGetPathMnemonicKey(OpenPath, "cdrom", &Id)) {
|
||
IsCdRom = TRUE;
|
||
} else if (!FwGetPathMnemonicKey(OpenPath, "disk", &Id)) {
|
||
IsCdRom = FALSE;
|
||
} else {
|
||
return ENODEV;
|
||
}
|
||
|
||
Context->PathId = (UCHAR)(Id / SCSI_MAXIMUM_TARGETS_PER_BUS);
|
||
|
||
Context->TargetId = (UCHAR)(Id % SCSI_MAXIMUM_TARGETS_PER_BUS);
|
||
|
||
//
|
||
// Initialize any bad devices.
|
||
//
|
||
|
||
ScsiDiskFilterBad(Context);
|
||
|
||
//
|
||
// Read the capacity of the disk to determine the block size.
|
||
//
|
||
|
||
if (ReadDriveCapacity(Context)) {
|
||
return ENODEV;
|
||
}
|
||
|
||
//
|
||
// This is all that needs to be done for floppies and harddisks.
|
||
//
|
||
|
||
if (IsCdRom || IsFloppy) {
|
||
return(ESUCCESS);
|
||
}
|
||
|
||
if (FwGetPathMnemonicKey(OpenPath,
|
||
"partition",
|
||
&Partition
|
||
)) {
|
||
return ENODEV;
|
||
}
|
||
|
||
if (Partition != 0) {
|
||
if (ScsiDiskBootPartitionOpen(*FileId,0,(UCHAR)Partition) != STATUS_SUCCESS) {
|
||
return ENODEV;
|
||
}
|
||
}
|
||
//
|
||
// Initialize partition table
|
||
//
|
||
return ESUCCESS;
|
||
}
|
||
|
||
ARC_STATUS
|
||
ScsiDiskRead (
|
||
IN ULONG FileId,
|
||
IN PVOID Buffer,
|
||
IN ULONG Length,
|
||
OUT PULONG Count
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function reads data from the hard disk starting at the position
|
||
specified in the file table.
|
||
|
||
|
||
Arguments:
|
||
|
||
FileId - Supplies the file table index.
|
||
|
||
Buffer - Supplies a poiner to the buffer that receives the data
|
||
read.
|
||
|
||
Length - Supplies the number of bytes to be read.
|
||
|
||
Count - Supplies a pointer to a variable that receives the number of
|
||
bytes actually read.
|
||
|
||
Return Value:
|
||
|
||
The read operation is performed and the read completion status is
|
||
returned.
|
||
|
||
--*/
|
||
|
||
|
||
{
|
||
|
||
ARC_STATUS ArcStatus;
|
||
ULONG FrameNumber;
|
||
ULONG Index;
|
||
ULONG Limit;
|
||
PMDL MdlAddress;
|
||
UCHAR MdlBuffer[sizeof(MDL) + ((64 / 4) + 1) * sizeof(ULONG)];
|
||
NTSTATUS NtStatus;
|
||
ULONG NumberOfPages;
|
||
PULONG PageFrame;
|
||
ULONG Offset;
|
||
LARGE_INTEGER Position;
|
||
LARGE_INTEGER LogicalBlock;
|
||
PCHAR TempPointer;
|
||
PIO_SCSI_CAPABILITIES PortCapabilities;
|
||
ULONG adapterLimit;
|
||
ULONG alignmentMask;
|
||
ULONG SectorSize;
|
||
ULONG TransferCount;
|
||
ULONG BytesToTransfer;
|
||
|
||
//
|
||
// If the requested size of the transfer is zero return ESUCCESS
|
||
//
|
||
if (Length==0) {
|
||
return ESUCCESS;
|
||
}
|
||
|
||
if (!CheckFileId(FileId)) {
|
||
return(ENODEV);
|
||
}
|
||
|
||
//
|
||
// Compute a Dcache aligned pointer into the temporary buffer.
|
||
//
|
||
|
||
TempPointer = (PVOID)((ULONG)(ScsiTempBuffer +
|
||
KeGetDcacheFillSize() - 1) & ~(KeGetDcacheFillSize() - 1));
|
||
|
||
|
||
//
|
||
// Calculate the actual sector size.
|
||
//
|
||
|
||
SectorSize = 1 << BlFileTable[FileId].u.PartitionContext.SectorShift;
|
||
|
||
ArcStatus = GetAdapterCapabilities(
|
||
BlFileTable[FileId].u.PartitionContext.PortDeviceObject,
|
||
&PortCapabilities
|
||
);
|
||
|
||
if (ArcStatus != ESUCCESS) {
|
||
|
||
adapterLimit = 0x10000;
|
||
alignmentMask = KeGetDcacheFillSize();
|
||
|
||
} else {
|
||
|
||
if (PortCapabilities->MaximumTransferLength < 0x1000 ||
|
||
PortCapabilities->MaximumTransferLength > 0x10000) {
|
||
|
||
adapterLimit = 0x10000;
|
||
|
||
} else {
|
||
|
||
adapterLimit = PortCapabilities->MaximumTransferLength;
|
||
|
||
}
|
||
|
||
alignmentMask = PortCapabilities->AlignmentMask;
|
||
}
|
||
|
||
//
|
||
// If the current position is not at a sector boundary or if the data
|
||
// buffer is not properly aligned, then read the first sector separately
|
||
// and copy the data.
|
||
//
|
||
|
||
Offset = BlFileTable[FileId].Position.LowPart & (SectorSize - 1);
|
||
*Count = 0;
|
||
while (Offset != 0 || (ULONG) Buffer & alignmentMask) {
|
||
|
||
Position = BlFileTable[FileId].Position;
|
||
BlFileTable[FileId].Position.QuadPart = Position.QuadPart - Offset;
|
||
|
||
ArcStatus = ScsiDiskRead(FileId, TempPointer, SectorSize, &TransferCount);
|
||
if (ArcStatus != ESUCCESS) {
|
||
BlFileTable[FileId].Position = Position;
|
||
return ArcStatus;
|
||
}
|
||
|
||
//
|
||
// Copy the data to the specified buffer.
|
||
//
|
||
|
||
if ((SectorSize - Offset) > Length) {
|
||
Limit = Offset + Length;
|
||
|
||
} else {
|
||
Limit = SectorSize;
|
||
}
|
||
|
||
for (Index = Offset; Index < Limit; Index += 1) {
|
||
((PCHAR)Buffer)[Index - Offset] = TempPointer[Index];
|
||
}
|
||
|
||
//
|
||
// Update transfer parameters.
|
||
//
|
||
|
||
*Count += Limit - Offset;
|
||
Length -= Limit - Offset;
|
||
Buffer = (PVOID)((PCHAR)Buffer + Limit - Offset);
|
||
BlFileTable[FileId].Position.QuadPart = Position.QuadPart + (Limit - Offset);
|
||
|
||
Offset = BlFileTable[FileId].Position.LowPart & (SectorSize - 1);
|
||
|
||
if (Length == 0) {
|
||
break;
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// The position is aligned on a sector boundary. Read as many sectors
|
||
// as possible in a contiguous run in 64Kb chunks.
|
||
//
|
||
|
||
BytesToTransfer = Length & (~(SectorSize - 1));
|
||
while (BytesToTransfer != 0) {
|
||
|
||
//
|
||
// The scsi controller doesn't support transfers bigger than 64Kb.
|
||
// Transfer the maximum number of bytes possible.
|
||
//
|
||
|
||
Limit = (BytesToTransfer > adapterLimit ? adapterLimit : BytesToTransfer);
|
||
|
||
//
|
||
// Build the memory descriptor list.
|
||
//
|
||
|
||
|
||
MdlAddress = (PMDL)&MdlBuffer[0];
|
||
MdlAddress->Next = NULL;
|
||
MdlAddress->Size = sizeof(MDL) +
|
||
ADDRESS_AND_SIZE_TO_SPAN_PAGES(Buffer, Limit) * sizeof(ULONG);
|
||
MdlAddress->StartVa = (PVOID)PAGE_ALIGN(Buffer);
|
||
MdlAddress->ByteCount = Limit;
|
||
MdlAddress->ByteOffset = BYTE_OFFSET(Buffer);
|
||
PageFrame = (PULONG)(MdlAddress + 1);
|
||
FrameNumber = (((ULONG)MdlAddress->StartVa) & 0x1fffffff) >> PAGE_SHIFT;
|
||
NumberOfPages = (MdlAddress->ByteCount +
|
||
MdlAddress->ByteOffset + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||
for (Index = 0; Index < NumberOfPages; Index += 1) {
|
||
*PageFrame++ = FrameNumber++;
|
||
}
|
||
|
||
//
|
||
// Flush I/O buffers and read from the boot device.
|
||
//
|
||
|
||
KeFlushIoBuffers(MdlAddress, TRUE, TRUE);
|
||
LogicalBlock.QuadPart = BlFileTable[FileId].Position.QuadPart >>
|
||
BlFileTable[FileId].u.PartitionContext.SectorShift;
|
||
LogicalBlock.LowPart += BlFileTable[FileId].u.PartitionContext.StartingSector;
|
||
NtStatus = ScsiDiskBootIO(MdlAddress,
|
||
LogicalBlock.LowPart,
|
||
&BlFileTable[FileId].u.PartitionContext,
|
||
TRUE);
|
||
|
||
if (NtStatus != ESUCCESS) {
|
||
return EIO;
|
||
}
|
||
|
||
*Count += Limit;
|
||
Length -= Limit;
|
||
Buffer = (PVOID)((PCHAR)Buffer + Limit);
|
||
BytesToTransfer -= Limit;
|
||
BlFileTable[FileId].Position.QuadPart = BlFileTable[FileId].Position.QuadPart + Limit;
|
||
}
|
||
|
||
//
|
||
// If there is any residual data to read, then read the last sector
|
||
// separately and copy the data.
|
||
//
|
||
|
||
if (Length != 0) {
|
||
Position = BlFileTable[FileId].Position;
|
||
ArcStatus = ScsiDiskRead(FileId, TempPointer, SectorSize, &TransferCount);
|
||
if (ArcStatus != ESUCCESS) {
|
||
BlFileTable[FileId].Position = Position;
|
||
return ArcStatus;
|
||
}
|
||
|
||
//
|
||
// Copy the data to the specified buffer.
|
||
//
|
||
RtlCopyMemory(Buffer,TempPointer,Length);
|
||
|
||
//
|
||
// Update transfer parameters.
|
||
//
|
||
|
||
*Count += Length;
|
||
BlFileTable[FileId].Position.QuadPart = Position.QuadPart + Length;
|
||
}
|
||
|
||
return ESUCCESS;
|
||
|
||
}
|
||
|
||
ARC_STATUS
|
||
ScsiDiskGetReadStatus (
|
||
IN ULONG FileId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
return ESUCCESS;
|
||
}
|
||
|
||
ARC_STATUS
|
||
ScsiDiskSeek (
|
||
IN ULONG FileId,
|
||
IN PLARGE_INTEGER Offset,
|
||
IN SEEK_MODE SeekMode
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function sets the device position to the specified offset for
|
||
the specified file id.
|
||
|
||
Arguments:
|
||
|
||
FileId - Supplies the file table index.
|
||
|
||
Offset - Supplies to new device position.
|
||
|
||
SeekMode - Supplies the mode for the position.
|
||
|
||
Return Value:
|
||
|
||
ESUCCESS is returned.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
//
|
||
// Set the current device position as specifed by the seek mode.
|
||
//
|
||
|
||
if (SeekMode == SeekAbsolute) {
|
||
BlFileTable[FileId].Position = *Offset;
|
||
|
||
} else if (SeekMode == SeekRelative) {
|
||
BlFileTable[FileId].Position.QuadPart = BlFileTable[FileId].Position.QuadPart + Offset->QuadPart;
|
||
}
|
||
|
||
return ESUCCESS;
|
||
}
|
||
|
||
ARC_STATUS
|
||
ScsiDiskWrite (
|
||
IN ULONG FileId,
|
||
IN PVOID Buffer,
|
||
IN ULONG Length,
|
||
OUT PULONG Count
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function writes data to the hard disk starting at the position
|
||
specified in the file table.
|
||
|
||
|
||
Arguments:
|
||
|
||
FileId - Supplies the file table index.
|
||
|
||
Buffer - Supplies a poiner to the buffer that contains the write data.
|
||
|
||
Length - Supplies the number of bytes to be written.
|
||
|
||
Count - Supplies a pointer to a variable that receives the number of
|
||
bytes actually written.
|
||
|
||
Return Value:
|
||
|
||
The write operation is performed and the write completion status is
|
||
returned.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
ARC_STATUS ArcStatus;
|
||
ULONG FrameNumber;
|
||
ULONG Index;
|
||
ULONG Limit;
|
||
PMDL MdlAddress;
|
||
UCHAR MdlBuffer[sizeof(MDL) + ((64 / 4) + 1) * sizeof(ULONG)];
|
||
NTSTATUS NtStatus;
|
||
ULONG NumberOfPages;
|
||
ULONG Offset;
|
||
PULONG PageFrame;
|
||
LARGE_INTEGER Position;
|
||
LARGE_INTEGER WritePosition;
|
||
LARGE_INTEGER LogicalBlock;
|
||
CHAR TempBuffer[MAXIMUM_SECTOR_SIZE + 128];
|
||
PIO_SCSI_CAPABILITIES PortCapabilities;
|
||
ULONG adapterLimit;
|
||
PCHAR TempPointer;
|
||
ULONG SectorSize;
|
||
ULONG TransferCount;
|
||
ULONG BytesToTransfer;
|
||
ULONG alignmentMask;
|
||
//
|
||
// If the requested size of the transfer is zero return ESUCCESS
|
||
//
|
||
|
||
if (Length==0) {
|
||
return ESUCCESS;
|
||
}
|
||
|
||
if (!CheckFileId(FileId)) {
|
||
return(ENODEV);
|
||
}
|
||
|
||
//
|
||
// Compute a Dcache aligned pointer into the temporary buffer.
|
||
//
|
||
|
||
TempPointer = (PVOID)((ULONG)(TempBuffer +
|
||
KeGetDcacheFillSize() - 1) & ~(KeGetDcacheFillSize() - 1));
|
||
|
||
|
||
//
|
||
// Calculate the actual sector size.
|
||
//
|
||
|
||
SectorSize = 1 << BlFileTable[FileId].u.PartitionContext.SectorShift;
|
||
|
||
ArcStatus = GetAdapterCapabilities(
|
||
BlFileTable[FileId].u.PartitionContext.PortDeviceObject,
|
||
&PortCapabilities
|
||
);
|
||
|
||
if (ArcStatus != ESUCCESS) {
|
||
|
||
adapterLimit = 0x10000;
|
||
alignmentMask = KeGetDcacheFillSize();
|
||
|
||
} else {
|
||
|
||
if (PortCapabilities->MaximumTransferLength < 0x1000 ||
|
||
PortCapabilities->MaximumTransferLength > 0x10000) {
|
||
|
||
adapterLimit = 0x10000;
|
||
|
||
} else {
|
||
|
||
adapterLimit = PortCapabilities->MaximumTransferLength;
|
||
|
||
}
|
||
|
||
alignmentMask = PortCapabilities->AlignmentMask;
|
||
}
|
||
|
||
//
|
||
// If the current position is not at a sector boundary or if the data
|
||
// buffer is not properly aligned, then read the first sector separately
|
||
// and copy the data.
|
||
//
|
||
|
||
Offset = BlFileTable[FileId].Position.LowPart & (SectorSize - 1);
|
||
*Count = 0;
|
||
while (Offset != 0 || (ULONG) Buffer & alignmentMask) {
|
||
|
||
Position = BlFileTable[FileId].Position;
|
||
BlFileTable[FileId].Position.QuadPart = Position.QuadPart - Offset;
|
||
WritePosition = BlFileTable[FileId].Position;
|
||
ArcStatus = ScsiDiskRead(FileId, TempPointer, SectorSize, &TransferCount);
|
||
if (ArcStatus != ESUCCESS) {
|
||
BlFileTable[FileId].Position = Position;
|
||
return ArcStatus;
|
||
}
|
||
//
|
||
// Reset the position as it was before the read.
|
||
//
|
||
|
||
BlFileTable[FileId].Position = WritePosition;
|
||
|
||
//
|
||
// If the length of write is less than the number of bytes from
|
||
// the offset to the end of the sector, then copy only the number
|
||
// of bytes required to fulfil the request. Otherwise copy to the end
|
||
// of the sector and, read the remaining data.
|
||
//
|
||
|
||
if ((SectorSize - Offset) > Length) {
|
||
Limit = Offset + Length;
|
||
|
||
} else {
|
||
Limit = SectorSize;
|
||
}
|
||
|
||
//
|
||
// Merge the data from the specified buffer.
|
||
//
|
||
for (Index = Offset; Index < Limit; Index += 1) {
|
||
TempPointer[Index] = ((PCHAR)Buffer)[Index-Offset];
|
||
}
|
||
|
||
//
|
||
// Write the modified sector.
|
||
//
|
||
ArcStatus = ScsiDiskWrite(FileId, TempPointer, SectorSize, &TransferCount);
|
||
|
||
if (ArcStatus != ESUCCESS) {
|
||
return ArcStatus;
|
||
}
|
||
|
||
//
|
||
// Update transfer parameters.
|
||
//
|
||
|
||
*Count += Limit - Offset;
|
||
Length -= Limit - Offset;
|
||
Buffer = (PVOID)((PCHAR)Buffer + Limit - Offset);
|
||
BlFileTable[FileId].Position.QuadPart = Position.QuadPart + (Limit - Offset);
|
||
|
||
Offset = BlFileTable[FileId].Position.LowPart & (SectorSize - 1);
|
||
|
||
if (Length == 0) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// The position is aligned on a sector boundary. Write as many sectors
|
||
// as possible in a contiguous run.
|
||
//
|
||
|
||
BytesToTransfer = Length & (~(SectorSize - 1));
|
||
while (BytesToTransfer != 0) {
|
||
|
||
//
|
||
// The scsi controller doesn't support transfers bigger than 64Kb.
|
||
// Transfer the maximum number of bytes possible.
|
||
//
|
||
Limit = (BytesToTransfer > adapterLimit ? adapterLimit : BytesToTransfer);
|
||
|
||
//
|
||
// Build the memory descriptor list.
|
||
//
|
||
|
||
MdlAddress = (PMDL)&MdlBuffer[0];
|
||
MdlAddress->Next = NULL;
|
||
MdlAddress->Size = sizeof(MDL) +
|
||
ADDRESS_AND_SIZE_TO_SPAN_PAGES(Buffer, Limit) * sizeof(ULONG);
|
||
MdlAddress->StartVa = (PVOID)PAGE_ALIGN(Buffer);
|
||
MdlAddress->ByteCount = Limit;
|
||
MdlAddress->ByteOffset = BYTE_OFFSET(Buffer);
|
||
PageFrame = (PULONG)(MdlAddress + 1);
|
||
FrameNumber = (((ULONG)MdlAddress->StartVa) & 0x1fffffff) >> PAGE_SHIFT;
|
||
NumberOfPages = (MdlAddress->ByteCount +
|
||
MdlAddress->ByteOffset + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||
for (Index = 0; Index < NumberOfPages; Index += 1) {
|
||
*PageFrame++ = FrameNumber++;
|
||
}
|
||
|
||
//
|
||
// Flush I/O buffers and write to the boot device.
|
||
//
|
||
|
||
KeFlushIoBuffers(MdlAddress, FALSE, TRUE);
|
||
LogicalBlock.QuadPart = BlFileTable[FileId].Position.QuadPart >>
|
||
BlFileTable[FileId].u.PartitionContext.SectorShift;
|
||
LogicalBlock.LowPart += BlFileTable[FileId].u.PartitionContext.StartingSector;
|
||
NtStatus = ScsiDiskBootIO(MdlAddress,
|
||
LogicalBlock.LowPart,
|
||
&BlFileTable[FileId].u.PartitionContext,
|
||
FALSE);
|
||
|
||
if (NtStatus != ESUCCESS) {
|
||
return EIO;
|
||
}
|
||
|
||
*Count += Limit;
|
||
Length -= Limit;
|
||
Buffer = (PVOID)((PCHAR)Buffer + Limit);
|
||
BytesToTransfer -= Limit;
|
||
BlFileTable[FileId].Position.QuadPart = BlFileTable[FileId].Position.QuadPart + Limit;
|
||
}
|
||
|
||
//
|
||
// If there is any residual data to write, then read the last sector
|
||
// separately merge the write data and write it.
|
||
//
|
||
|
||
if (Length != 0) {
|
||
Position = BlFileTable[FileId].Position;
|
||
ArcStatus = ScsiDiskRead(FileId, TempPointer, SectorSize, &TransferCount);
|
||
|
||
//
|
||
// Reset the position as it was before the read.
|
||
//
|
||
|
||
BlFileTable[FileId].Position = Position;
|
||
|
||
if (ArcStatus != ESUCCESS) {
|
||
return ArcStatus;
|
||
}
|
||
//
|
||
// Merge the data with the read sector from the buffer.
|
||
//
|
||
|
||
for (Index = 0; Index < Length; Index += 1) {
|
||
TempPointer[Index] = ((PCHAR)Buffer)[Index];
|
||
}
|
||
|
||
//
|
||
// Write the merged sector
|
||
//
|
||
|
||
ArcStatus = ScsiDiskWrite(FileId, TempPointer, SectorSize, &TransferCount);
|
||
|
||
//
|
||
// Reset the postion.
|
||
//
|
||
|
||
BlFileTable[FileId].Position = Position;
|
||
|
||
//
|
||
// Update transfer parameters.
|
||
//
|
||
|
||
*Count += Length;
|
||
|
||
//
|
||
// Position is aligned to a sector boundary and Length is less than
|
||
// a sector, therefore the addition will never overflow.
|
||
//
|
||
|
||
BlFileTable[FileId].Position.LowPart += Length;
|
||
}
|
||
|
||
return ESUCCESS;
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
ScsiDiskBootPartitionOpen(
|
||
IN ULONG FileId,
|
||
IN UCHAR DeviceUnit,
|
||
IN UCHAR PartitionNumber
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the initialization routine for the hard disk boot driver
|
||
for the given partition. It sets the partition info in the
|
||
FileTable at the specified index and initializes the Device entry
|
||
table to point to the table of ScsiDisk routines.
|
||
|
||
It reads the partition information until the requested partition
|
||
is found or no more partitions are defined.
|
||
|
||
Arguments:
|
||
|
||
FileId - Supplies the file id for the file table entry.
|
||
|
||
DeviceUnit - Supplies the device number in the scis bus.
|
||
|
||
PartitionNumber - Supplies the partition number must be bigger than zero.
|
||
To get the size of the disk call ReadDriveCapacity.
|
||
|
||
|
||
Return Value:
|
||
|
||
If a valid FAT file system structure is found on the hard disk, then
|
||
STATUS_SUCCESS is returned. Otherwise, STATUS_UNSUCCESSFUL is returned.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PMDL MdlAddress;
|
||
USHORT DataBuffer[MAXIMUM_SECTOR_SIZE / sizeof(USHORT) + 128];
|
||
PUSHORT DataPointer;
|
||
ULONG DummyMdl[(sizeof(MDL) + 16) / sizeof(ULONG)];
|
||
PULONG PageFrame;
|
||
PPARTITION_DESCRIPTOR Partition;
|
||
PPARTITION_CONTEXT Context;
|
||
ULONG PartitionLength;
|
||
ULONG StartingSector;
|
||
ULONG VolumeOffset;
|
||
NTSTATUS Status;
|
||
BOOLEAN PrimaryPartitionTable;
|
||
ULONG PartitionOffset=0;
|
||
ULONG PartitionIndex,PartitionCount=0;
|
||
ULONG SectorSize;
|
||
|
||
BlFileTable[FileId].Position.LowPart = 0;
|
||
BlFileTable[FileId].Position.HighPart = 0;
|
||
|
||
VolumeOffset=0;
|
||
PrimaryPartitionTable=TRUE;
|
||
|
||
Context = &BlFileTable[FileId].u.PartitionContext;
|
||
|
||
//
|
||
// Calculate the actual sector size
|
||
//
|
||
|
||
SectorSize = 1 << Context->SectorShift;
|
||
|
||
//
|
||
// Make the sector size the minimum of 512 or the sector size.
|
||
//
|
||
|
||
if (SectorSize < 512) {
|
||
SectorSize = 512;
|
||
}
|
||
|
||
//
|
||
// Align the buffer on a Dcache line size.
|
||
//
|
||
|
||
DataPointer = (PVOID) ((ULONG) ((PCHAR) DataBuffer +
|
||
KeGetDcacheFillSize() - 1) & ~(KeGetDcacheFillSize() - 1));
|
||
|
||
//
|
||
// Initialize a memory descriptor list to read the master boot record
|
||
// from the specified hard disk drive.
|
||
//
|
||
|
||
MdlAddress = (PMDL)&DummyMdl[0];
|
||
MdlAddress->StartVa = (PVOID)(((ULONG)DataPointer) & (~(PAGE_SIZE - 1)));
|
||
MdlAddress->ByteCount = SectorSize;
|
||
MdlAddress->ByteOffset = ((ULONG)DataPointer) & (PAGE_SIZE - 1);
|
||
PageFrame = (PULONG)(MdlAddress + 1);
|
||
*PageFrame++ = ((((ULONG)DataPointer) & 0x1fffffff) >> PAGE_SHIFT);
|
||
*PageFrame++ = ((((ULONG)DataPointer) & 0x1fffffff) >> PAGE_SHIFT) + 1;
|
||
do {
|
||
Status = ScsiDiskBootIO(MdlAddress,PartitionOffset,Context,TRUE);
|
||
if (NT_SUCCESS(Status) != FALSE) {
|
||
|
||
//
|
||
// If sector zero is not a master boot record, then return failure
|
||
// status. Otherwise return success.
|
||
//
|
||
|
||
if (*(DataPointer + BOOT_SIGNATURE_OFFSET) != BOOT_RECORD_SIGNATURE) {
|
||
DbgPrint("Boot record signature not found\n");
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
//
|
||
// Read the partition information until the four entries are
|
||
// checked or until we found the requested one.
|
||
//
|
||
Partition = (PPARTITION_DESCRIPTOR)(DataPointer+PARTITION_TABLE_OFFSET);
|
||
for (PartitionIndex=0;
|
||
PartitionIndex < NUM_PARTITION_TABLE_ENTRIES;
|
||
PartitionIndex++,Partition++) {
|
||
//
|
||
// Count first the partitions in the MBR. The units
|
||
// inside the extended partition are counted later.
|
||
//
|
||
if (!IsContainerPartition(Partition->PartitionType) &&
|
||
(Partition->PartitionType != PARTITION_ENTRY_UNUSED)) {
|
||
PartitionCount++; // another partition found.
|
||
}
|
||
|
||
//
|
||
// Check if the requested partition has already been found.
|
||
// set the partition info in the file table and return.
|
||
//
|
||
if (PartitionCount == (ULONG)PartitionNumber) {
|
||
StartingSector = (ULONG)(Partition->StartingSectorLsb0) |
|
||
(ULONG)(Partition->StartingSectorLsb1 << 8) |
|
||
(ULONG)(Partition->StartingSectorMsb0 << 16) |
|
||
(ULONG)(Partition->StartingSectorMsb1 << 24);
|
||
PartitionLength = (ULONG)(Partition->PartitionLengthLsb0) |
|
||
(ULONG)(Partition->PartitionLengthLsb1 << 8) |
|
||
(ULONG)(Partition->PartitionLengthMsb0 << 16) |
|
||
(ULONG)(Partition->PartitionLengthMsb1 << 24);
|
||
|
||
Context->PartitionLength.QuadPart = PartitionLength;
|
||
Context->PartitionLength.QuadPart <<= Context->SectorShift;
|
||
Context->StartingSector = PartitionOffset + StartingSector;
|
||
Context->EndingSector = Context->StartingSector + PartitionLength;
|
||
return Status;
|
||
}
|
||
}
|
||
|
||
//
|
||
// If requested partition was not yet found.
|
||
// Look for an extended partition.
|
||
//
|
||
Partition = (PPARTITION_DESCRIPTOR)(DataPointer + PARTITION_TABLE_OFFSET);
|
||
PartitionOffset = 0;
|
||
for (PartitionIndex=0;
|
||
PartitionIndex < NUM_PARTITION_TABLE_ENTRIES;
|
||
PartitionIndex++,Partition++) {
|
||
if (IsContainerPartition(Partition->PartitionType)) {
|
||
StartingSector = (ULONG)(Partition->StartingSectorLsb0) |
|
||
(ULONG)(Partition->StartingSectorLsb1 << 8) |
|
||
(ULONG)(Partition->StartingSectorMsb0 << 16) |
|
||
(ULONG)(Partition->StartingSectorMsb1 << 24);
|
||
PartitionOffset = VolumeOffset+StartingSector;
|
||
if (PrimaryPartitionTable) {
|
||
VolumeOffset = StartingSector;
|
||
}
|
||
break; // only one partition can be extended.
|
||
}
|
||
}
|
||
}
|
||
PrimaryPartitionTable=FALSE;
|
||
} while (PartitionOffset != 0);
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
//
|
||
// This silly callback messes a lot of things up. There is no clean definition
|
||
// for it anywhere, so it has to be defined in all modules that reference it.
|
||
//
|
||
|
||
#ifndef SCSI_INFO_CALLBACK_DEFINED
|
||
|
||
typedef
|
||
VOID
|
||
(*PSCSI_INFO_CALLBACK_ROUTINE) (
|
||
IN ULONG AdapterNumber,
|
||
IN ULONG ScsiId,
|
||
IN ULONG Lun,
|
||
IN BOOLEAN Cdrom
|
||
);
|
||
#endif
|
||
|
||
VOID
|
||
HardDiskInitialize(
|
||
IN OUT PDRIVER_LOOKUP_ENTRY LookupTable,
|
||
IN ULONG Entries,
|
||
IN PSCSI_INFO_CALLBACK_ROUTINE DeviceFound
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine initializes the scsi controller and the
|
||
device entry table for the scsi driver.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG lookupTableIndex = 0;
|
||
ULONG scsiNumber;
|
||
ULONG busNumber;
|
||
PCHAR Identifier;
|
||
PLUNINFO lunInfo;
|
||
PSCSI_CONFIGURATION_INFO configInfo;
|
||
PSCSI_BUS_SCAN_DATA busScanData;
|
||
PDEVICE_EXTENSION scsiPort;
|
||
PINQUIRYDATA inquiryData;
|
||
PCONFIGURATION_COMPONENT RootComponent;
|
||
PCONFIGURATION_COMPONENT ScsiComponent;
|
||
PCONFIGURATION_COMPONENT ControllerComponent;
|
||
PCONFIGURATION_COMPONENT PeripheralComponent;
|
||
PCONFIGURATION_COMPONENT NextComponent;
|
||
CHAR ComponentPath[10];
|
||
CONFIGURATION_COMPONENT ControllerEntry;
|
||
CONFIGURATION_COMPONENT AdapterEntry;
|
||
CONFIGURATION_COMPONENT PeripheralEntry;
|
||
PARTITION_CONTEXT Context;
|
||
BOOLEAN IsFloppy;
|
||
|
||
RtlZeroMemory(&Context, sizeof(PARTITION_CONTEXT));
|
||
|
||
//
|
||
// Initialize the common buffers.
|
||
//
|
||
|
||
ReadCapacityBuffer = ExAllocatePool( NonPagedPool, sizeof(READ_CAPACITY_DATA));
|
||
|
||
SenseInfoBuffer = ExAllocatePool( NonPagedPool, SENSE_BUFFER_SIZE);
|
||
|
||
if (ReadCapacityBuffer == NULL || SenseInfoBuffer == NULL) {
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Scan the scsi ports looking for disk devices.
|
||
//
|
||
|
||
for (scsiNumber = 0; ScsiPortDeviceObject[scsiNumber]; scsiNumber++) {
|
||
|
||
scsiPort = ScsiPortDeviceObject[scsiNumber]->DeviceExtension;
|
||
configInfo = scsiPort->ScsiInfo;
|
||
Context.PortDeviceObject = ScsiPortDeviceObject[scsiNumber];
|
||
|
||
//
|
||
// Search the configuration database for scsi disk and cdrom devices and
|
||
// delete them.
|
||
//
|
||
|
||
sprintf(ComponentPath,"scsi(%1d)", scsiNumber);
|
||
ScsiComponent = FwGetComponent(ComponentPath);
|
||
|
||
if (ScsiComponent != NULL) {
|
||
if (ScsiComponent->Type == ScsiAdapter) {
|
||
ControllerComponent = FwGetChild(ScsiComponent);
|
||
|
||
while (ControllerComponent != NULL) {
|
||
NextComponent = FwGetPeer(ControllerComponent);
|
||
|
||
if ((ControllerComponent->Type == DiskController) ||
|
||
(ControllerComponent->Type == CdromController)) {
|
||
|
||
PeripheralComponent = FwGetChild(ControllerComponent);
|
||
if (FwDeleteComponent(PeripheralComponent) == ESUCCESS) {
|
||
FwDeleteComponent(ControllerComponent);
|
||
}
|
||
}
|
||
ControllerComponent = NextComponent;
|
||
}
|
||
} else {
|
||
RootComponent = FwGetChild(NULL);
|
||
AdapterEntry.Class = AdapterClass;
|
||
AdapterEntry.Type = ScsiAdapter;
|
||
AdapterEntry.Flags.ReadOnly = 0;
|
||
AdapterEntry.Flags.Removable = 0;
|
||
AdapterEntry.Flags.ConsoleIn = 0;
|
||
AdapterEntry.Flags.ConsoleOut = 0;
|
||
AdapterEntry.Flags.Output = 1;
|
||
AdapterEntry.Flags.Input = 1;
|
||
AdapterEntry.Version = 0;
|
||
AdapterEntry.Revision = 0;
|
||
AdapterEntry.Key = scsiNumber;
|
||
AdapterEntry.AffinityMask = 0xffffffff;
|
||
AdapterEntry.ConfigurationDataLength = 0;
|
||
AdapterEntry.IdentifierLength = 0;
|
||
AdapterEntry.Identifier = 0;
|
||
ScsiComponent = FwAddChild(RootComponent, &AdapterEntry, NULL);
|
||
}
|
||
}
|
||
|
||
for (busNumber=0; busNumber < (ULONG)configInfo->NumberOfBuses; busNumber++) {
|
||
|
||
busScanData = configInfo->BusScanData[busNumber];
|
||
|
||
//
|
||
// Set LunInfo to beginning of list.
|
||
//
|
||
|
||
lunInfo = busScanData->LunInfoList;
|
||
|
||
while (lunInfo != NULL) {
|
||
|
||
inquiryData = (PVOID)lunInfo->InquiryData;
|
||
|
||
ScsiDebugPrint(3,"FindScsiDevices: Inquiry data at %lx\n",
|
||
inquiryData);
|
||
|
||
if ((inquiryData->DeviceType == DIRECT_ACCESS_DEVICE
|
||
|| inquiryData->DeviceType == OPTICAL_DEVICE) &&
|
||
!lunInfo->DeviceClaimed) {
|
||
|
||
ScsiDebugPrint(1,
|
||
"FindScsiDevices: Vendor string is %.24s\n",
|
||
inquiryData->VendorId);
|
||
|
||
IsFloppy = FALSE;
|
||
|
||
//
|
||
// Create a dummy paritition context so that I/O can be
|
||
// done on the device. SendSrbSynchronous only uses the
|
||
// port device object pointer and the scsi address of the
|
||
// logical unit.
|
||
//
|
||
|
||
Context.PathId = lunInfo->PathId;
|
||
Context.TargetId = lunInfo->TargetId;
|
||
Context.DiskId = lunInfo->Lun;
|
||
|
||
//
|
||
// Create name for disk object.
|
||
//
|
||
|
||
LookupTable->DevicePath =
|
||
ExAllocatePool(NonPagedPool,
|
||
sizeof("scsi(%d)disk(%d)rdisk(%d)"));
|
||
|
||
if (LookupTable->DevicePath == NULL) {
|
||
return;
|
||
}
|
||
|
||
//
|
||
// If this is a removable. Check to see if the device is
|
||
// a floppy.
|
||
//
|
||
|
||
if (inquiryData->RemovableMedia &&
|
||
inquiryData->DeviceType == DIRECT_ACCESS_DEVICE &&
|
||
IsFloppyDevice(&Context) ) {
|
||
|
||
sprintf(LookupTable->DevicePath,
|
||
"scsi(%d)disk(%d)fdisk(%d)",
|
||
scsiNumber,
|
||
lunInfo->TargetId + lunInfo->PathId * SCSI_MAXIMUM_TARGETS_PER_BUS,
|
||
lunInfo->Lun
|
||
);
|
||
|
||
IsFloppy = TRUE;
|
||
} else {
|
||
|
||
sprintf(LookupTable->DevicePath,
|
||
"scsi(%d)disk(%d)rdisk(%d)",
|
||
scsiNumber,
|
||
lunInfo->TargetId + lunInfo->PathId * SCSI_MAXIMUM_TARGETS_PER_BUS,
|
||
lunInfo->Lun
|
||
);
|
||
|
||
if (DeviceFound) {
|
||
DeviceFound( scsiNumber,
|
||
lunInfo->TargetId + lunInfo->PathId * SCSI_MAXIMUM_TARGETS_PER_BUS,
|
||
lunInfo->Lun,
|
||
FALSE
|
||
);
|
||
}
|
||
}
|
||
|
||
LookupTable->DispatchTable = &ScsiDiskEntryTable;
|
||
|
||
//
|
||
// If the disk controller entry does not exist, add it to
|
||
// the configuration database.
|
||
//
|
||
|
||
ControllerComponent = FwGetComponent(LookupTable->DevicePath);
|
||
|
||
if (ControllerComponent != NULL) {
|
||
if (ControllerComponent->Type != DiskController) {
|
||
|
||
ControllerEntry.Class = ControllerClass;
|
||
ControllerEntry.Type = DiskController;
|
||
ControllerEntry.Flags.Failed = 0;
|
||
ControllerEntry.Flags.ReadOnly = 0;
|
||
ControllerEntry.Flags.Removable = 0;
|
||
ControllerEntry.Flags.ConsoleIn = 0;
|
||
ControllerEntry.Flags.ConsoleOut = 0;
|
||
ControllerEntry.Flags.Output = 1;
|
||
ControllerEntry.Flags.Input = 1;
|
||
ControllerEntry.Version = 0;
|
||
ControllerEntry.Revision = 0;
|
||
ControllerEntry.Key = lunInfo->TargetId + lunInfo->PathId * SCSI_MAXIMUM_TARGETS_PER_BUS;
|
||
ControllerEntry.AffinityMask = 0xffffffff;
|
||
ControllerEntry.ConfigurationDataLength = 0;
|
||
|
||
Identifier =
|
||
ExAllocatePool(NonPagedPool,
|
||
strlen(inquiryData->VendorId)
|
||
);
|
||
|
||
if (Identifier == NULL) {
|
||
return;
|
||
}
|
||
|
||
sprintf(Identifier,
|
||
"%s",
|
||
inquiryData->VendorId
|
||
);
|
||
|
||
ControllerEntry.IdentifierLength = strlen(Identifier);
|
||
ControllerEntry.Identifier = Identifier;
|
||
|
||
ControllerComponent = FwAddChild(ScsiComponent, &ControllerEntry, NULL);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Add disk peripheral entry to the configuration database.
|
||
//
|
||
|
||
PeripheralEntry.Class = PeripheralClass;
|
||
PeripheralEntry.Type = IsFloppy ? FloppyDiskPeripheral : DiskPeripheral;
|
||
PeripheralEntry.Flags.Failed = 0;
|
||
PeripheralEntry.Flags.ReadOnly = 0;
|
||
PeripheralEntry.Flags.Removable = IsFloppy;
|
||
PeripheralEntry.Flags.ConsoleIn = 0;
|
||
PeripheralEntry.Flags.ConsoleOut = 0;
|
||
PeripheralEntry.Flags.Output = 1;
|
||
PeripheralEntry.Flags.Input = 1;
|
||
PeripheralEntry.Version = 0;
|
||
PeripheralEntry.Revision = 0;
|
||
PeripheralEntry.Key = lunInfo->Lun;
|
||
PeripheralEntry.AffinityMask = 0xffffffff;
|
||
PeripheralEntry.ConfigurationDataLength = 0;
|
||
PeripheralEntry.IdentifierLength = 0;
|
||
PeripheralEntry.Identifier = NULL;
|
||
|
||
FwAddChild(ControllerComponent, &PeripheralEntry, NULL);
|
||
|
||
//
|
||
// Increment to the next entry.
|
||
//
|
||
|
||
LookupTable++;
|
||
lookupTableIndex++;
|
||
if (lookupTableIndex >= Entries) {
|
||
|
||
//
|
||
// There is no more space in the caller provided buffer
|
||
// for disk information. Return.
|
||
//
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Claim disk device by marking configuration
|
||
// record owned.
|
||
//
|
||
|
||
lunInfo->DeviceClaimed = TRUE;
|
||
|
||
}
|
||
|
||
if ((inquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE) &&
|
||
(!lunInfo->DeviceClaimed)) {
|
||
|
||
ScsiDebugPrint(1,"FindScsiDevices: Vendor string is %s\n", inquiryData->VendorId);
|
||
|
||
//
|
||
// Create name for cdrom object.
|
||
//
|
||
|
||
LookupTable->DevicePath =
|
||
ExAllocatePool( NonPagedPool, sizeof("scsi(%d)cdrom(%d)fdisk(%d)"));
|
||
|
||
if (LookupTable->DevicePath == NULL) {
|
||
return;
|
||
}
|
||
|
||
sprintf(LookupTable->DevicePath,
|
||
"scsi(%d)cdrom(%d)fdisk(%d)",
|
||
scsiNumber,
|
||
lunInfo->TargetId + lunInfo->PathId * SCSI_MAXIMUM_TARGETS_PER_BUS,
|
||
lunInfo->Lun
|
||
);
|
||
|
||
LookupTable->DispatchTable = &ScsiDiskEntryTable;
|
||
|
||
if (DeviceFound) {
|
||
DeviceFound( scsiNumber,
|
||
lunInfo->TargetId + lunInfo->PathId * SCSI_MAXIMUM_TARGETS_PER_BUS,
|
||
lunInfo->Lun,
|
||
TRUE
|
||
);
|
||
}
|
||
|
||
//
|
||
// If the cdrom controller entry does not exist, add it to
|
||
// the configuration database.
|
||
//
|
||
|
||
ControllerComponent = FwGetComponent(LookupTable->DevicePath);
|
||
|
||
if (ControllerComponent != NULL) {
|
||
if (ControllerComponent->Type != CdromController) {
|
||
|
||
ControllerEntry.Class = ControllerClass;
|
||
ControllerEntry.Type = CdromController;
|
||
ControllerEntry.Flags.Failed = 0;
|
||
ControllerEntry.Flags.ReadOnly = 1;
|
||
ControllerEntry.Flags.Removable = 1;
|
||
ControllerEntry.Flags.ConsoleIn = 0;
|
||
ControllerEntry.Flags.ConsoleOut = 0;
|
||
ControllerEntry.Flags.Output = 0;
|
||
ControllerEntry.Flags.Input = 1;
|
||
ControllerEntry.Version = 0;
|
||
ControllerEntry.Revision = 0;
|
||
ControllerEntry.Key = lunInfo->TargetId + lunInfo->PathId * SCSI_MAXIMUM_TARGETS_PER_BUS;
|
||
ControllerEntry.AffinityMask = 0xffffffff;
|
||
ControllerEntry.ConfigurationDataLength = 0;
|
||
|
||
Identifier =
|
||
ExAllocatePool( NonPagedPool,
|
||
strlen(inquiryData->VendorId)
|
||
);
|
||
|
||
if (Identifier == NULL) {
|
||
return;
|
||
}
|
||
|
||
sprintf(Identifier,
|
||
inquiryData->VendorId
|
||
);
|
||
|
||
ControllerEntry.IdentifierLength = strlen(Identifier);
|
||
ControllerEntry.Identifier = Identifier;
|
||
|
||
ControllerComponent = FwAddChild(ScsiComponent, &ControllerEntry, NULL);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Add disk peripheral entry to the configuration database.
|
||
//
|
||
|
||
PeripheralEntry.Class = PeripheralClass;
|
||
PeripheralEntry.Type = FloppyDiskPeripheral;
|
||
PeripheralEntry.Flags.Failed = 0;
|
||
PeripheralEntry.Flags.ReadOnly = 1;
|
||
PeripheralEntry.Flags.Removable = 1;
|
||
PeripheralEntry.Flags.ConsoleIn = 0;
|
||
PeripheralEntry.Flags.ConsoleOut = 0;
|
||
PeripheralEntry.Flags.Output = 0;
|
||
PeripheralEntry.Flags.Input = 1;
|
||
PeripheralEntry.Version = 0;
|
||
PeripheralEntry.Revision = 0;
|
||
PeripheralEntry.Key = lunInfo->Lun;
|
||
PeripheralEntry.AffinityMask = 0xffffffff;
|
||
PeripheralEntry.ConfigurationDataLength = 0;
|
||
PeripheralEntry.IdentifierLength = 0;
|
||
PeripheralEntry.Identifier = NULL;
|
||
|
||
FwAddChild(ControllerComponent, &PeripheralEntry, NULL);
|
||
|
||
//
|
||
// Increment to the next entry.
|
||
//
|
||
|
||
LookupTable++;
|
||
lookupTableIndex++;
|
||
if (lookupTableIndex >= Entries) {
|
||
|
||
//
|
||
// There is no more space in the caller provided buffer
|
||
// for disk information. Return.
|
||
//
|
||
return;
|
||
}
|
||
|
||
|
||
//
|
||
// Claim disk device by marking configuration
|
||
// record owned.
|
||
//
|
||
|
||
lunInfo->DeviceClaimed = TRUE;
|
||
|
||
}
|
||
|
||
//
|
||
// Get next LunInfo.
|
||
//
|
||
|
||
lunInfo = lunInfo->NextLunInfo;
|
||
}
|
||
}
|
||
}
|
||
|
||
// ScsiDebugPrint(1,"FindScsiDevices: Hit any key\n");
|
||
// PAUSE;
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
ScsiDiskBootIO (
|
||
IN PMDL MdlAddress,
|
||
IN ULONG LogicalBlock,
|
||
IN PPARTITION_CONTEXT PartitionContext,
|
||
IN BOOLEAN Operation
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is the read/write routine for the hard disk boot driver.
|
||
|
||
Arguments:
|
||
|
||
MdlAddress - Supplies a pointer to an MDL for the IO operation.
|
||
|
||
LogicalBlock - Supplies the starting block number.
|
||
|
||
DeviceUnit - Supplies the SCSI Id number.
|
||
|
||
Operation - Specifies the IO operation to perform
|
||
TRUE = SCSI_READ
|
||
FALSE = SCSI_WRITE.
|
||
|
||
Return Value:
|
||
|
||
The final status of the read operation (STATUS_UNSUCCESSFUL or
|
||
STATUS_SUCCESS).
|
||
|
||
--*/
|
||
|
||
{
|
||
ARC_STATUS Status;
|
||
PIRP Irp;
|
||
PIO_STACK_LOCATION NextIrpStack;
|
||
PSCSI_REQUEST_BLOCK Srb;
|
||
ULONG RetryCount = MAXIMUM_RETRIES;
|
||
|
||
//
|
||
// Check that the request is within the limits of the partition.
|
||
//
|
||
if (PartitionContext->StartingSector > LogicalBlock) {
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
if (PartitionContext->EndingSector <
|
||
LogicalBlock + (MdlAddress->ByteCount >> PartitionContext->SectorShift)) {
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
Retry:
|
||
|
||
//
|
||
// Build the I/O Request.
|
||
//
|
||
|
||
Irp = BuildRequest(PartitionContext, MdlAddress, LogicalBlock, Operation);
|
||
|
||
NextIrpStack = IoGetNextIrpStackLocation(Irp);
|
||
Srb = NextIrpStack->Parameters.Others.Argument1;
|
||
|
||
//
|
||
// Call the port driver.
|
||
//
|
||
|
||
IoCallDriver(PartitionContext->PortDeviceObject, Irp);
|
||
|
||
//
|
||
// Check the status.
|
||
//
|
||
|
||
if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) {
|
||
|
||
//
|
||
// Determine the cause of the error.
|
||
//
|
||
|
||
if (InterpretSenseInfo(Srb, &Status, PartitionContext) && RetryCount--) {
|
||
|
||
goto Retry;
|
||
}
|
||
|
||
if (Status == EAGAIN) {
|
||
Status = EIO;
|
||
}
|
||
|
||
DebugPrint((1, "SCSI: Read request failed. Arc Status: %d, Srb Status: %x\n",
|
||
Status,
|
||
Srb->SrbStatus
|
||
));
|
||
|
||
} else {
|
||
|
||
Status = ESUCCESS;
|
||
|
||
}
|
||
|
||
return(Status);
|
||
}
|
||
|
||
ARC_STATUS
|
||
ReadDriveCapacity(
|
||
IN PPARTITION_CONTEXT PartitionContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sends a read capacity to a target id and returns
|
||
when it is complete.
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
Status is returned.
|
||
|
||
--*/
|
||
{
|
||
PCDB Cdb;
|
||
PSCSI_REQUEST_BLOCK Srb = &PrimarySrb.Srb;
|
||
ULONG LastSector;
|
||
ULONG retries = 1;
|
||
ARC_STATUS status;
|
||
ULONG BytesPerSector;
|
||
|
||
ScsiDebugPrint(3,"SCSI ReadCapacity: Enter routine\n");
|
||
|
||
|
||
//
|
||
// Build the read capacity CDB.
|
||
//
|
||
|
||
Srb->CdbLength = 10;
|
||
Cdb = (PCDB)Srb->Cdb;
|
||
|
||
//
|
||
// Zero CDB in SRB on stack.
|
||
//
|
||
|
||
RtlZeroMemory(Cdb, MAXIMUM_CDB_SIZE);
|
||
|
||
Cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
|
||
|
||
Retry:
|
||
|
||
status = SendSrbSynchronous(PartitionContext,
|
||
Srb,
|
||
ReadCapacityBuffer,
|
||
sizeof(READ_CAPACITY_DATA),
|
||
FALSE);
|
||
|
||
if (status == ESUCCESS) {
|
||
|
||
#if 0
|
||
//
|
||
// Copy sector size from read capacity buffer to device extension
|
||
// in reverse byte order.
|
||
//
|
||
|
||
deviceExtension->DiskGeometry->BytesPerSector = 0;
|
||
|
||
((PFOUR_BYTE)&deviceExtension->DiskGeometry->BytesPerSector)->Byte0 =
|
||
((PFOUR_BYTE)&ReadCapacityBuffer->BytesPerBlock)->Byte3;
|
||
|
||
((PFOUR_BYTE)&deviceExtension->DiskGeometry->BytesPerSector)->Byte1 =
|
||
((PFOUR_BYTE)&ReadCapacityBuffer->BytesPerBlock)->Byte2;
|
||
|
||
if (BytesPerSector == 0) {
|
||
|
||
//
|
||
// Assume this is a brain dead cd-rom and the sector size is 2048.
|
||
//
|
||
|
||
BytesPerSector = 2048;
|
||
|
||
}
|
||
|
||
//
|
||
// Make sure the sector size is less than the maximum expected.
|
||
//
|
||
|
||
ASSERT(BytesPerSector <= MAXIMUM_SECTOR_SIZE);
|
||
|
||
if (BytesPerSector > MAXIMUM_SECTOR_SIZE) {
|
||
return(EINVAL);
|
||
}
|
||
|
||
//
|
||
// Copy last sector in reverse byte order.
|
||
//
|
||
|
||
((PFOUR_BYTE)&LastSector)->Byte0 =
|
||
((PFOUR_BYTE)&ReadCapacityBuffer->LogicalBlockAddress)->Byte3;
|
||
|
||
((PFOUR_BYTE)&LastSector)->Byte1 =
|
||
((PFOUR_BYTE)&ReadCapacityBuffer->LogicalBlockAddress)->Byte2;
|
||
|
||
((PFOUR_BYTE)&LastSector)->Byte2 =
|
||
((PFOUR_BYTE)&ReadCapacityBuffer->LogicalBlockAddress)->Byte1;
|
||
|
||
((PFOUR_BYTE)&LastSector)->Byte3 =
|
||
((PFOUR_BYTE)&ReadCapacityBuffer->LogicalBlockAddress)->Byte0;
|
||
|
||
//
|
||
// Calculate sector to byte shift.
|
||
//
|
||
|
||
WHICH_BIT(deviceExtension->DiskGeometry->BytesPerSector, deviceExtension->SectorShift);
|
||
|
||
ScsiDebugPrint(2,"SCSI ReadDriveCapacity: Sector size is %d\n",
|
||
deviceExtension->DiskGeometry->BytesPerSector);
|
||
|
||
ScsiDebugPrint(2,"SCSI ReadDriveCapacity: Number of Sectors is %d\n",
|
||
LastSector + 1);
|
||
|
||
//
|
||
// Calculate media capacity in bytes.
|
||
//
|
||
|
||
deviceExtension->PartitionLength = LastSector + 1;
|
||
|
||
deviceExtension->PartitionLength.QuadPart <<= deviceExtension->SectorShift.QuadPart;
|
||
|
||
//
|
||
// Assume media type is fixed disk.
|
||
//
|
||
|
||
deviceExtension->DiskGeometry->MediaType = FixedMedia;
|
||
|
||
//
|
||
// Assume sectors per track are 32;
|
||
//
|
||
|
||
deviceExtension->DiskGeometry->SectorsPerTrack = 32;
|
||
|
||
//
|
||
// Assume tracks per cylinder (number of heads) is 64.
|
||
//
|
||
|
||
deviceExtension->DiskGeometry->TracksPerCylinder = 64;
|
||
#else
|
||
|
||
BytesPerSector = 0;
|
||
|
||
//
|
||
// Copy sector size from read capacity buffer to device extension
|
||
// in reverse byte order.
|
||
//
|
||
|
||
((PFOUR_BYTE)&BytesPerSector)->Byte0 =
|
||
((PFOUR_BYTE)&ReadCapacityBuffer->BytesPerBlock)->Byte3;
|
||
|
||
((PFOUR_BYTE)&BytesPerSector)->Byte1 =
|
||
((PFOUR_BYTE)&ReadCapacityBuffer->BytesPerBlock)->Byte2;
|
||
|
||
if (BytesPerSector == 0) {
|
||
|
||
//
|
||
// Assume this is a brain dead cd-rom and the sector size is 2048.
|
||
//
|
||
|
||
BytesPerSector = 2048;
|
||
|
||
}
|
||
|
||
//
|
||
// Calculate sector to byte shift.
|
||
//
|
||
|
||
WHICH_BIT(BytesPerSector, PartitionContext->SectorShift);
|
||
|
||
//
|
||
// Copy last sector in reverse byte order.
|
||
//
|
||
|
||
((PFOUR_BYTE)&LastSector)->Byte0 =
|
||
((PFOUR_BYTE)&ReadCapacityBuffer->LogicalBlockAddress)->Byte3;
|
||
|
||
((PFOUR_BYTE)&LastSector)->Byte1 =
|
||
((PFOUR_BYTE)&ReadCapacityBuffer->LogicalBlockAddress)->Byte2;
|
||
|
||
((PFOUR_BYTE)&LastSector)->Byte2 =
|
||
((PFOUR_BYTE)&ReadCapacityBuffer->LogicalBlockAddress)->Byte1;
|
||
|
||
((PFOUR_BYTE)&LastSector)->Byte3 =
|
||
((PFOUR_BYTE)&ReadCapacityBuffer->LogicalBlockAddress)->Byte0;
|
||
|
||
|
||
PartitionContext->PartitionLength.QuadPart = LastSector + 1;
|
||
PartitionContext->PartitionLength.QuadPart <<= PartitionContext->SectorShift;
|
||
|
||
PartitionContext->StartingSector=0;
|
||
PartitionContext->EndingSector = LastSector + 1;
|
||
|
||
ScsiDebugPrint(2,"SCSI ReadDriveCapacity: Sector size is %d\n",
|
||
BytesPerSector);
|
||
|
||
ScsiDebugPrint(2,"SCSI ReadDriveCapacity: Number of Sectors is %d\n",
|
||
LastSector + 1);
|
||
|
||
|
||
#endif
|
||
}
|
||
|
||
if (status == EAGAIN || status == EBUSY) {
|
||
|
||
if (retries--) {
|
||
|
||
//
|
||
// Retry request.
|
||
//
|
||
|
||
goto Retry;
|
||
}
|
||
}
|
||
|
||
return status;
|
||
|
||
} // end ReadDriveCapacity()
|
||
|
||
|
||
ARC_STATUS
|
||
SendSrbSynchronous(
|
||
PPARTITION_CONTEXT PartitionContext,
|
||
PSCSI_REQUEST_BLOCK Srb,
|
||
PVOID BufferAddress,
|
||
ULONG BufferLength,
|
||
BOOLEAN WriteToDevice
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called by SCSI device controls to complete an
|
||
SRB and send it to the port driver synchronously (ie wait for
|
||
completion).
|
||
The CDB is already completed along with the SRB CDB size and
|
||
request timeout value.
|
||
|
||
Arguments:
|
||
|
||
PartitionContext
|
||
SRB
|
||
Buffer address and length (if transfer)
|
||
|
||
WriteToDevice - Indicates the direction of the transfer.
|
||
|
||
Return Value:
|
||
|
||
ARC_STATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
PIRP Irp;
|
||
PIO_STACK_LOCATION IrpStack;
|
||
ULONG retryCount = 1;
|
||
ARC_STATUS status;
|
||
|
||
//
|
||
// Write length to SRB.
|
||
//
|
||
|
||
Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
|
||
|
||
//
|
||
// Set SCSI bus address.
|
||
//
|
||
|
||
Srb->PathId = PartitionContext->PathId;
|
||
Srb->TargetId = PartitionContext->TargetId;
|
||
Srb->Lun = PartitionContext->DiskId;
|
||
|
||
Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
|
||
|
||
//
|
||
// Enable auto request sense.
|
||
//
|
||
|
||
Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
|
||
|
||
if (SenseInfoBuffer == NULL) {
|
||
DbgPrint("SendSrbSynchronous: Can't allocate request sense buffer\n");
|
||
return(ENOMEM);
|
||
}
|
||
|
||
Srb->SenseInfoBuffer = SenseInfoBuffer;
|
||
|
||
Srb->DataBuffer = BufferAddress;
|
||
|
||
//
|
||
// Start retries here.
|
||
//
|
||
|
||
retry:
|
||
|
||
Irp = InitializeIrp(
|
||
&PrimarySrb,
|
||
IRP_MJ_SCSI,
|
||
PartitionContext->PortDeviceObject,
|
||
BufferAddress,
|
||
BufferLength
|
||
);
|
||
|
||
if (BufferAddress != NULL) {
|
||
|
||
if (WriteToDevice) {
|
||
|
||
Srb->SrbFlags = SRB_FLAGS_DATA_OUT;
|
||
|
||
} else {
|
||
|
||
Srb->SrbFlags = SRB_FLAGS_DATA_IN;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// Clear flags.
|
||
//
|
||
|
||
Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
|
||
}
|
||
|
||
//
|
||
// Disable synchronous transfers.
|
||
//
|
||
|
||
Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
|
||
|
||
//
|
||
// Set the transfer length.
|
||
//
|
||
|
||
Srb->DataTransferLength = BufferLength;
|
||
|
||
//
|
||
// Zero out status.
|
||
//
|
||
|
||
Srb->ScsiStatus = Srb->SrbStatus = 0;
|
||
|
||
//
|
||
// Get next stack location and
|
||
// set major function code.
|
||
//
|
||
|
||
IrpStack = IoGetNextIrpStackLocation(Irp);
|
||
|
||
|
||
//
|
||
// Set up SRB for execute scsi request.
|
||
// Save SRB address in next stack for port driver.
|
||
//
|
||
|
||
IrpStack->Parameters.Others.Argument1 = (PVOID)Srb;
|
||
|
||
//
|
||
// Set up IRP Address.
|
||
//
|
||
|
||
Srb->OriginalRequest = Irp;
|
||
|
||
Srb->NextSrb = 0;
|
||
|
||
//
|
||
// No need to check the following 2 returned statuses as
|
||
// SRB will have ending status.
|
||
//
|
||
|
||
(VOID)IoCallDriver(PartitionContext->PortDeviceObject, Irp);
|
||
|
||
//
|
||
// Check that request completed without error.
|
||
//
|
||
|
||
if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) {
|
||
|
||
//
|
||
// Update status and determine if request should be retried.
|
||
//
|
||
|
||
if (InterpretSenseInfo(Srb, &status, PartitionContext)) {
|
||
|
||
//
|
||
// If retries are not exhausted then
|
||
// retry this operation.
|
||
//
|
||
|
||
if (retryCount--) {
|
||
goto retry;
|
||
}
|
||
}
|
||
|
||
} else {
|
||
|
||
status = ESUCCESS;
|
||
}
|
||
|
||
return status;
|
||
|
||
} // end SendSrbSynchronous()
|
||
|
||
|
||
BOOLEAN
|
||
InterpretSenseInfo(
|
||
IN PSCSI_REQUEST_BLOCK Srb,
|
||
OUT ARC_STATUS *Status,
|
||
PPARTITION_CONTEXT PartitionContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine interprets the data returned from the SCSI
|
||
request sense. It determines the status to return in the
|
||
IRP and whether this request can be retried.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject
|
||
SRB
|
||
ARC_STATUS to update IRP
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN TRUE: Drivers should retry this request.
|
||
FALSE: Drivers should not retry this request.
|
||
|
||
--*/
|
||
|
||
{
|
||
PSENSE_DATA SenseBuffer = Srb->SenseInfoBuffer;
|
||
BOOLEAN retry;
|
||
|
||
//
|
||
// Check that request sense buffer is valid.
|
||
//
|
||
|
||
if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) {
|
||
|
||
ScsiDebugPrint(2,"InterpretSenseInfo: Error code is %x\n",
|
||
SenseBuffer->ErrorCode);
|
||
|
||
ScsiDebugPrint(2,"InterpretSenseInfo: Sense key is %x\n",
|
||
SenseBuffer->SenseKey);
|
||
|
||
ScsiDebugPrint(2,"InterpretSenseInfo: Additional sense code is %x\n",
|
||
SenseBuffer->AdditionalSenseCode);
|
||
|
||
ScsiDebugPrint(2,"InterpretSenseInfo: Additional sense code qualifier is %x\n",
|
||
SenseBuffer->AdditionalSenseCodeQualifier);
|
||
|
||
switch (SenseBuffer->SenseKey) {
|
||
|
||
case SCSI_SENSE_NOT_READY:
|
||
|
||
ScsiDebugPrint(1,"InterpretSenseInfo: Device not ready\n");
|
||
|
||
ScsiDebugPrint(1,"InterpretSenseInfo: Waiting for device\n");
|
||
|
||
*Status = EBUSY;
|
||
|
||
retry = TRUE;
|
||
|
||
switch (SenseBuffer->AdditionalSenseCode) {
|
||
|
||
case SCSI_ADSENSE_LUN_NOT_READY:
|
||
|
||
ScsiDebugPrint(1,"InterpretSenseInfo: Lun not ready\n");
|
||
|
||
switch (SenseBuffer->AdditionalSenseCodeQualifier) {
|
||
|
||
case SCSI_SENSEQ_BECOMING_READY:
|
||
|
||
ScsiDebugPrint(1,
|
||
"InterpretSenseInfo:"
|
||
" In process of becoming ready\n");
|
||
|
||
FwStallExecution( 1000 * 1000 * 3 );
|
||
|
||
break;
|
||
|
||
case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED:
|
||
|
||
ScsiDebugPrint(1,
|
||
"InterpretSenseInfo:"
|
||
" Manual intervention required\n");
|
||
*Status = (ARC_STATUS)STATUS_NO_MEDIA_IN_DEVICE;
|
||
retry = FALSE;
|
||
break;
|
||
|
||
case SCSI_SENSEQ_FORMAT_IN_PROGRESS:
|
||
|
||
ScsiDebugPrint(1,
|
||
"InterpretSenseInfo:"
|
||
" Format in progress\n");
|
||
retry = FALSE;
|
||
break;
|
||
|
||
default:
|
||
|
||
FwStallExecution( 1000 * 1000 * 3 );
|
||
|
||
//
|
||
// Try a start unit too.
|
||
//
|
||
|
||
case SCSI_SENSEQ_INIT_COMMAND_REQUIRED:
|
||
|
||
ScsiDebugPrint(1,
|
||
"InterpretSenseInfo:"
|
||
" Initializing command required\n");
|
||
|
||
//
|
||
// This sense code/additional sense code
|
||
// combination may indicate that the device
|
||
// needs to be started.
|
||
//
|
||
|
||
ScsiDiskStartUnit(PartitionContext);
|
||
break;
|
||
|
||
}
|
||
|
||
} // end switch
|
||
|
||
break;
|
||
|
||
case SCSI_SENSE_DATA_PROTECT:
|
||
|
||
ScsiDebugPrint(1,"InterpretSenseInfo: Media write protected\n");
|
||
|
||
*Status = EACCES;
|
||
|
||
retry = FALSE;
|
||
|
||
break;
|
||
|
||
case SCSI_SENSE_MEDIUM_ERROR:
|
||
|
||
ScsiDebugPrint(1,"InterpretSenseInfo: Bad media\n");
|
||
*Status = EIO;
|
||
|
||
retry = TRUE;
|
||
|
||
break;
|
||
|
||
case SCSI_SENSE_HARDWARE_ERROR:
|
||
|
||
ScsiDebugPrint(1,"InterpretSenseInfo: Hardware error\n");
|
||
*Status = EIO;
|
||
|
||
retry = TRUE;
|
||
|
||
break;
|
||
|
||
case SCSI_SENSE_ILLEGAL_REQUEST:
|
||
|
||
ScsiDebugPrint(1,"InterpretSenseInfo: Illegal SCSI request\n");
|
||
|
||
switch (SenseBuffer->AdditionalSenseCode) {
|
||
|
||
case SCSI_ADSENSE_ILLEGAL_COMMAND:
|
||
ScsiDebugPrint(1,"InterpretSenseInfo: Illegal command\n");
|
||
break;
|
||
|
||
case SCSI_ADSENSE_ILLEGAL_BLOCK:
|
||
ScsiDebugPrint(1,"InterpretSenseInfo: Illegal block address\n");
|
||
break;
|
||
|
||
case SCSI_ADSENSE_INVALID_LUN:
|
||
ScsiDebugPrint(1,"InterpretSenseInfo: Invalid LUN\n");
|
||
break;
|
||
|
||
case SCSI_ADSENSE_MUSIC_AREA:
|
||
ScsiDebugPrint(1,"InterpretSenseInfo: Music area\n");
|
||
break;
|
||
|
||
case SCSI_ADSENSE_DATA_AREA:
|
||
ScsiDebugPrint(1,"InterpretSenseInfo: Data area\n");
|
||
break;
|
||
|
||
case SCSI_ADSENSE_VOLUME_OVERFLOW:
|
||
ScsiDebugPrint(1,"InterpretSenseInfo: Volume overflow\n");
|
||
|
||
} // end switch ...
|
||
|
||
*Status = EINVAL;
|
||
|
||
retry = FALSE;
|
||
|
||
break;
|
||
|
||
case SCSI_SENSE_UNIT_ATTENTION:
|
||
|
||
ScsiDebugPrint(3,"InterpretSenseInfo: Unit attention\n");
|
||
|
||
switch (SenseBuffer->AdditionalSenseCode) {
|
||
|
||
case SCSI_ADSENSE_MEDIUM_CHANGED:
|
||
ScsiDebugPrint(1,"InterpretSenseInfo: Media changed\n");
|
||
break;
|
||
|
||
case SCSI_ADSENSE_BUS_RESET:
|
||
ScsiDebugPrint(1,"InterpretSenseInfo: Bus reset\n");
|
||
|
||
}
|
||
|
||
*Status = EAGAIN;
|
||
|
||
retry = TRUE;
|
||
|
||
break;
|
||
|
||
case SCSI_SENSE_ABORTED_COMMAND:
|
||
|
||
ScsiDebugPrint(1,"InterpretSenseInfo: Command aborted\n");
|
||
|
||
*Status = EIO;
|
||
|
||
retry = TRUE;
|
||
|
||
break;
|
||
|
||
case SCSI_SENSE_NO_SENSE:
|
||
|
||
ScsiDebugPrint(1,"InterpretSenseInfo: No specific sense key\n");
|
||
|
||
*Status = EIO;
|
||
|
||
retry = TRUE;
|
||
|
||
break;
|
||
|
||
default:
|
||
|
||
ScsiDebugPrint(1,"InterpretSenseInfo: Unrecognized sense code\n");
|
||
|
||
*Status = (ARC_STATUS)STATUS_UNSUCCESSFUL;
|
||
|
||
retry = TRUE;
|
||
|
||
} // end switch
|
||
|
||
} else {
|
||
|
||
//
|
||
// Request sense buffer not valid. No sense information
|
||
// to pinpoint the error. Return general request fail.
|
||
//
|
||
|
||
ScsiDebugPrint(1,"InterpretSenseInfo: Request sense info not valid\n");
|
||
|
||
*Status = EIO;
|
||
|
||
retry = TRUE;
|
||
}
|
||
|
||
//
|
||
// If this is the primary srb, then reinitialize any bad scsi devices.
|
||
//
|
||
|
||
if (Srb == &PrimarySrb.Srb) {
|
||
|
||
ScsiDiskFilterBad(PartitionContext);
|
||
}
|
||
|
||
return retry;
|
||
|
||
} // end InterpretSenseInfo()
|
||
|
||
|
||
VOID
|
||
RetryRequest(
|
||
PPARTITION_CONTEXT PartitionContext,
|
||
PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
|
||
{
|
||
PIO_STACK_LOCATION NextIrpStack = IoGetNextIrpStackLocation(Irp);
|
||
PSCSI_REQUEST_BLOCK Srb = &PrimarySrb.Srb;
|
||
PMDL Mdl = Irp->MdlAddress;
|
||
ULONG TransferByteCount = Mdl->ByteCount;
|
||
|
||
|
||
//
|
||
// Reset byte count of transfer in SRB Extension.
|
||
//
|
||
|
||
Srb->DataTransferLength = TransferByteCount;
|
||
|
||
//
|
||
// Zero SRB statuses.
|
||
//
|
||
|
||
Srb->SrbStatus = Srb->ScsiStatus = 0;
|
||
|
||
//
|
||
// Set up major SCSI function.
|
||
//
|
||
|
||
NextIrpStack->MajorFunction = IRP_MJ_SCSI;
|
||
|
||
//
|
||
// Save SRB address in next stack for port driver.
|
||
//
|
||
|
||
NextIrpStack->Parameters.Others.Argument1 = (PVOID)Srb;
|
||
|
||
//
|
||
// Return the results of the call to the port driver.
|
||
//
|
||
|
||
(PVOID)IoCallDriver(PartitionContext->PortDeviceObject, Irp);
|
||
|
||
return;
|
||
|
||
} // end RetryRequest()
|
||
|
||
PIRP
|
||
BuildRequest(
|
||
IN PPARTITION_CONTEXT PartitionContext,
|
||
IN PMDL Mdl,
|
||
IN ULONG LogicalBlockAddress,
|
||
IN BOOLEAN Operation
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Note:
|
||
|
||
If the IRP is for a disk transfer, the byteoffset field
|
||
will already have been adjusted to make it relative to
|
||
the beginning of the disk. In this way, this routine can
|
||
be shared between the disk and cdrom class drivers.
|
||
|
||
- Operation TRUE specifies that this is a READ operation
|
||
FALSE specifies that this is a WRITE operation
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
|
||
{
|
||
PIRP Irp = &PrimarySrb.Irp;
|
||
PIO_STACK_LOCATION NextIrpStack;
|
||
PSCSI_REQUEST_BLOCK Srb = &PrimarySrb.Srb;
|
||
PCDB Cdb;
|
||
USHORT TransferBlocks;
|
||
|
||
//
|
||
// Initialize the rest of the IRP.
|
||
//
|
||
|
||
Irp->MdlAddress = Mdl;
|
||
|
||
Irp->Tail.Overlay.CurrentStackLocation = &PrimarySrb.IrpStack[IRP_STACK_SIZE];
|
||
|
||
NextIrpStack = IoGetNextIrpStackLocation(Irp);
|
||
|
||
//
|
||
// Write length to SRB.
|
||
//
|
||
|
||
Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
|
||
|
||
//
|
||
// Set up IRP Address.
|
||
//
|
||
|
||
Srb->OriginalRequest = Irp;
|
||
|
||
Srb->NextSrb = 0;
|
||
|
||
//
|
||
// Set up target id and logical unit number.
|
||
//
|
||
|
||
Srb->PathId = PartitionContext->PathId;
|
||
Srb->TargetId = PartitionContext->TargetId;
|
||
Srb->Lun = PartitionContext->DiskId;
|
||
|
||
Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
|
||
|
||
Srb->DataBuffer = MmGetMdlVirtualAddress(Mdl);
|
||
|
||
//
|
||
// Save byte count of transfer in SRB Extension.
|
||
//
|
||
|
||
Srb->DataTransferLength = Mdl->ByteCount;
|
||
|
||
//
|
||
// Indicate auto request sense by specifying buffer and size.
|
||
//
|
||
|
||
Srb->SenseInfoBuffer = SenseInfoBuffer;
|
||
|
||
Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
|
||
|
||
//
|
||
// Set timeout value in seconds.
|
||
//
|
||
|
||
Srb->TimeOutValue = SCSI_DISK_TIMEOUT;
|
||
|
||
//
|
||
// Zero statuses.
|
||
//
|
||
|
||
Srb->SrbStatus = Srb->ScsiStatus = 0;
|
||
|
||
//
|
||
// Indicate that 10-byte CDB's will be used.
|
||
//
|
||
|
||
Srb->CdbLength = 10;
|
||
|
||
//
|
||
// Fill in CDB fields.
|
||
//
|
||
|
||
Cdb = (PCDB)Srb->Cdb;
|
||
|
||
Cdb->CDB10.LogicalUnitNumber = PartitionContext->DiskId;
|
||
|
||
TransferBlocks = (USHORT)(Mdl->ByteCount >> PartitionContext->SectorShift);
|
||
|
||
//
|
||
// Move little endian values into CDB in big endian format.
|
||
//
|
||
|
||
Cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte3;
|
||
Cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte2;
|
||
Cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte1;
|
||
Cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&LogicalBlockAddress)->Byte0;
|
||
|
||
Cdb->CDB10.Reserved2 = 0;
|
||
|
||
Cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&TransferBlocks)->Byte1;
|
||
Cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&TransferBlocks)->Byte0;
|
||
|
||
Cdb->CDB10.Control = 0;
|
||
|
||
//
|
||
// Set transfer direction flag and Cdb command.
|
||
//
|
||
|
||
if (Operation) {
|
||
ScsiDebugPrint(3, "BuildRequest: Read Command\n");
|
||
|
||
Srb->SrbFlags = SRB_FLAGS_DATA_IN;
|
||
|
||
Cdb->CDB10.OperationCode = SCSIOP_READ;
|
||
} else {
|
||
ScsiDebugPrint(3, "BuildRequest: Write Command\n");
|
||
|
||
Srb->SrbFlags = SRB_FLAGS_DATA_OUT;
|
||
|
||
Cdb->CDB10.OperationCode = SCSIOP_WRITE;
|
||
}
|
||
|
||
//
|
||
// Disable synchronous transfers.
|
||
//
|
||
|
||
Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
|
||
|
||
//
|
||
// Set up major SCSI function.
|
||
//
|
||
|
||
NextIrpStack->MajorFunction = IRP_MJ_SCSI;
|
||
|
||
//
|
||
// Save SRB address in next stack for port driver.
|
||
//
|
||
|
||
NextIrpStack->Parameters.Others.Argument1 = (PVOID)Srb;
|
||
|
||
return(Irp);
|
||
|
||
} // end BuildRequest()
|
||
|
||
VOID
|
||
ScsiDiskStartUnit(
|
||
IN PPARTITION_CONTEXT PartitionContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Send command to SCSI unit to start or power up.
|
||
Because this command is issued asynchronounsly, that is without
|
||
waiting on it to complete, the IMMEDIATE flag is not set. This
|
||
means that the CDB will not return until the drive has powered up.
|
||
This should keep subsequent requests from being submitted to the
|
||
device before it has completely spun up.
|
||
This routine is called from the InterpretSense routine, when a
|
||
request sense returns data indicating that a drive must be
|
||
powered up.
|
||
|
||
Arguments:
|
||
|
||
PartitionContext - structure containing pointer to port device driver.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PIO_STACK_LOCATION irpStack;
|
||
PIRP irp;
|
||
PSCSI_REQUEST_BLOCK srb = &AbortSrb.Srb;
|
||
PSCSI_REQUEST_BLOCK originalSrb = &PrimarySrb.Srb;
|
||
PCDB cdb;
|
||
|
||
ScsiDebugPrint(1,"StartUnit: Enter routine\n");
|
||
|
||
//
|
||
// Write length to SRB.
|
||
//
|
||
|
||
srb->Length = SCSI_REQUEST_BLOCK_SIZE;
|
||
|
||
//
|
||
// Set up SCSI bus address.
|
||
//
|
||
|
||
srb->PathId = originalSrb->PathId;
|
||
srb->TargetId = originalSrb->TargetId;
|
||
srb->Lun = originalSrb->Lun;
|
||
|
||
srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
|
||
|
||
//
|
||
// Zero out status.
|
||
//
|
||
|
||
srb->ScsiStatus = srb->SrbStatus = 0;
|
||
|
||
//
|
||
// Set timeout value large enough for drive to spin up.
|
||
// NOTE: This value is arbitrary.
|
||
//
|
||
|
||
srb->TimeOutValue = 30;
|
||
|
||
//
|
||
// Set the transfer length.
|
||
//
|
||
|
||
srb->DataTransferLength = 0;
|
||
srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER | SRB_FLAGS_DISABLE_AUTOSENSE;
|
||
srb->SenseInfoBufferLength = 0;
|
||
srb->SenseInfoBuffer = NULL;
|
||
|
||
//
|
||
// Build the start unit CDB.
|
||
//
|
||
|
||
srb->CdbLength = 6;
|
||
cdb = (PCDB)srb->Cdb;
|
||
|
||
RtlZeroMemory(cdb, sizeof(CDB));
|
||
|
||
cdb->CDB10.OperationCode = SCSIOP_START_STOP_UNIT;
|
||
cdb->START_STOP.Start = 1;
|
||
|
||
//
|
||
// Build the IRP
|
||
// to be sent to the port driver.
|
||
//
|
||
|
||
irp = InitializeIrp(
|
||
&AbortSrb,
|
||
IRP_MJ_SCSI,
|
||
PartitionContext->PortDeviceObject,
|
||
NULL,
|
||
0
|
||
);
|
||
|
||
irpStack = IoGetNextIrpStackLocation(irp);
|
||
|
||
irpStack->MajorFunction = IRP_MJ_SCSI;
|
||
|
||
srb->OriginalRequest = irp;
|
||
|
||
//
|
||
// Save SRB address in next stack for port driver.
|
||
//
|
||
|
||
irpStack->Parameters.Others.Argument1 = srb;
|
||
|
||
//
|
||
// No need to check the following 2 returned statuses as
|
||
// SRB will have ending status.
|
||
//
|
||
|
||
IoCallDriver(PartitionContext->PortDeviceObject, irp);
|
||
|
||
} // end StartUnit()
|
||
|
||
ULONG
|
||
ClassModeSense(
|
||
IN PPARTITION_CONTEXT Context,
|
||
IN PCHAR ModeSenseBuffer,
|
||
IN ULONG Length,
|
||
IN UCHAR PageMode
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sends a mode sense command to a target id and returns
|
||
when it is complete.
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
Length of the transferred data is returned.
|
||
|
||
--*/
|
||
{
|
||
PCDB cdb;
|
||
PSCSI_REQUEST_BLOCK Srb = &PrimarySrb.Srb;
|
||
ULONG retries = 1;
|
||
NTSTATUS status;
|
||
|
||
DebugPrint((3,"SCSI ModeSense: Enter routine\n"));
|
||
|
||
//
|
||
// Build the read capacity CDB.
|
||
//
|
||
|
||
Srb->CdbLength = 6;
|
||
cdb = (PCDB)Srb->Cdb;
|
||
|
||
//
|
||
// Set timeout value.
|
||
//
|
||
|
||
Srb->TimeOutValue = 2;
|
||
|
||
RtlZeroMemory(cdb, MAXIMUM_CDB_SIZE);
|
||
|
||
cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
|
||
cdb->MODE_SENSE.PageCode = PageMode;
|
||
cdb->MODE_SENSE.AllocationLength = (UCHAR)Length;
|
||
|
||
Retry:
|
||
|
||
status = SendSrbSynchronous(Context,
|
||
Srb,
|
||
ModeSenseBuffer,
|
||
Length,
|
||
FALSE);
|
||
|
||
|
||
if (status == EAGAIN || status == EBUSY) {
|
||
|
||
//
|
||
// Routine SendSrbSynchronous does not retry
|
||
// requests returned with this status.
|
||
// Read Capacities should be retried
|
||
// anyway.
|
||
//
|
||
|
||
if (retries--) {
|
||
|
||
//
|
||
// Retry request.
|
||
//
|
||
|
||
goto Retry;
|
||
}
|
||
} else if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
return(Srb->DataTransferLength);
|
||
} else {
|
||
return(0);
|
||
}
|
||
|
||
} // end ClassModeSense()
|
||
|
||
PVOID
|
||
ClassFindModePage(
|
||
IN PCHAR ModeSenseBuffer,
|
||
IN ULONG Length,
|
||
IN UCHAR PageMode
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine scans through the mode sense data and finds the requested
|
||
mode sense page code.
|
||
|
||
Arguments:
|
||
ModeSenseBuffer - Supplies a pointer to the mode sense data.
|
||
|
||
Length - Indicates the length of valid data.
|
||
|
||
PageMode - Supplies the page mode to be searched for.
|
||
|
||
Return Value:
|
||
|
||
A pointer to the the requested mode page. If the mode page was not found
|
||
then NULL is return.
|
||
|
||
--*/
|
||
{
|
||
PUCHAR limit;
|
||
|
||
limit = ModeSenseBuffer + Length;
|
||
|
||
//
|
||
// Skip the mode select header and block descriptors.
|
||
//
|
||
|
||
if (Length < sizeof(MODE_PARAMETER_HEADER)) {
|
||
return(NULL);
|
||
}
|
||
|
||
ModeSenseBuffer += sizeof(MODE_PARAMETER_HEADER) +
|
||
((PMODE_PARAMETER_HEADER) ModeSenseBuffer)->BlockDescriptorLength;
|
||
|
||
//
|
||
// ModeSenseBuffer now points at pages walk the pages looking for the
|
||
// requested page until the limit is reached.
|
||
//
|
||
|
||
while (ModeSenseBuffer < limit) {
|
||
|
||
if (((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageCode == PageMode) {
|
||
return(ModeSenseBuffer);
|
||
}
|
||
|
||
//
|
||
// Adavance to the next page.
|
||
//
|
||
|
||
ModeSenseBuffer += ((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageLength + 2;
|
||
}
|
||
|
||
return(NULL);
|
||
|
||
}
|
||
|
||
BOOLEAN
|
||
IsFloppyDevice(
|
||
PPARTITION_CONTEXT Context
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The routine performs the necessary functioons to determinee if a device is
|
||
really a floppy rather than a harddisk. This is done by a mode sense
|
||
command. First, a check is made to see if the medimum type is set. Second
|
||
a check is made for the flexible parameters mode page.
|
||
|
||
Arguments:
|
||
|
||
Context - Supplies the device object to be tested.
|
||
|
||
Return Value:
|
||
|
||
Return TRUE if the indicated device is a floppy.
|
||
|
||
--*/
|
||
{
|
||
|
||
PVOID modeData;
|
||
PUCHAR pageData;
|
||
ULONG length;
|
||
|
||
modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
|
||
|
||
if (modeData == NULL) {
|
||
return(FALSE);
|
||
}
|
||
|
||
RtlZeroMemory(modeData, MODE_DATA_SIZE);
|
||
|
||
length = ClassModeSense(Context,
|
||
modeData,
|
||
MODE_DATA_SIZE,
|
||
MODE_SENSE_RETURN_ALL);
|
||
|
||
if (length < sizeof(MODE_PARAMETER_HEADER)) {
|
||
|
||
//
|
||
// Retry the request in case of a check condition.
|
||
//
|
||
|
||
length = ClassModeSense(Context,
|
||
modeData,
|
||
MODE_DATA_SIZE,
|
||
MODE_SENSE_RETURN_ALL);
|
||
|
||
if (length < sizeof(MODE_PARAMETER_HEADER)) {
|
||
|
||
ExFreePool(modeData);
|
||
return(FALSE);
|
||
|
||
}
|
||
}
|
||
#if 0
|
||
if (((PMODE_PARAMETER_HEADER) modeData)->MediumType >= MODE_FD_SINGLE_SIDE
|
||
&& ((PMODE_PARAMETER_HEADER) modeData)->MediumType <= MODE_FD_MAXIMUM_TYPE) {
|
||
|
||
DebugPrint((1, "Scsidisk: MediumType value %2x, This is a floppy.\n", ((PMODE_PARAMETER_HEADER) modeData)->MediumType));
|
||
ExFreePool(modeData);
|
||
return(TRUE);
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Look for the flexible disk mode page.
|
||
//
|
||
|
||
pageData = ClassFindModePage( modeData, length, MODE_PAGE_FLEXIBILE);
|
||
|
||
if (pageData != NULL) {
|
||
|
||
DebugPrint((1, "Scsidisk: Flexible disk page found, This is a floppy.\n"));
|
||
ExFreePool(modeData);
|
||
return(TRUE);
|
||
|
||
}
|
||
|
||
ExFreePool(modeData);
|
||
return(FALSE);
|
||
|
||
} // end IsFloppyDevice()
|
||
|
||
VOID
|
||
ScsiDiskFilterBad(
|
||
IN PPARTITION_CONTEXT PartitionContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine looks for SCSI units which need special initialization
|
||
to operate correctly.
|
||
|
||
Arguments:
|
||
|
||
PartitionContext - structure containing pointer to port device driver.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PSCSI_REQUEST_BLOCK srb = &AbortSrb.Srb;
|
||
PCDB cdb;
|
||
PDEVICE_EXTENSION scsiPort;
|
||
PSCSI_CONFIGURATION_INFO configInfo;
|
||
PSCSI_BUS_SCAN_DATA busScanData;
|
||
PUCHAR modePage;
|
||
ULONG busNumber;
|
||
PLUNINFO lunInfo;
|
||
PINQUIRYDATA inquiryData;
|
||
|
||
ScsiDebugPrint(3,"FilterBad: Enter routine\n");
|
||
|
||
scsiPort = PartitionContext->PortDeviceObject->DeviceExtension;
|
||
configInfo = scsiPort->ScsiInfo;
|
||
|
||
//
|
||
// Search the configuration database for scsi disk and cdrom devices
|
||
// which require special initializaion.
|
||
//
|
||
|
||
for (busNumber=0; busNumber < (ULONG)configInfo->NumberOfBuses; busNumber++) {
|
||
|
||
busScanData = configInfo->BusScanData[busNumber];
|
||
|
||
//
|
||
// Set LunInfo to beginning of list.
|
||
//
|
||
|
||
lunInfo = busScanData->LunInfoList;
|
||
|
||
while (lunInfo != NULL) {
|
||
|
||
inquiryData = (PVOID)lunInfo->InquiryData;
|
||
|
||
//
|
||
// Determin if this is the correct lun.
|
||
//
|
||
|
||
if (PartitionContext->PathId == lunInfo->PathId &&
|
||
PartitionContext->TargetId == lunInfo->TargetId &&
|
||
PartitionContext->DiskId == lunInfo->Lun) {
|
||
|
||
goto FoundOne;
|
||
}
|
||
|
||
//
|
||
// Get next LunInfo.
|
||
//
|
||
|
||
lunInfo = lunInfo->NextLunInfo;
|
||
}
|
||
}
|
||
|
||
return;
|
||
|
||
FoundOne:
|
||
|
||
|
||
|
||
//
|
||
// Zero out status.
|
||
//
|
||
|
||
srb->ScsiStatus = srb->SrbStatus = 0;
|
||
|
||
//
|
||
// Set timeout value.
|
||
//
|
||
|
||
srb->TimeOutValue = 2;
|
||
|
||
//
|
||
// Look for a bad devices.
|
||
//
|
||
|
||
if (strncmp(inquiryData->VendorId, "HITACHI CDR-1750S", strlen("HITACHI CDR-1750S")) == 0 ||
|
||
strncmp(inquiryData->VendorId, "HITACHI CDR-3650/1650S", strlen("HITACHI CDR-3650/1650S")) == 0) {
|
||
|
||
ScsiDebugPrint(1, "ScsiDiskFilterBad: Found Hitachi CDR-1750S.\n");
|
||
|
||
//
|
||
// Found a bad HITACHI cd-rom. These devices do not work with PIO
|
||
// adapters when read-ahead is enabled. Read-ahead is disabled by
|
||
// a mode select command. The mode select page code is zero and the
|
||
// length is 6 bytes. All of the other bytes should be zero.
|
||
//
|
||
|
||
modePage = ExAllocatePool(NonPagedPool, HITACHI_MODE_DATA_SIZE);
|
||
|
||
if (modePage == NULL) {
|
||
return;
|
||
}
|
||
|
||
RtlZeroMemory(modePage, HITACHI_MODE_DATA_SIZE);
|
||
|
||
//
|
||
// Set the page length field to 6.
|
||
//
|
||
|
||
modePage[5] = 6;
|
||
|
||
//
|
||
// Build the mode select CDB.
|
||
//
|
||
|
||
srb->CdbLength = 6;
|
||
cdb = (PCDB)srb->Cdb;
|
||
|
||
RtlZeroMemory(cdb, sizeof(CDB));
|
||
|
||
cdb->MODE_SELECT.OperationCode = SCSIOP_MODE_SELECT;
|
||
cdb->MODE_SELECT.ParameterListLength = HITACHI_MODE_DATA_SIZE;
|
||
|
||
//
|
||
// Send the request to the device.
|
||
//
|
||
|
||
SendSrbSynchronous(PartitionContext,
|
||
srb,
|
||
modePage,
|
||
HITACHI_MODE_DATA_SIZE,
|
||
TRUE);
|
||
|
||
ExFreePool(modePage);
|
||
}
|
||
|
||
} // end ScsiDiskFilterBad()
|
||
|
||
BOOLEAN
|
||
CheckFileId(
|
||
ULONG FileId
|
||
)
|
||
{
|
||
|
||
if (BlFileTable[FileId].u.PartitionContext.PortDeviceObject != NULL) {
|
||
return TRUE;
|
||
}
|
||
|
||
#if 0
|
||
DbgPrint("\n\rScsidisk: Bad file id passed to read or write. FileId = %lx\n", FileId);
|
||
DbgPrint("Start sector = %lx; Ending sector = %lx; Disk Id = %x; DeviceUnit = %x\n",
|
||
BlFileTable[FileId].u.PartitionContext.StartingSector,
|
||
BlFileTable[FileId].u.PartitionContext.EndingSector,
|
||
BlFileTable[FileId].u.PartitionContext.DiskId,
|
||
BlFileTable[FileId].u.PartitionContext.DeviceUnit
|
||
);
|
||
|
||
DbgPrint("Target Id = %d; Path Id = %d; Sector Shift = %lx; Size = %lx\n",
|
||
BlFileTable[FileId].u.PartitionContext.TargetId,
|
||
BlFileTable[FileId].u.PartitionContext.PathId,
|
||
BlFileTable[FileId].u.PartitionContext.SectorShift,
|
||
BlFileTable[FileId].u.PartitionContext.Size
|
||
);
|
||
|
||
DbgPrint("Hit any key\n");
|
||
while(!GET_KEY());
|
||
#endif
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
|
||
#endif
|