Ignore:
File:
1 edited

Legend:

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

    r5048be7 r4ef117f8  
    3535 * @brief ATA disk driver
    3636 *
    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.
     37 * This driver currently works only with CHS addressing and uses PIO.
     38 * Currently based on the (now obsolete) ATA-1, ATA-2 standards.
    4539 *
    4640 * The driver services a single controller which can have up to two disks
     
    9589static int drive_identify(int drive_id, void *buf);
    9690static void disk_print_summary(disk_t *d);
    97 static int coord_calc(disk_t *d, uint64_t blk_idx, block_coord_t *bc);
    98 static void coord_sc_program(const block_coord_t *bc, uint16_t scnt);
    9991static int wait_status(unsigned set, unsigned n_reset, uint8_t *pstatus,
    10092    unsigned timeout);
     
    108100        printf(NAME ": ATA disk driver\n");
    109101
    110         printf("I/O address 0x%p/0x%p\n", ctl_physical, cmd_physical);
     102        printf("I/O address 0x%x\n", cmd_physical);
    111103
    112104        if (ata_bd_init() != EOK)
     
    164156        printf("%s: ", d->model);
    165157
    166         switch (d->amode) {
    167         case am_chs:
     158        if (d->amode == am_chs) {
    168159                printf("CHS %u cylinders, %u heads, %u sectors",
    169160                    disk->geom.cylinders, disk->geom.heads, disk->geom.sectors);
    170                 break;
    171         case am_lba28:
     161        } else {
    172162                printf("LBA-28");
    173                 break;
    174         case am_lba48:
    175                 printf("LBA-48");
    176                 break;
    177163        }
    178164
     
    302288        size_t pos, len;
    303289        int rc;
    304         unsigned i;
     290        int i;
    305291
    306292        rc = drive_identify(disk_id, &idata);
     
    319305
    320306                d->blocks = d->geom.cylinders * d->geom.heads * d->geom.sectors;
    321         } else if ((idata.cmd_set1 & cs1_addr48) == 0) {
    322                 /* Device only supports LBA-28 addressing. */
     307        } else {
     308                /* Device supports LBA-28. */
    323309                d->amode = am_lba28;
    324310
     
    328314
    329315                d->blocks =
    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);
     316                    (uint32_t) idata.total_lba_sec0 |
     317                    ((uint32_t) idata.total_lba_sec1 << 16);
    345318        }
    346319
     
    478451        uint16_t data;
    479452        uint8_t status;
     453        uint64_t c, h, s;
     454        uint64_t idx;
    480455        uint8_t drv_head;
    481456        disk_t *d;
    482         block_coord_t bc;
    483457
    484458        d = &disk[disk_id];
    485         bc.h = 0;       /* Silence warning. */
    486 
    487         /* Compute block coordinates. */
    488         if (coord_calc(d, blk_idx, &bc) != EOK)
     459
     460        /* Check device bounds. */
     461        if (blk_idx >= d->blocks)
    489462                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        }
    490477
    491478        /* New value for Drive/Head register */
     
    493480            ((disk_id != 0) ? DHR_DRV : 0) |
    494481            ((d->amode != am_chs) ? DHR_LBA : 0) |
    495             (bc.h & 0x0f);
     482            (h & 0x0f);
    496483
    497484        fibril_mutex_lock(&d->lock);
     
    511498        }
    512499
    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);
     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);
    518506
    519507        if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
     
    552540        size_t i;
    553541        uint8_t status;
     542        uint64_t c, h, s;
     543        uint64_t idx;
    554544        uint8_t drv_head;
    555545        disk_t *d;
    556         block_coord_t bc;
    557546
    558547        d = &disk[disk_id];
    559         bc.h = 0;       /* Silence warning. */
    560 
    561         /* Compute block coordinates. */
    562         if (coord_calc(d, blk_idx, &bc) != EOK)
     548
     549        /* Check device bounds. */
     550        if (blk_idx >= d->blocks)
    563551                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        }
    564566
    565567        /* New value for Drive/Head register */
     
    567569            ((disk_id != 0) ? DHR_DRV : 0) |
    568570            ((d->amode != am_chs) ? DHR_LBA : 0) |
    569             (bc.h & 0x0f);
     571            (h & 0x0f);
    570572
    571573        fibril_mutex_lock(&d->lock);
     
    585587        }
    586588
    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);
     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);
    592595
    593596        if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
     
    610613
    611614        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  */
    622 static 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  */
    672 static 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);
    687615}
    688616
Note: See TracChangeset for help on using the changeset viewer.