Ignore:
File:
1 edited

Legend:

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

    r47b7006 raa893e0  
    5151#include <libarch/ddi.h>
    5252#include <ddi.h>
     53#include <ipc/ipc.h>
    5354#include <ipc/bd.h>
    5455#include <async.h>
    5556#include <as.h>
    5657#include <fibril_synch.h>
     58#include <stdint.h>
    5759#include <str.h>
    5860#include <devmap.h>
     
    6163#include <errno.h>
    6264#include <bool.h>
     65#include <byteorder.h>
    6366#include <task.h>
    6467#include <macros.h>
     
    7376#define LEGACY_CTLS 4
    7477
    75 /** Physical block size. Should be always 512. */
    76 static const size_t block_size = 512;
     78/**
     79 * Size of data returned from Identify Device or Identify Packet Device
     80 * command.
     81 */
     82static const size_t identify_data_size = 512;
    7783
    7884/** Size of the communication area. */
     
    105111static int ata_bd_write_blocks(int disk_id, uint64_t ba, size_t cnt,
    106112    const void *buf);
    107 static int ata_bd_read_block(int disk_id, uint64_t ba, size_t cnt,
     113static int ata_rcmd_read(int disk_id, uint64_t ba, size_t cnt,
    108114    void *buf);
    109 static int ata_bd_write_block(int disk_id, uint64_t ba, size_t cnt,
     115static int ata_rcmd_write(int disk_id, uint64_t ba, size_t cnt,
    110116    const void *buf);
    111117static int disk_init(disk_t *d, int disk_id);
    112118static int drive_identify(int drive_id, void *buf);
     119static int identify_pkt_dev(int dev_idx, void *buf);
     120static int ata_cmd_packet(int dev_idx, const void *cpkt, size_t cpkt_size,
     121    void *obuf, size_t obuf_size);
     122static int ata_pcmd_inquiry(int dev_idx, void *obuf, size_t obuf_size);
     123static int ata_pcmd_read_12(int dev_idx, uint64_t ba, size_t cnt,
     124    void *obuf, size_t obuf_size);
    113125static void disk_print_summary(disk_t *d);
    114126static int coord_calc(disk_t *d, uint64_t ba, block_coord_t *bc);
     
    203215        printf("%s: ", d->model);
    204216
    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;
     217        if (d->dev_type == ata_reg_dev) {
     218                switch (d->amode) {
     219                case am_chs:
     220                        printf("CHS %u cylinders, %u heads, %u sectors",
     221                            disk->geom.cylinders, disk->geom.heads,
     222                            disk->geom.sectors);
     223                        break;
     224                case am_lba28:
     225                        printf("LBA-28");
     226                        break;
     227                case am_lba48:
     228                        printf("LBA-48");
     229                        break;
     230                }
     231        } else {
     232                printf("PACKET");
    216233        }
    217234
     
    265282        sysarg_t method;
    266283        devmap_handle_t dh;
    267         unsigned int flags;
     284        int flags;
    268285        int retval;
    269286        uint64_t ba;
     
    281298
    282299        if (disk_id < 0 || disk[disk_id].present == false) {
    283                 async_answer_0(iid, EINVAL);
     300                ipc_answer_0(iid, EINVAL);
    284301                return;
    285302        }
    286303
    287304        /* Answer the IPC_M_CONNECT_ME_TO call. */
    288         async_answer_0(iid, EOK);
     305        ipc_answer_0(iid, EOK);
    289306
    290307        if (!async_share_out_receive(&callid, &comm_size, &flags)) {
    291                 async_answer_0(callid, EHANGUP);
     308                ipc_answer_0(callid, EHANGUP);
    292309                return;
    293310        }
     
    295312        fs_va = as_get_mappable_page(comm_size);
    296313        if (fs_va == NULL) {
    297                 async_answer_0(callid, EHANGUP);
     314                ipc_answer_0(callid, EHANGUP);
    298315                return;
    299316        }
     
    307324                case IPC_M_PHONE_HUNGUP:
    308325                        /* The other side has hung up. */
    309                         async_answer_0(callid, EOK);
     326                        ipc_answer_0(callid, EOK);
    310327                        return;
    311328                case BD_READ_BLOCKS:
     
    313330                            IPC_GET_ARG2(call));
    314331                        cnt = IPC_GET_ARG3(call);
    315                         if (cnt * block_size > comm_size) {
     332                        if (cnt * disk[disk_id].block_size > comm_size) {
    316333                                retval = ELIMIT;
    317334                                break;
     
    323340                            IPC_GET_ARG2(call));
    324341                        cnt = IPC_GET_ARG3(call);
    325                         if (cnt * block_size > comm_size) {
     342                        if (cnt * disk[disk_id].block_size > comm_size) {
    326343                                retval = ELIMIT;
    327344                                break;
     
    330347                        break;
    331348                case BD_GET_BLOCK_SIZE:
    332                         async_answer_1(callid, EOK, block_size);
     349                        ipc_answer_1(callid, EOK, disk[disk_id].block_size);
    333350                        continue;
    334351                case BD_GET_NUM_BLOCKS:
    335                         async_answer_2(callid, EOK, LOWER32(disk[disk_id].blocks),
     352                        ipc_answer_2(callid, EOK, LOWER32(disk[disk_id].blocks),
    336353                            UPPER32(disk[disk_id].blocks));
    337354                        continue;
     
    340357                        break;
    341358                }
    342                 async_answer_0(callid, retval);
     359                ipc_answer_0(callid, retval);
    343360        }
    344361}
     
    353370        identify_data_t idata;
    354371        uint8_t model[40];
     372        ata_inquiry_data_t inq_data;
    355373        uint16_t w;
    356374        uint8_t c;
     
    359377        unsigned i;
    360378
     379        d->present = false;
     380        fibril_mutex_initialize(&d->lock);
     381
     382        /* Try identify command. */
    361383        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) {
     384        if (rc == EOK) {
     385                /* Success. It's a register (non-packet) device. */
     386                printf("ATA register-only device found.\n");
     387                d->dev_type = ata_reg_dev;
     388        } else if (rc == EIO) {
     389                /*
     390                 * There is something, but not a register device.
     391                 * It could be a packet device.
     392                 */
     393                rc = identify_pkt_dev(disk_id, &idata);
     394                if (rc == EOK) {
     395                        /* We have a packet device. */
     396                        d->dev_type = ata_pkt_dev;
     397                } else {
     398                        /* Nope. Something's there, but not recognized. */
     399                        return EIO;
     400                }
     401        } else {
     402                /* Operation timed out. That means there is no device there. */
     403                return EIO;
     404        }
     405
     406        printf("device caps: 0x%04x\n", idata.caps);
     407        if (d->dev_type == ata_pkt_dev) {
     408                /* Packet device */
     409                d->amode = 0;
     410
     411                d->geom.cylinders = 0;
     412                d->geom.heads = 0;
     413                d->geom.sectors = 0;
     414
     415                d->blocks = 0;
     416        } else if ((idata.caps & rd_cap_lba) == 0) {
    368417                /* Device only supports CHS addressing. */
    369418                d->amode = am_chs;
     
    422471        d->model[pos] = '\0';
    423472
     473        if (d->dev_type == ata_pkt_dev) {
     474                /* Send inquiry. */
     475                rc = ata_pcmd_inquiry(0, &inq_data, sizeof(inq_data));
     476                if (rc != EOK) {
     477                        printf("Device inquiry failed.\n");
     478                        d->present = false;
     479                        return EIO;
     480                }
     481
     482                /* Check device type. */
     483                if (INQUIRY_PDEV_TYPE(inq_data.pdev_type) != PDEV_TYPE_CDROM)
     484                        printf("Warning: Peripheral device type is not CD-ROM.\n");
     485
     486                /* Assume 2k block size for now. */
     487                d->block_size = 2048;
     488        } else {
     489                /* Assume register Read always uses 512-byte blocks. */
     490                d->block_size = 512;
     491        }
     492
    424493        d->present = true;
    425         fibril_mutex_initialize(&d->lock);
    426 
    427494        return EOK;
    428495}
     
    435502
    436503        while (cnt > 0) {
    437                 rc = ata_bd_read_block(disk_id, ba, 1, buf);
     504                if (disk[disk_id].dev_type == ata_reg_dev)
     505                        rc = ata_rcmd_read(disk_id, ba, 1, buf);
     506                else
     507                        rc = ata_pcmd_read_12(disk_id, ba, 1, buf,
     508                            disk[disk_id].block_size);
     509
    438510                if (rc != EOK)
    439511                        return rc;
     
    441513                ++ba;
    442514                --cnt;
    443                 buf += block_size;
     515                buf += disk[disk_id].block_size;
    444516        }
    445517
     
    453525        int rc;
    454526
     527        if (disk[disk_id].dev_type != ata_reg_dev)
     528                return ENOTSUP;
     529
    455530        while (cnt > 0) {
    456                 rc = ata_bd_write_block(disk_id, ba, 1, buf);
     531                rc = ata_rcmd_write(disk_id, ba, 1, buf);
    457532                if (rc != EOK)
    458533                        return rc;
     
    460535                ++ba;
    461536                --cnt;
    462                 buf += block_size;
     537                buf += disk[disk_id].block_size;
    463538        }
    464539
     
    473548 * @param disk_id       Device ID, 0 or 1.
    474549 * @param buf           Pointer to a 512-byte buffer.
     550 *
     551 * @return              ETIMEOUT on timeout (this can mean the device is
     552 *                      not present). EIO if device responds with error.
    475553 */
    476554static int drive_identify(int disk_id, void *buf)
     
    484562
    485563        if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
    486                 return EIO;
     564                return ETIMEOUT;
    487565
    488566        pio_write_8(&cmd->drive_head, drv_head);
     
    493571         */
    494572        if (wait_status(SR_DRDY, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
    495                 return EIO;
     573                return ETIMEOUT;
    496574
    497575        pio_write_8(&cmd->command, CMD_IDENTIFY_DRIVE);
    498576
    499577        if (wait_status(0, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK)
    500                 return EIO;
     578                return ETIMEOUT;
    501579
    502580        /* Read data from the disk buffer. */
    503581
    504582        if ((status & SR_DRQ) != 0) {
    505                 for (i = 0; i < block_size / 2; i++) {
     583                for (i = 0; i < identify_data_size / 2; i++) {
    506584                        data = pio_read_16(&cmd->data_port);
    507585                        ((uint16_t *) buf)[i] = data;
     
    509587        }
    510588
     589        if ((status & SR_ERR) != 0) {
     590                return EIO;
     591        }
     592
     593        return EOK;
     594}
     595
     596/** Issue Identify Packet Device command.
     597 *
     598 * Reads @c identify data into the provided buffer. This is used to detect
     599 * whether an ATAPI device is present and if so, to determine its parameters.
     600 *
     601 * @param dev_idx       Device index, 0 or 1.
     602 * @param buf           Pointer to a 512-byte buffer.
     603 */
     604static int identify_pkt_dev(int dev_idx, void *buf)
     605{
     606        uint16_t data;
     607        uint8_t status;
     608        uint8_t drv_head;
     609        size_t i;
     610
     611        drv_head = ((dev_idx != 0) ? DHR_DRV : 0);
     612
     613        if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
     614                return EIO;
     615
     616        pio_write_8(&cmd->drive_head, drv_head);
     617
     618        /* For ATAPI commands we do not need to wait for DRDY. */
     619        if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
     620                return EIO;
     621
     622        pio_write_8(&cmd->command, CMD_IDENTIFY_PKT_DEV);
     623
     624        if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK)
     625                return EIO;
     626
     627        /* Read data from the device buffer. */
     628
     629        if ((status & SR_DRQ) != 0) {
     630                for (i = 0; i < identify_data_size / 2; i++) {
     631                        data = pio_read_16(&cmd->data_port);
     632                        ((uint16_t *) buf)[i] = data;
     633                }
     634        }
     635
    511636        if ((status & SR_ERR) != 0)
    512637                return EIO;
     638
     639        return EOK;
     640}
     641
     642/** Issue packet command (i. e. write a command packet to the device).
     643 *
     644 * Only data-in commands are supported (e.g. inquiry, read).
     645 *
     646 * @param dev_idx       Device index (0 or 1)
     647 * @param obuf          Buffer for storing data read from device
     648 * @param obuf_size     Size of obuf in bytes
     649 *
     650 * @return EOK on success, EIO on error.
     651 */
     652static int ata_cmd_packet(int dev_idx, const void *cpkt, size_t cpkt_size,
     653    void *obuf, size_t obuf_size)
     654{
     655        size_t i;
     656        uint8_t status;
     657        uint8_t drv_head;
     658        disk_t *d;
     659        size_t data_size;
     660        uint16_t val;
     661
     662        d = &disk[dev_idx];
     663        fibril_mutex_lock(&d->lock);
     664
     665        /* New value for Drive/Head register */
     666        drv_head =
     667            ((dev_idx != 0) ? DHR_DRV : 0);
     668
     669        if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) {
     670                fibril_mutex_unlock(&d->lock);
     671                return EIO;
     672        }
     673
     674        pio_write_8(&cmd->drive_head, drv_head);
     675
     676        if (wait_status(0, ~(SR_BSY|SR_DRQ), NULL, TIMEOUT_BSY) != EOK) {
     677                fibril_mutex_unlock(&d->lock);
     678                return EIO;
     679        }
     680
     681        /* Byte count <- max. number of bytes we can read in one transfer. */
     682        pio_write_8(&cmd->cylinder_low, 0xfe);
     683        pio_write_8(&cmd->cylinder_high, 0xff);
     684
     685        pio_write_8(&cmd->command, CMD_PACKET);
     686
     687        if (wait_status(SR_DRQ, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
     688                fibril_mutex_unlock(&d->lock);
     689                return EIO;
     690        }
     691
     692        /* Write command packet. */
     693        for (i = 0; i < (cpkt_size + 1) / 2; i++)
     694                pio_write_16(&cmd->data_port, ((uint16_t *) cpkt)[i]);
     695
     696        if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
     697                fibril_mutex_unlock(&d->lock);
     698                return EIO;
     699        }
     700
     701        if ((status & SR_DRQ) == 0) {
     702                fibril_mutex_unlock(&d->lock);
     703                return EIO;
     704        }
     705
     706        /* Read byte count. */
     707        data_size = (uint16_t) pio_read_8(&cmd->cylinder_low) +
     708            ((uint16_t) pio_read_8(&cmd->cylinder_high) << 8);
     709
     710        /* Check whether data fits into output buffer. */
     711        if (data_size > obuf_size) {
     712                /* Output buffer is too small to store data. */
     713                fibril_mutex_unlock(&d->lock);
     714                return EIO;
     715        }
     716
     717        /* Read data from the device buffer. */
     718        for (i = 0; i < (data_size + 1) / 2; i++) {
     719                val = pio_read_16(&cmd->data_port);
     720                ((uint16_t *) obuf)[i] = val;
     721        }
     722
     723        if (status & SR_ERR) {
     724                fibril_mutex_unlock(&d->lock);
     725                return EIO;
     726        }
     727
     728        fibril_mutex_unlock(&d->lock);
     729
     730        return EOK;
     731}
     732
     733/** Issue ATAPI Inquiry.
     734 *
     735 * @param dev_idx       Device index (0 or 1)
     736 * @param obuf          Buffer for storing inquiry data read from device
     737 * @param obuf_size     Size of obuf in bytes
     738 *
     739 * @return EOK on success, EIO on error.
     740 */
     741static int ata_pcmd_inquiry(int dev_idx, void *obuf, size_t obuf_size)
     742{
     743        ata_pcmd_inquiry_t cp;
     744        int rc;
     745
     746        memset(&cp, 0, sizeof(cp));
     747
     748        cp.opcode = PCMD_INQUIRY;
     749        cp.alloc_len = min(obuf_size, 0xff); /* Allocation length */
     750
     751        rc = ata_cmd_packet(0, &cp, sizeof(cp), obuf, obuf_size);
     752        if (rc != EOK)
     753                return rc;
     754
     755        return EOK;
     756}
     757
     758/** Issue ATAPI read(12) command.
     759 *
     760 * Output buffer must be large enough to hold the data, otherwise the
     761 * function will fail.
     762 *
     763 * @param dev_idx       Device index (0 or 1)
     764 * @param ba            Starting block address
     765 * @param cnt           Number of blocks to read
     766 * @param obuf          Buffer for storing inquiry data read from device
     767 * @param obuf_size     Size of obuf in bytes
     768 *
     769 * @return EOK on success, EIO on error.
     770 */
     771static int ata_pcmd_read_12(int dev_idx, uint64_t ba, size_t cnt,
     772    void *obuf, size_t obuf_size)
     773{
     774        ata_pcmd_read_12_t cp;
     775        int rc;
     776
     777        if (ba > UINT32_MAX)
     778                return EINVAL;
     779
     780        memset(&cp, 0, sizeof(cp));
     781
     782        cp.opcode = PCMD_READ_12;
     783        cp.ba = host2uint32_t_be(ba);
     784        cp.nblocks = host2uint32_t_be(cnt);
     785
     786        rc = ata_cmd_packet(0, &cp, sizeof(cp), obuf, obuf_size);
     787        if (rc != EOK)
     788                return rc;
    513789
    514790        return EOK;
     
    524800 * @return EOK on success, EIO on error.
    525801 */
    526 static int ata_bd_read_block(int disk_id, uint64_t ba, size_t blk_cnt,
     802static int ata_rcmd_read(int disk_id, uint64_t ba, size_t blk_cnt,
    527803    void *buf)
    528804{
     
    579855                /* Read data from the device buffer. */
    580856
    581                 for (i = 0; i < block_size / 2; i++) {
     857                for (i = 0; i < disk[disk_id].block_size / 2; i++) {
    582858                        data = pio_read_16(&cmd->data_port);
    583859                        ((uint16_t *) buf)[i] = data;
     
    601877 * @return EOK on success, EIO on error.
    602878 */
    603 static int ata_bd_write_block(int disk_id, uint64_t ba, size_t cnt,
     879static int ata_rcmd_write(int disk_id, uint64_t ba, size_t cnt,
    604880    const void *buf)
    605881{
     
    655931                /* Write data to the device buffer. */
    656932
    657                 for (i = 0; i < block_size / 2; i++) {
     933                for (i = 0; i < disk[disk_id].block_size / 2; i++) {
    658934                        pio_write_16(&cmd->data_port, ((uint16_t *) buf)[i]);
    659935                }
Note: See TracChangeset for help on using the changeset viewer.