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

📄 scsi2.c

📁 Windows CE 5.0下的U盘驱动源代码。
💻 C
📖 第 1 页 / 共 4 页
字号:
    Returns: If fail, Win32 error.
             If pass, total number of bytes transferred.
                 Completion status returned in pSqReq->sr_status.    
--*/
DWORD
ScsiRWSG(
    PSCSI_DEVICE pDevice,
    PSG_REQ pSgReq,
    UCHAR Lun,
    BOOL bRead
    )
{
    UINT uiExpectedBytesXferred = 0; // Expected total size of transfer (bytes).
    UINT uiActualBytesXferred = 0;   // Actual total size of transfer (bytes).
    DWORD dwFlags = 0;               // Flags indicating need for double buffering.
    DWORD dwErr;                     // Error code.

    DEBUGMSG(ZONE_TRACE,(TEXT("USBMSC>ScsiRWSG\n")));
	
    //
    // Don't trust pSqReq.
    //
	dwErr = InspectSgReq(pSgReq, pDevice->DiskInfo.di_bytes_per_sect);
	if (dwErr != ERROR_SUCCESS) {		
        DEBUGMSG(ZONE_ERR, (TEXT("USBMSC>ScsiRWSG: Invalid SG_REQ (%d)\r\n"), dwErr));
		return dwErr;
    }
	
    dwErr = AcquireRemoveLock(&pDevice->RemoveLock, NULL);
    if (ERROR_SUCCESS != dwErr) {
		DEBUGMSG(ZONE_ERR, (TEXT("USBMSC>ScsiRWSG: AcquireRemoveLock failed. Error: %d\n"), dwErr));
        return dwErr;
    }
	
    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.
		
        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++) {
				
                //
				// Map the caller's buffer into our context, if necessary.
				//
                PVOID pBuffer = MapCallerPtr((LPVOID)pSgReq->sr_sglist[sg].sb_buf, pSgReq->sr_sglist[sg].sb_len);
                if (pSgReq->sr_sglist[sg].sb_buf != NULL && pBuffer == NULL) {
                    DEBUGMSG(ZONE_ERR,(TEXT("USBMSC>ScsiRWSG: Security violation\r\n")));
                    return ERROR_ACCESS_DENIED;
                }
				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);				
                if (ERROR_SUCCESS == dwErr) {
					llSectorsRemaining  -= uiSectorsToXfer;
					ASSERT(llSectorsRemaining >= 0);
                    uiStartingSector += uiSectorsToXfer;                    
                    pBuffer = (PVOID) ((PUCHAR) pBuffer + uiBytesXferred);
                    uiActualBytesXferred += uiBytesXferred;
                }
                else {
                    LeaveCriticalSection(&pDevice->Lock);
                    ReleaseRemoveLock(&pDevice->RemoveLock, NULL);
                    DEBUGMSG(ZONE_ERR,(TEXT("USBMSC>ScsiRWSG: ScsiReadWrite failed. Error: %d\n"), dwErr));
                    return dwErr;					
                }                
            }        
        }
		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) {
				
                pucSgBuffOffset = MapCallerPtr((LPVOID)pSgReq->sr_sglist[sg].sb_buf, pSgReq->sr_sglist[sg].sb_len);
                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.
                    //
					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);
						return dwErr;
					}
					uiDbBuffOffset = 0;
                    llSectorsRemaining -= uiSectorsToXfer;
                    uiStartingSector += uiSectorsToXfer;
			        if ((uiBytesXferred != (uiSectorsToXfer * pDevice->DiskInfo.di_bytes_per_sect))) {
						LeaveCriticalSection(&pDevice->Lock);
					    ReleaseRemoveLock(&pDevice->RemoveLock, NULL);
						return ERROR_DISK_OPERATION_FAILED;
			        }
					if (bRead) goto __DbRead;
					goto __DbWrite;
__DbEnd:
                    ;
				}
		    }

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