[9ca9758] | 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 |
---|
[c499856] | 9 | * http://www.rtems.org/license/LICENSE. |
---|
[9ca9758] | 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 | */ |
---|
| 31 | void |
---|
| 32 | ata_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 */ |
---|
[5d64fef2] | 36 | uint8_t i; |
---|
| 37 | #if 0 |
---|
| 38 | uint8_t dev; |
---|
| 39 | #endif |
---|
[9ca9758] | 40 | uint16_t val, val1; |
---|
| 41 | volatile unsigned retries; |
---|
| 42 | |
---|
| 43 | assert(areq); |
---|
| 44 | |
---|
[5d64fef2] | 45 | #if 0 |
---|
[9ca9758] | 46 | dev = areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] & |
---|
| 47 | IDE_REGISTER_DEVICE_HEAD_DEV; |
---|
[5d64fef2] | 48 | #endif |
---|
[9ca9758] | 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 | |
---|
| 132 | void 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 | |
---|
| 142 | rtems_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 | } |
---|