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

📄 satadrv.c

📁 vxworks下SATA控制器SIL3124A的驱动代码
💻 C
📖 第 1 页 / 共 4 页
字号:
#include "vxWorks.h"
#include "sataDrv.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "logLib.h"
#include "wdLib.h"
#include "memLib.h"
#include "ioLib.h"
#include "cacheLib.h"
#include "m8260IntrCtl.h"
#include "pciConfigLib.h"
#include "taskLib.h"
#include "errnoLib.h"
#include "private/semLibP.h"
#include "intLib.h"
#include "iv.h"
#include "sysLib.h"
#include "fcntl.h"
#include "sys/fcntlcom.h"
#include "drv/pcmcia/pcmciaLib.h"
#include "config.h"

/* Driver debug control */

#define MOT_SATA_DBG
#define MOT_SATA_DBG_OFF                 0x00000
#define MOT_SATA_DBG_DRV                 0x00001
#define MOT_SATA_DBG_INIT                0x00002
#define MOT_SATA_DBG_IDENT               0x00004
#define MOT_SATA_DBG_PRESENT             0x00008
#define MOT_SATA_DBG_READY               0x00010
#define MOT_SATA_DBG_DRESET              0x00020
#define MOT_SATA_DBG_DINIT               0x00040
#define MOT_SATA_DBG_SRESET              0x00080
#define MOT_SATA_DBG_WDOG              	 0x00100
#define MOT_SATA_DBG_SATACMD           	 0x00200
#define MOT_SATA_DBG_SATAINIT          	 0x00400
#define MOT_SATA_DBG_SATASTAT          	 0x00800
#define MOT_SATA_DBG_SATAINTR          	 0x01000
#define MOT_SATA_DBG_SATABRW          	 0x02000
#define MOT_SATA_DBG_SATAIOCTL         	 0x04000
#define MOT_SATA_DBG_SATARESET         	 0x08000
#define MOT_SATA_DBG_CREATE         	   0x10000
#define MOT_SATA_DBG_SSTAT							 0x20000
#define MOT_SATA_DBG_PREAD							 0x40000
#define MOT_SATA_DBG_SATARAW						 0x80000

UINT32  motSataDbg = 0x0;
typedef volatile INT32 VINT32; /* volatile unsigned word */

#define MOT_SATA_LOG(FLG, X0, X1, X2, X3, X4, X5, X6)        \
    {                                                        \
    if (motSataDbg & FLG)                                    \
            logMsg (X0, X1, X2, X3, X4, X5, X6);         		 \
    }

SIL24_SATA_BLOCK *sata_cmd_block = NULL;
SATA_CTRL  sataCtrl [SATA_MAX_CTRLS];
BOOL	  sataDrvInstalled = FALSE;	/* TRUE if installed */
BOOL	  ataForceCHSonLBA = FALSE;	/* hack, forces use of CHS params */
LOCAL int       ataRetry = 3;		/* max retry count */
static int ourRwMode = ATA_PIO;

/* Used to hold LBA information, if larger than calculated CHS value */
LOCAL UINT32 ataLbaTotalSecs [SATA_MAX_CTRLS][SATA_MAX_DRIVES];


IMPORT ATA_RESOURCE	sataResources [SATA_MAX_CTRLS];
IMPORT SATA_TYPE		sataTypes [SATA_MAX_CTRLS][SATA_MAX_DRIVES];

STATUS sataDriveInit(int	ctrl, int	drive);
STATUS sataDevIdentify (int ctrl, int drive);
STATUS Sata_Device_Present(int ctrl, int drive);
STATUS Sata_Device_Ready(int ctrl, int drive);
STATUS Sata_Device_Reset(int ctrl, int drive);
STATUS Sata_Port_Initialize(int ctrl, int drive);
STATUS Sata_Port_SoftReset(int ctrl, int drive);
LOCAL void sataWdog(int ctrl);
LOCAL STATUS sataCmd	(int ctrl, int drive, int cmd, int arg0, int arg1);
LOCAL STATUS sataInit (int ctrl, int dev);
STATUS Sata_Portwait_Status( int ctrl, int drive, UINT32 reg, UINT32 status, BOOL	neg);
void sataIntr(int ctrl);
void sata_port_intr(int ctrl, int portNum);
void sata_error_intr(int ctrl, int portNum);
void sata_update_tf(int ctrl, int drive);	

LOCAL STATUS sataBlkRd	(SATA_DEV *pDev, int startBlk, int nBlks, char *p);
LOCAL STATUS sataBlkWrt	(SATA_DEV *pDev, int startBlk, int nBlks, char *p);
LOCAL STATUS sataReset	(SATA_DEV *pDev);
LOCAL STATUS sataStatus	(SATA_DEV *pDev);
LOCAL STATUS sataIoctl	(SATA_DEV *pDev, int function, int arg);
LOCAL STATUS sataBlkRW	(SATA_DEV *pDev, int startBlk, int nBlks, char *p,
			 int direction);
LOCAL STATUS sataRW	(int ctrl, int drive, int cylinder, int head, int sec, 
	 		 char *p, int nSecs, int direction);
STATUS sataPread(int ctrl, int drive, void *buffer);
IMPORT void sysPciOutLong (UINT32*, UINT32);
IMPORT UINT32 sysPciInLong (UINT32*); 
IMPORT void sysPciOutWord (USHORT *,USHORT);
IMPORT USHORT sysPciInWord(USHORT *);
IMPORT UINT8 sysPciInByte(UINT8 *);
IMPORT UINT32 vxImmrGet (void);

/*******************************************************************************
*
* sataDrv - initialize the SATA driver
*/

STATUS sataDrv
    (
    int  ctrl,			/* controller no. */
    int  drives,		/* number of drives */
    int  vector,		/* interrupt vector */
    int  level,			/* interrupt level */
    int  configType,		/* configuration type */
    int  semTimeout,		/* timeout seconds for sync semaphore */
    int  wdgTimeout		/* timeout seconds for watch dog */
    )
    {
    SATA_CTRL        *pCtrl	= &sataCtrl[ctrl];
    ATA_RESOURCE    *pAta	= &sataResources[ctrl];
    PCCARD_RESOURCE *pResource	= &pAta->resource;
    SATA_DRIVE       *pDrive;
    SATA_PARAM       *pParam;
    SATA_TYPE        *pType;
    int             drive;
    int             ix;
    UINT32 immrVal;

    if ((ctrl >= SATA_MAX_CTRLS) || (drives > SATA_MAX_DRIVES))
			return (ERROR);
		MOT_SATA_LOG (MOT_SATA_DBG_DRV, "Enter into ataDrv\n", 1, 2, 3, 4, 5, 6);
    if (!sataDrvInstalled)
			{

				for (ix = 0; ix < SATA_MAX_CTRLS; ix++)
            sataCtrl[ix].wdgId = wdCreate ();
		
				sata_cmd_block = memalign (8,64);
  			if ( sata_cmd_block == NULL )
  			{
  				MOT_SATA_LOG(MOT_SATA_DBG_DRV,"could not obtain memory!\n",1,2,3,4,5,6);	
  				return (ERROR);
  			}
  			memset(sata_cmd_block, 0, 64);
  			MOT_SATA_LOG(MOT_SATA_DBG_DRV,"sata_cmd_block = 0x%x!\n",(UINT32)sata_cmd_block,2,3,4,5,6);	
    		
    		sataDrvInstalled = TRUE;
			}

    if (!pCtrl->installed)
			{

			if (semTimeout == 0)
	    	pCtrl->semTimeout = SATA_SEM_TIMEOUT_DEF;
			else
	    	pCtrl->semTimeout = semTimeout;

			if (wdgTimeout == 0)
	  	  pCtrl->wdgTimeout = SATA_WDG_TIMEOUT_DEF;
			else
	    	pCtrl->wdgTimeout = wdgTimeout;

       semBInit (&pCtrl->syncSem, SEM_Q_FIFO, SEM_EMPTY);
       semBInit (&pCtrl->rdsyncSem, SEM_Q_FIFO, SEM_EMPTY);
       semMInit (&pCtrl->muteSem, SEM_Q_PRIORITY | SEM_DELETE_SAFE |
	          SEM_INVERSION_SAFE);

			pCtrl->globalAddr	= pResource->ioStart[0];
			pCtrl->portAddr	= pResource->ioStart[1];
			pCtrl->intLevel = level;
			pCtrl->wdgOkay  = TRUE;
			pCtrl->configType = configType;

			semTake (&pCtrl->muteSem, WAIT_FOREVER);
			pCtrl->changed = FALSE;
			pCtrl->installed = TRUE;
			pCtrl->drives = drives;
			pCtrl->ctrlType = pAta->ctrlType;
			
			/* GPIO off */
			sysPciOutLong((UINT32*)(pCtrl->globalAddr + HOST_FLASH_CMD),0x00000000);
  		/* Gloabal reset cleared */
  		sysPciOutLong((UINT32*)(pCtrl->globalAddr + HOST_CTRL),0x00000000);
  		 /* Turn on interrupts */
  		sysPciOutLong((UINT32*)(pCtrl->globalAddr + HOST_CTRL),0xf);
     				
			immrVal = vxImmrGet();
		  *M8260_SIEXR(immrVal) |= 0x00000800;
  		*M8260_SIPNR_H(immrVal) |= 0x00000800;
  		
  		(void) intConnect ((VOIDFUNCPTR *)INUM_TO_IVEC (level),
		           (VOIDFUNCPTR)sataIntr, ctrl);
		  intEnable(level);
			
      for (drive = 0; drive < drives; drive++)
	    	{
	    		pType  = &sataTypes[ctrl][drive];
	    		pDrive = &pCtrl->drive[drive];
	    		pParam = &pDrive->param;
          pDrive->state	= SATA_DEV_INIT;
          pDrive->type	= SATA_TYPE_INIT;
          pDrive->diagCode	= 0;
          pDrive->Reset	= sataInit;
          if (sataDriveInit (ctrl, drive) != OK)
          	MOT_SATA_LOG (MOT_SATA_DBG_DRV, "drive %d initialization failed! \n", drive, 2, 3, 4, 5, 6);
          	
        }
     	semGive (&pCtrl->muteSem);
			}

    return (OK);
    }

/*******************************************************************************
*
* sataDriveInit - initialize SATA drive
*
* This routine checks the drive presents, identifies its type, initializes the 
* drive controller and driver control structers.
*
* RETURNS: OK if drive was initialized successfuly, or ERROR.
*/

STATUS sataDriveInit
    (
    int	ctrl,
    int	drive
    )
    {
    SATA_CTRL    *pCtrl		= &sataCtrl[ctrl];
    SATA_DRIVE   *pDrive		= &pCtrl->drive[drive];
    SATA_PARAM   *pParam		= &pDrive->param;
    SATA_TYPE    *pType		= &sataTypes[ctrl][drive];
    int		configType	= pCtrl->configType;	/* configuration type */
    int tmp;
    
    MOT_SATA_LOG (MOT_SATA_DBG_INIT, "Enter into ataDriveInit! \n", 1, 2, 3, 4, 5, 6);
		if (!pCtrl->installed)
        return (ERROR);

    if (pType->cylinders == 0)
        return (ERROR);		/* user specified the device as not present */

    semTake (&pCtrl->muteSem, WAIT_FOREVER);
    
    /* initialize PHY setting */
  	sysPciOutLong((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + PORT_PHY_CFG),0x0000020c);
  
  	/* clear port reset */
  	tmp = sysPciInLong ((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE +PORT_CTRL_STAT));
  	if(tmp & PORT_CS_PORT_RST)
  	{
  		sysPciOutLong ((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE +PORT_CTRL_CLR), PORT_CS_PORT_RST);
  		if(Sata_Portwait_Status(ctrl, drive, PORT_CTRL_STAT, PORT_CS_PORT_RST, TRUE) != OK)
  		{
  				MOT_SATA_LOG(MOT_SATA_DBG_INIT,"Failed to clear port reset!\n",1,2,3,4,5,6);
  				goto driveInitExit;
  		}
  	}
  
  	/* interrupt no clear on read dismissed */
  	sysPciOutLong ((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + PORT_CTRL_CLR), PORT_CS_IRQ_WOC);
  
 	 /* zero error counters */
  	sysPciOutWord ((USHORT*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + PORT_DECODE_ERR_THRESH), 0x8000);
  	sysPciOutWord ((USHORT*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + PORT_CRC_ERR_THRESH), 0x8000);
  	sysPciOutWord ((USHORT*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + PORT_HSHK_ERR_THRESH), 0x8000);
  	sysPciOutWord ((USHORT*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + PORT_DECODE_ERR_CNT), 0x0000);
  	sysPciOutWord ((USHORT*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + PORT_CRC_ERR_CNT), 0x0000);
  	sysPciOutWord ((USHORT*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + PORT_HSHK_ERR_CNT), 0x0000);
  
  	/* 32-bit activation  */
  	sysPciOutLong ((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + PORT_CTRL_STAT), PORT_CS_32BIT_ACTV);
  	
  	/* Clear port multiplier enable and resume bits */
  	sysPciOutLong ((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + PORT_CTRL_CLR), PORT_CS_PMP_EN | PORT_CS_PMP_RESUME);
  
  	/* enable port  command completion and command error interrupt  */
  	sysPciOutLong ((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + PORT_IRQ_ENABLE_CLR), 0xffff);
  	sysPciOutLong ((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + PORT_IRQ_ENABLE_SET), PORT_IRQ_COMPLETE | PORT_IRQ_ERROR);
  
  	/* clear interrupts */
  	sysPciOutLong ((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + PORT_IRQ_STAT), 0x0fff0fff);
  

    /* Identify device presence and its type */

    if (sataDevIdentify (ctrl, drive) != OK)
        goto driveInitExit;

    /* Set Reset function according to device type */

    if (pDrive->type == SATA_TYPE_ATA)
        pDrive->Reset = sataInit;
 
    if (pDrive->type == SATA_TYPE_ATA)
        {

        if (sataPread (ctrl, drive, (char *)pParam) == OK)
            {
            	
            	if (sataCmd (ctrl, drive, ATA_CMD_DIAGNOSE, 0, 0) != OK)
		    			{
	            		semGive (&pCtrl->muteSem);

	            		return (ERROR);
		    			}
													
	    			 /* find out geometry */

            if ((configType & ATA_GEO_MASK) == ATA_GEO_PHYSICAL)
                {
                pType->cylinders = pParam->cylinders - 1;
                pType->heads     = pParam->heads;
                pType->sectors   = pParam->sectors;
                }
            else
            		{
            		pType->cylinders = pParam->cylinders - 1;
                pType->heads     = pParam->heads;
                pType->sectors   = pParam->sectors;
            		}
            /* 
             * Not all modern hard drives report a true capacity value 
             * in their IDENTIFY DEVICE CHS fields.
             * For example, a Western Digital 20 Gb drive reports 
             * its CHS as 16383 cylinders, 16 heads, and 63 spt.
             * This is about 8.4GB, but the LBA sectors is reported
             * as 0x02607780, which is closer to 20Gb, the true capacity
             * of the drive.  The reason for this is PC BIOS can have a 
             * 8.4GB limitation, and drive manufacturers have broken the 
             * ATA specification to be compatable.  Negative competition. 
             * Note that the ATA specifications original limit is 
             * about 136.9 Gb, however when combinined with a PC BIOS 
             * interface, a 8.4 Gb limit is produced.    
             * VxWorks does not have such limitations being a true 32bit OS,
             * but since the drive manufactures are not honoring the CHS
             * values, we have to allow for devices that demand "pure" LBA
             * and present incorrect CHS.
             * If the drive supports Logical Block Addresses (LBA)
             * then we need to check the field located at 16bit words 60 & 61,
             * "Total number of user addressable sectors (LBA mode only)". 
             * If this value is greater than the CHS fields report, 
             * then 60-61 holds the true size of the disk and that 
             * will be reported to the block device interface.
             * Note that the CHS values are still left as the disk reported.
             * This is tracked at WRS as SPR#22830
             */

            if (pParam->capabilities & 0x0200)  /* if (drive supports LBA) */
                {
                ataLbaTotalSecs[ctrl][drive] =  (UINT32) 
			((((UINT32) ((pParam->sectors0) & 0x0000ffff)) <<  0) | 
			 (((UINT32) ((pParam->sectors1) & 0x0000ffff)) << 16));

                MOT_SATA_LOG (MOT_SATA_DBG_INIT, "ID_DRIVE reports LBA (60-61) as 0x%08lx\n",
                               ataLbaTotalSecs[ctrl][drive], 2, 3, 4, 5, 6);
                }
             /*
             * reinitialize the controller with parameters read from the
             * controller.
             */

            (void) sataCmd (ctrl, drive, ATA_CMD_INITP, 0, 0);

            /* recalibrate (this command !!! is absent in ATA-4) */

            (void) sataCmd (ctrl, drive, ATA_CMD_RECALIB, 0, 0);
            }
        else
            {
            pDrive->state = SATA_DEV_PREAD_F;
            goto driveInitExit;
            }
        }
    
    /* find out supported capabilities of the drive */

    pDrive->multiSecs = pParam->multiSecs & 0x00ff;
    pDrive->okMulti   = (pDrive->multiSecs != 0) ? TRUE : FALSE;
    pDrive->okIordy   = (pParam->capabilities & 0x0800) ? TRUE : FALSE;
    pDrive->okLba     = (pParam->capabilities & 0x0200) ? TRUE : FALSE;
    pDrive->okDma     = (pParam->capabilities & 0x0100) ? TRUE : FALSE;

    /* find out supported max PIO mode */

    pDrive->pioMode = (pParam->pioMode >> 8) & 0x03;	/* PIO 0,1,2 */

    if (pDrive->pioMode > 2)
        pDrive->pioMode = 0;

    if ((pDrive->okIordy) && (pParam->valid & 0x02))	/* PIO 3,4 */
        {

        	if (pParam->advancedPio & 0x01)
            pDrive->pioMode = 3;

        	if (pParam->advancedPio & 0x02)
            pDrive->pioMode = 4;
        }

    /* find out supported max DMA mode */

    if ( pDrive->okDma )
				{

					if( pParam->valid & 0x02 )
							{
								pDrive->singleDmaMode = (pParam->dmaMode >> 8) & 0x03;
								if (pDrive->singleDmaMode >= 2)
									pDrive->singleDmaMode = 0;
								if (pParam->singleDma & 0x04)
									pDrive->singleDmaMode = 2;
								else if (pParam->singleDma & 0x02)
									pDrive->singleDmaMode = 1;
								else if (pParam->singleDma & 0x01)

⌨️ 快捷键说明

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