Changeset 1787e527 in mainline for uspace/srv/bd/ata_bd/ata_bd.c


Ignore:
Timestamp:
2009-11-16T21:22:54Z (14 years ago)
Author:
Lenka Trochtova <trochtova.lenka@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
5ebdf94
Parents:
fcbd1be (diff), 9c70ed6 (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:

merged with head (unstable)

File:
1 edited

Legend:

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

    rfcbd1be r1787e527  
    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
     
    5056#include <as.h>
    5157#include <fibril_sync.h>
     58#include <string.h>
    5259#include <devmap.h>
    5360#include <sys/types.h>
     
    5562#include <bool.h>
    5663#include <task.h>
     64#include <macros.h>
    5765
    5866#include "ata_bd.h"
     
    7987static int ata_bd_init(void);
    8088static 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,
     89static int ata_bd_read_blocks(int disk_id, uint64_t ba, size_t cnt,
    8290    void *buf);
    83 static int ata_bd_read_block(int disk_id, uint64_t blk_idx, size_t blk_cnt,
     91static int ata_bd_write_blocks(int disk_id, uint64_t ba, size_t cnt,
     92    const void *buf);
     93static int ata_bd_read_block(int disk_id, uint64_t ba, size_t cnt,
    8494    void *buf);
    85 static int ata_bd_write_block(int disk_id, uint64_t blk_idx, size_t blk_cnt,
     95static int ata_bd_write_block(int disk_id, uint64_t ba, size_t cnt,
    8696    const void *buf);
    87 static int drive_identify(int drive_id, disk_t *d);
     97static int disk_init(disk_t *d, int disk_id);
     98static int drive_identify(int drive_id, void *buf);
     99static void disk_print_summary(disk_t *d);
     100static int coord_calc(disk_t *d, uint64_t ba, block_coord_t *bc);
     101static void coord_sc_program(const block_coord_t *bc, uint16_t scnt);
    88102static int wait_status(unsigned set, unsigned n_reset, uint8_t *pstatus,
    89103    unsigned timeout);
     
    97111        printf(NAME ": ATA disk driver\n");
    98112
    99         printf("I/O address 0x%x\n", cmd_physical);
     113        printf("I/O address 0x%p/0x%p\n", ctl_physical, cmd_physical);
    100114
    101115        if (ata_bd_init() != EOK)
     
    106120                fflush(stdout);
    107121
    108                 rc = drive_identify(i, &disk[i]);
     122                rc = disk_init(&disk[i], i);
    109123
    110124                if (rc == EOK) {
    111                         printf("%u cylinders, %u heads, %u sectors\n",
    112                             disk[i].cylinders, disk[i].heads, disk[i].sectors);
     125                        disk_print_summary(&disk[i]);
    113126                } else {
    114127                        printf("Not found.\n");
     
    147160}
    148161
     162/** Print one-line device summary. */
     163static void disk_print_summary(disk_t *d)
     164{
     165        uint64_t mbytes;
     166
     167        printf("%s: ", d->model);
     168
     169        switch (d->amode) {
     170        case am_chs:
     171                printf("CHS %u cylinders, %u heads, %u sectors",
     172                    disk->geom.cylinders, disk->geom.heads, disk->geom.sectors);
     173                break;
     174        case am_lba28:
     175                printf("LBA-28");
     176                break;
     177        case am_lba48:
     178                printf("LBA-48");
     179                break;
     180        }
     181
     182        printf(" %llu blocks", d->blocks, d->blocks / (2 * 1024));
     183
     184        mbytes = d->blocks / (2 * 1024);
     185        if (mbytes > 0)
     186                printf(" %llu MB.", mbytes);
     187
     188        printf("\n");
     189}
    149190
    150191/** Register driver and enable device I/O. */
     
    190231        int flags;
    191232        int retval;
    192         off_t idx;
    193         size_t size;
     233        uint64_t ba;
     234        size_t cnt;
    194235        int disk_id, i;
    195236
     
    211252        ipc_answer_0(iid, EOK);
    212253
    213         if (!ipc_share_out_receive(&callid, &comm_size, &flags)) {
     254        if (!async_share_out_receive(&callid, &comm_size, &flags)) {
    214255                ipc_answer_0(callid, EHANGUP);
    215256                return;
     
    222263        }
    223264
    224         (void) ipc_share_out_finalize(callid, fs_va);
     265        (void) async_share_out_finalize(callid, fs_va);
    225266
    226267        while (1) {
     
    232273                        ipc_answer_0(callid, EOK);
    233274                        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;
     275                case BD_READ_BLOCKS:
     276                        ba = MERGE_LOUP32(IPC_GET_ARG1(call),
     277                            IPC_GET_ARG2(call));
     278                        cnt = IPC_GET_ARG3(call);
     279                        if (cnt * block_size > comm_size) {
     280                                retval = ELIMIT;
    240281                                break;
    241282                        }
    242                         retval = ata_bd_rdwr(disk_id, method, idx,
    243                             size, fs_va);
     283                        retval = ata_bd_read_blocks(disk_id, ba, cnt, fs_va);
    244284                        break;
     285                case BD_WRITE_BLOCKS:
     286                        ba = MERGE_LOUP32(IPC_GET_ARG1(call),
     287                            IPC_GET_ARG2(call));
     288                        cnt = IPC_GET_ARG3(call);
     289                        if (cnt * block_size > comm_size) {
     290                                retval = ELIMIT;
     291                                break;
     292                        }
     293                        retval = ata_bd_write_blocks(disk_id, ba, cnt, fs_va);
     294                        break;
     295                case BD_GET_BLOCK_SIZE:
     296                        ipc_answer_1(callid, EOK, block_size);
     297                        continue;
    245298                default:
    246299                        retval = EINVAL;
     
    251304}
    252305
    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 {
     306/** Initialize a disk.
     307 *
     308 * Probes for a disk, determines its parameters and initializes
     309 * the disk structure.
     310 */
     311static int disk_init(disk_t *d, int disk_id)
     312{
     313        identify_data_t idata;
     314        uint8_t model[40];
     315        uint16_t w;
     316        uint8_t c;
     317        size_t pos, len;
    266318        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);
    276                 else
    277                         rc = ata_bd_write_block(disk_id, blk_idx, 1, buf);
    278 
     319        unsigned i;
     320
     321        rc = drive_identify(disk_id, &idata);
     322        if (rc != EOK) {
     323                d->present = false;
     324                return rc;
     325        }
     326
     327        if ((idata.caps & cap_lba) == 0) {
     328                /* Device only supports CHS addressing. */
     329                d->amode = am_chs;
     330
     331                d->geom.cylinders = idata.cylinders;
     332                d->geom.heads = idata.heads;
     333                d->geom.sectors = idata.sectors;
     334
     335                d->blocks = d->geom.cylinders * d->geom.heads * d->geom.sectors;
     336        } else if ((idata.cmd_set1 & cs1_addr48) == 0) {
     337                /* Device only supports LBA-28 addressing. */
     338                d->amode = am_lba28;
     339
     340                d->geom.cylinders = 0;
     341                d->geom.heads = 0;
     342                d->geom.sectors = 0;
     343
     344                d->blocks =
     345                     (uint32_t) idata.total_lba28_0 |
     346                    ((uint32_t) idata.total_lba28_1 << 16);
     347        } else {
     348                /* Device supports LBA-48 addressing. */
     349                d->amode = am_lba48;
     350
     351                d->geom.cylinders = 0;
     352                d->geom.heads = 0;
     353                d->geom.sectors = 0;
     354
     355                d->blocks =
     356                     (uint64_t) idata.total_lba48_0 |
     357                    ((uint64_t) idata.total_lba48_1 << 16) |
     358                    ((uint64_t) idata.total_lba48_2 << 32) |
     359                    ((uint64_t) idata.total_lba48_3 << 48);
     360        }
     361
     362        /*
     363         * Convert model name to string representation.
     364         */
     365        for (i = 0; i < 20; i++) {
     366                w = idata.model_name[i];
     367                model[2 * i] = w >> 8;
     368                model[2 * i + 1] = w & 0x00ff;
     369        }
     370
     371        len = 40;
     372        while (len > 0 && model[len - 1] == 0x20)
     373                --len;
     374
     375        pos = 0;
     376        for (i = 0; i < len; ++i) {
     377                c = model[i];
     378                if (c >= 0x80) c = '?';
     379
     380                chr_encode(c, d->model, &pos, 40);
     381        }
     382        d->model[pos] = '\0';
     383
     384        d->present = true;
     385        fibril_mutex_initialize(&d->lock);
     386
     387        return EOK;
     388}
     389
     390/** Read multiple blocks from the device. */
     391static int ata_bd_read_blocks(int disk_id, uint64_t ba, size_t cnt,
     392    void *buf) {
     393
     394        int rc;
     395
     396        while (cnt > 0) {
     397                rc = ata_bd_read_block(disk_id, ba, 1, buf);
    279398                if (rc != EOK)
    280399                        return rc;
    281400
     401                ++ba;
     402                --cnt;
    282403                buf += block_size;
    283                 blk_idx++;
    284 
    285                 if (size > block_size)
    286                         size -= block_size;
    287                 else
    288                         size = 0;
     404        }
     405
     406        return EOK;
     407}
     408
     409/** Write multiple blocks to the device. */
     410static int ata_bd_write_blocks(int disk_id, uint64_t ba, size_t cnt,
     411    const void *buf) {
     412
     413        int rc;
     414
     415        while (cnt > 0) {
     416                rc = ata_bd_write_block(disk_id, ba, 1, buf);
     417                if (rc != EOK)
     418                        return rc;
     419
     420                ++ba;
     421                --cnt;
     422                buf += block_size;
    289423        }
    290424
     
    294428/** Issue IDENTIFY command.
    295429 *
    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.
     430 * Reads @c identify data into the provided buffer. This is used to detect
     431 * whether an ATA device is present and if so, to determine its parameters.
    298432 *
    299433 * @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)
     434 * @param buf           Pointer to a 512-byte buffer.
     435 */
     436static int drive_identify(int disk_id, void *buf)
    303437{
    304438        uint16_t data;
     
    308442
    309443        drv_head = ((disk_id != 0) ? DHR_DRV : 0);
    310         d->present = false;
    311444
    312445        if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
     
    330463
    331464        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++) {
    338                         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                         }
    345                 }
    346         }
    347 
    348         if ((status & SR_ERR) != 0)
    349                 return EIO;
    350 
    351         d->blocks = d->cylinders * d->heads * d->sectors;
    352 
    353         d->present = true;
    354         fibril_mutex_initialize(&d->lock);
    355 
    356         return EOK;
    357 }
    358 
    359 /** Read a physical from the device.
    360  *
    361  * @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.
    364  * @param buf           Buffer for holding the data.
    365  *
    366  * @return EOK on success, EIO on error.
    367  */
    368 static int ata_bd_read_block(int disk_id, uint64_t blk_idx, size_t blk_cnt,
    369     void *buf)
    370 {
    371         size_t i;
    372         uint16_t data;
    373         uint8_t status;
    374         uint64_t c, h, s;
    375         uint64_t idx;
    376         uint8_t drv_head;
    377         disk_t *d;
    378 
    379         d = &disk[disk_id];
    380 
    381         /* Check device bounds. */
    382         if (blk_idx >= d->blocks)
    383                 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);
    391 
    392         /* New value for Drive/Head register */
    393         drv_head =
    394             ((disk_id != 0) ? DHR_DRV : 0) |
    395             (h & 0x0f);
    396 
    397         fibril_mutex_lock(&d->lock);
    398 
    399         /* Program a Read Sectors operation. */
    400 
    401         if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_BSY) != EOK) {
    402                 fibril_mutex_unlock(&d->lock);
    403                 return EIO;
    404         }
    405 
    406         pio_write_8(&cmd->drive_head, drv_head);
    407 
    408         if (wait_status(SR_DRDY, ~SR_BSY, NULL, TIMEOUT_DRDY) != EOK) {
    409                 fibril_mutex_unlock(&d->lock);
    410                 return EIO;
    411         }
    412 
    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);
    419 
    420         if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
    421                 fibril_mutex_unlock(&d->lock);
    422                 return EIO;
    423         }
    424 
    425         if ((status & SR_DRQ) != 0) {
    426                 /* Read data from the device buffer. */
    427 
    428465                for (i = 0; i < block_size / 2; i++) {
    429466                        data = pio_read_16(&cmd->data_port);
     
    435472                return EIO;
    436473
    437         fibril_mutex_unlock(&d->lock);
    438         return EOK;
    439 }
    440 
    441 /** Write a physical block to the device.
     474        return EOK;
     475}
     476
     477/** Read a physical from the device.
    442478 *
    443479 * @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.
    446  * @param buf           Buffer holding the data to write.
     480 * @param ba            Address the first block.
     481 * @param cnt           Number of blocks to transfer.
     482 * @param buf           Buffer for holding the data.
    447483 *
    448484 * @return EOK on success, EIO on error.
    449485 */
    450 static int ata_bd_write_block(int disk_id, uint64_t blk_idx, size_t blk_cnt,
    451     const void *buf)
     486static int ata_bd_read_block(int disk_id, uint64_t ba, size_t blk_cnt,
     487    void *buf)
    452488{
    453489        size_t i;
     490        uint16_t data;
    454491        uint8_t status;
    455         uint64_t c, h, s;
    456         uint64_t idx;
    457492        uint8_t drv_head;
    458493        disk_t *d;
     494        block_coord_t bc;
    459495
    460496        d = &disk[disk_id];
    461 
    462         /* Check device bounds. */
    463         if (blk_idx >= d->blocks)
     497        bc.h = 0;       /* Silence warning. */
     498
     499        /* Compute block coordinates. */
     500        if (coord_calc(d, ba, &bc) != EOK)
    464501                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);
    472502
    473503        /* New value for Drive/Head register */
    474504        drv_head =
    475505            ((disk_id != 0) ? DHR_DRV : 0) |
    476             (h & 0x0f);
     506            ((d->amode != am_chs) ? DHR_LBA : 0) |
     507            (bc.h & 0x0f);
    477508
    478509        fibril_mutex_lock(&d->lock);
    479510
    480         /* Program a Write Sectors operation. */
     511        /* Program a Read Sectors operation. */
    481512
    482513        if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_BSY) != EOK) {
     
    492523        }
    493524
    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);
     525        /* Program block coordinates into the device. */
     526        coord_sc_program(&bc, 1);
     527
     528        pio_write_8(&cmd->command, d->amode == am_lba48 ?
     529            CMD_READ_SECTORS_EXT : CMD_READ_SECTORS);
     530
     531        if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
     532                fibril_mutex_unlock(&d->lock);
     533                return EIO;
     534        }
     535
     536        if ((status & SR_DRQ) != 0) {
     537                /* Read data from the device buffer. */
     538
     539                for (i = 0; i < block_size / 2; i++) {
     540                        data = pio_read_16(&cmd->data_port);
     541                        ((uint16_t *) buf)[i] = data;
     542                }
     543        }
     544
     545        if ((status & SR_ERR) != 0)
     546                return EIO;
     547
     548        fibril_mutex_unlock(&d->lock);
     549        return EOK;
     550}
     551
     552/** Write a physical block to the device.
     553 *
     554 * @param disk_id       Device index (0 or 1)
     555 * @param ba            Address of the first block.
     556 * @param cnt           Number of blocks to transfer.
     557 * @param buf           Buffer holding the data to write.
     558 *
     559 * @return EOK on success, EIO on error.
     560 */
     561static int ata_bd_write_block(int disk_id, uint64_t ba, size_t cnt,
     562    const void *buf)
     563{
     564        size_t i;
     565        uint8_t status;
     566        uint8_t drv_head;
     567        disk_t *d;
     568        block_coord_t bc;
     569
     570        d = &disk[disk_id];
     571        bc.h = 0;       /* Silence warning. */
     572
     573        /* Compute block coordinates. */
     574        if (coord_calc(d, ba, &bc) != EOK)
     575                return EINVAL;
     576
     577        /* New value for Drive/Head register */
     578        drv_head =
     579            ((disk_id != 0) ? DHR_DRV : 0) |
     580            ((d->amode != am_chs) ? DHR_LBA : 0) |
     581            (bc.h & 0x0f);
     582
     583        fibril_mutex_lock(&d->lock);
     584
     585        /* Program a Write Sectors operation. */
     586
     587        if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_BSY) != EOK) {
     588                fibril_mutex_unlock(&d->lock);
     589                return EIO;
     590        }
     591
     592        pio_write_8(&cmd->drive_head, drv_head);
     593
     594        if (wait_status(SR_DRDY, ~SR_BSY, NULL, TIMEOUT_DRDY) != EOK) {
     595                fibril_mutex_unlock(&d->lock);
     596                return EIO;
     597        }
     598
     599        /* Program block coordinates into the device. */
     600        coord_sc_program(&bc, 1);
     601
     602        pio_write_8(&cmd->command, d->amode == am_lba48 ?
     603            CMD_WRITE_SECTORS_EXT : CMD_WRITE_SECTORS);
    500604
    501605        if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
     
    518622
    519623        return EOK;
     624}
     625
     626/** Calculate block coordinates.
     627 *
     628 * Calculates block coordinates in the best coordinate system supported
     629 * by the device. These can be later programmed into the device using
     630 * @c coord_sc_program().
     631 *
     632 * @return EOK on success or EINVAL if block index is past end of device.
     633 */
     634static int coord_calc(disk_t *d, uint64_t ba, block_coord_t *bc)
     635{
     636        uint64_t c;
     637        uint64_t idx;
     638
     639        /* Check device bounds. */
     640        if (ba >= d->blocks)
     641                return EINVAL;
     642
     643        bc->amode = d->amode;
     644
     645        switch (d->amode) {
     646        case am_chs:
     647                /* Compute CHS coordinates. */
     648                c = ba / (d->geom.heads * d->geom.sectors);
     649                idx = ba % (d->geom.heads * d->geom.sectors);
     650
     651                bc->cyl_lo = c & 0xff;
     652                bc->cyl_hi = (c >> 8) & 0xff;
     653                bc->h      = (idx / d->geom.sectors) & 0x0f;
     654                bc->sector = (1 + (idx % d->geom.sectors)) & 0xff;
     655                break;
     656
     657        case am_lba28:
     658                /* Compute LBA-28 coordinates. */
     659                bc->c0 = ba & 0xff;             /* bits 0-7 */
     660                bc->c1 = (ba >> 8) & 0xff;      /* bits 8-15 */
     661                bc->c2 = (ba >> 16) & 0xff;     /* bits 16-23 */
     662                bc->h  = (ba >> 24) & 0x0f;     /* bits 24-27 */
     663                break;
     664
     665        case am_lba48:
     666                /* Compute LBA-48 coordinates. */
     667                bc->c0 = ba & 0xff;             /* bits 0-7 */
     668                bc->c1 = (ba >> 8) & 0xff;      /* bits 8-15 */
     669                bc->c2 = (ba >> 16) & 0xff;     /* bits 16-23 */
     670                bc->c3 = (ba >> 24) & 0xff;     /* bits 24-31 */
     671                bc->c4 = (ba >> 32) & 0xff;     /* bits 32-39 */
     672                bc->c5 = (ba >> 40) & 0xff;     /* bits 40-47 */
     673                bc->h  = 0;
     674                break;
     675        }
     676
     677        return EOK;
     678}
     679
     680/** Program block coordinates and sector count into ATA registers.
     681 *
     682 * Note that bc->h must be programmed separately into the device/head register.
     683 */
     684static void coord_sc_program(const block_coord_t *bc, uint16_t scnt)
     685{
     686        if (bc->amode == am_lba48) {
     687                /* Write high-order bits. */
     688                pio_write_8(&cmd->sector_count, scnt >> 8);
     689                pio_write_8(&cmd->sector_number, bc->c3);
     690                pio_write_8(&cmd->cylinder_low, bc->c4);
     691                pio_write_8(&cmd->cylinder_high, bc->c5);
     692        }
     693
     694        /* Write low-order bits. */
     695        pio_write_8(&cmd->sector_count, scnt & 0x00ff);
     696        pio_write_8(&cmd->sector_number, bc->c0);
     697        pio_write_8(&cmd->cylinder_low, bc->c1);
     698        pio_write_8(&cmd->cylinder_high, bc->c2);
    520699}
    521700
Note: See TracChangeset for help on using the changeset viewer.