source: rtems/c/src/libchip/ide/ata_util.c @ 74172b7d

5
Last change on this file since 74172b7d was c499856, checked in by Chris Johns <chrisj@…>, on Mar 20, 2014 at 9:10:47 PM

Change all references of rtems.com to rtems.org.

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