通过发送SRB的方式来读写U盘的物理扇区

来源:互联网 发布:英灵召唤师 知乎 编辑:程序博客网 时间:2024/05/17 09:38

ULONG g_ulBytesPerSector = 0x200;

NTSTATUS ReadSector(PDEVICE_OBJECT fido,PVOID buffer,ULONG SectorNum, int SectorCount)

 {

          NTSTATUS status;

          PSCSI_REQUEST_BLOCK  pSrb;

          PSENSE_DATA Sense;

          KEVENT Event;

          PIRP pIrp;

          PMDL pMdl;

          IO_STATUS_BLOCK IoSb;

          PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fido->DeviceExtension;

     PCDB cdb;

 

          pSrb = (PSCSI_REQUEST_BLOCK)ExAllocatePool(NonPagedPool,sizeof(SCSI_REQUEST_BLOCK));

     Sense = (PSENSE_DATA)ExAllocatePool(NonPagedPool,sizeof(SENSE_DATA));

 

          RtlZeroMemory(pSrb,sizeof(SCSI_REQUEST_BLOCK));

          RtlZeroMemory(Sense,sizeof(SENSE_DATA));

 

          pSrb->Length = sizeof(SCSI_REQUEST_BLOCK);

          pSrb->Function = SRB_FUNCTION_EXECUTE_SCSI;

 

          pSrb->PathId = 0 ;

          pSrb->TargetId = 1 ;

          pSrb->Lun = 0 ;

          pSrb->SrbStatus = 0 ;

          pSrb->ScsiStatus = 0 ;

          pSrb->NextSrb = 0 ;

          pSrb->QueueAction = SRB_FLAGS_DISABLE_AUTOSENSE;

          pSrb->DataBuffer = buffer ;

          pSrb->DataTransferLength = 512 ;

          pSrb->QueueSortKey = SectorNum ;

          pSrb->SenseInfoBufferLength = sizeof(SENSE_DATA);

          pSrb->SenseInfoBuffer = Sense;

          pSrb->SrbFlags = SRB_FLAGS_DATA_IN ;

          pSrb->SrbFlags |= SRB_FLAGS_ADAPTER_CACHE_ENABLE;

          pSrb->SrbFlags |= SRB_FLAGS_DISABLE_AUTOSENSE;

          pSrb->CdbLength = 10;

 

          cdb = (PCDB)pSrb->Cdb;

 

          cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&SectorNum)->Byte3;

          cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&SectorNum)->Byte2;

          cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&SectorNum)->Byte1;

          cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&SectorNum)->Byte0;

     cdb->CDB10.TransferBlocksMsb = 0;

          cdb->CDB10.TransferBlocksLsb = 1;

          cdb->CDB10.OperationCode = SCSIOP_READ;

          cdb->CDB10.ForceUnitAccess = TRUE;

 

          KeInitializeEvent(&Event,NotificationEvent,FALSE);

          pIrp = IoAllocateIrp(fido->StackSize,0);

          pMdl = IoAllocateMdl(buffer,SectorCount*512,0,0,pIrp);

          pIrp->MdlAddress = pMdl;

          if(!pMdl)

          {

                    ExFreePool(pSrb);

                    ExFreePool(Sense);

                    ExFreePool(pIrp);

         return STATUS_INSUFFICIENT_RESOURCES;

          }

          MmProbeAndLockPages(pMdl,0,IoReadAccess);

          

          pSrb->OriginalRequest = pIrp;

          pIrp->UserIosb = &IoSb;

          pIrp->UserEvent = &Event;

          pIrp->IoStatus.Status = 0;

          pIrp->IoStatus.Information = 0;

          pIrp->Flags = IRP_NOCACHE | IRP_SYNCHRONOUS_API;

          pIrp->Cancel = 0;

          pIrp->RequestorMode = 0;

          pIrp->CancelRoutine = 0;

          pIrp->AssociatedIrp.SystemBuffer = 0;

     pIrp->Tail.Overlay.Thread = PsGetCurrentThread();

 

          PIO_STACK_LOCATION pIrpSp = IoGetNextIrpStackLocation(pIrp);

    

          pIrpSp->DeviceObject = fido;

     pIrpSp->MajorFunction = IRP_MJ_SCSI;

          pIrpSp->Parameters.Scsi.Srb = pSrb;

     pIrpSp->CompletionRoutine = ReadSectorCompletionRoutine;

          pIrpSp->Context = pSrb;

          pIrpSp->Control = SL_INVOKE_ON_CANCEL | SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR;

 

          IoSetCompletionRoutine(pIrp,ReadSectorCompletionRoutine,pSrb,1,1,1);

     status = IoCallDriver(pdx->LowerDeviceObject,pIrp);

     if (status == STATUS_PENDING)

          {

                    KeWaitForSingleObject(&Event,Executive,KernelMode,0,0);

                    status = STATUS_SUCCESS;

          }

     if (NT_SUCCESS(status) && pSrb->SrbStatus == SRB_STATUS_SUCCESS && pSrb->ScsiStatus == SCSISTAT_GOOD)

    {

        status = STATUS_SUCCESS;

    }

    else

    {

        status = STATUS_UNSUCCESSFUL;

    }

        

__end:

    if (pSrb->SenseInfoBuffer && pSrb->SenseInfoBuffer != Sense)

    {

        ExFreePool(pSrb->SenseInfoBuffer);

    }

        

    if (pSrb != NULL)

    {

        ExFreePool(pSrb);

    }

        

    if (Sense != NULL)

    {

        ExFreePool(Sense);

    }

        

    return status;

 }

 NTSTATUS ReadSectorCompletionRoutine(PDEVICE_OBJECT fido, PIRP pIrp, PVOID Context)

 {

         pIrp->UserIosb->Information = pIrp->IoStatus.Information;

    pIrp->UserIosb->Status = pIrp->IoStatus.Status;

 

    if (Context != NULL && pIrp->MdlAddress != NULL)

    {

        MmUnlockPages(pIrp->MdlAddress);

        IoFreeMdl(pIrp->MdlAddress);

    }

 

    KeSetEvent(pIrp->UserEvent, 0, FALSE);

    IoFreeIrp(pIrp);

 

    return STATUS_MORE_PROCESSING_REQUIRED; //交回我们的例程处理

 }