Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:04

0001 /*
0002  * Copyright (c) 2010 embedded brains GmbH & Co. KG
0003  *
0004  * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
0005  * Authors: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
0006  *
0007  * The license and distribution terms for this file may be
0008  * found in the file LICENSE in this distribution or at
0009  * http://www.rtems.org/license/LICENSE.
0010  */
0011 
0012 #include <assert.h>
0013 #include <string.h>
0014 
0015 #include <libchip/ide_ctrl_io.h>
0016 #include <libchip/ide_ctrl_cfg.h>
0017 #include <libchip/ata_internal.h>
0018 
0019 /* ata_process_request_on_init_phase --
0020  *     Process the ATA request during system initialization. Request
0021  *     processing is syncronous and doesn't use multiprocessing enviroment.
0022  *
0023  * PARAMETERS:
0024  *     ctrl_minor - controller identifier
0025  *     areq       - ATA request
0026  *
0027  * RETURNS:
0028  *     NONE
0029  */
0030 void
0031 ata_process_request_on_init_phase(rtems_device_minor_number  ctrl_minor,
0032                                   ata_req_t                 *areq)
0033 {
0034     uint16_t           byte;/* emphasize that only 8 low bits is meaningful */
0035     uint8_t            i;
0036 #if 0
0037     uint8_t            dev;
0038 #endif
0039     uint16_t           val, val1;
0040     volatile unsigned  retries;
0041 
0042     assert(areq);
0043 
0044 #if 0
0045     dev =  areq->regs.regs[IDE_REGISTER_DEVICE_HEAD] &
0046            IDE_REGISTER_DEVICE_HEAD_DEV;
0047 #endif
0048 
0049     ide_controller_write_register(ctrl_minor, IDE_REGISTER_DEVICE_HEAD,
0050                                   areq->regs.regs[IDE_REGISTER_DEVICE_HEAD]);
0051 
0052     retries = 0;
0053     do {
0054         ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &byte);
0055         /* If device (on INIT, i.e. it should be idle) is neither
0056          * busy nor ready something's fishy, i.e., there is probably
0057          * no device present.
0058          * I'd like to do a proper timeout but don't know of a portable
0059          * timeout routine (w/o using multitasking / rtems_task_wake_after())
0060          */
0061         if ( ! (byte & (IDE_REGISTER_STATUS_BSY | IDE_REGISTER_STATUS_DRDY))) {
0062             retries++;
0063             if ( 10000 == retries ) {
0064               /* probably no drive connected */
0065               areq->breq->status = RTEMS_UNSATISFIED;
0066               return;
0067             }
0068         }
0069     } while ((byte & IDE_REGISTER_STATUS_BSY) ||
0070              (!(byte & IDE_REGISTER_STATUS_DRDY)));
0071 
0072     for (i=0; i< ATA_MAX_CMD_REG_OFFSET; i++)
0073     {
0074         uint32_t   reg = (1 << i);
0075         if (areq->regs.to_write & reg)
0076             ide_controller_write_register(ctrl_minor, i,
0077                                           areq->regs.regs[i]);
0078     }
0079 
0080     do {
0081         ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &byte);
0082     } while (byte & IDE_REGISTER_STATUS_BSY);
0083 
0084     ide_controller_read_register(ctrl_minor, IDE_REGISTER_STATUS, &val);
0085     ide_controller_read_register(ctrl_minor, IDE_REGISTER_ERROR, &val1);
0086 
0087     if (val & IDE_REGISTER_STATUS_ERR)
0088     {
0089         areq->breq->status = RTEMS_IO_ERROR;
0090         return;
0091     }
0092 
0093     switch(areq->type)
0094     {
0095         case ATA_COMMAND_TYPE_PIO_IN:
0096             if (areq->cnt)
0097             {
0098               int ccbuf = areq->cbuf;
0099               ide_controller_read_data_block(ctrl_minor,
0100                                              areq->breq->bufs[0].length * areq->cnt,
0101                                              areq->breq->bufs, &areq->cbuf,
0102                                              &areq->pos);
0103               ccbuf = areq->cbuf - ccbuf;
0104               areq->cnt -= ccbuf;
0105             }
0106             if (areq->cnt == 0)
0107             {
0108                 areq->breq->status = RTEMS_SUCCESSFUL;
0109             }
0110             else
0111             {
0112                 /*
0113                  * this shouldn't happend on the initialization
0114                  * phase!
0115                  */
0116                 rtems_fatal_error_occurred(RTEMS_INTERNAL_ERROR);
0117             }
0118             break;
0119 
0120         case ATA_COMMAND_TYPE_NON_DATA:
0121             areq->breq->status = RTEMS_SUCCESSFUL;
0122             areq->info = val1;
0123             break;
0124 
0125         default:
0126             areq->breq->status = RTEMS_IO_ERROR;
0127             break;
0128     }
0129 }
0130 
0131 void ata_breq_init(blkdev_request1 *breq, uint16_t *sector_buffer)
0132 {
0133   memset(breq, 0, sizeof(*breq));
0134 
0135   breq->req.done_arg = breq;
0136   breq->req.bufnum = 1;
0137   breq->req.bufs [0].length = ATA_SECTOR_SIZE;
0138   breq->req.bufs [0].buffer = sector_buffer;
0139 }
0140 
0141 rtems_status_code ata_identify_device(
0142   rtems_device_minor_number ctrl_minor,
0143   int dev,
0144   uint16_t *sector_buffer,
0145   ata_dev_t *device_entry
0146 )
0147 {
0148   ata_req_t areq;
0149   blkdev_request1 breq;
0150 
0151   ata_breq_init(&breq, sector_buffer);
0152 
0153   /*
0154    * Issue DEVICE IDENTIFY ATA command and get device
0155    * configuration
0156    */
0157   memset(&areq, 0, sizeof(ata_req_t));
0158   areq.type = ATA_COMMAND_TYPE_PIO_IN;
0159   areq.regs.to_write = ATA_REGISTERS_VALUE(IDE_REGISTER_COMMAND);
0160   areq.regs.regs [IDE_REGISTER_COMMAND] = ATA_COMMAND_IDENTIFY_DEVICE;
0161   areq.regs.to_read = ATA_REGISTERS_VALUE(IDE_REGISTER_STATUS);
0162   areq.breq = (rtems_blkdev_request *)&breq;
0163   areq.cnt = breq.req.bufnum;
0164   areq.regs.regs [IDE_REGISTER_DEVICE_HEAD] |=
0165     dev << IDE_REGISTER_DEVICE_HEAD_DEV_POS;
0166 
0167   /*
0168    * Process the request. Special processing of requests on
0169    * initialization phase is needed because at this moment there
0170    * is no multitasking enviroment
0171    */
0172   ata_process_request_on_init_phase(ctrl_minor, &areq);
0173 
0174   /* check status of I/O operation */
0175   if (breq.req.status != RTEMS_SUCCESSFUL) {
0176     return RTEMS_IO_ERROR;
0177   }
0178 
0179   /*
0180    * Parse returned device configuration and fill in ATA internal
0181    * device info structure
0182    */
0183   device_entry->cylinders =
0184       CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_CURR_LOG_CLNDS]);
0185   device_entry->heads =
0186       CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_CURR_LOG_HEADS]);
0187   device_entry->sectors =
0188       CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_CURR_LOG_SECS]);
0189   device_entry->lba_sectors =
0190       CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_USR_SECS1]);
0191   device_entry->lba_sectors <<= 16;
0192   device_entry->lba_sectors += CF_LE_W(sector_buffer[ATA_IDENT_WORD_NUM_OF_USR_SECS0]);
0193   device_entry->lba_avaible =
0194       (CF_LE_W(sector_buffer[ATA_IDENT_WORD_CAPABILITIES]) >> 9) & 0x1;
0195 
0196   if ((CF_LE_W(sector_buffer[ATA_IDENT_WORD_FIELD_VALIDITY]) &
0197        ATA_IDENT_BIT_VALID) == 0) {
0198     /* no "supported modes" info -> use default */
0199     device_entry->mode_active = ATA_MODES_PIO3;
0200   } else {
0201     device_entry->modes_available =
0202       ((CF_LE_W(sector_buffer[64]) & 0x1) ? ATA_MODES_PIO3 : 0) |
0203       ((CF_LE_W(sector_buffer[64]) & 0x2) ? ATA_MODES_PIO4 : 0) |
0204       ((CF_LE_W(sector_buffer[63]) & 0x1) ? ATA_MODES_DMA0 : 0) |
0205       ((CF_LE_W(sector_buffer[63]) & 0x2) ?
0206        ATA_MODES_DMA0 | ATA_MODES_DMA1 : 0) |
0207       ((CF_LE_W(sector_buffer[63]) & 0x4) ?
0208        ATA_MODES_DMA0 | ATA_MODES_DMA1 | ATA_MODES_DMA2 : 0);
0209     if (device_entry->modes_available == 0) {
0210       return RTEMS_IO_ERROR;
0211     }
0212   }
0213 
0214   return RTEMS_SUCCESSFUL;
0215 }