📄 satadrv.c
字号:
#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 + -