mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2025-11-16 12:34:45 +00:00
218 lines
6.7 KiB
C
218 lines
6.7 KiB
C
/* SPDX-License-Identifier: GPL-2.0+-with-RTEMS-exception */
|
|
|
|
/*
|
|
* Copyright (c) 2010 embedded brains GmbH & Co. KG
|
|
*
|
|
* Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
|
|
* Authors: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
|
|
*
|
|
* The license and distribution terms for this file may be
|
|
* found in the file LICENSE in this distribution or at
|
|
* http://www.rtems.org/license/LICENSE.
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
|
|
#include <libchip/ide_ctrl_io.h>
|
|
#include <libchip/ide_ctrl_cfg.h>
|
|
#include <libchip/ata_internal.h>
|
|
|
|
/* ata_process_request_on_init_phase --
|
|
* Process the ATA request during system initialization. Request
|
|
* processing is syncronous and doesn't use multiprocessing enviroment.
|
|
*
|
|
* PARAMETERS:
|
|
* ctrl_minor - controller identifier
|
|
* areq - ATA request
|
|
*
|
|
* RETURNS:
|
|
* NONE
|
|
*/
|
|
void
|
|
ata_process_request_on_init_phase(rtems_device_minor_number ctrl_minor,
|
|
ata_req_t *areq)
|
|
{
|
|
uint16_t byte;/* emphasize that only 8 low bits is meaningful */
|
|
uint8_t i;
|
|
#if 0
|
|
uint8_t dev;
|
|
#endif
|
|
uint16_t val, val1;
|
|
volatile unsigned retries;
|
|
|
|
assert(areq);
|
|
|
|
#if 0
|
|
dev = areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] &
|
|
IDE_REGISTER_DEVICE_HEAD_DEV;
|
|
#endif
|
|
|
|
ide_controller_write_register(ctrl_minor, IDE_REGISTER_DEVICE_HEAD,
|
|
areq->regs.regs[IDE_REGISTER_DEVICE_HEAD]);
|
|
|
|
retries = 0;
|
|
do {
|
|
ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &byte);
|
|
/* If device (on INIT, i.e. it should be idle) is neither
|
|
* busy nor ready something's fishy, i.e., there is probably
|
|
* no device present.
|
|
* I'd like to do a proper timeout but don't know of a portable
|
|
* timeout routine (w/o using multitasking / rtems_task_wake_after())
|
|
*/
|
|
if ( ! (byte & (IDE_REGISTER_STATUS_BSY | IDE_REGISTER_STATUS_DRDY))) {
|
|
retries++;
|
|
if ( 10000 == retries ) {
|
|
/* probably no drive connected */
|
|
areq->breq->status = RTEMS_UNSATISFIED;
|
|
return;
|
|
}
|
|
}
|
|
} while ((byte & IDE_REGISTER_STATUS_BSY) ||
|
|
(!(byte & IDE_REGISTER_STATUS_DRDY)));
|
|
|
|
for (i=0; i< ATA_MAX_CMD_REG_OFFSET; i++)
|
|
{
|
|
uint32_t reg = (1 << i);
|
|
if (areq->regs.to_write & reg)
|
|
ide_controller_write_register(ctrl_minor, i,
|
|
areq->regs.regs[i]);
|
|
}
|
|
|
|
do {
|
|
ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &byte);
|
|
} while (byte & IDE_REGISTER_STATUS_BSY);
|
|
|
|
ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &val);
|
|
ide_controller_read_register(ctrl_minor, IDE_REGISTER_ERROR, &val1);
|
|
|
|
if (val & IDE_REGISTER_STATUS_ERR)
|
|
{
|
|
areq->breq->status = RTEMS_IO_ERROR;
|
|
return;
|
|
}
|
|
|
|
switch(areq->type)
|
|
{
|
|
case ATA_COMMAND_TYPE_PIO_IN:
|
|
if (areq->cnt)
|
|
{
|
|
int ccbuf = areq->cbuf;
|
|
ide_controller_read_data_block(ctrl_minor,
|
|
areq->breq->bufs[0].length * areq->cnt,
|
|
areq->breq->bufs, &areq->cbuf,
|
|
&areq->pos);
|
|
ccbuf = areq->cbuf - ccbuf;
|
|
areq->cnt -= ccbuf;
|
|
}
|
|
if (areq->cnt == 0)
|
|
{
|
|
areq->breq->status = RTEMS_SUCCESSFUL;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* this shouldn't happend on the initialization
|
|
* phase!
|
|
*/
|
|
rtems_fatal_error_occurred(RTEMS_INTERNAL_ERROR);
|
|
}
|
|
break;
|
|
|
|
case ATA_COMMAND_TYPE_NON_DATA:
|
|
areq->breq->status = RTEMS_SUCCESSFUL;
|
|
areq->info = val1;
|
|
break;
|
|
|
|
default:
|
|
areq->breq->status = RTEMS_IO_ERROR;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void ata_breq_init(blkdev_request1 *breq, uint16_t *sector_buffer)
|
|
{
|
|
memset(breq, 0, sizeof(*breq));
|
|
|
|
breq->req.done_arg = breq;
|
|
breq->req.bufnum = 1;
|
|
breq->req.bufs [0].length = ATA_SECTOR_SIZE;
|
|
breq->req.bufs [0].buffer = sector_buffer;
|
|
}
|
|
|
|
rtems_status_code ata_identify_device(
|
|
rtems_device_minor_number ctrl_minor,
|
|
int dev,
|
|
uint16_t *sector_buffer,
|
|
ata_dev_t *device_entry
|
|
)
|
|
{
|
|
ata_req_t areq;
|
|
blkdev_request1 breq;
|
|
|
|
ata_breq_init(&breq, sector_buffer);
|
|
|
|
/*
|
|
* Issue DEVICE IDENTIFY ATA command and get device
|
|
* configuration
|
|
*/
|
|
memset(&areq, 0, sizeof(ata_req_t));
|
|
areq.type = ATA_COMMAND_TYPE_PIO_IN;
|
|
areq.regs.to_write = ATA_REGISTERS_VALUE(IDE_REGISTER_COMMAND);
|
|
areq.regs.regs [IDE_REGISTER_COMMAND] = ATA_COMMAND_IDENTIFY_DEVICE;
|
|
areq.regs.to_read = ATA_REGISTERS_VALUE(IDE_REGISTER_STATUS);
|
|
areq.breq = (rtems_blkdev_request *)&breq;
|
|
areq.cnt = breq.req.bufnum;
|
|
areq.regs.regs [IDE_REGISTER_DEVICE_HEAD] |=
|
|
dev << IDE_REGISTER_DEVICE_HEAD_DEV_POS;
|
|
|
|
/*
|
|
* Process the request. Special processing of requests on
|
|
* initialization phase is needed because at this moment there
|
|
* is no multitasking enviroment
|
|
*/
|
|
ata_process_request_on_init_phase(ctrl_minor, &areq);
|
|
|
|
/* check status of I/O operation */
|
|
if (breq.req.status != RTEMS_SUCCESSFUL) {
|
|
return RTEMS_IO_ERROR;
|
|
}
|
|
|
|
/*
|
|
* Parse returned device configuration and fill in ATA internal
|
|
* device info structure
|
|
*/
|
|
device_entry->cylinders =
|
|
CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_CURR_LOG_CLNDS]);
|
|
device_entry->heads =
|
|
CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_CURR_LOG_HEADS]);
|
|
device_entry->sectors =
|
|
CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_CURR_LOG_SECS]);
|
|
device_entry->lba_sectors =
|
|
CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_USR_SECS1]);
|
|
device_entry->lba_sectors <<= 16;
|
|
device_entry->lba_sectors += CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_USR_SECS0]);
|
|
device_entry->lba_avaible =
|
|
(CF_LE_W(sector_buffer[ATA_IDENT_WORD_CAPABILITIES]) >> 9) & 0x1;
|
|
|
|
if ((CF_LE_W(sector_buffer[ATA_IDENT_WORD_FIELD_VALIDITY]) &
|
|
ATA_IDENT_BIT_VALID) == 0) {
|
|
/* no "supported modes" info -> use default */
|
|
device_entry->mode_active = ATA_MODES_PIO3;
|
|
} else {
|
|
device_entry->modes_available =
|
|
((CF_LE_W(sector_buffer[64]) & 0x1) ? ATA_MODES_PIO3 : 0) |
|
|
((CF_LE_W(sector_buffer[64]) & 0x2) ? ATA_MODES_PIO4 : 0) |
|
|
((CF_LE_W(sector_buffer[63]) & 0x1) ? ATA_MODES_DMA0 : 0) |
|
|
((CF_LE_W(sector_buffer[63]) & 0x2) ?
|
|
ATA_MODES_DMA0 | ATA_MODES_DMA1 : 0) |
|
|
((CF_LE_W(sector_buffer[63]) & 0x4) ?
|
|
ATA_MODES_DMA0 | ATA_MODES_DMA1 | ATA_MODES_DMA2 : 0);
|
|
if (device_entry->modes_available == 0) {
|
|
return RTEMS_IO_ERROR;
|
|
}
|
|
}
|
|
|
|
return RTEMS_SUCCESSFUL;
|
|
}
|