source: rtems/c/src/libchip/ide/ata_util.c @ 230acc55

5
Last change on this file since 230acc55 was 230acc55, checked in by Chris Johns <chrisj@…>, on 01/04/18 at 07:52:26

libchip: Use public include path

Update #3254.

  • Property mode set to 100644
File size: 6.7 KB
Line 
1/*
2 * Copyright (c) 2010 embedded brains GmbH.
3 *
4 * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
5 * Authors: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
6 *
7 * The license and distribution terms for this file may be
8 * found in the file LICENSE in this distribution or at
9 * http://www.rtems.org/license/LICENSE.
10 */
11
12#include <assert.h>
13#include <string.h>
14
15#include <libchip/ide_ctrl_io.h>
16#include <libchip/ide_ctrl_cfg.h>
17#include <libchip/ata_internal.h>
18
19/* ata_process_request_on_init_phase --
20 *     Process the ATA request during system initialization. Request
21 *     processing is syncronous and doesn't use multiprocessing enviroment.
22 *
23 * PARAMETERS:
24 *     ctrl_minor - controller identifier
25 *     areq       - ATA request
26 *
27 * RETURNS:
28 *     NONE
29 */
30void
31ata_process_request_on_init_phase(rtems_device_minor_number  ctrl_minor,
32                                  ata_req_t                 *areq)
33{
34    uint16_t           byte;/* emphasize that only 8 low bits is meaningful */
35    uint8_t            i;
36#if 0
37    uint8_t            dev;
38#endif
39    uint16_t           val, val1;
40    volatile unsigned  retries;
41
42    assert(areq);
43
44#if 0
45    dev =  areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] &
46           IDE_REGISTER_DEVICE_HEAD_DEV;
47#endif
48
49    ide_controller_write_register(ctrl_minor, IDE_REGISTER_DEVICE_HEAD,
50                                  areq->regs.regs[IDE_REGISTER_DEVICE_HEAD]);
51
52        retries = 0;
53    do {
54        ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &byte);
55        /* If device (on INIT, i.e. it should be idle) is neither
56         * busy nor ready something's fishy, i.e., there is probably
57         * no device present.
58         * I'd like to do a proper timeout but don't know of a portable
59         * timeout routine (w/o using multitasking / rtems_task_wake_after())
60         */
61        if ( ! (byte & (IDE_REGISTER_STATUS_BSY | IDE_REGISTER_STATUS_DRDY))) {
62            retries++;
63            if ( 10000 == retries ) {
64              /* probably no drive connected */
65              areq->breq->status = RTEMS_UNSATISFIED;
66              return;
67            }
68        }
69    } while ((byte & IDE_REGISTER_STATUS_BSY) ||
70             (!(byte & IDE_REGISTER_STATUS_DRDY)));
71
72    for (i=0; i< ATA_MAX_CMD_REG_OFFSET; i++)
73    {
74        uint32_t   reg = (1 << i);
75        if (areq->regs.to_write & reg)
76            ide_controller_write_register(ctrl_minor, i,
77                                          areq->regs.regs[i]);
78    }
79
80    do {
81        ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &byte);
82    } while (byte & IDE_REGISTER_STATUS_BSY);
83
84    ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &val);
85    ide_controller_read_register(ctrl_minor, IDE_REGISTER_ERROR, &val1);
86
87    if (val & IDE_REGISTER_STATUS_ERR)
88    {
89        areq->breq->status = RTEMS_IO_ERROR;
90        return;
91    }
92
93    switch(areq->type)
94    {
95        case ATA_COMMAND_TYPE_PIO_IN:
96            if (areq->cnt)
97            {
98              int ccbuf = areq->cbuf;
99              ide_controller_read_data_block(ctrl_minor,
100                                             areq->breq->bufs[0].length * areq->cnt,
101                                             areq->breq->bufs, &areq->cbuf,
102                                             &areq->pos);
103              ccbuf = areq->cbuf - ccbuf;
104              areq->cnt -= ccbuf;
105            }
106            if (areq->cnt == 0)
107            {
108                areq->breq->status = RTEMS_SUCCESSFUL;
109            }
110            else
111            {
112                /*
113                 * this shouldn't happend on the initialization
114                 * phase!
115                 */
116                rtems_fatal_error_occurred(RTEMS_INTERNAL_ERROR);
117            }
118            break;
119
120        case ATA_COMMAND_TYPE_NON_DATA:
121            areq->breq->status = RTEMS_SUCCESSFUL;
122            areq->info = val1;
123            break;
124
125        default:
126            areq->breq->status = RTEMS_IO_ERROR;
127            break;
128    }
129}
130
131void ata_breq_init(blkdev_request1 *breq, uint16_t *sector_buffer)
132{
133  memset(breq, 0, sizeof(*breq));
134
135  breq->req.done_arg = breq;
136  breq->req.bufnum = 1;
137  breq->req.bufs [0].length = ATA_SECTOR_SIZE;
138  breq->req.bufs [0].buffer = sector_buffer;
139}
140
141rtems_status_code ata_identify_device(
142  rtems_device_minor_number ctrl_minor,
143  int dev,
144  uint16_t *sector_buffer,
145  ata_dev_t *device_entry
146)
147{
148  ata_req_t areq;
149  blkdev_request1 breq;
150
151  ata_breq_init(&breq, sector_buffer);
152
153  /*
154   * Issue DEVICE IDENTIFY ATA command and get device
155   * configuration
156   */
157  memset(&areq, 0, sizeof(ata_req_t));
158  areq.type = ATA_COMMAND_TYPE_PIO_IN;
159  areq.regs.to_write = ATA_REGISTERS_VALUE(IDE_REGISTER_COMMAND);
160  areq.regs.regs [IDE_REGISTER_COMMAND] = ATA_COMMAND_IDENTIFY_DEVICE;
161  areq.regs.to_read = ATA_REGISTERS_VALUE(IDE_REGISTER_STATUS);
162  areq.breq = (rtems_blkdev_request *)&breq;
163  areq.cnt = breq.req.bufnum;
164  areq.regs.regs [IDE_REGISTER_DEVICE_HEAD] |=
165    dev << IDE_REGISTER_DEVICE_HEAD_DEV_POS;
166
167  /*
168   * Process the request. Special processing of requests on
169   * initialization phase is needed because at this moment there
170   * is no multitasking enviroment
171   */
172  ata_process_request_on_init_phase(ctrl_minor, &areq);
173
174  /* check status of I/O operation */
175  if (breq.req.status != RTEMS_SUCCESSFUL) {
176    return RTEMS_IO_ERROR;
177  }
178
179  /*
180   * Parse returned device configuration and fill in ATA internal
181   * device info structure
182   */
183  device_entry->cylinders =
184      CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_CURR_LOG_CLNDS]);
185  device_entry->heads =
186      CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_CURR_LOG_HEADS]);
187  device_entry->sectors =
188      CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_CURR_LOG_SECS]);
189  device_entry->lba_sectors =
190      CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_USR_SECS1]);
191  device_entry->lba_sectors <<= 16;
192  device_entry->lba_sectors += CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_USR_SECS0]);
193  device_entry->lba_avaible =
194      (CF_LE_W(sector_buffer[ATA_IDENT_WORD_CAPABILITIES]) >> 9) & 0x1;
195
196  if ((CF_LE_W(sector_buffer[ATA_IDENT_WORD_FIELD_VALIDITY]) &
197       ATA_IDENT_BIT_VALID) == 0) {
198    /* no "supported modes" info -> use default */
199    device_entry->mode_active = ATA_MODES_PIO3;
200  } else {
201    device_entry->modes_available =
202      ((CF_LE_W(sector_buffer[64]) & 0x1) ? ATA_MODES_PIO3 : 0) |
203      ((CF_LE_W(sector_buffer[64]) & 0x2) ? ATA_MODES_PIO4 : 0) |
204      ((CF_LE_W(sector_buffer[63]) & 0x1) ? ATA_MODES_DMA0 : 0) |
205      ((CF_LE_W(sector_buffer[63]) & 0x2) ?
206       ATA_MODES_DMA0 | ATA_MODES_DMA1 : 0) |
207      ((CF_LE_W(sector_buffer[63]) & 0x4) ?
208       ATA_MODES_DMA0 | ATA_MODES_DMA1 | ATA_MODES_DMA2 : 0);
209    if (device_entry->modes_available == 0) {
210      return RTEMS_IO_ERROR;
211    }
212  }
213
214  return RTEMS_SUCCESSFUL;
215}
Note: See TracBrowser for help on using the repository browser.