📄 satadrv.c
字号:
{
MOT_SATA_LOG(MOT_SATA_DBG_DINIT,"device is not initialized!\n",1,2,3,4,5,6);
return (ERROR);
}
MOT_SATA_LOG(MOT_SATA_DBG_DINIT,"device is initialized!\n",1,2,3,4,5,6);
return (OK);
}
STATUS Sata_Device_Ready(int ctrl, int drive)
{
SATA_CTRL *pCtrl = &sataCtrl[ctrl];
sysPciOutLong ((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + PORT_CTRL_STAT), PORT_CS_INIT);
if(Sata_Portwait_Status(ctrl, drive, PORT_CTRL_STAT, PORT_CS_RDY, FALSE) != OK)
{
MOT_SATA_LOG(MOT_SATA_DBG_READY,"device is not ready!\n",1,2,3,4,5,6);
return (ERROR);
}
MOT_SATA_LOG(MOT_SATA_DBG_READY,"device is ready!\n",1,2,3,4,5,6);
return (OK);
}
STATUS Sata_Device_Reset(int ctrl, int drive)
{
SATA_CTRL *pCtrl = &sataCtrl[ctrl];
sysPciOutLong ((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + PORT_CTRL_STAT), PORT_CS_DEV_RST);
if(Sata_Portwait_Status(ctrl, drive, PORT_CTRL_STAT, PORT_CS_DEV_RST, TRUE) != OK)
{
MOT_SATA_LOG(MOT_SATA_DBG_DRESET,"device reset is not Reset!\n",1,2,3,4,5,6);
return (ERROR);
}
MOT_SATA_LOG(MOT_SATA_DBG_DRESET,"device reset is over!\n",1,2,3,4,5,6);
return (OK);
}
STATUS Sata_Port_SoftReset(int ctrl, int drive)
{
UINT32 mask;
int irq_stat;
int tmp;
int slot_stat;
SATA_CTRL *pCtrl = &sataCtrl[ctrl];
if (Sata_Device_Present(ctrl, drive) != OK)
return (ERROR);
if (Sata_Port_Initialize(ctrl, drive) != OK)
return (ERROR);
if (Sata_Device_Ready(ctrl, drive) != OK)
return (ERROR);
/* disable interrupts */
tmp = sysPciInLong ((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + PORT_IRQ_ENABLE_SET));
sysPciOutLong ((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + PORT_IRQ_ENABLE_CLR), tmp);
/* fill in the PRB slot 0 */
sysPciOutLong ((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE ), 0x00000080);
sysPciOutLong ((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + 8 ), 0x00000000);
/* write excutin FIFO */
sysPciOutLong ((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + PORT_EXEC_FIFO), 0x0);
mask = PORT_IRQ_COMPLETE << PORT_IRQ_RAW_SHIFT;
if(Sata_Portwait_Status(ctrl, drive, PORT_IRQ_STAT, mask, FALSE) != OK)
{
MOT_SATA_LOG(MOT_SATA_DBG_SRESET,"device softreset timeout!\n",1,2,3,4,5,6);
return (ERROR);
}
irq_stat = sysPciInLong ((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE +PORT_IRQ_STAT));
irq_stat >>= PORT_IRQ_RAW_SHIFT;
if (!(irq_stat & PORT_IRQ_COMPLETE))
{
if (irq_stat & PORT_IRQ_ERROR)
{
MOT_SATA_LOG(MOT_SATA_DBG_SRESET,"Command excuted error !\n",1,2,3,4,5,6);
return (ERROR);
}
else
{
MOT_SATA_LOG(MOT_SATA_DBG_SRESET,"Command excuted timeout !\n",1,2,3,4,5,6);
return (ERROR);
}
}
/* clear interrupts pending */
slot_stat = sysPciInLong((UINT32 *)(pCtrl->portAddr + drive * PORT_REGS_SIZE + PORT_SLOT_STAT));
sysPciOutLong ((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + PORT_IRQ_STAT), 0x0fff0fff);
sysPciOutLong ((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + PORT_IRQ_ENABLE_SET), tmp);
MOT_SATA_LOG(MOT_SATA_DBG_SRESET,"softreset success !\n",1,2,3,4,5,6);
return (OK);
}
LOCAL void sataWdog(int ctrl)
{
SATA_CTRL *pCtrl = &sataCtrl[ctrl];
MOT_SATA_LOG(MOT_SATA_DBG_WDOG,"softreset success !\n",1,2,3,4,5,6);
pCtrl->wdgOkay = FALSE;
}
STATUS Sata_Portwait_Status( int ctrl, int drive, UINT32 reg, UINT32 status, BOOL neg)
{
SATA_CTRL *pCtrl = &sataCtrl[ctrl];
MOT_SATA_LOG(MOT_SATA_DBG_SATASTAT,"softreset success !\n",1,2,3,4,5,6);
wdStart (pCtrl->wdgId, (sysClkRateGet() * pCtrl->wdgTimeout), (FUNCPTR)sataWdog, ctrl);
if(!neg)
{
while (((sysPciInLong ((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + reg)) & status) != status) && pCtrl->wdgOkay)
;
}
else
{
while (((sysPciInLong ((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + reg)) & status) == status) && pCtrl->wdgOkay)
;
}
wdCancel (pCtrl->wdgId);
if (!pCtrl->wdgOkay)
{
pCtrl->wdgOkay = TRUE;
return (ERROR);
}
return (OK);
}
void sataIntr(int ctrl)
{
UINT32 status;
int portNum = 0;
UINT32 immrVal;
SATA_CTRL *pCtrl = &sataCtrl[ctrl];
pCtrl->intStatus = 0;
/* disable interrupts */
immrVal = vxImmrGet();
*M8260_SIPNR_H(immrVal) |= 0x00000800;
status = sysPciInLong((UINT32*)(pCtrl->globalAddr + HOST_IRQ_STAT));
MOT_SATA_LOG(MOT_SATA_DBG_SATAINTR,"enter into inthandler!\n",1,2,3,4,5,6);
if (status == 0xffffffff)
{
MOT_SATA_LOG(MOT_SATA_DBG_SATAINTR,"PCI fault or device removal?\n",1,2,3,4,5,6);
return;
}
if (!(status & IRQ_STAT_4PORTS))
return;
pCtrl->intCount++;
for(portNum = 0; portNum < SATA_MAX_DRIVES; portNum++)
{
if (status & (1 << portNum))
sata_port_intr(ctrl, portNum);
}
semGive (&pCtrl->syncSem);
return;
}
void sata_port_intr(int ctrl, int portNum)
{
UINT32 slot_status;
SATA_CTRL *pCtrl = &sataCtrl[ctrl];
slot_status = sysPciInLong ((UINT32*)(pCtrl->portAddr + portNum * PORT_REGS_SIZE +PORT_SLOT_STAT));
if(slot_status & HOST_SSTAT_ATTN)
{
sata_error_intr(ctrl, portNum);
return;
}
sata_update_tf(ctrl, portNum);
MOT_SATA_LOG(MOT_SATA_DBG_SATAINTR,"enter into sata_port_intr port = %d!\n",portNum,2,3,4,5,6);
return;
}
void sata_error_intr(int ctrl, int portNum)
{
UINT32 irq_status;
UINT32 cmd_err, sstatus, serror;
SATA_CTRL *pCtrl = &sataCtrl[ctrl];
/* on error, we need to clear IRQ explicitly */
irq_status = sysPciInLong ((UINT32*)(pCtrl->portAddr + portNum * PORT_REGS_SIZE +PORT_IRQ_STAT));
sysPciOutLong ((UINT32*)(pCtrl->portAddr + portNum * PORT_REGS_SIZE + PORT_IRQ_STAT), irq_status);
if (!(irq_status & PORT_IRQ_ERROR))
{
MOT_SATA_LOG(MOT_SATA_DBG_SATAINTR,"non-error exception irq !\n",1,2,3,4,5,6);
return;
}
pCtrl->intStatus = irq_status;
cmd_err = sysPciInLong ((UINT32*)(pCtrl->portAddr + portNum * PORT_REGS_SIZE +PORT_CMD_ERR));
sstatus = sysPciInLong ((UINT32*)(pCtrl->portAddr + portNum * PORT_REGS_SIZE +PORT_SSTATUS));
serror = sysPciInLong ((UINT32*)(pCtrl->portAddr + portNum * PORT_REGS_SIZE +PORT_SERROR));
if(serror)
sysPciOutLong ((UINT32*)(pCtrl->portAddr + portNum * PORT_REGS_SIZE + PORT_SERROR), serror);
if(cmd_err > PORT_CERR_SDB)
MOT_SATA_LOG(MOT_SATA_DBG_SATAINTR,"error interrupt on port%d, irq=0x%x cmd_err=%d sstatus=0x%x serror=0x%x\n",portNum,irq_status,cmd_err,sstatus,serror,6);
if (cmd_err == PORT_CERR_DEV || cmd_err == PORT_CERR_SDB)
{
sata_update_tf(ctrl, portNum);
if (Sata_Device_Ready(ctrl, portNum) != OK)
return;
}
else
{
if (Sata_Device_Reset(ctrl, portNum) != OK)
return;
if (Sata_Device_Ready(ctrl, portNum) != OK)
return;
}
return;
}
void sata_update_tf(int ctrl, int drive)
{
int i;
SATA_CTRL *pCtrl = &sataCtrl[ctrl];
sata_cmd_block->prb.ctrl = sysPciInWord ((USHORT*)(pCtrl->portAddr + drive * PORT_REGS_SIZE));
sata_cmd_block->prb.prot = sysPciInWord ((USHORT*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + 2));
sata_cmd_block->prb.rx_cnt = sysPciInLong ((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + 4));
for(i = 0; i < 24; i++)
sata_cmd_block->prb.fis[i] = sysPciInByte ((UINT8*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + 8 + i));
}
STATUS sataPread(int ctrl, int drive, void *buffer)
{
int semStatus;
SATA_CTRL *pCtrl = &sataCtrl[ctrl];
char *ident_param = NULL;
BOOL retry = TRUE;
int retryCount = 0;
UINT16 *bufPtr;
UINT16 val;
int i;
ident_param = memalign (8, 4096);
if ( ident_param == NULL )
{
MOT_SATA_LOG(MOT_SATA_DBG_PREAD,"could not obtain memory!\n",1,2,3,4,5,6);
return (ERROR);
}
while (retry)
{
memset(ident_param, 0, 4096);
MOT_SATA_LOG(MOT_SATA_DBG_PREAD,"ident_param = 0x%x!\n",(UINT32)ident_param,2,3,4,5,6);
/* fill in the PRB slot 0 */
sysPciOutLong((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE), 0x00000000);
sysPciOutLong((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + 4), 0x00000000);
sysPciOutLong((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + 8), 0x00EC8027);
sysPciOutLong((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + 12), 0xa0000000);
sysPciOutLong((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + 16), 0x00000000);
sysPciOutLong((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + 20), 0x00000000);
sysPciOutLong((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + 24), 0x00000000);
sysPciOutLong((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + 28), 0x00000000);
sysPciOutLong((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + 32), (UINT32)ident_param);
sysPciOutLong((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + 36), 0x00000000);
sysPciOutLong((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + 40), 0x00001000);
sysPciOutLong((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + 44), 0x80000000);
/* write excutin FIFO */
sysPciOutLong ((UINT32*)(pCtrl->portAddr + drive * PORT_REGS_SIZE + PORT_EXEC_FIFO), 0x0);
semStatus = semTake (&pCtrl->syncSem, sysClkRateGet() * pCtrl->semTimeout);
if((semStatus == ERROR) || (pCtrl->intStatus))
{
MOT_SATA_LOG(MOT_SATA_DBG_PREAD,"identify command failed!\n",1,2,3,4,5,6);
if (++retryCount > ataRetry)
{
free(ident_param);
return (ERROR);
}
}
else
retry = FALSE;
}
bufPtr = buffer;
for(i = 0; i < 256; i++)
{
val = *(volatile UINT16 *)(ident_param + i*2);
*(volatile UINT16 *)(bufPtr++) = (val << 8) | (val>>8);
}
free(ident_param);
return (OK);
}
/*******************************************************************************
*
* sataInit
*/
LOCAL STATUS sataInit
(
int ctrl,
int dev
)
{
SATA_CTRL *pCtrl = &sataCtrl[ctrl];
MOT_SATA_LOG(MOT_SATA_DBG_SATAINIT,"enter into sataInit!\n",1,2,3,4,5,6);
if (Sata_Port_SoftReset(ctrl, dev) != OK)
{
pCtrl->wdgOkay = TRUE;
return (ERROR);
}
pCtrl->wdgOkay = TRUE;
/*
* The following allows recovery after an interrupt
* caused by drive software reset
*/
semBInit(&pCtrl->syncSem, SEM_Q_FIFO, SEM_EMPTY);
semBInit(&pCtrl->rdsyncSem, SEM_Q_FIFO, SEM_EMPTY);
MOT_SATA_LOG(MOT_SATA_DBG_SATAINIT,"sataInit end!\n",1,2,3,4,5,6);
return (OK);
}
/*******************************************************************************
*
* sataRawio - do raw I/O access
*
* This routine is called to perform raw I/O access.
*
* <drive> is a drive number for the hard drive: it must be 0 or 1.
*
* The <pAtaRaw> is a pointer to the structure SATA_RAW which is defined in
* sataDrv.h.
*
* RETURNS:
* OK, or ERROR if the parameters are not valid.
*
*/
STATUS sataRawio
(
int ctrl,
int drive,
SATA_RAW *pAtaRaw
)
{
SATA_CTRL *pCtrl = &sataCtrl[ctrl];
SATA_DRIVE *pDrive = &pCtrl->drive[drive];
SATA_TYPE *pType = &sataTypes[ctrl][drive];
SATA_DEV sataDev;
BLK_DEV *pBlkdev = &sataDev.blkDev;
UINT startBlk;
MOT_SATA_LOG(MOT_SATA_DBG_SATARAW,"Enter into ataRawio!\n",1,2,3,4,5,6);
if ((ctrl >= SATA_MAX_CTRLS) || (drive >= SATA_MAX_DRIVES) ||
!sataDrvInstalled || !pCtrl->installed)
return (ERROR);
if ((pAtaRaw->cylinder >= pType->cylinders) ||
(pAtaRaw->head >= pType->heads) ||
(pAtaRaw->sector > pType->sectors) ||
(pAtaRaw->sector == 0))
return (ERROR);
/*
* if LBA is supported and ataLbaTotalSecs is not zero
* and ataLbaTotalSecs is greater than the product of
* CHS, then we should use the LBA value.
*/
if ((pDrive->okLba == TRUE) &&
(ataLbaTotalSecs[ctrl][drive] != 0) &&
(ataForceCHSonLBA != TRUE) &&
(ataLbaTotalSecs[ctrl][drive] >
(pType->cylinders * pType->heads * pType->sectors)))
{
pBlkdev->bd_nBlocks = ataLbaTotalSecs[ctrl][drive];
}
else /* just use CHS value */
{
pBlkdev->bd_nBlocks = pType->cylinders * pType->heads *
pType->sectors;
}
pBlkdev->bd_bytesPerBlk = pType->bytes;
pBlkdev->bd_blksPerTrack = pType->sectors;
pBlkdev->bd_nHeads = pType->heads;
pBlkdev->bd_removable = FALSE;
pBlkdev->bd_retry = 0;
pBlkdev->bd_mode = O_RDWR;
pBlkdev->bd_readyChanged = TRUE;
pBlkdev->bd_blkRd = sataBlkRd;
pBlkdev->bd_blkWrt = sataBlkWrt;
pBlkdev->bd_ioctl = sataIoctl;
pBlkdev->bd_reset = NULL;
pBlkdev->bd_statusChk = NULL;
sataDev.ctrl = ctrl;
sataDev.drive = drive;
sataDev.blkOffset = 0;
startBlk = pAtaRaw->cylinder * (pType->sectors * pType->heads) +
pAtaRaw->head * pType->sectors + pAtaRaw->sector - 1;
return (sataBlkRW (&sataDev, startBlk, pAtaRaw->nSecs, pAtaRaw->pBuf,
pAtaRaw->direction));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -