Changeset 8b5690f in mainline for uspace/srv/bd/ata_bd/ata_bd.c


Ignore:
Timestamp:
2011-02-03T05:11:01Z (13 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
ba38f72c
Parents:
22027b6e (diff), 86d7bfa (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

    r22027b6e r8b5690f  
    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);
     
    171181                rc = devmap_device_register(name, &disk[i].devmap_handle);
    172182                if (rc != EOK) {
    173                         devmap_hangup_phone(DEVMAP_DRIVER);
    174183                        printf(NAME ": Unable to register device %s.\n", name);
    175184                        return rc;
     
    205214        printf("%s: ", d->model);
    206215
    207         switch (d->amode) {
    208         case am_chs:
    209                 printf("CHS %u cylinders, %u heads, %u sectors",
    210                     disk->geom.cylinders, disk->geom.heads, disk->geom.sectors);
    211                 break;
    212         case am_lba28:
    213                 printf("LBA-28");
    214                 break;
    215         case am_lba48:
    216                 printf("LBA-48");
    217                 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");
    218232        }
    219233
     
    267281        sysarg_t method;
    268282        devmap_handle_t dh;
    269         int flags;
     283        unsigned int flags;
    270284        int retval;
    271285        uint64_t ba;
     
    283297
    284298        if (disk_id < 0 || disk[disk_id].present == false) {
    285                 ipc_answer_0(iid, EINVAL);
     299                async_answer_0(iid, EINVAL);
    286300                return;
    287301        }
    288302
    289303        /* Answer the IPC_M_CONNECT_ME_TO call. */
    290         ipc_answer_0(iid, EOK);
     304        async_answer_0(iid, EOK);
    291305
    292306        if (!async_share_out_receive(&callid, &comm_size, &flags)) {
    293                 ipc_answer_0(callid, EHANGUP);
     307                async_answer_0(callid, EHANGUP);
    294308                return;
    295309        }
     
    297311        fs_va = as_get_mappable_page(comm_size);
    298312        if (fs_va == NULL) {
    299                 ipc_answer_0(callid, EHANGUP);
     313                async_answer_0(callid, EHANGUP);
    300314                return;
    301315        }
     
    309323                case IPC_M_PHONE_HUNGUP:
    310324                        /* The other side has hung up. */
    311                         ipc_answer_0(callid, EOK);
     325                        async_answer_0(callid, EOK);
    312326                        return;
    313327                case BD_READ_BLOCKS:
     
    315329                            IPC_GET_ARG2(call));
    316330                        cnt = IPC_GET_ARG3(call);
    317                         if (cnt * block_size > comm_size) {
     331                        if (cnt * disk[disk_id].block_size > comm_size) {
    318332                                retval = ELIMIT;
    319333                                break;
     
    325339                            IPC_GET_ARG2(call));
    326340                        cnt = IPC_GET_ARG3(call);
    327                         if (cnt * block_size > comm_size) {
     341                        if (cnt * disk[disk_id].block_size > comm_size) {
    328342                                retval = ELIMIT;
    329343                                break;
     
    332346                        break;
    333347                case BD_GET_BLOCK_SIZE:
    334                         ipc_answer_1(callid, EOK, block_size);
     348                        async_answer_1(callid, EOK, disk[disk_id].block_size);
    335349                        continue;
    336350                case BD_GET_NUM_BLOCKS:
    337                         ipc_answer_2(callid, EOK, LOWER32(disk[disk_id].blocks),
     351                        async_answer_2(callid, EOK, LOWER32(disk[disk_id].blocks),
    338352                            UPPER32(disk[disk_id].blocks));
    339353                        continue;
     
    342356                        break;
    343357                }
    344                 ipc_answer_0(callid, retval);
     358                async_answer_0(callid, retval);
    345359        }
    346360}
     
    355369        identify_data_t idata;
    356370        uint8_t model[40];
     371        ata_inquiry_data_t inq_data;
    357372        uint16_t w;
    358373        uint8_t c;
     
    361376        unsigned i;
    362377
     378        d->present = false;
     379        fibril_mutex_initialize(&d->lock);
     380
     381        /* Try identify command. */
    363382        rc = drive_identify(disk_id, &idata);
    364         if (rc != EOK) {
    365                 d->present = false;
    366                 return rc;
    367         }
    368 
    369         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) {
    370416                /* Device only supports CHS addressing. */
    371417                d->amode = am_chs;
     
    424470        d->model[pos] = '\0';
    425471
     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
    426492        d->present = true;
    427         fibril_mutex_initialize(&d->lock);
    428 
    429493        return EOK;
    430494}
     
    437501
    438502        while (cnt > 0) {
    439                 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
    440509                if (rc != EOK)
    441510                        return rc;
     
    443512                ++ba;
    444513                --cnt;
    445                 buf += block_size;
     514                buf += disk[disk_id].block_size;
    446515        }
    447516
     
    455524        int rc;
    456525
     526        if (disk[disk_id].dev_type != ata_reg_dev)
     527                return ENOTSUP;
     528
    457529        while (cnt > 0) {
    458                 rc = ata_bd_write_block(disk_id, ba, 1, buf);
     530                rc = ata_rcmd_write(disk_id, ba, 1, buf);
    459531                if (rc != EOK)
    460532                        return rc;
     
    462534                ++ba;
    463535                --cnt;
    464                 buf += block_size;
     536                buf += disk[disk_id].block_size;
    465537        }
    466538
     
    475547 * @param disk_id       Device ID, 0 or 1.
    476548 * @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.
    477552 */
    478553static int drive_identify(int disk_id, void *buf)
     
    486561
    487562        if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
    488                 return EIO;
     563                return ETIMEOUT;
    489564
    490565        pio_write_8(&cmd->drive_head, drv_head);
     
    495570         */
    496571        if (wait_status(SR_DRDY, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
    497                 return EIO;
     572                return ETIMEOUT;
    498573
    499574        pio_write_8(&cmd->command, CMD_IDENTIFY_DRIVE);
    500575
    501576        if (wait_status(0, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK)
    502                 return EIO;
     577                return ETIMEOUT;
    503578
    504579        /* Read data from the disk buffer. */
    505580
    506581        if ((status & SR_DRQ) != 0) {
    507                 for (i = 0; i < block_size / 2; i++) {
     582                for (i = 0; i < identify_data_size / 2; i++) {
    508583                        data = pio_read_16(&cmd->data_port);
    509584                        ((uint16_t *) buf)[i] = data;
     
    511586        }
    512587
     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
    513635        if ((status & SR_ERR) != 0)
    514636                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;
    515788
    516789        return EOK;
     
    526799 * @return EOK on success, EIO on error.
    527800 */
    528 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,
    529802    void *buf)
    530803{
     
    581854                /* Read data from the device buffer. */
    582855
    583                 for (i = 0; i < block_size / 2; i++) {
     856                for (i = 0; i < disk[disk_id].block_size / 2; i++) {
    584857                        data = pio_read_16(&cmd->data_port);
    585858                        ((uint16_t *) buf)[i] = data;
     
    603876 * @return EOK on success, EIO on error.
    604877 */
    605 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,
    606879    const void *buf)
    607880{
     
    657930                /* Write data to the device buffer. */
    658931
    659                 for (i = 0; i < block_size / 2; i++) {
     932                for (i = 0; i < disk[disk_id].block_size / 2; i++) {
    660933                        pio_write_16(&cmd->data_port, ((uint16_t *) buf)[i]);
    661934                }
Note: See TracChangeset for help on using the changeset viewer.