Changeset 04803bf in mainline for uspace/srv/bd/ata_bd/ata_bd.c


Ignore:
Timestamp:
2011-03-21T22:00:17Z (15 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
143932e3
Parents:
b50b5af2 (diff), 7308e84 (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 (needs fixes).

File:
1 edited

Legend:

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

    rb50b5af2 r04803bf  
    3535 * @brief ATA disk driver
    3636 *
    37  * This driver currently works only with CHS addressing and uses PIO.
    38  * Currently based on the (now obsolete) ATA-1, ATA-2 standards.
     37 * This driver supports CHS, 28-bit and 48-bit LBA addressing. It only uses
     38 * PIO transfers. There is no support DMA, the PACKET feature set or any other
     39 * fancy features such as S.M.A.R.T, removable devices, etc.
     40 *
     41 * This driver is based on the ATA-1, ATA-2, ATA-3 and ATA/ATAPI-4 through 7
     42 * standards, as published by the ANSI, NCITS and INCITS standards bodies,
     43 * which are freely available. This driver contains no vendor-specific
     44 * code at this moment.
    3945 *
    4046 * The driver services a single controller which can have up to two disks
     
    4551#include <libarch/ddi.h>
    4652#include <ddi.h>
    47 #include <ipc/ipc.h>
    4853#include <ipc/bd.h>
    4954#include <async.h>
    5055#include <as.h>
    51 #include <fibril_sync.h>
     56#include <fibril_synch.h>
     57#include <stdint.h>
     58#include <str.h>
    5259#include <devmap.h>
    5360#include <sys/types.h>
     61#include <inttypes.h>
    5462#include <errno.h>
    5563#include <bool.h>
     64#include <byteorder.h>
    5665#include <task.h>
    57 
     66#include <macros.h>
     67
     68#include "ata_hw.h"
    5869#include "ata_bd.h"
    5970
    60 #define NAME "ata_bd"
    61 
    62 /** Physical block size. Should be always 512. */
    63 static const size_t block_size = 512;
     71#define NAME       "ata_bd"
     72#define NAMESPACE  "bd"
     73
     74/** Number of defined legacy controller base addresses. */
     75#define LEGACY_CTLS 4
     76
     77/**
     78 * Size of data returned from Identify Device or Identify Packet Device
     79 * command.
     80 */
     81static const size_t identify_data_size = 512;
    6482
    6583/** Size of the communication area. */
     
    6785
    6886/** I/O base address of the command registers. */
    69 static uintptr_t cmd_physical = 0x1f0;
     87static uintptr_t cmd_physical;
    7088/** I/O base address of the control registers. */
    71 static uintptr_t ctl_physical = 0x170;
     89static uintptr_t ctl_physical;
     90
     91/** I/O base addresses for legacy (ISA-compatible) controllers. */
     92static ata_base_t legacy_base[LEGACY_CTLS] = {
     93        { 0x1f0, 0x3f0 },
     94        { 0x170, 0x370 },
     95        { 0x1e8, 0x3e8 },
     96        { 0x168, 0x368 }
     97};
    7298
    7399static ata_cmd_t *cmd;
     
    77103static disk_t disk[MAX_DISKS];
    78104
     105static void print_syntax(void);
    79106static int ata_bd_init(void);
    80107static void ata_bd_connection(ipc_callid_t iid, ipc_call_t *icall);
    81 static int ata_bd_rdwr(int disk_id, ipcarg_t method, off_t offset, size_t size,
     108static int ata_bd_read_blocks(int disk_id, uint64_t ba, size_t cnt,
    82109    void *buf);
    83 static int ata_bd_read_block(int disk_id, uint64_t blk_idx, size_t blk_cnt,
     110static int ata_bd_write_blocks(int disk_id, uint64_t ba, size_t cnt,
     111    const void *buf);
     112static int ata_rcmd_read(int disk_id, uint64_t ba, size_t cnt,
    84113    void *buf);
    85 static int ata_bd_write_block(int disk_id, uint64_t blk_idx, size_t blk_cnt,
     114static int ata_rcmd_write(int disk_id, uint64_t ba, size_t cnt,
    86115    const void *buf);
    87 static int drive_identify(int drive_id, disk_t *d);
     116static int disk_init(disk_t *d, int disk_id);
     117static 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);
     124static void disk_print_summary(disk_t *d);
     125static int coord_calc(disk_t *d, uint64_t ba, block_coord_t *bc);
     126static void coord_sc_program(const block_coord_t *bc, uint16_t scnt);
    88127static int wait_status(unsigned set, unsigned n_reset, uint8_t *pstatus,
    89128    unsigned timeout);
     
    94133        int i, rc;
    95134        int n_disks;
     135        unsigned ctl_num;
     136        char *eptr;
    96137
    97138        printf(NAME ": ATA disk driver\n");
    98139
    99         printf("I/O address 0x%x\n", cmd_physical);
     140        if (argc > 1) {
     141                ctl_num = strtoul(argv[1], &eptr, 0);
     142                if (*eptr != '\0' || ctl_num == 0 || ctl_num > 4) {
     143                        printf("Invalid argument.\n");
     144                        print_syntax();
     145                        return -1;
     146                }
     147        } else {
     148                ctl_num = 1;
     149        }
     150
     151        cmd_physical = legacy_base[ctl_num - 1].cmd;
     152        ctl_physical = legacy_base[ctl_num - 1].ctl;
     153
     154        printf("I/O address %p/%p\n", (void *) cmd_physical,
     155            (void *) ctl_physical);
    100156
    101157        if (ata_bd_init() != EOK)
     
    106162                fflush(stdout);
    107163
    108                 rc = drive_identify(i, &disk[i]);
     164                rc = disk_init(&disk[i], i);
    109165
    110166                if (rc == EOK) {
    111                         printf("%u cylinders, %u heads, %u sectors\n",
    112                             disk[i].cylinders, disk[i].heads, disk[i].sectors);
     167                        disk_print_summary(&disk[i]);
    113168                } else {
    114169                        printf("Not found.\n");
     
    122177                if (disk[i].present == false)
    123178                        continue;
    124 
    125                 snprintf(name, 16, "disk%d", i);
    126                 rc = devmap_device_register(name, &disk[i].dev_handle);
     179               
     180                snprintf(name, 16, "%s/ata%udisk%d", NAMESPACE, ctl_num, i);
     181                rc = devmap_device_register(name, &disk[i].devmap_handle);
    127182                if (rc != EOK) {
    128                         devmap_hangup_phone(DEVMAP_DRIVER);
    129                         printf(NAME ": Unable to register device %s.\n",
    130                                 name);
     183                        printf(NAME ": Unable to register device %s.\n", name);
    131184                        return rc;
    132185                }
     
    147200}
    148201
     202
     203static void print_syntax(void)
     204{
     205        printf("Syntax: " NAME " <controller_number>\n");
     206        printf("Controller number = 1..4\n");
     207}
     208
     209/** Print one-line device summary. */
     210static void disk_print_summary(disk_t *d)
     211{
     212        uint64_t mbytes;
     213
     214        printf("%s: ", d->model);
     215
     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");
     232        }
     233
     234        printf(" %" PRIu64 " blocks", d->blocks);
     235
     236        mbytes = d->blocks / (2 * 1024);
     237        if (mbytes > 0)
     238                printf(" %" PRIu64 " MB.", mbytes);
     239
     240        printf("\n");
     241}
    149242
    150243/** Register driver and enable device I/O. */
     
    186279        ipc_callid_t callid;
    187280        ipc_call_t call;
    188         ipcarg_t method;
    189         dev_handle_t dh;
    190         int flags;
     281        sysarg_t method;
     282        devmap_handle_t dh;
     283        unsigned int flags;
    191284        int retval;
    192         off_t idx;
    193         size_t size;
     285        uint64_t ba;
     286        size_t cnt;
    194287        int disk_id, i;
    195288
     
    200293        disk_id = -1;
    201294        for (i = 0; i < MAX_DISKS; i++)
    202                 if (disk[i].dev_handle == dh)
     295                if (disk[i].devmap_handle == dh)
    203296                        disk_id = i;
    204297
    205298        if (disk_id < 0 || disk[disk_id].present == false) {
    206                 ipc_answer_0(iid, EINVAL);
     299                async_answer_0(iid, EINVAL);
    207300                return;
    208301        }
    209302
    210303        /* Answer the IPC_M_CONNECT_ME_TO call. */
    211         ipc_answer_0(iid, EOK);
    212 
    213         if (!ipc_share_out_receive(&callid, &comm_size, &flags)) {
    214                 ipc_answer_0(callid, EHANGUP);
     304        async_answer_0(iid, EOK);
     305
     306        if (!async_share_out_receive(&callid, &comm_size, &flags)) {
     307                async_answer_0(callid, EHANGUP);
    215308                return;
    216309        }
     
    218311        fs_va = as_get_mappable_page(comm_size);
    219312        if (fs_va == NULL) {
    220                 ipc_answer_0(callid, EHANGUP);
     313                async_answer_0(callid, EHANGUP);
    221314                return;
    222315        }
    223316
    224         (void) ipc_share_out_finalize(callid, fs_va);
     317        (void) async_share_out_finalize(callid, fs_va);
    225318
    226319        while (1) {
    227320                callid = async_get_call(&call);
    228                 method = IPC_GET_METHOD(call);
     321                method = IPC_GET_IMETHOD(call);
    229322                switch (method) {
    230323                case IPC_M_PHONE_HUNGUP:
    231324                        /* The other side has hung up. */
    232                         ipc_answer_0(callid, EOK);
     325                        async_answer_0(callid, EOK);
    233326                        return;
    234                 case BD_READ_BLOCK:
    235                 case BD_WRITE_BLOCK:
    236                         idx = IPC_GET_ARG1(call);
    237                         size = IPC_GET_ARG2(call);
    238                         if (size > comm_size) {
    239                                 retval = EINVAL;
     327                case BD_READ_BLOCKS:
     328                        ba = MERGE_LOUP32(IPC_GET_ARG1(call),
     329                            IPC_GET_ARG2(call));
     330                        cnt = IPC_GET_ARG3(call);
     331                        if (cnt * disk[disk_id].block_size > comm_size) {
     332                                retval = ELIMIT;
    240333                                break;
    241334                        }
    242                         retval = ata_bd_rdwr(disk_id, method, idx,
    243                             size, fs_va);
     335                        retval = ata_bd_read_blocks(disk_id, ba, cnt, fs_va);
    244336                        break;
     337                case BD_WRITE_BLOCKS:
     338                        ba = MERGE_LOUP32(IPC_GET_ARG1(call),
     339                            IPC_GET_ARG2(call));
     340                        cnt = IPC_GET_ARG3(call);
     341                        if (cnt * disk[disk_id].block_size > comm_size) {
     342                                retval = ELIMIT;
     343                                break;
     344                        }
     345                        retval = ata_bd_write_blocks(disk_id, ba, cnt, fs_va);
     346                        break;
     347                case BD_GET_BLOCK_SIZE:
     348                        async_answer_1(callid, EOK, disk[disk_id].block_size);
     349                        continue;
     350                case BD_GET_NUM_BLOCKS:
     351                        async_answer_2(callid, EOK, LOWER32(disk[disk_id].blocks),
     352                            UPPER32(disk[disk_id].blocks));
     353                        continue;
    245354                default:
    246355                        retval = EINVAL;
    247356                        break;
    248357                }
    249                 ipc_answer_0(callid, retval);
    250         }
    251 }
    252 
    253 /** Transfer a logical block from/to the device.
    254  *
    255  * @param disk_id       Device index (0 or 1)
    256  * @param method        @c BD_READ_BLOCK or @c BD_WRITE_BLOCK
    257  * @param blk_idx       Index of the first block.
    258  * @param size          Size of the logical block.
    259  * @param buf           Data buffer.
    260  *
    261  * @return EOK on success, EIO on error.
    262  */
    263 static int ata_bd_rdwr(int disk_id, ipcarg_t method, off_t blk_idx, size_t size,
    264     void *buf)
    265 {
     358                async_answer_0(callid, retval);
     359        }
     360}
     361
     362/** Initialize a disk.
     363 *
     364 * Probes for a disk, determines its parameters and initializes
     365 * the disk structure.
     366 */
     367static int disk_init(disk_t *d, int disk_id)
     368{
     369        identify_data_t idata;
     370        uint8_t model[40];
     371        ata_inquiry_data_t inq_data;
     372        uint16_t w;
     373        uint8_t c;
     374        size_t pos, len;
    266375        int rc;
    267         size_t now;
    268 
    269         while (size > 0) {
    270                 now = size < block_size ? size : block_size;
    271                 if (now != block_size)
    272                         return EINVAL;
    273 
    274                 if (method == BD_READ_BLOCK)
    275                         rc = ata_bd_read_block(disk_id, blk_idx, 1, buf);
     376        unsigned i;
     377
     378        d->present = false;
     379        fibril_mutex_initialize(&d->lock);
     380
     381        /* Try identify command. */
     382        rc = drive_identify(disk_id, &idata);
     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) {
     416                /* Device only supports CHS addressing. */
     417                d->amode = am_chs;
     418
     419                d->geom.cylinders = idata.cylinders;
     420                d->geom.heads = idata.heads;
     421                d->geom.sectors = idata.sectors;
     422
     423                d->blocks = d->geom.cylinders * d->geom.heads * d->geom.sectors;
     424        } else if ((idata.cmd_set1 & cs1_addr48) == 0) {
     425                /* Device only supports LBA-28 addressing. */
     426                d->amode = am_lba28;
     427
     428                d->geom.cylinders = 0;
     429                d->geom.heads = 0;
     430                d->geom.sectors = 0;
     431
     432                d->blocks =
     433                     (uint32_t) idata.total_lba28_0 |
     434                    ((uint32_t) idata.total_lba28_1 << 16);
     435        } else {
     436                /* Device supports LBA-48 addressing. */
     437                d->amode = am_lba48;
     438
     439                d->geom.cylinders = 0;
     440                d->geom.heads = 0;
     441                d->geom.sectors = 0;
     442
     443                d->blocks =
     444                     (uint64_t) idata.total_lba48_0 |
     445                    ((uint64_t) idata.total_lba48_1 << 16) |
     446                    ((uint64_t) idata.total_lba48_2 << 32) |
     447                    ((uint64_t) idata.total_lba48_3 << 48);
     448        }
     449
     450        /*
     451         * Convert model name to string representation.
     452         */
     453        for (i = 0; i < 20; i++) {
     454                w = idata.model_name[i];
     455                model[2 * i] = w >> 8;
     456                model[2 * i + 1] = w & 0x00ff;
     457        }
     458
     459        len = 40;
     460        while (len > 0 && model[len - 1] == 0x20)
     461                --len;
     462
     463        pos = 0;
     464        for (i = 0; i < len; ++i) {
     465                c = model[i];
     466                if (c >= 0x80) c = '?';
     467
     468                chr_encode(c, d->model, &pos, 40);
     469        }
     470        d->model[pos] = '\0';
     471
     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
     492        d->present = true;
     493        return EOK;
     494}
     495
     496/** Read multiple blocks from the device. */
     497static int ata_bd_read_blocks(int disk_id, uint64_t ba, size_t cnt,
     498    void *buf) {
     499
     500        int rc;
     501
     502        while (cnt > 0) {
     503                if (disk[disk_id].dev_type == ata_reg_dev)
     504                        rc = ata_rcmd_read(disk_id, ba, 1, buf);
    276505                else
    277                         rc = ata_bd_write_block(disk_id, blk_idx, 1, buf);
     506                        rc = ata_pcmd_read_12(disk_id, ba, 1, buf,
     507                            disk[disk_id].block_size);
    278508
    279509                if (rc != EOK)
    280510                        return rc;
    281511
    282                 buf += block_size;
    283                 blk_idx++;
    284 
    285                 if (size > block_size)
    286                         size -= block_size;
    287                 else
    288                         size = 0;
     512                ++ba;
     513                --cnt;
     514                buf += disk[disk_id].block_size;
     515        }
     516
     517        return EOK;
     518}
     519
     520/** Write multiple blocks to the device. */
     521static int ata_bd_write_blocks(int disk_id, uint64_t ba, size_t cnt,
     522    const void *buf) {
     523
     524        int rc;
     525
     526        if (disk[disk_id].dev_type != ata_reg_dev)
     527                return ENOTSUP;
     528
     529        while (cnt > 0) {
     530                rc = ata_rcmd_write(disk_id, ba, 1, buf);
     531                if (rc != EOK)
     532                        return rc;
     533
     534                ++ba;
     535                --cnt;
     536                buf += disk[disk_id].block_size;
    289537        }
    290538
     
    294542/** Issue IDENTIFY command.
    295543 *
    296  * This is used to detect whether an ATA device is present and if so,
    297  * to determine its parameters. The parameters are written to @a d.
     544 * Reads @c identify data into the provided buffer. This is used to detect
     545 * whether an ATA device is present and if so, to determine its parameters.
    298546 *
    299547 * @param disk_id       Device ID, 0 or 1.
    300  * @param d             Device structure to store parameters in.
    301  */
    302 static int drive_identify(int disk_id, disk_t *d)
     548 * @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.
     552 */
     553static int drive_identify(int disk_id, void *buf)
    303554{
    304555        uint16_t data;
     
    308559
    309560        drv_head = ((disk_id != 0) ? DHR_DRV : 0);
    310         d->present = false;
    311561
    312562        if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
    313                 return EIO;
     563                return ETIMEOUT;
    314564
    315565        pio_write_8(&cmd->drive_head, drv_head);
     
    320570         */
    321571        if (wait_status(SR_DRDY, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
    322                 return EIO;
     572                return ETIMEOUT;
    323573
    324574        pio_write_8(&cmd->command, CMD_IDENTIFY_DRIVE);
    325575
    326576        if (wait_status(0, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK)
    327                 return EIO;
     577                return ETIMEOUT;
    328578
    329579        /* Read data from the disk buffer. */
    330580
    331581        if ((status & SR_DRQ) != 0) {
    332 //              for (i = 0; i < block_size / 2; i++) {
    333 //                      data = pio_read_16(&cmd->data_port);
    334 //                      ((uint16_t *) buf)[i] = data;
    335 //              }
    336 
    337                 for (i = 0; i < block_size / 2; i++) {
     582                for (i = 0; i < identify_data_size / 2; i++) {
    338583                        data = pio_read_16(&cmd->data_port);
    339 
    340                         switch (i) {
    341                         case 1: d->cylinders = data; break;
    342                         case 3: d->heads = data; break;
    343                         case 6: d->sectors = data; break;
    344                         }
     584                        ((uint16_t *) buf)[i] = data;
    345585                }
    346586        }
    347587
     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
    348635        if ((status & SR_ERR) != 0)
    349636                return EIO;
    350637
    351         d->blocks = d->cylinders * d->heads * d->sectors;
    352 
    353         d->present = true;
    354         fibril_mutex_initialize(&d->lock);
     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;
    355788
    356789        return EOK;
     
    360793 *
    361794 * @param disk_id       Device index (0 or 1)
    362  * @param blk_idx       Index of the first block.
    363  * @param blk_cnt       Number of blocks to transfer.
     795 * @param ba            Address the first block.
     796 * @param cnt           Number of blocks to transfer.
    364797 * @param buf           Buffer for holding the data.
    365798 *
    366799 * @return EOK on success, EIO on error.
    367800 */
    368 static int ata_bd_read_block(int disk_id, uint64_t blk_idx, size_t blk_cnt,
     801static int ata_rcmd_read(int disk_id, uint64_t ba, size_t blk_cnt,
    369802    void *buf)
    370803{
     
    372805        uint16_t data;
    373806        uint8_t status;
    374         uint64_t c, h, s;
    375         uint64_t idx;
    376807        uint8_t drv_head;
    377808        disk_t *d;
     809        block_coord_t bc;
    378810
    379811        d = &disk[disk_id];
    380 
    381         /* Check device bounds. */
    382         if (blk_idx >= d->blocks)
     812       
     813        /* Silence warning. */
     814        memset(&bc, 0, sizeof(bc));
     815
     816        /* Compute block coordinates. */
     817        if (coord_calc(d, ba, &bc) != EOK)
    383818                return EINVAL;
    384 
    385         /* Compute CHS. */
    386         c = blk_idx / (d->heads * d->sectors);
    387         idx = blk_idx % (d->heads * d->sectors);
    388 
    389         h = idx / d->sectors;
    390         s = 1 + (idx % d->sectors);
    391819
    392820        /* New value for Drive/Head register */
    393821        drv_head =
    394822            ((disk_id != 0) ? DHR_DRV : 0) |
    395             (h & 0x0f);
     823            ((d->amode != am_chs) ? DHR_LBA : 0) |
     824            (bc.h & 0x0f);
    396825
    397826        fibril_mutex_lock(&d->lock);
     
    411840        }
    412841
    413         pio_write_8(&cmd->sector_count, 1);
    414         pio_write_8(&cmd->sector_number, s);
    415         pio_write_8(&cmd->cylinder_low, c & 0xff);
    416         pio_write_8(&cmd->cylinder_high, c >> 16);
    417 
    418         pio_write_8(&cmd->command, CMD_READ_SECTORS);
     842        /* Program block coordinates into the device. */
     843        coord_sc_program(&bc, 1);
     844
     845        pio_write_8(&cmd->command, d->amode == am_lba48 ?
     846            CMD_READ_SECTORS_EXT : CMD_READ_SECTORS);
    419847
    420848        if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
     
    426854                /* Read data from the device buffer. */
    427855
    428                 for (i = 0; i < block_size / 2; i++) {
     856                for (i = 0; i < disk[disk_id].block_size / 2; i++) {
    429857                        data = pio_read_16(&cmd->data_port);
    430858                        ((uint16_t *) buf)[i] = data;
     
    442870 *
    443871 * @param disk_id       Device index (0 or 1)
    444  * @param blk_idx       Index of the first block.
    445  * @param blk_cnt       Number of blocks to transfer.
     872 * @param ba            Address of the first block.
     873 * @param cnt           Number of blocks to transfer.
    446874 * @param buf           Buffer holding the data to write.
    447875 *
    448876 * @return EOK on success, EIO on error.
    449877 */
    450 static int ata_bd_write_block(int disk_id, uint64_t blk_idx, size_t blk_cnt,
     878static int ata_rcmd_write(int disk_id, uint64_t ba, size_t cnt,
    451879    const void *buf)
    452880{
    453881        size_t i;
    454882        uint8_t status;
    455         uint64_t c, h, s;
    456         uint64_t idx;
    457883        uint8_t drv_head;
    458884        disk_t *d;
     885        block_coord_t bc;
    459886
    460887        d = &disk[disk_id];
    461 
    462         /* Check device bounds. */
    463         if (blk_idx >= d->blocks)
     888       
     889        /* Silence warning. */
     890        memset(&bc, 0, sizeof(bc));
     891
     892        /* Compute block coordinates. */
     893        if (coord_calc(d, ba, &bc) != EOK)
    464894                return EINVAL;
    465 
    466         /* Compute CHS. */
    467         c = blk_idx / (d->heads * d->sectors);
    468         idx = blk_idx % (d->heads * d->sectors);
    469 
    470         h = idx / d->sectors;
    471         s = 1 + (idx % d->sectors);
    472895
    473896        /* New value for Drive/Head register */
    474897        drv_head =
    475898            ((disk_id != 0) ? DHR_DRV : 0) |
    476             (h & 0x0f);
     899            ((d->amode != am_chs) ? DHR_LBA : 0) |
     900            (bc.h & 0x0f);
    477901
    478902        fibril_mutex_lock(&d->lock);
     
    492916        }
    493917
    494         pio_write_8(&cmd->sector_count, 1);
    495         pio_write_8(&cmd->sector_number, s);
    496         pio_write_8(&cmd->cylinder_low, c & 0xff);
    497         pio_write_8(&cmd->cylinder_high, c >> 16);
    498 
    499         pio_write_8(&cmd->command, CMD_WRITE_SECTORS);
     918        /* Program block coordinates into the device. */
     919        coord_sc_program(&bc, 1);
     920
     921        pio_write_8(&cmd->command, d->amode == am_lba48 ?
     922            CMD_WRITE_SECTORS_EXT : CMD_WRITE_SECTORS);
    500923
    501924        if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
     
    507930                /* Write data to the device buffer. */
    508931
    509                 for (i = 0; i < block_size / 2; i++) {
     932                for (i = 0; i < disk[disk_id].block_size / 2; i++) {
    510933                        pio_write_16(&cmd->data_port, ((uint16_t *) buf)[i]);
    511934                }
     
    518941
    519942        return EOK;
     943}
     944
     945/** Calculate block coordinates.
     946 *
     947 * Calculates block coordinates in the best coordinate system supported
     948 * by the device. These can be later programmed into the device using
     949 * @c coord_sc_program().
     950 *
     951 * @return EOK on success or EINVAL if block index is past end of device.
     952 */
     953static int coord_calc(disk_t *d, uint64_t ba, block_coord_t *bc)
     954{
     955        uint64_t c;
     956        uint64_t idx;
     957
     958        /* Check device bounds. */
     959        if (ba >= d->blocks)
     960                return EINVAL;
     961
     962        bc->amode = d->amode;
     963
     964        switch (d->amode) {
     965        case am_chs:
     966                /* Compute CHS coordinates. */
     967                c = ba / (d->geom.heads * d->geom.sectors);
     968                idx = ba % (d->geom.heads * d->geom.sectors);
     969
     970                bc->cyl_lo = c & 0xff;
     971                bc->cyl_hi = (c >> 8) & 0xff;
     972                bc->h      = (idx / d->geom.sectors) & 0x0f;
     973                bc->sector = (1 + (idx % d->geom.sectors)) & 0xff;
     974                break;
     975
     976        case am_lba28:
     977                /* Compute LBA-28 coordinates. */
     978                bc->c0 = ba & 0xff;             /* bits 0-7 */
     979                bc->c1 = (ba >> 8) & 0xff;      /* bits 8-15 */
     980                bc->c2 = (ba >> 16) & 0xff;     /* bits 16-23 */
     981                bc->h  = (ba >> 24) & 0x0f;     /* bits 24-27 */
     982                break;
     983
     984        case am_lba48:
     985                /* Compute LBA-48 coordinates. */
     986                bc->c0 = ba & 0xff;             /* bits 0-7 */
     987                bc->c1 = (ba >> 8) & 0xff;      /* bits 8-15 */
     988                bc->c2 = (ba >> 16) & 0xff;     /* bits 16-23 */
     989                bc->c3 = (ba >> 24) & 0xff;     /* bits 24-31 */
     990                bc->c4 = (ba >> 32) & 0xff;     /* bits 32-39 */
     991                bc->c5 = (ba >> 40) & 0xff;     /* bits 40-47 */
     992                bc->h  = 0;
     993                break;
     994        }
     995
     996        return EOK;
     997}
     998
     999/** Program block coordinates and sector count into ATA registers.
     1000 *
     1001 * Note that bc->h must be programmed separately into the device/head register.
     1002 */
     1003static void coord_sc_program(const block_coord_t *bc, uint16_t scnt)
     1004{
     1005        if (bc->amode == am_lba48) {
     1006                /* Write high-order bits. */
     1007                pio_write_8(&cmd->sector_count, scnt >> 8);
     1008                pio_write_8(&cmd->sector_number, bc->c3);
     1009                pio_write_8(&cmd->cylinder_low, bc->c4);
     1010                pio_write_8(&cmd->cylinder_high, bc->c5);
     1011        }
     1012
     1013        /* Write low-order bits. */
     1014        pio_write_8(&cmd->sector_count, scnt & 0x00ff);
     1015        pio_write_8(&cmd->sector_number, bc->c0);
     1016        pio_write_8(&cmd->cylinder_low, bc->c1);
     1017        pio_write_8(&cmd->cylinder_high, bc->c2);
    5201018}
    5211019
Note: See TracChangeset for help on using the changeset viewer.