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


Ignore:
Timestamp:
2011-04-15T19:38:07Z (13 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
9dd730d1
Parents:
6b9e85b (diff), b2fb47f (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

    r6b9e85b r8b655705  
    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;
     374        uint16_t bc;
    358375        size_t pos, len;
    359376        int rc;
    360377        unsigned i;
    361378
     379        d->present = false;
     380        fibril_mutex_initialize(&d->lock);
     381
     382        /* Try identify command. */
    362383        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) {
     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. Check to see
     391                 * whether the IDENTIFY command left the packet signature in
     392                 * the registers in case this is a packet device.
     393                 *
     394                 * According to the ATA specification, the LBA low and
     395                 * interrupt reason registers should be set to 0x01. However,
     396                 * there are many devices that do not follow this and only set
     397                 * the byte count registers. So, only check these.
     398                 */
     399                bc = ((uint16_t)pio_read_8(&cmd->cylinder_high) << 8) |
     400                    pio_read_8(&cmd->cylinder_low);
     401
     402                if (bc == PDEV_SIGNATURE_BC) {
     403                        rc = identify_pkt_dev(disk_id, &idata);
     404                        if (rc == EOK) {
     405                                /* We have a packet device. */
     406                                d->dev_type = ata_pkt_dev;
     407                        } else {
     408                                return EIO;
     409                        }
     410                } else {
     411                        /* Nope. Something's there, but not recognized. */
     412                        return EIO;
     413                }
     414        } else {
     415                /* Operation timed out. That means there is no device there. */
     416                return EIO;
     417        }
     418
     419        if (d->dev_type == ata_pkt_dev) {
     420                /* Packet device */
     421                d->amode = 0;
     422
     423                d->geom.cylinders = 0;
     424                d->geom.heads = 0;
     425                d->geom.sectors = 0;
     426
     427                d->blocks = 0;
     428        } else if ((idata.caps & rd_cap_lba) == 0) {
    369429                /* Device only supports CHS addressing. */
    370430                d->amode = am_chs;
     
    423483        d->model[pos] = '\0';
    424484
     485        if (d->dev_type == ata_pkt_dev) {
     486                /* Send inquiry. */
     487                rc = ata_pcmd_inquiry(0, &inq_data, sizeof(inq_data));
     488                if (rc != EOK) {
     489                        printf("Device inquiry failed.\n");
     490                        d->present = false;
     491                        return EIO;
     492                }
     493
     494                /* Check device type. */
     495                if (INQUIRY_PDEV_TYPE(inq_data.pdev_type) != PDEV_TYPE_CDROM)
     496                        printf("Warning: Peripheral device type is not CD-ROM.\n");
     497
     498                /* Assume 2k block size for now. */
     499                d->block_size = 2048;
     500        } else {
     501                /* Assume register Read always uses 512-byte blocks. */
     502                d->block_size = 512;
     503        }
     504
    425505        d->present = true;
    426         fibril_mutex_initialize(&d->lock);
    427 
    428506        return EOK;
    429507}
     
    436514
    437515        while (cnt > 0) {
    438                 rc = ata_bd_read_block(disk_id, ba, 1, buf);
     516                if (disk[disk_id].dev_type == ata_reg_dev)
     517                        rc = ata_rcmd_read(disk_id, ba, 1, buf);
     518                else
     519                        rc = ata_pcmd_read_12(disk_id, ba, 1, buf,
     520                            disk[disk_id].block_size);
     521
    439522                if (rc != EOK)
    440523                        return rc;
     
    442525                ++ba;
    443526                --cnt;
    444                 buf += block_size;
     527                buf += disk[disk_id].block_size;
    445528        }
    446529
     
    454537        int rc;
    455538
     539        if (disk[disk_id].dev_type != ata_reg_dev)
     540                return ENOTSUP;
     541
    456542        while (cnt > 0) {
    457                 rc = ata_bd_write_block(disk_id, ba, 1, buf);
     543                rc = ata_rcmd_write(disk_id, ba, 1, buf);
    458544                if (rc != EOK)
    459545                        return rc;
     
    461547                ++ba;
    462548                --cnt;
    463                 buf += block_size;
     549                buf += disk[disk_id].block_size;
    464550        }
    465551
     
    474560 * @param disk_id       Device ID, 0 or 1.
    475561 * @param buf           Pointer to a 512-byte buffer.
     562 *
     563 * @return              ETIMEOUT on timeout (this can mean the device is
     564 *                      not present). EIO if device responds with error.
    476565 */
    477566static int drive_identify(int disk_id, void *buf)
     
    485574
    486575        if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
    487                 return EIO;
     576                return ETIMEOUT;
    488577
    489578        pio_write_8(&cmd->drive_head, drv_head);
    490579
    491580        /*
    492          * This is where we would most likely expect a non-existing device to
    493          * show up by not setting SR_DRDY.
     581         * Do not wait for DRDY to be set in case this is a packet device.
     582         * We determine whether the device is present by waiting for DRQ to be
     583         * set after issuing the command.
    494584         */
    495         if (wait_status(SR_DRDY, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
    496                 return EIO;
     585        if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
     586                return ETIMEOUT;
    497587
    498588        pio_write_8(&cmd->command, CMD_IDENTIFY_DRIVE);
    499589
    500590        if (wait_status(0, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK)
    501                 return EIO;
     591                return ETIMEOUT;
     592
     593        /*
     594         * If ERR is set, this may be a packet device, so return EIO to cause
     595         * the caller to check for one.
     596         */
     597        if ((status & SR_ERR) != 0) {
     598                return EIO;
     599        }
     600
     601        if (wait_status(SR_DRQ, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK)
     602                return ETIMEOUT;
    502603
    503604        /* Read data from the disk buffer. */
    504605
     606        for (i = 0; i < identify_data_size / 2; i++) {
     607                data = pio_read_16(&cmd->data_port);
     608                ((uint16_t *) buf)[i] = data;
     609        }
     610
     611        return EOK;
     612}
     613
     614/** Issue Identify Packet Device command.
     615 *
     616 * Reads @c identify data into the provided buffer. This is used to detect
     617 * whether an ATAPI device is present and if so, to determine its parameters.
     618 *
     619 * @param dev_idx       Device index, 0 or 1.
     620 * @param buf           Pointer to a 512-byte buffer.
     621 */
     622static int identify_pkt_dev(int dev_idx, void *buf)
     623{
     624        uint16_t data;
     625        uint8_t status;
     626        uint8_t drv_head;
     627        size_t i;
     628
     629        drv_head = ((dev_idx != 0) ? DHR_DRV : 0);
     630
     631        if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
     632                return EIO;
     633
     634        pio_write_8(&cmd->drive_head, drv_head);
     635
     636        /* For ATAPI commands we do not need to wait for DRDY. */
     637        if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
     638                return EIO;
     639
     640        pio_write_8(&cmd->command, CMD_IDENTIFY_PKT_DEV);
     641
     642        if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK)
     643                return EIO;
     644
     645        /* Read data from the device buffer. */
     646
    505647        if ((status & SR_DRQ) != 0) {
    506                 for (i = 0; i < block_size / 2; i++) {
     648                for (i = 0; i < identify_data_size / 2; i++) {
    507649                        data = pio_read_16(&cmd->data_port);
    508650                        ((uint16_t *) buf)[i] = data;
     
    512654        if ((status & SR_ERR) != 0)
    513655                return EIO;
     656
     657        return EOK;
     658}
     659
     660/** Issue packet command (i. e. write a command packet to the device).
     661 *
     662 * Only data-in commands are supported (e.g. inquiry, read).
     663 *
     664 * @param dev_idx       Device index (0 or 1)
     665 * @param obuf          Buffer for storing data read from device
     666 * @param obuf_size     Size of obuf in bytes
     667 *
     668 * @return EOK on success, EIO on error.
     669 */
     670static int ata_cmd_packet(int dev_idx, const void *cpkt, size_t cpkt_size,
     671    void *obuf, size_t obuf_size)
     672{
     673        size_t i;
     674        uint8_t status;
     675        uint8_t drv_head;
     676        disk_t *d;
     677        size_t data_size;
     678        uint16_t val;
     679
     680        d = &disk[dev_idx];
     681        fibril_mutex_lock(&d->lock);
     682
     683        /* New value for Drive/Head register */
     684        drv_head =
     685            ((dev_idx != 0) ? DHR_DRV : 0);
     686
     687        if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) {
     688                fibril_mutex_unlock(&d->lock);
     689                return EIO;
     690        }
     691
     692        pio_write_8(&cmd->drive_head, drv_head);
     693
     694        if (wait_status(0, ~(SR_BSY|SR_DRQ), NULL, TIMEOUT_BSY) != EOK) {
     695                fibril_mutex_unlock(&d->lock);
     696                return EIO;
     697        }
     698
     699        /* Byte count <- max. number of bytes we can read in one transfer. */
     700        pio_write_8(&cmd->cylinder_low, 0xfe);
     701        pio_write_8(&cmd->cylinder_high, 0xff);
     702
     703        pio_write_8(&cmd->command, CMD_PACKET);
     704
     705        if (wait_status(SR_DRQ, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
     706                fibril_mutex_unlock(&d->lock);
     707                return EIO;
     708        }
     709
     710        /* Write command packet. */
     711        for (i = 0; i < (cpkt_size + 1) / 2; i++)
     712                pio_write_16(&cmd->data_port, ((uint16_t *) cpkt)[i]);
     713
     714        if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
     715                fibril_mutex_unlock(&d->lock);
     716                return EIO;
     717        }
     718
     719        if ((status & SR_DRQ) == 0) {
     720                fibril_mutex_unlock(&d->lock);
     721                return EIO;
     722        }
     723
     724        /* Read byte count. */
     725        data_size = (uint16_t) pio_read_8(&cmd->cylinder_low) +
     726            ((uint16_t) pio_read_8(&cmd->cylinder_high) << 8);
     727
     728        /* Check whether data fits into output buffer. */
     729        if (data_size > obuf_size) {
     730                /* Output buffer is too small to store data. */
     731                fibril_mutex_unlock(&d->lock);
     732                return EIO;
     733        }
     734
     735        /* Read data from the device buffer. */
     736        for (i = 0; i < (data_size + 1) / 2; i++) {
     737                val = pio_read_16(&cmd->data_port);
     738                ((uint16_t *) obuf)[i] = val;
     739        }
     740
     741        if (status & SR_ERR) {
     742                fibril_mutex_unlock(&d->lock);
     743                return EIO;
     744        }
     745
     746        fibril_mutex_unlock(&d->lock);
     747
     748        return EOK;
     749}
     750
     751/** Issue ATAPI Inquiry.
     752 *
     753 * @param dev_idx       Device index (0 or 1)
     754 * @param obuf          Buffer for storing inquiry data read from device
     755 * @param obuf_size     Size of obuf in bytes
     756 *
     757 * @return EOK on success, EIO on error.
     758 */
     759static int ata_pcmd_inquiry(int dev_idx, void *obuf, size_t obuf_size)
     760{
     761        ata_pcmd_inquiry_t cp;
     762        int rc;
     763
     764        memset(&cp, 0, sizeof(cp));
     765
     766        cp.opcode = PCMD_INQUIRY;
     767        cp.alloc_len = min(obuf_size, 0xff); /* Allocation length */
     768
     769        rc = ata_cmd_packet(0, &cp, sizeof(cp), obuf, obuf_size);
     770        if (rc != EOK)
     771                return rc;
     772
     773        return EOK;
     774}
     775
     776/** Issue ATAPI read(12) command.
     777 *
     778 * Output buffer must be large enough to hold the data, otherwise the
     779 * function will fail.
     780 *
     781 * @param dev_idx       Device index (0 or 1)
     782 * @param ba            Starting block address
     783 * @param cnt           Number of blocks to read
     784 * @param obuf          Buffer for storing inquiry data read from device
     785 * @param obuf_size     Size of obuf in bytes
     786 *
     787 * @return EOK on success, EIO on error.
     788 */
     789static int ata_pcmd_read_12(int dev_idx, uint64_t ba, size_t cnt,
     790    void *obuf, size_t obuf_size)
     791{
     792        ata_pcmd_read_12_t cp;
     793        int rc;
     794
     795        if (ba > UINT32_MAX)
     796                return EINVAL;
     797
     798        memset(&cp, 0, sizeof(cp));
     799
     800        cp.opcode = PCMD_READ_12;
     801        cp.ba = host2uint32_t_be(ba);
     802        cp.nblocks = host2uint32_t_be(cnt);
     803
     804        rc = ata_cmd_packet(0, &cp, sizeof(cp), obuf, obuf_size);
     805        if (rc != EOK)
     806                return rc;
    514807
    515808        return EOK;
     
    525818 * @return EOK on success, EIO on error.
    526819 */
    527 static int ata_bd_read_block(int disk_id, uint64_t ba, size_t blk_cnt,
     820static int ata_rcmd_read(int disk_id, uint64_t ba, size_t blk_cnt,
    528821    void *buf)
    529822{
     
    580873                /* Read data from the device buffer. */
    581874
    582                 for (i = 0; i < block_size / 2; i++) {
     875                for (i = 0; i < disk[disk_id].block_size / 2; i++) {
    583876                        data = pio_read_16(&cmd->data_port);
    584877                        ((uint16_t *) buf)[i] = data;
     
    602895 * @return EOK on success, EIO on error.
    603896 */
    604 static int ata_bd_write_block(int disk_id, uint64_t ba, size_t cnt,
     897static int ata_rcmd_write(int disk_id, uint64_t ba, size_t cnt,
    605898    const void *buf)
    606899{
     
    656949                /* Write data to the device buffer. */
    657950
    658                 for (i = 0; i < block_size / 2; i++) {
     951                for (i = 0; i < disk[disk_id].block_size / 2; i++) {
    659952                        pio_write_16(&cmd->data_port, ((uint16_t *) buf)[i]);
    660953                }
Note: See TracChangeset for help on using the changeset viewer.