Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset 21d8020 in mainline


Ignore:
Timestamp:
2009-08-23T20:54:52Z (12 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master
Children:
e0565005
Parents:
22af3af (diff), 5048be7 (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 ATA LBA-48 feature.

Location:
uspace/srv/bd/ata_bd
Files:
2 edited

Legend:

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

    r22af3af r21d8020  
    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
     
    8995static int drive_identify(int drive_id, void *buf);
    9096static void disk_print_summary(disk_t *d);
     97static int coord_calc(disk_t *d, uint64_t blk_idx, block_coord_t *bc);
     98static void coord_sc_program(const block_coord_t *bc, uint16_t scnt);
    9199static int wait_status(unsigned set, unsigned n_reset, uint8_t *pstatus,
    92100    unsigned timeout);
     
    100108        printf(NAME ": ATA disk driver\n");
    101109
    102         printf("I/O address 0x%x\n", cmd_physical);
     110        printf("I/O address 0x%p/0x%p\n", ctl_physical, cmd_physical);
    103111
    104112        if (ata_bd_init() != EOK)
     
    156164        printf("%s: ", d->model);
    157165
    158         if (d->amode == am_chs) {
     166        switch (d->amode) {
     167        case am_chs:
    159168                printf("CHS %u cylinders, %u heads, %u sectors",
    160169                    disk->geom.cylinders, disk->geom.heads, disk->geom.sectors);
    161         } else {
     170                break;
     171        case am_lba28:
    162172                printf("LBA-28");
     173                break;
     174        case am_lba48:
     175                printf("LBA-48");
     176                break;
    163177        }
    164178
     
    288302        size_t pos, len;
    289303        int rc;
    290         int i;
     304        unsigned i;
    291305
    292306        rc = drive_identify(disk_id, &idata);
     
    305319
    306320                d->blocks = d->geom.cylinders * d->geom.heads * d->geom.sectors;
    307         } else {
    308                 /* Device supports LBA-28. */
     321        } else if ((idata.cmd_set1 & cs1_addr48) == 0) {
     322                /* Device only supports LBA-28 addressing. */
    309323                d->amode = am_lba28;
    310324
     
    314328
    315329                d->blocks =
    316                     (uint32_t) idata.total_lba_sec0 |
    317                     ((uint32_t) idata.total_lba_sec1 << 16);
     330                     (uint32_t) idata.total_lba28_0 |
     331                    ((uint32_t) idata.total_lba28_1 << 16);
     332        } else {
     333                /* Device supports LBA-48 addressing. */
     334                d->amode = am_lba48;
     335
     336                d->geom.cylinders = 0;
     337                d->geom.heads = 0;
     338                d->geom.sectors = 0;
     339
     340                d->blocks =
     341                     (uint64_t) idata.total_lba48_0 |
     342                    ((uint64_t) idata.total_lba48_1 << 16) |
     343                    ((uint64_t) idata.total_lba48_2 << 32) |
     344                    ((uint64_t) idata.total_lba48_3 << 48);
    318345        }
    319346
     
    451478        uint16_t data;
    452479        uint8_t status;
    453         uint64_t c, h, s;
    454         uint64_t idx;
    455480        uint8_t drv_head;
    456481        disk_t *d;
     482        block_coord_t bc;
    457483
    458484        d = &disk[disk_id];
    459 
    460         /* Check device bounds. */
    461         if (blk_idx >= d->blocks)
     485        bc.h = 0;       /* Silence warning. */
     486
     487        /* Compute block coordinates. */
     488        if (coord_calc(d, blk_idx, &bc) != EOK)
    462489                return EINVAL;
    463 
    464         if (d->amode == am_chs) {
    465                 /* Compute CHS coordinates. */
    466                 c = blk_idx / (d->geom.heads * d->geom.sectors);
    467                 idx = blk_idx % (d->geom.heads * d->geom.sectors);
    468 
    469                 h = idx / d->geom.sectors;
    470                 s = 1 + (idx % d->geom.sectors);
    471         } else {
    472                 /* Compute LBA-28 coordinates. */
    473                 s = blk_idx & 0xff;             /* bits 0-7 */
    474                 c = (blk_idx >> 8) & 0xffff;    /* bits 8-23 */
    475                 h = (blk_idx >> 24) & 0x0f;     /* bits 24-27 */
    476         }
    477490
    478491        /* New value for Drive/Head register */
     
    480493            ((disk_id != 0) ? DHR_DRV : 0) |
    481494            ((d->amode != am_chs) ? DHR_LBA : 0) |
    482             (h & 0x0f);
     495            (bc.h & 0x0f);
    483496
    484497        fibril_mutex_lock(&d->lock);
     
    498511        }
    499512
    500         pio_write_8(&cmd->sector_count, 1);
    501         pio_write_8(&cmd->sector_number, s);
    502         pio_write_8(&cmd->cylinder_low, c & 0xff);
    503         pio_write_8(&cmd->cylinder_high, c >> 16);
    504 
    505         pio_write_8(&cmd->command, CMD_READ_SECTORS);
     513        /* Program block coordinates into the device. */
     514        coord_sc_program(&bc, 1);
     515
     516        pio_write_8(&cmd->command, d->amode == am_lba48 ?
     517            CMD_READ_SECTORS_EXT : CMD_READ_SECTORS);
    506518
    507519        if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
     
    540552        size_t i;
    541553        uint8_t status;
    542         uint64_t c, h, s;
    543         uint64_t idx;
    544554        uint8_t drv_head;
    545555        disk_t *d;
     556        block_coord_t bc;
    546557
    547558        d = &disk[disk_id];
    548 
    549         /* Check device bounds. */
    550         if (blk_idx >= d->blocks)
     559        bc.h = 0;       /* Silence warning. */
     560
     561        /* Compute block coordinates. */
     562        if (coord_calc(d, blk_idx, &bc) != EOK)
    551563                return EINVAL;
    552 
    553         if (d->amode == am_chs) {
    554                 /* Compute CHS coordinates. */
    555                 c = blk_idx / (d->geom.heads * d->geom.sectors);
    556                 idx = blk_idx % (d->geom.heads * d->geom.sectors);
    557 
    558                 h = idx / d->geom.sectors;
    559                 s = 1 + (idx % d->geom.sectors);
    560         } else {
    561                 /* Compute LBA-28 coordinates. */
    562                 s = blk_idx & 0xff;             /* bits 0-7 */
    563                 c = (blk_idx >> 8) & 0xffff;    /* bits 8-23 */
    564                 h = (blk_idx >> 24) & 0x0f;     /* bits 24-27 */
    565         }
    566564
    567565        /* New value for Drive/Head register */
     
    569567            ((disk_id != 0) ? DHR_DRV : 0) |
    570568            ((d->amode != am_chs) ? DHR_LBA : 0) |
    571             (h & 0x0f);
     569            (bc.h & 0x0f);
    572570
    573571        fibril_mutex_lock(&d->lock);
     
    587585        }
    588586
    589         pio_write_8(&cmd->sector_count, 1);
    590         pio_write_8(&cmd->sector_number, s);
    591         pio_write_8(&cmd->cylinder_low, c & 0xff);
    592         pio_write_8(&cmd->cylinder_high, c >> 16);
    593 
    594         pio_write_8(&cmd->command, CMD_WRITE_SECTORS);
     587        /* Program block coordinates into the device. */
     588        coord_sc_program(&bc, 1);
     589
     590        pio_write_8(&cmd->command, d->amode == am_lba48 ?
     591            CMD_WRITE_SECTORS_EXT : CMD_WRITE_SECTORS);
    595592
    596593        if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
     
    613610
    614611        return EOK;
     612}
     613
     614/** Calculate block coordinates.
     615 *
     616 * Calculates block coordinates in the best coordinate system supported
     617 * by the device. These can be later programmed into the device using
     618 * @c coord_sc_program().
     619 *
     620 * @return EOK on success or EINVAL if block index is past end of device.
     621 */
     622static int coord_calc(disk_t *d, uint64_t blk_idx, block_coord_t *bc)
     623{
     624        uint64_t c;
     625        uint64_t idx;
     626
     627        /* Check device bounds. */
     628        if (blk_idx >= d->blocks)
     629                return EINVAL;
     630
     631        bc->amode = d->amode;
     632
     633        switch (d->amode) {
     634        case am_chs:
     635                /* Compute CHS coordinates. */
     636                c = blk_idx / (d->geom.heads * d->geom.sectors);
     637                idx = blk_idx % (d->geom.heads * d->geom.sectors);
     638
     639                bc->cyl_lo = c & 0xff;
     640                bc->cyl_hi = (c >> 8) & 0xff;
     641                bc->h      = (idx / d->geom.sectors) & 0x0f;
     642                bc->sector = (1 + (idx % d->geom.sectors)) & 0xff;
     643                break;
     644
     645        case am_lba28:
     646                /* Compute LBA-28 coordinates. */
     647                bc->c0 = blk_idx & 0xff;                /* bits 0-7 */
     648                bc->c1 = (blk_idx >> 8) & 0xff;         /* bits 8-15 */
     649                bc->c2 = (blk_idx >> 16) & 0xff;        /* bits 16-23 */
     650                bc->h  = (blk_idx >> 24) & 0x0f;        /* bits 24-27 */
     651                break;
     652
     653        case am_lba48:
     654                /* Compute LBA-48 coordinates. */
     655                bc->c0 = blk_idx & 0xff;                /* bits 0-7 */
     656                bc->c1 = (blk_idx >> 8) & 0xff;         /* bits 8-15 */
     657                bc->c2 = (blk_idx >> 16) & 0xff;        /* bits 16-23 */
     658                bc->c3 = (blk_idx >> 24) & 0xff;        /* bits 24-31 */
     659                bc->c4 = (blk_idx >> 32) & 0xff;        /* bits 32-39 */
     660                bc->c5 = (blk_idx >> 40) & 0xff;        /* bits 40-47 */
     661                bc->h  = 0;
     662                break;
     663        }
     664
     665        return EOK;
     666}
     667
     668/** Program block coordinates and sector count into ATA registers.
     669 *
     670 * Note that bc->h must be programmed separately into the device/head register.
     671 */
     672static void coord_sc_program(const block_coord_t *bc, uint16_t scnt)
     673{
     674        if (bc->amode == am_lba48) {
     675                /* Write high-order bits. */
     676                pio_write_8(&cmd->sector_count, scnt >> 8);
     677                pio_write_8(&cmd->sector_number, bc->c3);
     678                pio_write_8(&cmd->cylinder_low, bc->c4);
     679                pio_write_8(&cmd->cylinder_high, bc->c5);
     680        }
     681
     682        /* Write low-order bits. */
     683        pio_write_8(&cmd->sector_count, scnt & 0x00ff);
     684        pio_write_8(&cmd->sector_number, bc->c0);
     685        pio_write_8(&cmd->cylinder_low, bc->c1);
     686        pio_write_8(&cmd->cylinder_high, bc->c2);
    615687}
    616688
  • uspace/srv/bd/ata_bd/ata_bd.h

    r22af3af r21d8020  
    132132
    133133enum ata_command {
    134         CMD_IDENTIFY_DRIVE      = 0xEC,
    135134        CMD_READ_SECTORS        = 0x20,
    136         CMD_WRITE_SECTORS       = 0x30
     135        CMD_READ_SECTORS_EXT    = 0x24,
     136        CMD_WRITE_SECTORS       = 0x30,
     137        CMD_WRITE_SECTORS_EXT   = 0x34,
     138        CMD_IDENTIFY_DRIVE      = 0xEC
    137139};
    138140
     
    156158        uint16_t _vs8;
    157159        uint16_t _vs9;
     160
    158161        uint16_t serial_number[10];
    159162        uint16_t _vs20;
     
    162165        uint16_t firmware_rev[4];
    163166        uint16_t model_name[20];
     167
    164168        uint16_t max_rw_multiple;
    165169        uint16_t _res48;
     
    168172        uint16_t pio_timing;
    169173        uint16_t dma_timing;
     174
    170175        uint16_t validity;
    171176        uint16_t cur_cyl;
     
    175180        uint16_t cur_capacity1;
    176181        uint16_t mss;
    177         uint16_t total_lba_sec0;
    178         uint16_t total_lba_sec1;
     182        uint16_t total_lba28_0;
     183        uint16_t total_lba28_1;
    179184        uint16_t sw_dma;
    180185        uint16_t mw_dma;
     
    184189        uint16_t min_raw_pio_cycle;
    185190        uint16_t min_iordy_pio_cycle;
     191
    186192        uint16_t _res69;
    187193        uint16_t _res70;
    188         uint16_t _res71[1 + 127 - 71];
     194        uint16_t _res71;
     195        uint16_t _res72;
     196        uint16_t _res73;
     197        uint16_t _res74;
     198
     199        uint16_t queue_depth;
     200        uint16_t _res76[1 + 79 - 76];
     201        uint16_t version_maj;
     202        uint16_t version_min;
     203        uint16_t cmd_set0;
     204        uint16_t cmd_set1;
     205        uint16_t csf_sup_ext;
     206        uint16_t csf_enabled0;
     207        uint16_t csf_enabled1;
     208        uint16_t csf_default;
     209        uint16_t udma;
     210
     211        uint16_t _res89[1 + 99 - 89];
     212
     213        /* Total number of blocks in LBA-48 addressing */
     214        uint16_t total_lba48_0;
     215        uint16_t total_lba48_1;
     216        uint16_t total_lba48_2;
     217        uint16_t total_lba48_3;
     218
     219        /* Note: more fields are defined in ATA/ATAPI-7 */
     220        uint16_t _res104[1 + 127 - 104];
    189221        uint16_t _vs128[1 + 159 - 128];
    190222        uint16_t _res160[1 + 255 - 160];
     
    198230};
    199231
     232/** Bits of @c identify_data_t.cmd_set1 */
     233enum ata_cs1 {
     234        cs1_addr48      = 0x0400        /**< 48-bit address feature set */
     235};
     236
    200237/** Block addressing mode. */
    201238enum addr_mode {
    202         am_chs,
    203         am_lba28
    204 };
     239        am_chs,         /**< CHS block addressing */
     240        am_lba28,       /**< LBA-28 block addressing */
     241        am_lba48        /**< LBA-48 block addressing */
     242};
     243
     244/** Block coordinates */
     245typedef struct {
     246        /** Addressing mode used */
     247        enum addr_mode amode;
     248
     249        union {
     250                /** CHS coordinates */
     251                struct {
     252                        uint8_t sector;
     253                        uint8_t cyl_lo;
     254                        uint8_t cyl_hi;
     255                };
     256                /** LBA coordinates */
     257                struct {
     258                        uint8_t c0;
     259                        uint8_t c1;
     260                        uint8_t c2;
     261                        uint8_t c3;
     262                        uint8_t c4;
     263                        uint8_t c5;
     264                };
     265        };
     266
     267        /** Lower 4 bits for device/head register */
     268        uint8_t h;
     269} block_coord_t;
    205270
    206271typedef struct {
Note: See TracChangeset for help on using the changeset viewer.