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

📄 scsi2.c

📁 cayman提供的PXA270 wince下的bsp源码包
💻 C
📖 第 1 页 / 共 3 页
字号:

    if ( dwErr != ERROR_SUCCESS ) {

        dwErr = ScsiGetSenseData( pDevice, Lun );

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

        SetLastError(dwErr);

    }

    ReleaseRemoveLock(&pDevice->RemoveLock, NULL);
    
    DEBUGMSG(ZONE_SCSI,(TEXT("USBDISK6<ScsiStartStopUnit:%d\n"), dwErr));

    return dwErr;
}


//
// Checks the users SG to see if we can use it.
// Since we basically do a prescan then return flag saying
// if we need to use double buffering.
//
DWORD
CheckSegments(
    IN PSCSI_DEVICE    pDevice,
    IN PSG_REQ         pSgReq,
    IN OUT PDWORD      pTransferLength,
    IN OUT PDWORD      pFlags
    )
{
    DWORD dwErr = ERROR_SUCCESS;
    DWORD sg;

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


    if ( !pDevice || 0 == pDevice->DiskInfo.di_bytes_per_sect || 
         0 == pDevice->DiskInfo.di_total_sectors ) 
    {
        dwErr = ERROR_FLOPPY_UNKNOWN_ERROR;
        DEBUGMSG(ZONE_ERR,(TEXT("CheckSegments ERROR:1: di_bytes_per_sect:%d di_total_sectors:%d\n"),
            pDevice?pDevice->DiskInfo.di_bytes_per_sect:-1, pDevice?pDevice->DiskInfo.di_total_sectors:-1));
        
        TEST_TRAP();

    } else if ( !pSgReq || !pTransferLength || !pFlags) {

        dwErr=ERROR_INVALID_PARAMETER;
        DEBUGMSG(ZONE_ERR,(TEXT("CheckSegments ERROR:2: %d\n"), dwErr ));
    
    } else if (pSgReq->sr_num_sg > MAX_SG_BUF ||
               pSgReq->sr_start + pSgReq->sr_num_sec > pDevice->DiskInfo.di_total_sectors)
    {
            dwErr=ERROR_INVALID_PARAMETER;
            DEBUGMSG(ZONE_ERR,(TEXT("CheckSegments ERROR:3: sg:%d sr_start:%d, sr_num_sec:%d, di_total_sectors:%d di_bytes_per_sect:%d\n"),
                pSgReq->sr_num_sg, pSgReq->sr_start, pSgReq->sr_num_sec, pDevice->DiskInfo.di_total_sectors, pDevice->DiskInfo.di_bytes_per_sect));
    
    } else {
        //
        // ensure all the buffers in the SG list are OK
        //
        ASSERT(pFlags);
        ASSERT(pTransferLength);
	    EnterCriticalSection(&pDevice->Lock);

        for (sg = 0, *pTransferLength = 0, *pFlags = 0; sg < pSgReq->sr_num_sg; sg++) 
        {
            if ( !pSgReq->sr_sglist[sg].sb_buf )
            {
                dwErr = ERROR_INVALID_PARAMETER;
                DEBUGMSG(ZONE_ERR,(TEXT("CheckSegments ERROR:4:%d\n"), dwErr));
                break;
            }

            // do we need double buffering?
            if ((pSgReq->sr_sglist[sg].sb_len % pDevice->DiskInfo.di_bytes_per_sect) != 0)
            {
                *pFlags |= 0x1;
                DEBUGMSG(ZONE_READ,(TEXT("CheckSegments: Double Buffered\n")));
            }

            // sum all the buffer lengths to make sure they match 
            // the requested number of sectors
            *pTransferLength += pSgReq->sr_sglist[sg].sb_len;
        }

        if (dwErr == ERROR_SUCCESS && 
            *pTransferLength > (pSgReq->sr_num_sec * pDevice->DiskInfo.di_bytes_per_sect)) 
        {
            dwErr = ERROR_INVALID_PARAMETER;
            DEBUGMSG(ZONE_ERR,(TEXT("CheckSegments ERROR:5: invalid user SG buffers (%u > %u)\n"),
            *pTransferLength, (pSgReq->sr_num_sg * pDevice->DiskInfo.di_bytes_per_sect)));
        }

        // we are limited by our static sg buffer
        if (dwErr == ERROR_SUCCESS && *pFlags &&
            *pTransferLength > SG_BUFF_SIZE)
        {
            dwErr = ERROR_INVALID_PARAMETER;
            DEBUGMSG(ZONE_WARN,(TEXT("CheckSegments ERROR:6: overrun our SG buffer (%u > %u)\n"),
                *pTransferLength, SG_BUFF_SIZE));
            TEST_TRAP();
            *pFlags |= 0x2;
        }
	    LeaveCriticalSection(&pDevice->Lock);
    }

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

    return dwErr;
}


/* ++

Returns number of bytes transferred.
Returns Status in the PSG_REQ status field.

BUGBUG: this code does not pass "s tux -o -d rwtest -x1021-3099"
for the following case:

*** Test Name:      Buffer Sizes: 1025, 1025, 1025, 1025
*** Test ID:        1033
*** Library Path:   rwtest

The fix: use our SG buffer in a loop for the overrun case, signaled by dwFlags. 

-- */
DWORD
ScsiRWSG(
    PSCSI_DEVICE    pDevice,
    PSG_REQ         pSgReq,
    UCHAR           Lun,
    BOOL            bRead
    )
{
    DWORD dwTtlTransferLength;
    DWORD dwTtlBytesTransferred = 0;
    DWORD dwFlags = 0;
    DWORD dwErr;

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

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

    EnterCriticalSection(&pDevice->Lock);
    
    dwErr = CheckSegments(pDevice, pSgReq, &dwTtlTransferLength, &dwFlags);
    
    if (ERROR_SUCCESS == dwErr) 
    {
        LONGLONG iTotalSector  = pSgReq->sr_num_sec;
        DWORD    dwStartSector = pSgReq->sr_start;
        HANDLE   hProc         = GetCallerProcess();
        DWORD    dwContigSectors = 0;
        DWORD    dwBytesTransferred = 0;
        DWORD    sg;
        
        // sector aligned buffers require no double buffering
        //
        if (!dwFlags) {
            
            for (sg = 0;
                 sg < pSgReq->sr_num_sg && iTotalSector > 0 &&
                 pSgReq->sr_sglist[sg].sb_buf && pSgReq->sr_sglist[sg].sb_len;
                 sg++)
            {
                // map the current user buffer into our context if necessary
                PVOID pBuffer = (hProc == pDevice->hProc) ? pSgReq->sr_sglist[sg].sb_buf :
                                MapPtrToProcess((LPVOID)pSgReq->sr_sglist[sg].sb_buf, hProc);

                ASSERT((pSgReq->sr_sglist[sg].sb_len % pDevice->DiskInfo.di_bytes_per_sect) == 0);
                
                // get the number of contigious sectors we can transfer
                dwContigSectors = min((pSgReq->sr_sglist[sg].sb_len / pDevice->DiskInfo.di_bytes_per_sect),
                                      (DWORD)iTotalSector);

                dwBytesTransferred = pSgReq->sr_sglist[sg].sb_len;

                ASSERT(dwContigSectors);
                ASSERT(dwContigSectors <= iTotalSector);
                ASSERT(pBuffer);
            
                DEBUGMSG(ZONE_READ,(TEXT("Scsi%sSG[%d] dwStartSector:%d, dwContigSectors:%d\n"),
                    bRead ? TEXT("Read") : TEXT("Write"), sg, dwStartSector, dwContigSectors));

                //
                // transfer contigious sector segments
                //
                dwErr = ScsiReadWrite( pDevice,
                                        dwStartSector,
                                        dwContigSectors,
                                        pBuffer,
                                        &dwBytesTransferred,
                                        Lun, 
                                        bRead );

                if ( ERROR_SUCCESS == dwErr ) 
                {
                    iTotalSector  -= dwContigSectors;
                    dwStartSector += dwContigSectors;

                    ASSERT(iTotalSector >= 0);

                    pBuffer = (PVOID)((PUCHAR)pBuffer + dwBytesTransferred);

                    dwTtlBytesTransferred += dwBytesTransferred;

                } else {
                    DEBUGMSG(ZONE_ERR,(TEXT("ScsiRWSG ERROR:%d\n"), dwErr));
                    break;
                }
            }
        
        } else {
            //
            // Double Buffering
            //
            DWORD offset;

            dwContigSectors = pSgReq->sr_num_sec;
            dwBytesTransferred = dwContigSectors * pDevice->DiskInfo.di_bytes_per_sect;

            ASSERT(dwBytesTransferred <= SG_BUFF_SIZE);

            // BUGBUG: we need to use our SG buffer in a loop here for test case 1033
            // when overrun our SG buffer as set by the flags above.
            memset(&pDevice->SgBuff[0], 0, dwBytesTransferred);

            //
            // pre-copy all the write data into our local sg buffer
            //
            if (!bRead) 
            {
                for (sg = 0, offset = 0; sg < pSgReq->sr_num_sg; sg++) 
                {
                    // map the current buffer into our context if necessary
                    PVOID pBuffer = (hProc == pDevice->hProc) ? pSgReq->sr_sglist[sg].sb_buf :
                                    MapPtrToProcess((LPVOID)pSgReq->sr_sglist[sg].sb_buf, hProc);

                    memcpy(&pDevice->SgBuff[offset], pBuffer, pSgReq->sr_sglist[sg].sb_len);

                    offset += pSgReq->sr_sglist[sg].sb_len;
                }
            }

            DEBUGMSG(ZONE_READ,(TEXT("Scsi%sSG: dwStartSector:%d, dwContigSectors:%d, bBuffered:%d\n"),
                        bRead ? TEXT("Read") : TEXT("Write"), dwStartSector, dwContigSectors, dwFlags));

            //
            // transfer contigious sector segments
            //
            dwErr = ScsiReadWrite( pDevice,
                                    dwStartSector,
                                    dwContigSectors,
                                    &pDevice->SgBuff[0],
                                    &dwBytesTransferred,
                                    Lun, 
                                    bRead );

            if ( ERROR_SUCCESS == dwErr ) 
            {
                dwTtlBytesTransferred += dwBytesTransferred;

                //
                // post-copy all the read data from our local sg buffer
                //
                if (bRead) 
                {
                    for (sg = 0, offset = 0; sg < pSgReq->sr_num_sg; sg++) 
                    {
                        // map the current buffer into our context if necessary
                        PVOID pBuffer = (hProc == pDevice->hProc) ? pSgReq->sr_sglist[sg].sb_buf :
                                        MapPtrToProcess((LPVOID)pSgReq->sr_sglist[sg].sb_buf, hProc);

                        memcpy(pBuffer, &pDevice->SgBuff[offset], pSgReq->sr_sglist[sg].sb_len);

                        offset += pSgReq->sr_sglist[sg].sb_len;
                    }
                }
                
            } else {
                DEBUGMSG(ZONE_ERR,(TEXT("ScsiRWSG ERROR:%d\n"), dwErr));
            }
        }
               
    } else {
        DEBUGMSG(ZONE_ERR,(TEXT("CheckSegments ERROR:%d\n"),dwErr));
    }

    //
    // set Win32 status
    //
    pSgReq->sr_status = dwErr;

    LeaveCriticalSection(&pDevice->Lock);

    ReleaseRemoveLock(&pDevice->RemoveLock, NULL);

    DEBUGMSG(ZONE_TRACE,(TEXT("USBMSC<ScsiRWSG:%d\n"), dwErr));
    
    return dwTtlBytesTransferred;
}


/* ++

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: inlalid 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 = dwNumSectors * (bRead ? pDevice->Timeouts.ReadSector : pDevice->Timeouts.WriteSector);
    tCommand.Length = USBMSC_SUBCLASS_SCSI == pDevice->DiskSubClass ? SCSI_CDB_10 : UFI_CDB;
    tCommand.CommandBlock = bCDB;

    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 {
        // since we do retries we also have to (re)poke the device
        dwErr = ScsiUnitAttention(pDevice, pDevice->Lun);
        if (ERROR_SUCCESS != dwErr) 
            break;

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

        if ( ERROR_SUCCESS == dwErr ) {

            *pdwTransferSize = tData.TransferLength;

        } else {
        
            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 + -