⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scsi2.c

📁 WIN CE 下storage 存储外设的驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
        pSgReq->sr_status = dwErr;
        return 0;
    }
    
    EnterCriticalSection(&pDevice->Lock);   
    
    //
    // Determine whether the Scatter/Gather buffers are sector aligned.
    // If the buffers are not sector aligned, then double buffering is
    //     required.
    // If the buffers are sector aligned, then dwFlags == 0.
    // Otherwise, dwFlags != 0.
    //
    dwErr = CheckSegments(pDevice, pSgReq, (PDWORD) &uiExpectedBytesXferred, &dwFlags); 

    if (ERROR_SUCCESS == dwErr) {
        
        HANDLE hProc = GetCallerProcess();                // Calling process.
        LONGLONG llSectorsRemaining = pSgReq->sr_num_sec; // Total number of sectors to transfer.
        UINT uiStartingSector = pSgReq->sr_start;         // Starting sector.
        UINT uiSectorsToXfer = 0;                         // Number of sectors to transfer in current sub-transfer.
        UINT uiBytesXferred = 0;                          // Number of bytes to transfer in current sub-transfer.
        UINT sg;                                          // Index of current Scatter/Gather buffer.
        PVOID pBuffer = NULL;                             // Pointer to the current open Scatter/Gather buffer.
        
        if (dwFlags == 0) {
            
            //
            // Scatter/Gather buffers ARE sector aligned.
            // Double buffering is NOT required.
            // TRANSFER EACH SCATTER/GATHER BUFFER SEPARATELY.
            //            
            for (sg = 0; (sg < pSgReq->sr_num_sg) && (llSectorsRemaining > 0) && (pSgReq->sr_sglist[sg].sb_buf != NULL) && (pSgReq->sr_sglist[sg].sb_len != 0); sg++) {

                // Open the sg buffer; performs caller access check.
                if (FAILED (CeOpenCallerBuffer (
                        &pBuffer,
                        pSgReq->sr_sglist[sg].sb_buf,
                        pSgReq->sr_sglist[sg].sb_len,
                        bRead ? ARG_O_PTR : ARG_I_PTR,
                        FALSE
                        ))) {
                    LeaveCriticalSection(&pDevice->Lock);
                    ReleaseRemoveLock(&pDevice->RemoveLock, NULL);
                    pSgReq->sr_status = ERROR_INVALID_PARAMETER;
                    return 0;
                }                
                ASSERT(pBuffer != NULL);
                ASSERT((pSgReq->sr_sglist[sg].sb_len % pDevice->DiskInfo.di_bytes_per_sect) == 0);
                
                //
                // Calculate the number of contiguous sectors to transfer
                //    (from the current Scatter/Gather buffer).
                // This is not redundant, as pSgReq->sr_num_sec gives the total
                //    number of sectors transferred through the Scatter/Gather 
                //    request, and this calculation determines the number of
                //    contiguous sectors in the current Scatter/Gather buffer.
                //
                uiSectorsToXfer = min((pSgReq->sr_sglist[sg].sb_len / pDevice->DiskInfo.di_bytes_per_sect), (DWORD) llSectorsRemaining);
                uiBytesXferred = pSgReq->sr_sglist[sg].sb_len;

                ASSERT(uiSectorsToXfer != 0);
                ASSERT(uiSectorsToXfer <= llSectorsRemaining);

                DEBUGMSG(ZONE_READ, (TEXT("Scsi%sSG[%d] uiStartingSector: %d, uiSectorsToXfer: %d\n"), bRead ? TEXT("Read") : TEXT("Write"), sg, uiStartingSector, uiSectorsToXfer));
                
                //
                // Transfer the contiguous sectors in the current
                //     Scatter/Gather buffer.
                // (Recall) Double buffer is not required, as all buffers are 
                //     sector aligned.
                //
                dwErr = ScsiReadWrite(pDevice, uiStartingSector, uiSectorsToXfer, pBuffer, &uiBytesXferred, Lun,  bRead);

                // Close the sg buffer.
                VERIFY (SUCCEEDED (CeCloseCallerBuffer (
                    pBuffer,
                    pSgReq->sr_sglist[sg].sb_buf,
                    pSgReq->sr_sglist[sg].sb_len,
                    bRead ? ARG_O_PTR : ARG_I_PTR
                    )));
                pBuffer = NULL;
                
                if (ERROR_SUCCESS == dwErr) {
                    llSectorsRemaining  -= uiSectorsToXfer;
                    ASSERT(llSectorsRemaining >= 0);
                    uiStartingSector += uiSectorsToXfer;
                    uiActualBytesXferred += uiBytesXferred;
                }
                else {
                    LeaveCriticalSection(&pDevice->Lock);
                    ReleaseRemoveLock(&pDevice->RemoveLock, NULL);
                    DEBUGMSG(ZONE_ERR,(TEXT("USBMSC>ScsiRWSG: ScsiReadWrite failed. Error: %d\n"), dwErr));
                    pSgReq->sr_status = dwErr;
                    return 0;
                }                
            }        
        }
        else {
            
            //
            // Scatter/Gather buffers are NOT sector aligned.
            // Double buffering IS required.
            //          
            UINT uiDbBuffOffset = 0;       // Current position in double buffer.
            UINT uiBytesInSgBuff = 0;      // Number of bytes in current Scatter/Gather buffer.
            PUCHAR pucSgBuffOffset = NULL; // Pointer to current position in double buffer.
            
            memset(&pDevice->SgBuff[0], 0, SG_BUFF_SIZE);

            DEBUGMSG(ZONE_TRACE, (TEXT("USBMSC>ScsiRWSG: SgReq (%s) buffers not sector aligned, double buffer\n"), bRead ? (TEXT("Read")) : (TEXT("Write"))));

            //
            // If reading, read from storage device to double buffer, and fill
            //     each Scatter/Gather buffer in order, re-filling the double
            //     buffer as necessary.
            // If writing, fill double buffer from each Scatter/Gather buffer
            //     in order, flushing the double buffer to storage device as
            //     necessary.
            //
            for (sg = 0; sg < pSgReq->sr_num_sg; sg += 1) {

                // Open the sg buffer; performs caller access check.
                if (FAILED (CeOpenCallerBuffer (
                        &pBuffer,
                        pSgReq->sr_sglist[sg].sb_buf,
                        pSgReq->sr_sglist[sg].sb_len,
                        bRead ? ARG_O_PTR : ARG_I_PTR,
                        FALSE
                        ))) {
                    LeaveCriticalSection(&pDevice->Lock);
                    ReleaseRemoveLock(&pDevice->RemoveLock, NULL);
                    pSgReq->sr_status = ERROR_INVALID_PARAMETER;
                    return 0;
                }
                pucSgBuffOffset = pBuffer;
                ASSERT(pucSgBuffOffset);

                uiBytesInSgBuff = (bRead ? 0 : (UINT) pSgReq->sr_sglist[sg].sb_len);
                
                while (bRead ? (uiBytesInSgBuff < pSgReq->sr_sglist[sg].sb_len) : (uiBytesInSgBuff > 0)) {

                    if (bRead) {                       
                        if (uiDbBuffOffset == uiBytesXferred) {                                                     
                            uiSectorsToXfer = ((llSectorsRemaining > (SG_BUFF_SIZE / pDevice->DiskInfo.di_bytes_per_sect)) ? (SG_BUFF_SIZE / pDevice->DiskInfo.di_bytes_per_sect) : (UINT) llSectorsRemaining);
                            uiBytesXferred = uiSectorsToXfer * pDevice->DiskInfo.di_bytes_per_sect;
                            goto __DbXfer;
__DbRead:
                            ;
                        }
                    }

                    //
                    // If reading, copy a byte from the double buffer to the
                    //     current Scatter/Gather buffer.
                    // If writing, copy a byte from the current Scatter/Gather
                    //     buffer to the double buffer.
                    //
                    PREFAST_DEBUGCHK(pucSgBuffOffset);
                    bRead ? (*pucSgBuffOffset = pDevice->SgBuff[uiDbBuffOffset]) : (pDevice->SgBuff[uiDbBuffOffset] = *pucSgBuffOffset);
                    bRead ? (uiBytesInSgBuff += 1) : (uiBytesInSgBuff -= 1);
                    uiDbBuffOffset += 1;
                    pucSgBuffOffset++;
                    uiActualBytesXferred += 1;

                    if ( ! bRead ) {
                        uiSectorsToXfer = ((llSectorsRemaining > (SG_BUFF_SIZE / pDevice->DiskInfo.di_bytes_per_sect)) ? (SG_BUFF_SIZE / pDevice->DiskInfo.di_bytes_per_sect) : (UINT) llSectorsRemaining);
                        uiBytesXferred = uiSectorsToXfer * pDevice->DiskInfo.di_bytes_per_sect;
                        if (uiDbBuffOffset == uiBytesXferred) {
                            goto __DbXfer;
__DbWrite:                          
                            ;
                        }                       
                    }
                    goto __DbEnd;
__DbXfer:
                    //
                    // Fill/flush the double buffer from/to the storage device.
                    //                          
                    DEBUGMSG(ZONE_TRACE, (TEXT("USBMSC>ScsiRWSG: StartSec: %d, SecsToXfer: %d, BytesXfer'd: %d\n"), uiStartingSector, uiSectorsToXfer, uiBytesXferred));
                    dwErr = ScsiReadWrite(pDevice, uiStartingSector, uiSectorsToXfer, &pDevice->SgBuff[0], &uiBytesXferred, Lun, bRead);
                    if (dwErr != ERROR_SUCCESS) {
                        DEBUGMSG(ZONE_ERR, (TEXT("USBMSC>ScsiRWSG: ScsiReadWrite failed. Error: %d\n"), dwErr));
                        LeaveCriticalSection(&pDevice->Lock);
                        ReleaseRemoveLock(&pDevice->RemoveLock, NULL);
                        pSgReq->sr_status = dwErr;
                        return 0;
                    }
                    uiDbBuffOffset = 0;
                    llSectorsRemaining -= uiSectorsToXfer;
                    uiStartingSector += uiSectorsToXfer;
                    if ((uiBytesXferred != (uiSectorsToXfer * pDevice->DiskInfo.di_bytes_per_sect))) {
                        LeaveCriticalSection(&pDevice->Lock);
                        ReleaseRemoveLock(&pDevice->RemoveLock, NULL);
                        pSgReq->sr_status = ERROR_DISK_OPERATION_FAILED;
                        return 0;
                    }
                    if (bRead) goto __DbRead;
                    goto __DbWrite;
__DbEnd:
                    ;
                }
                
                // Close the sg buffer.
                VERIFY (SUCCEEDED (CeCloseCallerBuffer (
                    pBuffer,
                    pSgReq->sr_sglist[sg].sb_buf,
                    pSgReq->sr_sglist[sg].sb_len,
                    bRead ? ARG_O_PTR : ARG_I_PTR
                    )));
                pBuffer = NULL;
            }

            if ((llSectorsRemaining != 0) || (uiStartingSector != (pSgReq->sr_start + pSgReq->sr_num_sec))) {
                LeaveCriticalSection(&pDevice->Lock);
                ReleaseRemoveLock(&pDevice->RemoveLock, NULL);
                pSgReq->sr_status = ERROR_DISK_OPERATION_FAILED;
                return 0;
            }
            if (( ! bRead ) && uiBytesInSgBuff != 0) {
                LeaveCriticalSection(&pDevice->Lock);
                ReleaseRemoveLock(&pDevice->RemoveLock, NULL);
                pSgReq->sr_status = ERROR_DISK_OPERATION_FAILED;
                return 0;
            }
        }
    } else {
        DEBUGMSG(ZONE_ERR,(TEXT("USBMSC>ScsiRWSG: CheckSegments failed. Error: %d.\n"),dwErr));
    }
    
    if (uiExpectedBytesXferred != uiActualBytesXferred) {
        LeaveCriticalSection(&pDevice->Lock);
        ReleaseRemoveLock(&pDevice->RemoveLock, NULL);
        pSgReq->sr_status = ERROR_DISK_OPERATION_FAILED;
        return 0;
    }
    
    pSgReq->sr_status = dwErr;

    LeaveCriticalSection(&pDevice->Lock);
    ReleaseRemoveLock(&pDevice->RemoveLock, NULL);
    
    DEBUGMSG(ZONE_TRACE,(TEXT("USBMSC<ScsiRWSG: ->sr_status: %d\n"), dwErr));
    
    return uiActualBytesXferred;
}

/* ++

ScsiReadWrite: 
    
    Transfers full sectors.

-- */
DWORD
ScsiReadWrite(
    IN PSCSI_DEVICE pDevice,
    IN DWORD        dwStartSector,
    IN DWORD        dwNumSectors,
    IN OUT PVOID    pvBuffer,        // pointer to transfer buffer
    IN OUT PDWORD   pdwTransferSize, // IN: sizeof input buffer, OUT: number of bytes transferred
    IN UCHAR        Lun,
    IN BOOL         bRead
    )
{
    TRANSPORT_COMMAND tCommand;
    UCHAR             bCDB[MAX_CDB];
    TRANSPORT_DATA    tData;
    DWORD             dwErr;
    DWORD             dwSectorBytes;
    UCHAR             retries = 0;

    DEBUGMSG(ZONE_TRACE,(TEXT("USBMSC>ScsiReadWrite\n")));

    if (!pDevice || !pDevice->DiskInfo.di_bytes_per_sect || 
        !pvBuffer || !pdwTransferSize) {
        return ERROR_INVALID_PARAMETER;
    }

    // buffer size limitations.
    if (0 == *pdwTransferSize || !dwNumSectors) {
        DEBUGMSG(ZONE_ERR,(TEXT("ScsiReadWrite: invalid transfer size:%u, %u\n"),
            *pdwTransferSize, dwNumSectors));
        TEST_TRAP();
        return ERROR_INVALID_PARAMETER;
    }

    dwSectorBytes = dwNumSectors * pDevice->DiskInfo.di_bytes_per_sect;

    // Transfer buffers must be large enough to fit the requested # sectors
    if (*pdwTransferSize < dwSectorBytes)
    {
        DEBUGMSG(ZONE_ERR,(TEXT("ScsiReadWrite: buffer too small (%u < %u)\n"), *pdwTransferSize, dwSectorBytes));
        return ERROR_INSUFFICIENT_BUFFER;
    }

    dwErr = AcquireRemoveLock(&pDevice->RemoveLock, NULL);
    if ( ERROR_SUCCESS != dwErr) {
        return dwErr;
    }

    EnterCriticalSection(&pDevice->Lock);

    tCommand.Flags = bRead ? DATA_IN : DATA_OUT;

    tCommand.Timeout = bRead ? 
        pDevice->Timeouts.ReadSector + (dwSectorBytes/USBDISK_LEASTREADBANDWIDTH) :
        pDevice->Timeouts.WriteSector+ (dwSectorBytes/USBDISK_LEASTWRITEBANDWIDTH) ;

    tCommand.Length = USBMSC_SUBCLASS_SCSI == pDevice->DiskSubClass ? SCSI_CDB_10 : UFI_CDB;
    tCommand.CommandBlock = bCDB;
    tCommand.dwLun=Lun;

    memset(bCDB, 0, sizeof(bCDB) );
    bCDB[0] = bRead ? SCSI_READ10 : SCSI_WRITE10;

    ASSERT(Lun <= 0x7);
    bCDB[1] = ((Lun & 0x7) << 5);

    // Logical Block Address
    SetDWORD( &bCDB[2], dwStartSector);

    // TransferLength (in sectors)
    SetWORD( &bCDB[7], (WORD)dwNumSectors);

    tData.TransferLength = 0;
    tData.RequestLength  = dwSectorBytes;
    tData.DataBlock = pvBuffer;

    DEBUGMSG(ZONE_READ,(TEXT("Scsi%s - LBA:%d TL:%d TimeOut:%d\n"), 
        bRead ? TEXT("Read") : TEXT("Write"), dwStartSector, dwNumSectors, tCommand.Timeout));

    do {
        dwErr = UsbsDataTransfer( pDevice->hUsbTransport,
                                  &tCommand,
                                  &tData );

        if ( ERROR_SUCCESS == dwErr ) {

            *pdwTransferSize = tData.TransferLength;

        } else {
        
            // since we do retries we also have to (re)poke the device
            dwErr = ScsiUnitAttention(pDevice, pDevice->Lun);
            if (ERROR_SUCCESS != dwErr) 
                break;

            dwErr = ScsiGetSenseData(pDevice, Lun);

            if (ERROR_SUCCESS == dwErr)
                dwErr = ERROR_GEN_FAILURE;

            DEBUGMSG(ZONE_ERR,(TEXT("ScsiReadWrite ERROR:%d\n"), dwErr));

            *pdwTransferSize = 0;
        }

    } while ((ERROR_SUCCESS != dwErr) && (++retries < 3));

    LeaveCriticalSection(&pDevice->Lock);

    ReleaseRemoveLock(&pDevice->RemoveLock, NULL);

    DEBUGMSG(ZONE_TRACE,(TEXT("USBMSC<ScsiReadWrite:%d\n"), dwErr));

    return dwErr;
}

// EOF

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -