📄 atadrv.c
字号:
if ((ctrl >= ATA_MAX_CTRLS) || (drive >= ATA_MAX_DRIVES) ||
!ataDrvInstalled || !pCtrl->installed)
return (NULL);
if ((pDev = (ATA_DEV *)malloc(sizeof (ATA_DEV))) == NULL)
return (NULL);
pBlkdev = &pDev->blkDev;
/*
* 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)))
{
maxBlks = (ataLbaTotalSecs[ctrl][drive]) - blkOffset;
#ifdef ATA_DEBUG
printErr ("Using LBA value: maxBlks =0x%08lx\n", maxBlks);
#endif /* ATA_DEBUG */
}
else /* just use CHS */
{
maxBlks = pParam->sectors1 & 0xfffff;
maxBlks = maxBlks << 16;
maxBlks += pParam->sectors0;
#ifdef ATA_DEBUG
printErr ("Using CHS value: maxBlks =0x%08lx\n", maxBlks);
#endif /* ATA_DEBUG */
}
if (nBlocks == 0)
nBlocks = maxBlks;
if (nBlocks > maxBlks)
nBlocks = maxBlks;
pBlkdev->bd_nBlocks = nBlocks;
pBlkdev->bd_bytesPerBlk = pType->bytes;
pBlkdev->bd_blksPerTrack = pType->sectors;
pBlkdev->bd_nHeads = pType->heads;
pBlkdev->bd_removable = FALSE; //mlg changed from TRUE
pBlkdev->bd_retry = 1;
pBlkdev->bd_mode = O_RDWR;
pBlkdev->bd_readyChanged = TRUE;
pBlkdev->bd_blkRd = ataBlkRd;
pBlkdev->bd_blkWrt = ataBlkWrt;
pBlkdev->bd_ioctl = ataIoctl;
pBlkdev->bd_reset = ataReset;
pBlkdev->bd_statusChk = ataStatus;
pBlkdev->bd_reset = NULL;
pBlkdev->bd_statusChk = NULL;
pDev->ctrl = ctrl;
pDev->drive = drive;
pDev->blkOffset = blkOffset;
return (&pDev->blkDev);
}
/*******************************************************************************
*
* ataRawio - 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 ATA_RAW which is defined in
* ataDrv.h.
*
* RETURNS:
* OK, or ERROR if the parameters are not valid.
*
*/
STATUS ataRawio
(
int ctrl,
int drive,
ATA_RAW *pAtaRaw
)
{
ATA_CTRL *pCtrl = &ataCtrl[ctrl];
ATA_DRIVE *pDrive = &pCtrl->drive[drive];
ATA_TYPE *pType = &ataTypes[ctrl][drive];
ATA_DEV ataDev;
BLK_DEV *pBlkdev = &ataDev.blkDev;
UINT startBlk;
if ((ctrl >= ATA_MAX_CTRLS) || (drive >= ATA_MAX_DRIVES) ||
!ataDrvInstalled || !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 = 1;
pBlkdev->bd_mode = O_RDWR;
pBlkdev->bd_readyChanged = TRUE;
pBlkdev->bd_blkRd = ataBlkRd;
pBlkdev->bd_blkWrt = ataBlkWrt;
pBlkdev->bd_ioctl = ataIoctl;
pBlkdev->bd_reset = ataReset;
pBlkdev->bd_statusChk = ataStatus;
ataDev.ctrl = ctrl;
ataDev.drive = drive;
ataDev.blkOffset = 0;
startBlk = pAtaRaw->cylinder * (pType->sectors * pType->heads) +
pAtaRaw->head * pType->sectors + pAtaRaw->sector - 1;
return (ataBlkRW (&ataDev, startBlk, pAtaRaw->nSecs, pAtaRaw->pBuf,
pAtaRaw->direction));
}
/*******************************************************************************
*
* ataBlkRd - read one or more blocks from a ATA/IDE disk
*
* This routine reads one or more blocks from the specified device,
* starting with the specified block number.
*
* If any block offset was specified during ataDevCreate(), it is added
* to <startBlk> before the transfer takes place.
*
* RETURNS: OK, ERROR if the read command didn't succeed.
*/
LOCAL STATUS ataBlkRd
(
ATA_DEV *pDev,
int startBlk,
int nBlks,
char *pBuf
)
{
return (ataBlkRW (pDev, startBlk, nBlks, pBuf, O_RDONLY));
}
/*******************************************************************************
*
* ataBlkWrt - write one or more blocks to a ATA/IDE disk
*
* This routine writes one or more blocks to the specified device,
* starting with the specified block number.
*
* If any block offset was specified during ataDevCreate(), it is added
* to <startBlk> before the transfer takes place.
*
* RETURNS: OK, ERROR if the write command didn't succeed.
*/
LOCAL STATUS ataBlkWrt
(
ATA_DEV *pDev,
int startBlk,
int nBlks,
char *pBuf
)
{
return (ataBlkRW (pDev, startBlk, nBlks, pBuf, O_WRONLY));
}
/*******************************************************************************
*
* ataReset - reset a ATA/IDE disk controller
*
* This routine resets a ATA/IDE disk controller.
*
* RETURNS: OK, always.
*/
LOCAL STATUS ataReset
(
ATA_DEV *pDev
)
{
ATA_CTRL *pCtrl = &ataCtrl[pDev->ctrl];
if (!pCtrl->installed)
return (ERROR);
semTake (&pCtrl->muteSem, WAIT_FOREVER);
(void) ataInit (pDev->ctrl);
semGive (&pCtrl->muteSem);
return (OK);
}
/*******************************************************************************
*
* ataStatus - check status of a ATA/IDE disk controller
*
* This routine check status of a ATA/IDE disk controller.
*
* RETURNS: OK, ERROR if the card is removed.
*/
LOCAL STATUS ataStatus
(
ATA_DEV *pDev
)
{
ATA_CTRL *pCtrl = &ataCtrl[pDev->ctrl];
BLK_DEV *pBlkdev = &pDev->blkDev;
if (!pCtrl->installed)
return (ERROR);
if (pCtrl->changed)
{
pBlkdev->bd_readyChanged = TRUE;
pCtrl->changed = FALSE;
}
return (OK);
}
/*******************************************************************************
*
* ataIoctl - do device specific control function
*
* This routine is called when the file system cannot handle an ioctl()
* function.
*
* RETURNS: OK or ERROR.
*/
LOCAL STATUS ataIoctl
(
ATA_DEV *pDev,
int function,
int arg
)
{
ATA_CTRL *pCtrl = &ataCtrl[pDev->ctrl];
FAST int status = ERROR;
if (!pCtrl->installed)
return (ERROR);
semTake (&pCtrl->muteSem, WAIT_FOREVER);
switch (function)
{
case FIODISKFORMAT:
(void) errnoSet (S_ioLib_UNKNOWN_REQUEST);
break;
default:
(void) errnoSet (S_ioLib_UNKNOWN_REQUEST);
}
semGive (&pCtrl->muteSem);
return (status);
}
/*******************************************************************************
*
* ataBlkRW - read or write sectors to a ATA/IDE disk.
*
* Read or write sectors to a ATA/IDE disk.
*
* RETURNS: OK, ERROR if the command didn't succeed.
*/
LOCAL STATUS ataBlkRW
(
ATA_DEV *pDev,
int startBlk,
int nBlks,
char *pBuf,
int direction
)
{
ATA_CTRL *pCtrl = &ataCtrl[pDev->ctrl];
ATA_DRIVE *pDrive = &pCtrl->drive[pDev->drive];
BLK_DEV *pBlkdev = &pDev->blkDev;
int status = ERROR;
int retryRW0 = 0;
int retryRW1 = 0;
int retrySeek = 0;
int cylinder;
int head;
int sector;
int nSecs;
int ix;
/* sanity check */
if (!pCtrl->installed)
return (ERROR);
nSecs = pBlkdev->bd_nBlocks;
if ((startBlk + nBlks) > nSecs)
{
#ifdef ATA_DEBUG
printErr ("startBlk=%d nBlks=%d: 0 - %d\n", startBlk, nBlks, nSecs);
#endif /* ATA_DEBUG */
return (ERROR);
}
startBlk += pDev->blkOffset;
semTake (&pCtrl->muteSem, WAIT_FOREVER);
for (ix = 0; ix < nBlks; ix += nSecs)
{
if (pDrive->okLba)
{
head = (startBlk & 0x0f000000) >> 24;
cylinder = (startBlk & 0x00ffff00) >> 8;
sector = (startBlk & 0x000000ff);
}
else
{
cylinder = startBlk / (pBlkdev->bd_blksPerTrack * pBlkdev->bd_nHeads);
sector = startBlk % (pBlkdev->bd_blksPerTrack * pBlkdev->bd_nHeads);
head = sector / pBlkdev->bd_blksPerTrack;
sector = sector % pBlkdev->bd_blksPerTrack + 1;
}
nSecs = min (nBlks - ix, ATA_MAX_RW_SECTORS);
retryRW1 = 3;
retryRW0 = 3;
while (ataRW(pDev->ctrl, pDev->drive, cylinder, head, sector,
pBuf, nSecs, direction) != OK)
{
if (++retryRW0 > ataRetry)
{
(void)ataCmd (pDev->ctrl, pDev->drive, ATA_CMD_RECALIB, NULL,
NULL);
if (++retryRW1 > ataRetry)
goto done;
retrySeek = 0;
while (ataCmd (pDev->ctrl, pDev->drive, ATA_CMD_SEEK, cylinder,
head) != OK)
if (++retrySeek > ataRetry)
goto done;
retryRW0 = 0;
}
}
startBlk += nSecs;
pBuf += pBlkdev->bd_bytesPerBlk * nSecs;
}
status = OK;
done:
if (status == ERROR)
(void)errnoSet (S_ioLib_DEVICE_ERROR);
semGive (&pCtrl->muteSem);
return (status);
}
/*******************************************************************************
*
* ataIntr - ATA/IDE controller interrupt handler.
*
* RETURNS: N/A
*/
void ataIntr
(
int ctrl
)
{
ATA_CTRL *pCtrl = &ataCtrl[ctrl];
// UINT8 status;
// this check kills performance so I am commenting it out
// status = sysInByte( busMasterRegs + BM_STATUS_REG);
// if (status & 0x4)
// sysOutByte(busMasterRegs+BM_STATUS_REG,status);
pCtrl->intStatus = sysInByte (pCtrl->status);
#ifdef ATA_DEBUG
logMsg("ataIntr: status = 0x%x\n",pCtrl->intStatus,0,0,0,0,0);
#endif
pCtrl->intCount++;
semGive (&pCtrl->syncSem);
}
/*******************************************************************************
*
* ataWdog - ATA/IDE controller watchdog handler.
*
* RETURNS: N/A
*/
LOCAL void ataWdog
(
int ctrl
)
{
volatile ATA_CTRL *pCtrl = (volatile ATA_CTRL *)&ataCtrl[ctrl];
pCtrl->wdgOkay = FALSE;
}
/*******************************************************************************
*
* ataWait - wait the drive ready
*
* Wait the drive ready
*
* RETURNS: OK, ERROR if the drive didn't become ready in certain period of time.
*/
extern BOOL kernelState;
LOCAL void ataWait
(
int ctrl,
int request
)
{
volatile ATA_CTRL *pCtrl = (volatile ATA_CTRL *)&ataCtrl[ctrl];
#ifdef ATA_DEBUG
printErr ("ataWait: ctrl=%d request=0x%x\n", ctrl, request);
#endif /* ATA_DEBUG */
switch (request)
{
case ATA_STAT_READY:
wdStart (pCtrl->wdgId, (sysClkRateGet() * pCtrl->wdgTimeout),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -