📄 atadrv.c
字号:
/*******************************************************************************
*
* ataRW - read/write a number of sectors on the current track
*
* Read/write a number of sectors on the current track
*
* RETURNS: OK, ERROR if the command didn't succeed.
*/
LOCAL STATUS ataRW
(
int ctrl,
int drive,
int cylinder,
int head,
int sector,
void *buffer,
int nSecs,
int direction
)
{
ATA_CTRL *pCtrl = &ataCtrl[ctrl];
ATA_DRIVE *pDrive = &pCtrl->drive[drive];
ATA_TYPE *pType = &ataTypes[ctrl][drive];
int retryCount = 0;
int block = 1;
int nSectors;
int nWords;
int semStatus;
short *pBuf;
ATA_DEBUG_MSG (2, "ataRW: ctrl=%d drive=%d c=%d h=%d s=%d buf=0x%x ",
ctrl, drive, cylinder, head, sector, (int)buffer);
ATA_DEBUG_MSG (2, "n=%d dir=%d\n", nSecs, direction, 0, 0, 0, 0);
retryRW:
ataWait (ctrl, ATA_STAT_READY);
pBuf = (short *)buffer;
nSectors = nSecs;
ATA_IO_BYTE_WRITE (pCtrl->feature, pType->precomp);
ATA_IO_BYTE_WRITE (pCtrl->seccnt, nSecs);
ATA_IO_BYTE_WRITE (pCtrl->sector, sector);
ATA_IO_BYTE_WRITE (pCtrl->cylLo, cylinder);
ATA_IO_BYTE_WRITE (pCtrl->cylHi, cylinder>>8);
if (pDrive->okLba)
ATA_IO_BYTE_WRITE (pCtrl->sdh,
ATA_SDH_LBA | (drive << 4) | (head & 0xf));
else
ATA_IO_BYTE_WRITE (pCtrl->sdh,
ATA_SDH_IBM | (drive << 4) | (head & 0xf));
if (pDrive->rwPio == ATA_PIO_MULTI)
block = pDrive->multiSecs;
nWords = (pType->bytes * block) >> 1;
if (direction == O_WRONLY)
{
if (pDrive->rwPio == ATA_PIO_MULTI)
ATA_IO_BYTE_WRITE (pCtrl->command, ATA_CMD_WRITE_MULTI);
else
ATA_IO_BYTE_WRITE (pCtrl->command, ATA_CMD_WRITE);
while (nSectors > 0)
{
if ((pDrive->rwPio == ATA_PIO_MULTI) && (nSectors < block))
{
block = nSectors;
nWords = (pType->bytes * block) >> 1;
}
ataWait (ctrl, ATA_STAT_BUSY);
ataWait (ctrl, ATA_STAT_DRQ);
if (pDrive->rwBits == ATA_BITS_16)
ATA_IO_NWORD_WRITE (pCtrl->data, pBuf, nWords);
else
ATA_IO_NLONG_WRITE (pCtrl->data, (long *)pBuf, nWords >> 1);
semStatus = semTake (&pCtrl->syncSem,
sysClkRateGet() * pCtrl->semTimeout);
if ((pCtrl->intStatus & ATA_STAT_ERR) || (semStatus == ERROR))
goto errorRW;
pBuf += nWords;
nSectors -= block;
}
}
else
{
if (pDrive->rwPio == ATA_PIO_MULTI)
ATA_IO_BYTE_WRITE (pCtrl->command, ATA_CMD_READ_MULTI);
else
ATA_IO_BYTE_WRITE (pCtrl->command, ATA_CMD_READ);
while (nSectors > 0)
{
if ((pDrive->rwPio == ATA_PIO_MULTI) && (nSectors < block))
{
block = nSectors;
nWords = (pType->bytes * block) >> 1;
}
semStatus = semTake (&pCtrl->syncSem,
sysClkRateGet() * pCtrl->semTimeout);
if ((pCtrl->intStatus & ATA_STAT_ERR) || (semStatus == ERROR))
goto errorRW;
ataWait (ctrl, ATA_STAT_BUSY); /* wait for slow disk */
ataWait (ctrl, ATA_STAT_DRQ);
if (pDrive->rwBits == ATA_BITS_16)
ATA_IO_NWORD_READ (pCtrl->data, pBuf, nWords);
else
ATA_IO_NLONG_READ (pCtrl->data, (long *)pBuf, nWords >> 1);
pBuf += nWords;
nSectors -= block;
}
}
ATA_DEBUG_MSG (2, "ataRW: end\n", 0, 0, 0, 0, 0, 0);
return (OK);
errorRW:
ATA_DEBUG_MSG (1, "ataRW err: stat=0x%x 0x%x semStatus=%d error=0x%x\n",
pCtrl->intStatus, ATA_IO_BYTE_READ (pCtrl->aStatus),
semStatus, ATA_IO_BYTE_READ (pCtrl->error), 0, 0);
if (++retryCount < ataRetry)
goto retryRW;
return (ERROR);
}
/******************************* ATAPI Devices *********************************/
/*******************************************************************************
*
* ataDevIdentify - identify device
*
* This routine checks whether the device is connected to the controller, and if
* so determines its type. The routine set `type' field in the corresponding
* ATA_DRIVE structure.
* If device identification failed, the routine set `state' field in the
* corresponding ATA_DRIVE structure to ATA_DEV_NONE.
*
* RETURNS: TRUE if a device is present, FALSE otherwise
*/
STATUS ataDevIdentify
(
int ctrl,
int dev
)
{
ATA_CTRL *pCtrl = &ataCtrl[ctrl];
ATA_DRIVE *pDrive = &pCtrl->drive [dev];
ATA_PARAM *pParam = &pDrive->param;
pDrive->type = ATA_TYPE_NONE;
/* Select device */
ATA_IO_BYTE_WRITE (pCtrl->sdh, ATA_SDH_IBM | (dev << 4));
/* Wait for device selection */
ATA_WAIT_STATUS;
/* Clear semaphore: Selection of nonexistent device may rise an interrupt */
semTake (&pCtrl->syncSem, NO_WAIT);
ATA_IO_BYTE_WRITE (pCtrl->seccnt, 0xaa);
ATA_IO_BYTE_WRITE (pCtrl->sector, 0x55);
if (ATA_IO_BYTE_READ (pCtrl->seccnt) == 0xaa)
{
if (ataPiPread (ctrl, dev, pParam) == OK)
{
pDrive->type = ATA_TYPE_ATAPI;
}
else
if ( ((ATA_IO_BYTE_READ (ATAPI_STATUS) & (ATA_STAT_BUSY |
ATA_STAT_WRTFLT | ATA_STAT_DRQ | ATA_STAT_ERR)) ==
ATA_STAT_ERR) &&
(ATA_IO_BYTE_READ (ATAPI_ERROR) == ERR_ABRT) )
{
if (ataPiWait (ctrl, ATA_STAT_READY, FALSE) == OK)
pDrive->type = ATA_TYPE_ATA;
}
}
if (pDrive->type != ATA_TYPE_NONE)
return (OK);
ATA_DEBUG_MSG (1, "ataDevIdentify%d/%d: ERROR: status=0x%x dev=0x%x "
"error=0x%x\n", ctrl, dev, ATA_IO_BYTE_READ (pCtrl->status),
ATA_IO_BYTE_READ (pCtrl->sdh),
ATA_IO_BYTE_READ (pCtrl->error), 0);
/* Select present device */
ATA_IO_BYTE_WRITE (pCtrl->sdh, ATA_SDH_IBM | (((~dev) & 0x1) << 4)); /* define macro for 0x1 */
pDrive->state = ATA_DEV_NONE;
return (ERROR);
} /* ataDevIdentify */
/*******************************************************************************
*
* ataPiInit - init a ATAPI CD-ROM disk controller
*
* This routine resets a ATAPI CD-ROM disk controller.
*
* RETURNS: OK, ERROR if the command didn't succeed.
*/
LOCAL STATUS ataPiInit
(
int ctrl,
int drive
)
{
ATA_CTRL *pCtrl = &ataCtrl[ctrl];
int retryCount = 0;
int i;
ATA_DEBUG_MSG (2, "ataPiInit%d/%d: \n", ctrl, drive, 0, 0, 0, 0);
while (TRUE) /* Forever */
{
ATA_IO_BYTE_WRITE (ATAPI_D_SELECT, DSEL_FILLER | (drive << 4));
ATA_WAIT_STATUS;
ATA_IO_BYTE_WRITE (ATAPI_COMMAND, ATA_PI_CMD_SRST);
for (i = 0; i < 5000; i++) /* 2 ms */
{
ATA_WAIT_STATUS;
}
ATA_IO_BYTE_WRITE (ATAPI_D_SELECT, DSEL_FILLER | (drive << 4));
ATA_WAIT_STATUS;
pCtrl->wdgOkay = TRUE;
wdStart (pCtrl->wdgId, (sysClkRateGet() * pCtrl->wdgTimeout),
(FUNCPTR)ataWdog, ctrl);
while ( (ATA_IO_BYTE_READ (ATAPI_STATUS) & (ATA_STAT_BUSY |
ATA_STAT_READY | ATA_STAT_WRTFLT | ATA_STAT_DRQ |
ATA_STAT_ECCCOR | ATA_STAT_ERR)) && (pCtrl->wdgOkay) )
;
wdCancel (pCtrl->wdgId);
if (pCtrl->wdgOkay)
break;
pCtrl->wdgOkay = TRUE;
ATA_DEBUG_MSG (1, "ataPiInit%d/%d: ERROR: status=0x%x error=0x%x\n",
ctrl, drive, ATA_IO_BYTE_READ(ATAPI_STATUS),
ATA_IO_BYTE_READ(ATAPI_ERROR), 0, 0);
if (++retryCount == ataRetry)
return (ERROR);
}
/* The following allow to recover after accidental interrupt */
if (semTake (&pCtrl->syncSem, NO_WAIT) == OK)
{
ATA_DEBUG_MSG (2, "ataPiInit%d/%d: WARNING: interrupt cleared: "
"status=0x%x dev=0x%x error=0x%x\n", ctrl, drive,
ATA_IO_BYTE_READ(ATAPI_STATUS),
ATA_IO_BYTE_READ(ATAPI_D_SELECT),
ATA_IO_BYTE_READ(ATAPI_ERROR), 0);
}
else
{
ATA_DEBUG_MSG (2, "ataPiInit%d/%d: Ok: status=0x%x dev=0x%x error=0x%x"
"\n", ctrl, drive, ATA_IO_BYTE_READ(ATAPI_STATUS),
ATA_IO_BYTE_READ(ATAPI_D_SELECT),
ATA_IO_BYTE_READ(ATAPI_ERROR), 0);
}
return (OK);
} /* ataPiInit */
/*******************************************************************************
*
* ataPiPread - Read ATAPI drive parameters
*
* This routine reads drive parameters.
*
* RETURNS: OK, ERROR if the command didn't succeed.
*/
LOCAL STATUS ataPiPread
(
int ctrl,
int drive,
void *buffer
)
{
ATA_CTRL *pCtrl = &ataCtrl[ctrl];
int status;
int error;
int semStatus;
ATA_DEBUG_MSG (2, "ataPiPread%d/%d: \n", ctrl, drive, 0, 0, 0, 0);
ataPiWait (ctrl, ATA_STAT_ACCESS, TRUE);
/* Select device */
ATA_IO_BYTE_WRITE (ATAPI_D_SELECT, DSEL_FILLER | (drive << 4));
ATA_WAIT_STATUS;
if (ataPiWait (ctrl, ATA_STAT_ACCESS, TRUE) != OK)
{
ATA_IO_BYTE_WRITE (ATAPI_D_SELECT, DSEL_FILLER | (drive << 4));;
ATA_WAIT_STATUS;
}
/* ATAPI Identify Device Command */
ATA_IO_BYTE_WRITE (ATAPI_COMMAND, ATA_PI_CMD_IDENTD);
ATA_WAIT_STATUS;
/*
* Poll Status Register instead of wait for interrupt to avoid needless
* delay.
*/
ataPiWait (ctrl, ATA_STAT_BUSY, FALSE);
semStatus = semTake (&pCtrl->syncSem, 1);
status = ATA_IO_BYTE_READ (ATAPI_STATUS);
if ( (status & ATA_STAT_ERR) || !(status & ATA_STAT_DRQ) ||
(semStatus != OK) )
{
error = ATA_IO_BYTE_READ (ATAPI_ERROR);
ATA_DEBUG_MSG (1, "ataPiPread%d/%d: ERROR: status=0x%x intStatus=0x%x "
"error=0x%x semStatus=%d\n", ctrl, drive, status,
pCtrl->intStatus, error, semStatus);
return (ERROR);
}
/* Receive parameter information from the drive */
ATA_IO_NWORD_READ_SWAP (ATAPI_DATA, (short *)buffer,
sizeof(ATA_PARAM)/sizeof(short));
/* To prevent from reading status before it is valid */
ATA_IO_BYTE_READ (pCtrl->aStatus);
/* Wait for device to be ready !!! */
ataPiWait (ctrl, ATA_STAT_READY, TRUE);
ATA_DEBUG_MSG (2, "ataPiPread%d/%d:Ok: status=0x%x devReg=0x%x\n",
ctrl, drive, ATA_IO_BYTE_READ (pCtrl->status),
ATA_IO_BYTE_READ (pCtrl->sdh), 0, 0);
return (OK);
} /* ataPiPread */
/*******************************************************************************
*
* atapiDMAInit - initialize the DMA engine
*
* This routine initializes the DMA engine.
*
* RETURN: OK, or ERROR
*/
LOCAL STATUS atapiDMAInit (void)
{
printErr("ATAPI (DMA Init.) ERROR: DMA transfer is not emplemented.\n");
return ERROR;
}
/*******************************************************************************
*
* atapiDMATransfer - transfer a single data packet via DMA
*
* This routine transfers a single data packet via DMA.
*
* RETURN: OK, or ERROR
*
* SEE ALSO: ataPiPIOTransfer()
*/
LOCAL STATUS atapiDMATransfer
(
ATA_DEV *pAtapiDev
)
{
pAtapiDev->errNum = 27;
return ERROR;
}
/*******************************************************************************
*
* ataPiOverlapTransferLoop - loop for DRQ Interrupts with Overlapping
*
* This routine loops for Data Request Interrupts until all data packets are
* transferred. It is invoked when ataPiPktCmd() executes an Overlapped command.
* When Device executes an Overlapped command, it releases the ATA bus until the
* device is ready to transfer a data or to present the completion status.
*
* RETURN: OK, or ERROR
*
* SEE ALSO: ataPiNonOv
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -