Changeset c5f0bff in mainline


Ignore:
Timestamp:
2011-02-01T20:22:05Z (13 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
1e00216
Parents:
40fb017 (diff), aa893e0 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge minimalistic ATAPI CD-ROM support in ata_bd (only tested in Qemu).

Location:
uspace/srv/bd/ata_bd
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/bd/ata_bd/ata_bd.c

    r40fb017 rc5f0bff  
    5555#include <as.h>
    5656#include <fibril_synch.h>
     57#include <stdint.h>
    5758#include <str.h>
    5859#include <devmap.h>
     
    6162#include <errno.h>
    6263#include <bool.h>
     64#include <byteorder.h>
    6365#include <task.h>
    6466#include <macros.h>
     
    7375#define LEGACY_CTLS 4
    7476
    75 /** Physical block size. Should be always 512. */
    76 static const size_t block_size = 512;
     77/**
     78 * Size of data returned from Identify Device or Identify Packet Device
     79 * command.
     80 */
     81static const size_t identify_data_size = 512;
    7782
    7883/** Size of the communication area. */
     
    105110static int ata_bd_write_blocks(int disk_id, uint64_t ba, size_t cnt,
    106111    const void *buf);
    107 static int ata_bd_read_block(int disk_id, uint64_t ba, size_t cnt,
     112static int ata_rcmd_read(int disk_id, uint64_t ba, size_t cnt,
    108113    void *buf);
    109 static int ata_bd_write_block(int disk_id, uint64_t ba, size_t cnt,
     114static int ata_rcmd_write(int disk_id, uint64_t ba, size_t cnt,
    110115    const void *buf);
    111116static int disk_init(disk_t *d, int disk_id);
    112117static int drive_identify(int drive_id, void *buf);
     118static int identify_pkt_dev(int dev_idx, void *buf);
     119static int ata_cmd_packet(int dev_idx, const void *cpkt, size_t cpkt_size,
     120    void *obuf, size_t obuf_size);
     121static int ata_pcmd_inquiry(int dev_idx, void *obuf, size_t obuf_size);
     122static int ata_pcmd_read_12(int dev_idx, uint64_t ba, size_t cnt,
     123    void *obuf, size_t obuf_size);
    113124static void disk_print_summary(disk_t *d);
    114125static int coord_calc(disk_t *d, uint64_t ba, block_coord_t *bc);
     
    203214        printf("%s: ", d->model);
    204215
    205         switch (d->amode) {
    206         case am_chs:
    207                 printf("CHS %u cylinders, %u heads, %u sectors",
    208                     disk->geom.cylinders, disk->geom.heads, disk->geom.sectors);
    209                 break;
    210         case am_lba28:
    211                 printf("LBA-28");
    212                 break;
    213         case am_lba48:
    214                 printf("LBA-48");
    215                 break;
     216        if (d->dev_type == ata_reg_dev) {
     217                switch (d->amode) {
     218                case am_chs:
     219                        printf("CHS %u cylinders, %u heads, %u sectors",
     220                            disk->geom.cylinders, disk->geom.heads,
     221                            disk->geom.sectors);
     222                        break;
     223                case am_lba28:
     224                        printf("LBA-28");
     225                        break;
     226                case am_lba48:
     227                        printf("LBA-48");
     228                        break;
     229                }
     230        } else {
     231                printf("PACKET");
    216232        }
    217233
     
    313329                            IPC_GET_ARG2(call));
    314330                        cnt = IPC_GET_ARG3(call);
    315                         if (cnt * block_size > comm_size) {
     331                        if (cnt * disk[disk_id].block_size > comm_size) {
    316332                                retval = ELIMIT;
    317333                                break;
     
    323339                            IPC_GET_ARG2(call));
    324340                        cnt = IPC_GET_ARG3(call);
    325                         if (cnt * block_size > comm_size) {
     341                        if (cnt * disk[disk_id].block_size > comm_size) {
    326342                                retval = ELIMIT;
    327343                                break;
     
    330346                        break;
    331347                case BD_GET_BLOCK_SIZE:
    332                         async_answer_1(callid, EOK, block_size);
     348                        async_answer_1(callid, EOK, disk[disk_id].block_size);
    333349                        continue;
    334350                case BD_GET_NUM_BLOCKS:
     
    353369        identify_data_t idata;
    354370        uint8_t model[40];
     371        ata_inquiry_data_t inq_data;
    355372        uint16_t w;
    356373        uint8_t c;
     
    359376        unsigned i;
    360377
     378        d->present = false;
     379        fibril_mutex_initialize(&d->lock);
     380
     381        /* Try identify command. */
    361382        rc = drive_identify(disk_id, &idata);
    362         if (rc != EOK) {
    363                 d->present = false;
    364                 return rc;
    365         }
    366 
    367         if ((idata.caps & cap_lba) == 0) {
     383        if (rc == EOK) {
     384                /* Success. It's a register (non-packet) device. */
     385                printf("ATA register-only device found.\n");
     386                d->dev_type = ata_reg_dev;
     387        } else if (rc == EIO) {
     388                /*
     389                 * There is something, but not a register device.
     390                 * It could be a packet device.
     391                 */
     392                rc = identify_pkt_dev(disk_id, &idata);
     393                if (rc == EOK) {
     394                        /* We have a packet device. */
     395                        d->dev_type = ata_pkt_dev;
     396                } else {
     397                        /* Nope. Something's there, but not recognized. */
     398                        return EIO;
     399                }
     400        } else {
     401                /* Operation timed out. That means there is no device there. */
     402                return EIO;
     403        }
     404
     405        printf("device caps: 0x%04x\n", idata.caps);
     406        if (d->dev_type == ata_pkt_dev) {
     407                /* Packet device */
     408                d->amode = 0;
     409
     410                d->geom.cylinders = 0;
     411                d->geom.heads = 0;
     412                d->geom.sectors = 0;
     413
     414                d->blocks = 0;
     415        } else if ((idata.caps & rd_cap_lba) == 0) {
    368416                /* Device only supports CHS addressing. */
    369417                d->amode = am_chs;
     
    422470        d->model[pos] = '\0';
    423471
     472        if (d->dev_type == ata_pkt_dev) {
     473                /* Send inquiry. */
     474                rc = ata_pcmd_inquiry(0, &inq_data, sizeof(inq_data));
     475                if (rc != EOK) {
     476                        printf("Device inquiry failed.\n");
     477                        d->present = false;
     478                        return EIO;
     479                }
     480
     481                /* Check device type. */
     482                if (INQUIRY_PDEV_TYPE(inq_data.pdev_type) != PDEV_TYPE_CDROM)
     483                        printf("Warning: Peripheral device type is not CD-ROM.\n");
     484
     485                /* Assume 2k block size for now. */
     486                d->block_size = 2048;
     487        } else {
     488                /* Assume register Read always uses 512-byte blocks. */
     489                d->block_size = 512;
     490        }
     491
    424492        d->present = true;
    425         fibril_mutex_initialize(&d->lock);
    426 
    427493        return EOK;
    428494}
     
    435501
    436502        while (cnt > 0) {
    437                 rc = ata_bd_read_block(disk_id, ba, 1, buf);
     503                if (disk[disk_id].dev_type == ata_reg_dev)
     504                        rc = ata_rcmd_read(disk_id, ba, 1, buf);
     505                else
     506                        rc = ata_pcmd_read_12(disk_id, ba, 1, buf,
     507                            disk[disk_id].block_size);
     508
    438509                if (rc != EOK)
    439510                        return rc;
     
    441512                ++ba;
    442513                --cnt;
    443                 buf += block_size;
     514                buf += disk[disk_id].block_size;
    444515        }
    445516
     
    453524        int rc;
    454525
     526        if (disk[disk_id].dev_type != ata_reg_dev)
     527                return ENOTSUP;
     528
    455529        while (cnt > 0) {
    456                 rc = ata_bd_write_block(disk_id, ba, 1, buf);
     530                rc = ata_rcmd_write(disk_id, ba, 1, buf);
    457531                if (rc != EOK)
    458532                        return rc;
     
    460534                ++ba;
    461535                --cnt;
    462                 buf += block_size;
     536                buf += disk[disk_id].block_size;
    463537        }
    464538
     
    473547 * @param disk_id       Device ID, 0 or 1.
    474548 * @param buf           Pointer to a 512-byte buffer.
     549 *
     550 * @return              ETIMEOUT on timeout (this can mean the device is
     551 *                      not present). EIO if device responds with error.
    475552 */
    476553static int drive_identify(int disk_id, void *buf)
     
    484561
    485562        if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
    486                 return EIO;
     563                return ETIMEOUT;
    487564
    488565        pio_write_8(&cmd->drive_head, drv_head);
     
    493570         */
    494571        if (wait_status(SR_DRDY, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
    495                 return EIO;
     572                return ETIMEOUT;
    496573
    497574        pio_write_8(&cmd->command, CMD_IDENTIFY_DRIVE);
    498575
    499576        if (wait_status(0, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK)
    500                 return EIO;
     577                return ETIMEOUT;
    501578
    502579        /* Read data from the disk buffer. */
    503580
    504581        if ((status & SR_DRQ) != 0) {
    505                 for (i = 0; i < block_size / 2; i++) {
     582                for (i = 0; i < identify_data_size / 2; i++) {
    506583                        data = pio_read_16(&cmd->data_port);
    507584                        ((uint16_t *) buf)[i] = data;
     
    509586        }
    510587
     588        if ((status & SR_ERR) != 0) {
     589                return EIO;
     590        }
     591
     592        return EOK;
     593}
     594
     595/** Issue Identify Packet Device command.
     596 *
     597 * Reads @c identify data into the provided buffer. This is used to detect
     598 * whether an ATAPI device is present and if so, to determine its parameters.
     599 *
     600 * @param dev_idx       Device index, 0 or 1.
     601 * @param buf           Pointer to a 512-byte buffer.
     602 */
     603static int identify_pkt_dev(int dev_idx, void *buf)
     604{
     605        uint16_t data;
     606        uint8_t status;
     607        uint8_t drv_head;
     608        size_t i;
     609
     610        drv_head = ((dev_idx != 0) ? DHR_DRV : 0);
     611
     612        if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
     613                return EIO;
     614
     615        pio_write_8(&cmd->drive_head, drv_head);
     616
     617        /* For ATAPI commands we do not need to wait for DRDY. */
     618        if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
     619                return EIO;
     620
     621        pio_write_8(&cmd->command, CMD_IDENTIFY_PKT_DEV);
     622
     623        if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK)
     624                return EIO;
     625
     626        /* Read data from the device buffer. */
     627
     628        if ((status & SR_DRQ) != 0) {
     629                for (i = 0; i < identify_data_size / 2; i++) {
     630                        data = pio_read_16(&cmd->data_port);
     631                        ((uint16_t *) buf)[i] = data;
     632                }
     633        }
     634
    511635        if ((status & SR_ERR) != 0)
    512636                return EIO;
     637
     638        return EOK;
     639}
     640
     641/** Issue packet command (i. e. write a command packet to the device).
     642 *
     643 * Only data-in commands are supported (e.g. inquiry, read).
     644 *
     645 * @param dev_idx       Device index (0 or 1)
     646 * @param obuf          Buffer for storing data read from device
     647 * @param obuf_size     Size of obuf in bytes
     648 *
     649 * @return EOK on success, EIO on error.
     650 */
     651static int ata_cmd_packet(int dev_idx, const void *cpkt, size_t cpkt_size,
     652    void *obuf, size_t obuf_size)
     653{
     654        size_t i;
     655        uint8_t status;
     656        uint8_t drv_head;
     657        disk_t *d;
     658        size_t data_size;
     659        uint16_t val;
     660
     661        d = &disk[dev_idx];
     662        fibril_mutex_lock(&d->lock);
     663
     664        /* New value for Drive/Head register */
     665        drv_head =
     666            ((dev_idx != 0) ? DHR_DRV : 0);
     667
     668        if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) {
     669                fibril_mutex_unlock(&d->lock);
     670                return EIO;
     671        }
     672
     673        pio_write_8(&cmd->drive_head, drv_head);
     674
     675        if (wait_status(0, ~(SR_BSY|SR_DRQ), NULL, TIMEOUT_BSY) != EOK) {
     676                fibril_mutex_unlock(&d->lock);
     677                return EIO;
     678        }
     679
     680        /* Byte count <- max. number of bytes we can read in one transfer. */
     681        pio_write_8(&cmd->cylinder_low, 0xfe);
     682        pio_write_8(&cmd->cylinder_high, 0xff);
     683
     684        pio_write_8(&cmd->command, CMD_PACKET);
     685
     686        if (wait_status(SR_DRQ, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
     687                fibril_mutex_unlock(&d->lock);
     688                return EIO;
     689        }
     690
     691        /* Write command packet. */
     692        for (i = 0; i < (cpkt_size + 1) / 2; i++)
     693                pio_write_16(&cmd->data_port, ((uint16_t *) cpkt)[i]);
     694
     695        if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
     696                fibril_mutex_unlock(&d->lock);
     697                return EIO;
     698        }
     699
     700        if ((status & SR_DRQ) == 0) {
     701                fibril_mutex_unlock(&d->lock);
     702                return EIO;
     703        }
     704
     705        /* Read byte count. */
     706        data_size = (uint16_t) pio_read_8(&cmd->cylinder_low) +
     707            ((uint16_t) pio_read_8(&cmd->cylinder_high) << 8);
     708
     709        /* Check whether data fits into output buffer. */
     710        if (data_size > obuf_size) {
     711                /* Output buffer is too small to store data. */
     712                fibril_mutex_unlock(&d->lock);
     713                return EIO;
     714        }
     715
     716        /* Read data from the device buffer. */
     717        for (i = 0; i < (data_size + 1) / 2; i++) {
     718                val = pio_read_16(&cmd->data_port);
     719                ((uint16_t *) obuf)[i] = val;
     720        }
     721
     722        if (status & SR_ERR) {
     723                fibril_mutex_unlock(&d->lock);
     724                return EIO;
     725        }
     726
     727        fibril_mutex_unlock(&d->lock);
     728
     729        return EOK;
     730}
     731
     732/** Issue ATAPI Inquiry.
     733 *
     734 * @param dev_idx       Device index (0 or 1)
     735 * @param obuf          Buffer for storing inquiry data read from device
     736 * @param obuf_size     Size of obuf in bytes
     737 *
     738 * @return EOK on success, EIO on error.
     739 */
     740static int ata_pcmd_inquiry(int dev_idx, void *obuf, size_t obuf_size)
     741{
     742        ata_pcmd_inquiry_t cp;
     743        int rc;
     744
     745        memset(&cp, 0, sizeof(cp));
     746
     747        cp.opcode = PCMD_INQUIRY;
     748        cp.alloc_len = min(obuf_size, 0xff); /* Allocation length */
     749
     750        rc = ata_cmd_packet(0, &cp, sizeof(cp), obuf, obuf_size);
     751        if (rc != EOK)
     752                return rc;
     753
     754        return EOK;
     755}
     756
     757/** Issue ATAPI read(12) command.
     758 *
     759 * Output buffer must be large enough to hold the data, otherwise the
     760 * function will fail.
     761 *
     762 * @param dev_idx       Device index (0 or 1)
     763 * @param ba            Starting block address
     764 * @param cnt           Number of blocks to read
     765 * @param obuf          Buffer for storing inquiry data read from device
     766 * @param obuf_size     Size of obuf in bytes
     767 *
     768 * @return EOK on success, EIO on error.
     769 */
     770static int ata_pcmd_read_12(int dev_idx, uint64_t ba, size_t cnt,
     771    void *obuf, size_t obuf_size)
     772{
     773        ata_pcmd_read_12_t cp;
     774        int rc;
     775
     776        if (ba > UINT32_MAX)
     777                return EINVAL;
     778
     779        memset(&cp, 0, sizeof(cp));
     780
     781        cp.opcode = PCMD_READ_12;
     782        cp.ba = host2uint32_t_be(ba);
     783        cp.nblocks = host2uint32_t_be(cnt);
     784
     785        rc = ata_cmd_packet(0, &cp, sizeof(cp), obuf, obuf_size);
     786        if (rc != EOK)
     787                return rc;
    513788
    514789        return EOK;
     
    524799 * @return EOK on success, EIO on error.
    525800 */
    526 static int ata_bd_read_block(int disk_id, uint64_t ba, size_t blk_cnt,
     801static int ata_rcmd_read(int disk_id, uint64_t ba, size_t blk_cnt,
    527802    void *buf)
    528803{
     
    579854                /* Read data from the device buffer. */
    580855
    581                 for (i = 0; i < block_size / 2; i++) {
     856                for (i = 0; i < disk[disk_id].block_size / 2; i++) {
    582857                        data = pio_read_16(&cmd->data_port);
    583858                        ((uint16_t *) buf)[i] = data;
     
    601876 * @return EOK on success, EIO on error.
    602877 */
    603 static int ata_bd_write_block(int disk_id, uint64_t ba, size_t cnt,
     878static int ata_rcmd_write(int disk_id, uint64_t ba, size_t cnt,
    604879    const void *buf)
    605880{
     
    655930                /* Write data to the device buffer. */
    656931
    657                 for (i = 0; i < block_size / 2; i++) {
     932                for (i = 0; i < disk[disk_id].block_size / 2; i++) {
    658933                        pio_write_16(&cmd->data_port, ((uint16_t *) buf)[i]);
    659934                }
  • uspace/srv/bd/ata_bd/ata_bd.h

    r40fb017 rc5f0bff  
    5353};
    5454
    55 /** Block addressing mode. */
    56 enum addr_mode {
     55enum ata_dev_type {
     56        ata_reg_dev,    /* Register device (no packet feature set support) */
     57        ata_pkt_dev     /* Packet device (supports packet feature set). */
     58};
     59
     60/** Register device block addressing mode. */
     61enum rd_addr_mode {
    5762        am_chs,         /**< CHS block addressing */
    5863        am_lba28,       /**< LBA-28 block addressing */
     
    6267/** Block coordinates */
    6368typedef struct {
    64         /** Addressing mode used */
    65         enum addr_mode amode;
     69        enum rd_addr_mode amode;
    6670
    6771        union {
     
    9094typedef struct {
    9195        bool present;
    92         enum addr_mode amode;
     96
     97        /** Device type */
     98        enum ata_dev_type dev_type;
     99
     100        /** Addressing mode to use (if register device) */
     101        enum rd_addr_mode amode;
    93102
    94103        /*
     
    102111
    103112        uint64_t blocks;
     113        size_t block_size;
    104114
    105115        char model[STR_BOUNDS(40) + 1];
  • uspace/srv/bd/ata_bd/ata_hw.h

    r40fb017 rc5f0bff  
    134134        CMD_WRITE_SECTORS       = 0x30,
    135135        CMD_WRITE_SECTORS_EXT   = 0x34,
     136        CMD_PACKET              = 0xA0,
     137        CMD_IDENTIFY_PKT_DEV    = 0xA1,
    136138        CMD_IDENTIFY_DRIVE      = 0xEC
    137139};
    138140
    139 /** Data returned from @c identify command. */
     141/** Data returned from identify device and identify packet device command. */
    140142typedef struct {
    141143        uint16_t gen_conf;
     
    159161        uint16_t max_rw_multiple;
    160162        uint16_t _res48;
    161         uint16_t caps;
     163        uint16_t caps;          /* Different meaning for packet device */
    162164        uint16_t _res50;
    163165        uint16_t pio_timing;
     
    214216} identify_data_t;
    215217
    216 enum ata_caps {
    217         cap_iordy       = 0x0800,
    218         cap_iordy_cbd   = 0x0400,
    219         cap_lba         = 0x0200,
    220         cap_dma         = 0x0100
     218/** Capability bits for register device. */
     219enum ata_regdev_caps {
     220        rd_cap_iordy            = 0x0800,
     221        rd_cap_iordy_cbd        = 0x0400,
     222        rd_cap_lba              = 0x0200,
     223        rd_cap_dma              = 0x0100
     224};
     225
     226/** Capability bits for packet device. */
     227enum ata_pktdev_caps {
     228        pd_cap_ildma            = 0x8000,
     229        pd_cap_cmdqueue         = 0x4000,
     230        pd_cap_overlap          = 0x2000,
     231        pd_cap_need_softreset   = 0x1000,       /* Obsolete (ATAPI-6) */
     232        pd_cap_iordy            = 0x0800,
     233        pd_cap_iordy_dis        = 0x0400,
     234        pd_cap_lba              = 0x0200,       /* Must be on */
     235        pd_cap_dma              = 0x0100
    221236};
    222237
     
    226241};
    227242
     243/** ATA packet command codes. */
     244enum ata_pkt_command {
     245        PCMD_INQUIRY            = 0x12,
     246        PCMD_READ_12            = 0xa8
     247};
     248
     249/** ATAPI Inquiry command */
     250typedef struct {
     251        uint8_t opcode;         /**< Operation code (PCMD_INQUIRY) */
     252        uint8_t _res0;
     253        uint8_t _res1;
     254        uint8_t _res2;
     255        uint8_t alloc_len;      /**< Allocation length */
     256        uint8_t _res3;
     257        uint8_t _res4;
     258        uint8_t _res5;
     259        uint32_t _res6;
     260} __attribute__ ((packed)) ata_pcmd_inquiry_t;
     261
     262/** ATAPI Read(12) command */
     263typedef struct {
     264        uint8_t opcode;         /**< Operation code (PCMD_READ_12) */
     265        uint8_t _res0;
     266        uint32_t ba;            /**< Starting block address */
     267        uint32_t nblocks;       /**< Number of blocks to transfer */
     268        uint8_t _res1;
     269        uint8_t _res2;
     270} __attribute__ ((packed)) ata_pcmd_read_12_t;
     271
     272/** Data returned from Inquiry command (mandatory part) */
     273typedef struct {
     274        uint8_t pdev_type;      /** Reserved, Peripheral device type */
     275        uint8_t rmb;            /** RMB, Reserved */
     276        uint8_t std_version;    /** ISO version, ECMA version, ANSI version */
     277        uint8_t atapi_ver_rdf;  /** ATAPI version, Response data format */
     278        uint8_t additional_len; /** Additional length */
     279        uint8_t _res0;
     280        uint8_t _res1;
     281        uint8_t _res2;
     282        uint8_t vendor_id[8];   /** Vendor ID */
     283        uint8_t product_id[8];  /** Product ID */
     284        uint8_t product_rev[4]; /** Product revision level */
     285} ata_inquiry_data_t;
     286
     287/** Extract value of ata_inquiry_data_t.pdev_type */
     288#define INQUIRY_PDEV_TYPE(val) ((val) & 0x1f)
     289
     290/** Values for ata_inquiry_data_t.pdev_type */
     291enum ata_pdev_type {
     292        PDEV_TYPE_CDROM         = 0x05
     293};
     294
    228295#endif
    229296
Note: See TracChangeset for help on using the changeset viewer.