Ignore:
File:
1 edited

Legend:

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

    re092dc5 raa893e0  
    5656#include <as.h>
    5757#include <fibril_synch.h>
     58#include <stdint.h>
    5859#include <str.h>
    5960#include <devmap.h>
     
    6263#include <errno.h>
    6364#include <bool.h>
     65#include <byteorder.h>
    6466#include <task.h>
    6567#include <macros.h>
     
    7476#define LEGACY_CTLS 4
    7577
    76 /** Physical block size. Should be always 512. */
    77 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;
    7883
    7984/** Size of the communication area. */
     
    106111static int ata_bd_write_blocks(int disk_id, uint64_t ba, size_t cnt,
    107112    const void *buf);
    108 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,
    109114    void *buf);
    110 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,
    111116    const void *buf);
    112117static int disk_init(disk_t *d, int disk_id);
    113118static 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);
    114125static void disk_print_summary(disk_t *d);
    115126static int coord_calc(disk_t *d, uint64_t ba, block_coord_t *bc);
     
    171182                rc = devmap_device_register(name, &disk[i].devmap_handle);
    172183                if (rc != EOK) {
    173                         devmap_hangup_phone(DEVMAP_DRIVER);
    174184                        printf(NAME ": Unable to register device %s.\n", name);
    175185                        return rc;
     
    205215        printf("%s: ", d->model);
    206216
    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;
     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");
    218233        }
    219234
     
    315330                            IPC_GET_ARG2(call));
    316331                        cnt = IPC_GET_ARG3(call);
    317                         if (cnt * block_size > comm_size) {
     332                        if (cnt * disk[disk_id].block_size > comm_size) {
    318333                                retval = ELIMIT;
    319334                                break;
     
    325340                            IPC_GET_ARG2(call));
    326341                        cnt = IPC_GET_ARG3(call);
    327                         if (cnt * block_size > comm_size) {
     342                        if (cnt * disk[disk_id].block_size > comm_size) {
    328343                                retval = ELIMIT;
    329344                                break;
     
    332347                        break;
    333348                case BD_GET_BLOCK_SIZE:
    334                         ipc_answer_1(callid, EOK, block_size);
     349                        ipc_answer_1(callid, EOK, disk[disk_id].block_size);
    335350                        continue;
    336351                case BD_GET_NUM_BLOCKS:
     
    355370        identify_data_t idata;
    356371        uint8_t model[40];
     372        ata_inquiry_data_t inq_data;
    357373        uint16_t w;
    358374        uint8_t c;
     
    361377        unsigned i;
    362378
     379        d->present = false;
     380        fibril_mutex_initialize(&d->lock);
     381
     382        /* Try identify command. */
    363383        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) {
     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) {
    370417                /* Device only supports CHS addressing. */
    371418                d->amode = am_chs;
     
    424471        d->model[pos] = '\0';
    425472
     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
    426493        d->present = true;
    427         fibril_mutex_initialize(&d->lock);
    428 
    429494        return EOK;
    430495}
     
    437502
    438503        while (cnt > 0) {
    439                 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
    440510                if (rc != EOK)
    441511                        return rc;
     
    443513                ++ba;
    444514                --cnt;
    445                 buf += block_size;
     515                buf += disk[disk_id].block_size;
    446516        }
    447517
     
    455525        int rc;
    456526
     527        if (disk[disk_id].dev_type != ata_reg_dev)
     528                return ENOTSUP;
     529
    457530        while (cnt > 0) {
    458                 rc = ata_bd_write_block(disk_id, ba, 1, buf);
     531                rc = ata_rcmd_write(disk_id, ba, 1, buf);
    459532                if (rc != EOK)
    460533                        return rc;
     
    462535                ++ba;
    463536                --cnt;
    464                 buf += block_size;
     537                buf += disk[disk_id].block_size;
    465538        }
    466539
     
    475548 * @param disk_id       Device ID, 0 or 1.
    476549 * @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.
    477553 */
    478554static int drive_identify(int disk_id, void *buf)
     
    486562
    487563        if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
    488                 return EIO;
     564                return ETIMEOUT;
    489565
    490566        pio_write_8(&cmd->drive_head, drv_head);
     
    495571         */
    496572        if (wait_status(SR_DRDY, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
    497                 return EIO;
     573                return ETIMEOUT;
    498574
    499575        pio_write_8(&cmd->command, CMD_IDENTIFY_DRIVE);
    500576
    501577        if (wait_status(0, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK)
    502                 return EIO;
     578                return ETIMEOUT;
    503579
    504580        /* Read data from the disk buffer. */
    505581
    506582        if ((status & SR_DRQ) != 0) {
    507                 for (i = 0; i < block_size / 2; i++) {
     583                for (i = 0; i < identify_data_size / 2; i++) {
    508584                        data = pio_read_16(&cmd->data_port);
    509585                        ((uint16_t *) buf)[i] = data;
     
    511587        }
    512588
     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
    513636        if ((status & SR_ERR) != 0)
    514637                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;
    515789
    516790        return EOK;
     
    526800 * @return EOK on success, EIO on error.
    527801 */
    528 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,
    529803    void *buf)
    530804{
     
    581855                /* Read data from the device buffer. */
    582856
    583                 for (i = 0; i < block_size / 2; i++) {
     857                for (i = 0; i < disk[disk_id].block_size / 2; i++) {
    584858                        data = pio_read_16(&cmd->data_port);
    585859                        ((uint16_t *) buf)[i] = data;
     
    603877 * @return EOK on success, EIO on error.
    604878 */
    605 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,
    606880    const void *buf)
    607881{
     
    657931                /* Write data to the device buffer. */
    658932
    659                 for (i = 0; i < block_size / 2; i++) {
     933                for (i = 0; i < disk[disk_id].block_size / 2; i++) {
    660934                        pio_write_16(&cmd->data_port, ((uint16_t *) buf)[i]);
    661935                }
Note: See TracChangeset for help on using the changeset viewer.