Changeset e29e09cf in mainline for uspace/srv/bd/ata_bd/ata_bd.c


Ignore:
Timestamp:
2011-02-04T21:00:56Z (13 years ago)
Author:
Vojtech Horky <vojtechhorky@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
474afc9, 960ff451
Parents:
400575c5 (diff), 17aca1c (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 mainline changes

File:
1 edited

Legend:

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

    r400575c5 re29e09cf  
    5151#include <libarch/ddi.h>
    5252#include <ddi.h>
    53 #include <ipc/ipc.h>
    5453#include <ipc/bd.h>
    5554#include <async.h>
    5655#include <as.h>
    5756#include <fibril_synch.h>
     57#include <stdint.h>
    5858#include <str.h>
    5959#include <devmap.h>
     
    6262#include <errno.h>
    6363#include <bool.h>
     64#include <byteorder.h>
    6465#include <task.h>
    6566#include <macros.h>
     
    7475#define LEGACY_CTLS 4
    7576
    76 /** Physical block size. Should be always 512. */
    77 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;
    7882
    7983/** Size of the communication area. */
     
    106110static int ata_bd_write_blocks(int disk_id, uint64_t ba, size_t cnt,
    107111    const void *buf);
    108 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,
    109113    void *buf);
    110 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,
    111115    const void *buf);
    112116static int disk_init(disk_t *d, int disk_id);
    113117static 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);
    114124static void disk_print_summary(disk_t *d);
    115125static int coord_calc(disk_t *d, uint64_t ba, block_coord_t *bc);
     
    204214        printf("%s: ", d->model);
    205215
    206         switch (d->amode) {
    207         case am_chs:
    208                 printf("CHS %u cylinders, %u heads, %u sectors",
    209                     disk->geom.cylinders, disk->geom.heads, disk->geom.sectors);
    210                 break;
    211         case am_lba28:
    212                 printf("LBA-28");
    213                 break;
    214         case am_lba48:
    215                 printf("LBA-48");
    216                 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");
    217232        }
    218233
     
    266281        sysarg_t method;
    267282        devmap_handle_t dh;
    268         int flags;
     283        unsigned int flags;
    269284        int retval;
    270285        uint64_t ba;
     
    282297
    283298        if (disk_id < 0 || disk[disk_id].present == false) {
    284                 ipc_answer_0(iid, EINVAL);
     299                async_answer_0(iid, EINVAL);
    285300                return;
    286301        }
    287302
    288303        /* Answer the IPC_M_CONNECT_ME_TO call. */
    289         ipc_answer_0(iid, EOK);
     304        async_answer_0(iid, EOK);
    290305
    291306        if (!async_share_out_receive(&callid, &comm_size, &flags)) {
    292                 ipc_answer_0(callid, EHANGUP);
     307                async_answer_0(callid, EHANGUP);
    293308                return;
    294309        }
     
    296311        fs_va = as_get_mappable_page(comm_size);
    297312        if (fs_va == NULL) {
    298                 ipc_answer_0(callid, EHANGUP);
     313                async_answer_0(callid, EHANGUP);
    299314                return;
    300315        }
     
    308323                case IPC_M_PHONE_HUNGUP:
    309324                        /* The other side has hung up. */
    310                         ipc_answer_0(callid, EOK);
     325                        async_answer_0(callid, EOK);
    311326                        return;
    312327                case BD_READ_BLOCKS:
     
    314329                            IPC_GET_ARG2(call));
    315330                        cnt = IPC_GET_ARG3(call);
    316                         if (cnt * block_size > comm_size) {
     331                        if (cnt * disk[disk_id].block_size > comm_size) {
    317332                                retval = ELIMIT;
    318333                                break;
     
    324339                            IPC_GET_ARG2(call));
    325340                        cnt = IPC_GET_ARG3(call);
    326                         if (cnt * block_size > comm_size) {
     341                        if (cnt * disk[disk_id].block_size > comm_size) {
    327342                                retval = ELIMIT;
    328343                                break;
     
    331346                        break;
    332347                case BD_GET_BLOCK_SIZE:
    333                         ipc_answer_1(callid, EOK, block_size);
     348                        async_answer_1(callid, EOK, disk[disk_id].block_size);
    334349                        continue;
    335350                case BD_GET_NUM_BLOCKS:
    336                         ipc_answer_2(callid, EOK, LOWER32(disk[disk_id].blocks),
     351                        async_answer_2(callid, EOK, LOWER32(disk[disk_id].blocks),
    337352                            UPPER32(disk[disk_id].blocks));
    338353                        continue;
     
    341356                        break;
    342357                }
    343                 ipc_answer_0(callid, retval);
     358                async_answer_0(callid, retval);
    344359        }
    345360}
     
    354369        identify_data_t idata;
    355370        uint8_t model[40];
     371        ata_inquiry_data_t inq_data;
    356372        uint16_t w;
    357373        uint8_t c;
     
    360376        unsigned i;
    361377
     378        d->present = false;
     379        fibril_mutex_initialize(&d->lock);
     380
     381        /* Try identify command. */
    362382        rc = drive_identify(disk_id, &idata);
    363         if (rc != EOK) {
    364                 d->present = false;
    365                 return rc;
    366         }
    367 
    368         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) {
    369416                /* Device only supports CHS addressing. */
    370417                d->amode = am_chs;
     
    423470        d->model[pos] = '\0';
    424471
     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
    425492        d->present = true;
    426         fibril_mutex_initialize(&d->lock);
    427 
    428493        return EOK;
    429494}
     
    436501
    437502        while (cnt > 0) {
    438                 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
    439509                if (rc != EOK)
    440510                        return rc;
     
    442512                ++ba;
    443513                --cnt;
    444                 buf += block_size;
     514                buf += disk[disk_id].block_size;
    445515        }
    446516
     
    454524        int rc;
    455525
     526        if (disk[disk_id].dev_type != ata_reg_dev)
     527                return ENOTSUP;
     528
    456529        while (cnt > 0) {
    457                 rc = ata_bd_write_block(disk_id, ba, 1, buf);
     530                rc = ata_rcmd_write(disk_id, ba, 1, buf);
    458531                if (rc != EOK)
    459532                        return rc;
     
    461534                ++ba;
    462535                --cnt;
    463                 buf += block_size;
     536                buf += disk[disk_id].block_size;
    464537        }
    465538
     
    474547 * @param disk_id       Device ID, 0 or 1.
    475548 * @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.
    476552 */
    477553static int drive_identify(int disk_id, void *buf)
     
    485561
    486562        if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
    487                 return EIO;
     563                return ETIMEOUT;
    488564
    489565        pio_write_8(&cmd->drive_head, drv_head);
     
    494570         */
    495571        if (wait_status(SR_DRDY, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
    496                 return EIO;
     572                return ETIMEOUT;
    497573
    498574        pio_write_8(&cmd->command, CMD_IDENTIFY_DRIVE);
    499575
    500576        if (wait_status(0, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK)
    501                 return EIO;
     577                return ETIMEOUT;
    502578
    503579        /* Read data from the disk buffer. */
    504580
    505581        if ((status & SR_DRQ) != 0) {
    506                 for (i = 0; i < block_size / 2; i++) {
     582                for (i = 0; i < identify_data_size / 2; i++) {
    507583                        data = pio_read_16(&cmd->data_port);
    508584                        ((uint16_t *) buf)[i] = data;
     
    510586        }
    511587
     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
    512635        if ((status & SR_ERR) != 0)
    513636                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;
    514788
    515789        return EOK;
     
    525799 * @return EOK on success, EIO on error.
    526800 */
    527 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,
    528802    void *buf)
    529803{
     
    580854                /* Read data from the device buffer. */
    581855
    582                 for (i = 0; i < block_size / 2; i++) {
     856                for (i = 0; i < disk[disk_id].block_size / 2; i++) {
    583857                        data = pio_read_16(&cmd->data_port);
    584858                        ((uint16_t *) buf)[i] = data;
     
    602876 * @return EOK on success, EIO on error.
    603877 */
    604 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,
    605879    const void *buf)
    606880{
     
    656930                /* Write data to the device buffer. */
    657931
    658                 for (i = 0; i < block_size / 2; i++) {
     932                for (i = 0; i < disk[disk_id].block_size / 2; i++) {
    659933                        pio_write_16(&cmd->data_port, ((uint16_t *) buf)[i]);
    660934                }
Note: See TracChangeset for help on using the changeset viewer.