📄 atadrv.c
字号:
if (ataDevIdentify (ctrl, drive) != OK)
goto driveInitExit;
/* Set Reset function according to device type */
if (pDrive->type == ATA_TYPE_ATA)
pDrive->Reset = ataInit;
else if (pDrive->type == ATA_TYPE_ATAPI)
pDrive->Reset = ataPiInit;
if (pDrive->type == ATA_TYPE_ATA)
{
if (ataPread (ctrl, drive, (char *)pParam) == OK)
{
if ((pCtrl->ctrlType == ATA_PCMCIA) ||
((pCtrl->ctrlType != ATA_PCMCIA) && (drive == 0)))
{
if (ataCmd (ctrl, drive, ATA_CMD_DIAGNOSE, 0, 0) != OK)
{
semGive (&pCtrl->muteSem);
return (ERROR);
}
}
/* find out geometry */
if ((configType & ATA_GEO_MASK) == ATA_GEO_FORCE)
{
(void) ataCmd (ctrl, drive, ATA_CMD_INITP, 0, 0);
(void) ataPread (ctrl, drive, (char *)pParam);
}
else if ((configType & ATA_GEO_MASK) == ATA_GEO_PHYSICAL)
{
pType->cylinders = pParam->cylinders - 1;
pType->heads = pParam->heads;
pType->sectors = pParam->sectors;
}
else if ((configType & ATA_GEO_MASK) == ATA_GEO_CURRENT)
{
if ((pParam->currentCylinders != 0) &&
(pParam->currentHeads != 0) &&
(pParam->currentSectors != 0))
{
pType->cylinders = pParam->currentCylinders - 1;
pType->heads = pParam->currentHeads;
pType->sectors = pParam->currentSectors;
}
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));
ATA_DEBUG_MSG (1, "ID_DRIVE reports LBA (60-61) as 0x%08lx\n",
ataLbaTotalSecs[ctrl][drive], 0, 0, 0, 0, 0);
}
/*
* reinitialize the controller with parameters read from the
* controller.
*/
(void) ataCmd (ctrl, drive, ATA_CMD_INITP, 0, 0);
/* recalibrate (this command !!! is absent in ATA-4) */
(void) ataCmd (ctrl, drive, ATA_CMD_RECALIB, 0, 0);
}
else
{
pDrive->state = ATA_DEV_PREAD_F;
goto driveInitExit;
}
}
else if (pDrive->type == ATA_TYPE_ATAPI)
{
/* Although ATAPI device parameters have been read by ataDevIdentify(),
* execute ATAPI Identify Device command to allow ATA commands
* acceptance by an ATAPI device after Diagnostic or Reset commands.
*/
if (ataPiPread (ctrl, drive, pParam) != OK)
{
pDrive->state = ATA_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) && (pParam->valid & 0x02))
{
pDrive->singleDmaMode = (pParam->dmaMode >> 8) & 0x03;
if (pDrive->singleDmaMode >= 2)
pDrive->singleDmaMode = 0;
pDrive->multiDmaMode = 0;
if (pParam->singleDma & 0x04)
pDrive->singleDmaMode = 2;
else if (pParam->singleDma & 0x02)
pDrive->singleDmaMode = 1;
else if (pParam->singleDma & 0x01)
pDrive->singleDmaMode = 0;
if (pParam->multiDma & 0x04)
pDrive->multiDmaMode = 2;
else if (pParam->multiDma & 0x02)
pDrive->multiDmaMode = 1;
else if (pParam->multiDma & 0x01)
pDrive->multiDmaMode = 0;
}
/* find out transfer mode to use */
pDrive->rwBits = configType & ATA_BITS_MASK;
pDrive->rwPio = configType & ATA_PIO_MASK;
pDrive->rwDma = configType & ATA_DMA_MASK;
pDrive->rwMode = ATA_PIO_DEF_W;
switch (configType & ATA_MODE_MASK)
{
case ATA_PIO_0:
case ATA_PIO_1:
case ATA_PIO_2:
case ATA_PIO_3:
case ATA_PIO_4:
case ATA_PIO_DEF_0:
case ATA_PIO_DEF_1:
pDrive->rwMode = configType & ATA_MODE_MASK;
break;
case ATA_PIO_AUTO:
pDrive->rwMode = ATA_PIO_W_0 + pDrive->pioMode;
break;
case ATA_DMA_0:
case ATA_DMA_1:
case ATA_DMA_2:
if (pDrive->okDma)
{
if (pDrive->rwDma == ATA_DMA_SINGLE)
pDrive->rwMode |= ATA_DMA_SINGLE_0;
if (pDrive->rwDma == ATA_DMA_MULTI)
pDrive->rwMode |= ATA_DMA_MULTI_0;
}
break;
case ATA_DMA_AUTO:
if (pDrive->okDma)
{
if (pDrive->rwDma == ATA_DMA_SINGLE)
pDrive->rwMode = ATA_DMA_SINGLE_0 +
pDrive->singleDmaMode;
if (pDrive->rwDma == ATA_DMA_MULTI)
pDrive->rwMode = ATA_DMA_MULTI_0 +
pDrive->multiDmaMode;
}
break;
default:
break;
}
/* Set the transfer mode */
(void) ataCmd (ctrl, drive, ATA_CMD_SET_FEATURE, ATA_SUB_SET_RWMODE,
pDrive->rwMode);
/* Disable reverting to power on defaults */
(void) ataCmd (ctrl, drive, ATA_CMD_SET_FEATURE, ATA_SUB_DISABLE_REVE, 0);
/* Set multiple mode (multisector read/write) */
if ((pDrive->rwPio == ATA_PIO_MULTI) && (pDrive->type == ATA_TYPE_ATA))
{
if (pDrive->okMulti)
(void) ataCmd (ctrl, drive, ATA_CMD_SET_MULTI,
pDrive->multiSecs, 0);
else
pDrive->rwPio = ATA_PIO_SINGLE;
}
pDrive->state = ATA_DEV_OK;
driveInitExit:
semGive (&pCtrl->muteSem);
if (pDrive->state != ATA_DEV_OK)
{
ATA_DEBUG_MSG (1, "ataDriveInit%d/%d: ERROR: state=%d dev=0x%x "
"status=0x%x error=0x%x\n", ctrl, drive, pDrive->state,
ATA_IO_BYTE_READ (pCtrl->sdh),
ATA_IO_BYTE_READ (pCtrl->status),
ATA_IO_BYTE_READ (pCtrl->error));
return (ERROR);
}
return (OK);
} /* ataDriveInit */
/*******************************************************************************
*
* ataDrv - initialize the ATA driver
*
* This routine initializes the ATA/IDE/ATAPI CDROM driver, sets up interrupt
* vectors, and performs hardware initialization of the ATA/IDE chip.
*
* This routine must be called exactly once, before any reads, writes,
* or calls to ataDevCreate(). Normally, it is called by usrRoot()
* in usrConfig.c.
*
* RETURNS: OK, or ERROR if initialization fails.
*
* SEE ALSO: ataDevCreate()
*/
STATUS ataDrv
(
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 */
)
{
ATA_CTRL *pCtrl = &ataCtrl[ctrl];
ATA_RESOURCE *pAta = &ataResources[ctrl];
PCCARD_RESOURCE *pResource = &pAta->resource;
ATA_DRIVE *pDrive;
ATA_PARAM *pParam;
ATA_TYPE *pType;
int drive;
int ix;
if ((ctrl >= ATA_MAX_CTRLS) || (drives > ATA_MAX_DRIVES))
return (ERROR);
if (!ataDrvInstalled)
{
for (ix = 0; ix < ATA_MAX_CTRLS; ix++)
ataCtrl[ix].wdgId = wdCreate ();
ataDrvInstalled = TRUE;
}
if (!pCtrl->installed)
{
if (semTimeout == 0)
pCtrl->semTimeout = ATA_SEM_TIMEOUT_DEF;
else
pCtrl->semTimeout = semTimeout;
if (wdgTimeout == 0)
pCtrl->wdgTimeout = ATA_WDG_TIMEOUT_DEF;
else
pCtrl->wdgTimeout = wdgTimeout;
semBInit (&pCtrl->syncSem, SEM_Q_FIFO, SEM_EMPTY);
semMInit (&pCtrl->muteSem, SEM_Q_PRIORITY | SEM_DELETE_SAFE |
SEM_INVERSION_SAFE);
pCtrl->data = ATA_DATA (pResource->ioStart[0]);
pCtrl->error = ATA_ERROR (pResource->ioStart[0]);
pCtrl->feature = ATA_FEATURE (pResource->ioStart[0]);
pCtrl->seccnt = ATA_SECCNT (pResource->ioStart[0]);
pCtrl->sector = ATA_SECTOR (pResource->ioStart[0]);
pCtrl->cylLo = ATA_CYL_LO (pResource->ioStart[0]);
pCtrl->cylHi = ATA_CYL_HI (pResource->ioStart[0]);
pCtrl->sdh = ATA_SDH (pResource->ioStart[0]);
pCtrl->command = ATA_COMMAND (pResource->ioStart[0]);
pCtrl->status = ATA_STATUS (pResource->ioStart[0]);
pCtrl->aStatus = ATA_A_STATUS (pResource->ioStart[1]);
pCtrl->dControl = ATA_D_CONTROL (pResource->ioStart[1]);
pCtrl->dAddress = ATA_D_ADDRESS (pResource->ioStart[1]);
(void) intConnect ((VOIDFUNCPTR *)INUM_TO_IVEC (vector),
(VOIDFUNCPTR)ataIntr, ctrl);
sysIntEnablePIC (level); /* unmask the interrupt level */
pCtrl->intLevel = level;
pCtrl->wdgOkay = TRUE;
pCtrl->configType = configType;
semTake (&pCtrl->muteSem, WAIT_FOREVER);
pCtrl->installed = TRUE;
for (drive = 0; drive < drives; drive++)
{
pType = &ataTypes[ctrl][drive];
pDrive = &pCtrl->drive[drive];
pParam = &pDrive->param;
pDrive->state = ATA_DEV_INIT;
pDrive->type = ATA_TYPE_INIT;
pDrive->diagCode = 0;
pDrive->Reset = ataInit;
ataDriveInit (ctrl, drive);
}
ATA_DEBUG_MSG (1, "ataDrv Calling sysAtaInit (if present):\n",
0, 0, 0, 0, 0, 0);
/* Call system INIT routine to allow proper PIO mode setup */
SYS_ATA_INIT_RTN (ctrl);
ATA_DEBUG_MSG (1, "ataDrv sysAtaInit returned:\n",
0, 0, 0, 0, 0, 0);
semGive (&pCtrl->muteSem);
}
return (OK);
}
/*******************************************************************************
*
* ataDevCreate - create a device for a ATA/IDE disk
*
* This routine creates a device for a specified ATA/IDE or ATAPI CDROM disk.
*
* <ctrl> is a controller number for the ATA controller; the primary controller
* is 0. The maximum is specified via ATA_MAX_CTRLS.
*
* <drive> is the drive number for the ATA hard drive; the master drive
* is 0. The maximum is specified via ATA_MAX_DRIVES.
*
* The <nBlocks> parameter specifies the size of the device in blocks.
* If <nBlocks> is zero, the whole disk is used.
*
* The <blkOffset> parameter specifies an offset, in blocks, from the start
* of the device to be used when writing or reading the hard disk. This
* offset is added to the block numbers passed by the file system during
* disk accesses. (VxWorks file systems always use block numbers beginning
* at zero for the start of a device.)
*
*
* RETURNS:
* A pointer to a block device structure (BLK_DEV) or NULL if memory cannot
* be allocated for the device structure.
*
* SEE ALSO: dosFsMkfs(), dosFsDevInit(), rt11FsDevInit(), rt11FsMkfs(),
* rawFsDevInit()
*/
BLK_DEV *ataDevCreate
(
int ctrl, /* ATA controller number, 0 is the primary controller */
int drive, /* ATA drive number, 0 is the master drive */
int nBlocks, /* number of blocks on device, 0 = use entire disc */
int blkOffset /* offset BLK_DEV nBlocks from the start of the drive */
)
{
ATA_CTRL *pCtrl = &ataCtrl[ctrl];
ATA_TYPE *pType = &ataTypes[ctrl][drive];
ATA_DRIVE *pDrive = &pCtrl->drive[drive];
ATA_PARAM *pParam = &pDrive->param; /* move * */
ATA_DEV *pDev;
BLK_DEV *pBlkdev;
int maxBlks;
if ((ctrl >= ATA_MAX_CTRLS) || (drive >= ATA_MAX_DRIVES) ||
!ataDrvInstalled || !pCtrl->installed)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -