Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/ata/src/ata.c

    r743f2cdd r07039850  
    11/*
    2  * Copyright (c) 2024 Jiri Svoboda
     2 * Copyright (c) 2025 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    8484static uint8_t ata_read_cmd_8(ata_channel_t *, uint16_t);
    8585static void ata_write_cmd_8(ata_channel_t *, uint16_t, uint8_t);
     86static void ata_write_ctl_8(ata_channel_t *, uint16_t, uint8_t);
    8687
    8788static errno_t ata_bd_init_irq(ata_channel_t *);
     
    9697static errno_t ata_bd_get_block_size(bd_srv_t *, size_t *);
    9798static errno_t ata_bd_get_num_blocks(bd_srv_t *, aoff64_t *);
     99static errno_t ata_bd_eject(bd_srv_t *);
    98100static errno_t ata_bd_sync_cache(bd_srv_t *, aoff64_t, size_t);
    99101
     
    105107static errno_t ata_identify_dev(ata_device_t *, void *);
    106108static errno_t ata_identify_pkt_dev(ata_device_t *, void *);
    107 static errno_t ata_cmd_packet(ata_device_t *, const void *, size_t, void *,
     109static errno_t ata_cmd_packet_nondata(ata_device_t *, const void *, size_t);
     110static errno_t ata_cmd_packet_din(ata_device_t *, const void *, size_t, void *,
    108111    size_t, size_t *);
    109112static errno_t ata_pcmd_inquiry(ata_device_t *, void *, size_t, size_t *);
     
    111114static errno_t ata_pcmd_read_capacity(ata_device_t *, uint64_t *, size_t *);
    112115static errno_t ata_pcmd_read_toc(ata_device_t *, uint8_t, void *, size_t);
     116static errno_t ata_pcmd_start_stop_unit(ata_device_t *, uint8_t);
    113117static void disk_print_summary(ata_device_t *);
    114118static size_t ata_disk_maxnb(ata_device_t *);
     
    129133        .get_block_size = ata_bd_get_block_size,
    130134        .get_num_blocks = ata_bd_get_num_blocks,
    131         .sync_cache = ata_bd_sync_cache
     135        .sync_cache = ata_bd_sync_cache,
     136        .eject = ata_bd_eject
    132137};
    133138
     
    151156{
    152157        ata_channel_t *chan;
     158        int i;
    153159
    154160        chan = calloc(1, sizeof(ata_channel_t));
     
    162168        fibril_mutex_initialize(&chan->irq_lock);
    163169        fibril_condvar_initialize(&chan->irq_cv);
     170
     171        for (i = 0; i < MAX_DEVICES; i++)
     172                chan->device[i].chan = chan;
    164173
    165174        *rchan = chan;
     
    253262
    254263        for (i = 0; i < MAX_DEVICES; i++) {
     264                if (chan->device[i].present == false)
     265                        continue;
     266
    255267                rc = ata_device_remove(&chan->device[i]);
    256268                if (rc != EOK) {
    257269                        ata_msg_error(chan, "Unable to remove device %d.", i);
     270                        fibril_mutex_unlock(&chan->lock);
    258271                        return rc;
    259272                }
     
    262275        ata_bd_fini_irq(chan);
    263276        fibril_mutex_unlock(&chan->lock);
    264 
    265         return EOK;
     277        free(chan);
     278
     279        return rc;
     280}
     281
     282/** Quiesce ATA channel. */
     283void ata_channel_quiesce(ata_channel_t *chan)
     284{
     285        ata_msg_debug(chan, ": ata_channel_quiesce()");
     286
     287        fibril_mutex_lock(&chan->lock);
     288        ata_write_ctl_8(chan, REG_DEVCTL, DCR_SRST | DCR_nIEN);
     289        fibril_mutex_unlock(&chan->lock);
    266290}
    267291
     
    335359{
    336360        return chan->params.write_cmd_8(chan->params.arg, port, value);
     361}
     362
     363/** Write 8 bits to 8-bit control port.
     364 *
     365 * @param chan ATA channel
     366 * @param port Port number
     367 * @param value Register value
     368 */
     369static void ata_write_ctl_8(ata_channel_t *chan, uint16_t port, uint8_t value)
     370{
     371        return chan->params.write_ctl_8(chan->params.arg, port, value);
    337372}
    338373
     
    493528        unsigned i;
    494529
    495         d->chan = chan;
    496530        d->device_id = device_id;
    497531        d->present = false;
     
    750784}
    751785
     786/** Eject medium. */
     787static errno_t ata_bd_eject(bd_srv_t *bd)
     788{
     789        ata_device_t *device = bd_srv_device(bd);
     790
     791        ata_msg_debug(device->chan, "ata_bd_eject()");
     792        return ata_pcmd_start_stop_unit(device, ssf_pc_no_change |
     793            ssf_loej);
     794}
     795
    752796/** PIO data-in command protocol. */
    753797static errno_t ata_pio_data_in(ata_device_t *device, void *obuf, size_t obuf_size,
     
    10801124}
    10811125
    1082 /** Issue packet command (i. e. write a command packet to the device).
    1083  *
    1084  * Only data-in commands are supported (e.g. inquiry, read).
     1126/** Issue packet command (i. e. write a command packet to the device)
     1127 * with no data transfer.
    10851128 *
    10861129 * @param device        Device
     1130 * @param cpkt          Command packet
     1131 * @param cpkt_size     Command packet size in bytes
     1132 *
     1133 * @return EOK on success, EIO on error.
     1134 */
     1135static errno_t ata_cmd_packet_nondata(ata_device_t *device, const void *cpkt,
     1136    size_t cpkt_size)
     1137{
     1138        ata_channel_t *chan = device->chan;
     1139        uint8_t status;
     1140        uint8_t drv_head;
     1141        errno_t rc;
     1142
     1143        ata_msg_debug(chan, "ata_cmd_packet_nondata()");
     1144
     1145        fibril_mutex_lock(&chan->lock);
     1146
     1147        /* New value for Drive/Head register */
     1148        drv_head =
     1149            ((disk_dev_idx(device) != 0) ? DHR_DRV : 0);
     1150
     1151        if (wait_status(chan, 0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) {
     1152                fibril_mutex_unlock(&chan->lock);
     1153                return EIO;
     1154        }
     1155
     1156        ata_write_cmd_8(chan, REG_DRIVE_HEAD, drv_head);
     1157
     1158        if (wait_status(chan, 0, ~(SR_BSY | SR_DRQ), NULL, TIMEOUT_BSY) != EOK) {
     1159                fibril_mutex_unlock(&chan->lock);
     1160                return EIO;
     1161        }
     1162
     1163        ata_write_cmd_8(chan, REG_COMMAND, CMD_PACKET);
     1164
     1165        if (wait_status(chan, SR_DRQ, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
     1166                if (chan->params.use_dma)
     1167                        ata_dma_chan_teardown(device);
     1168                fibril_mutex_unlock(&chan->lock);
     1169                return EIO;
     1170        }
     1171
     1172        /* Write command packet. */
     1173        ata_write_data_16(chan, ((uint16_t *) cpkt), (cpkt_size + 1) / 2);
     1174
     1175        rc = ata_pio_nondata(device);
     1176
     1177        fibril_mutex_unlock(&chan->lock);
     1178
     1179        return rc;
     1180}
     1181
     1182/** Issue packet command (i. e. write a command packet to the device)
     1183 * performing data-in transfer.
     1184 *
     1185 * @param device        Device
     1186 * @param cpkt          Command packet
     1187 * @param cpkt_size     Command packet size in bytes
    10871188 * @param obuf          Buffer for storing data read from device
    10881189 * @param obuf_size     Size of obuf in bytes
     
    10911192 * @return EOK on success, EIO on error.
    10921193 */
    1093 static errno_t ata_cmd_packet(ata_device_t *device, const void *cpkt, size_t cpkt_size,
    1094     void *obuf, size_t obuf_size, size_t *rcvd_size)
     1194static errno_t ata_cmd_packet_din(ata_device_t *device, const void *cpkt,
     1195    size_t cpkt_size, void *obuf, size_t obuf_size, size_t *rcvd_size)
    10951196{
    10961197        ata_channel_t *chan = device->chan;
     
    11871288        cp->alloc_len = host2uint16_t_be(min(obuf_size, 0xff));
    11881289
    1189         rc = ata_cmd_packet(device, cpb, sizeof(cpb), obuf, obuf_size, rcvd_size);
     1290        rc = ata_cmd_packet_din(device, cpb, sizeof(cpb), obuf, obuf_size,
     1291            rcvd_size);
    11901292        if (rc != EOK)
    11911293                return rc;
     
    12131315        cdb.op_code = SCSI_CMD_READ_CAPACITY_10;
    12141316
    1215         rc = ata_cmd_packet(device, &cdb, sizeof(cdb), &data, sizeof(data), &rsize);
     1317        rc = ata_cmd_packet_din(device, &cdb, sizeof(cdb), &data, sizeof(data),
     1318            &rsize);
    12161319        if (rc != EOK)
    12171320                return rc;
     
    12541357        cp.xfer_len = host2uint32_t_be(cnt);
    12551358
    1256         rc = ata_cmd_packet(device, &cp, sizeof(cp), obuf, obuf_size, NULL);
     1359        rc = ata_cmd_packet_din(device, &cp, sizeof(cp), obuf, obuf_size, NULL);
    12571360        if (rc != EOK)
    12581361                return rc;
     
    12941397        cp->control = 0x40; /* 0x01 = multi-session mode (shifted to MSB) */
    12951398
    1296         rc = ata_cmd_packet(device, cpb, sizeof(cpb), obuf, obuf_size, NULL);
     1399        rc = ata_cmd_packet_din(device, cpb, sizeof(cpb), obuf, obuf_size,
     1400            NULL);
    12971401        if (rc != EOK)
    12981402                return rc;
     1403
     1404        return EOK;
     1405}
     1406
     1407/** Issue Start Stop Unit command.
     1408 *
     1409 * @param device        Device
     1410 * @param flags         Flags field of Start Stop Unit command (ssf_*)
     1411 * @return EOK on success, EIO on error.
     1412 */
     1413static errno_t ata_pcmd_start_stop_unit(ata_device_t *device, uint8_t flags)
     1414{
     1415        uint8_t cpb[12];
     1416        scsi_cdb_start_stop_unit_t *cp = (scsi_cdb_start_stop_unit_t *)cpb;
     1417        errno_t rc;
     1418
     1419        ata_msg_debug(device->chan, "ata_pcmd_start_stop_unit(device, 0x%x)",
     1420            flags);
     1421
     1422        memset(cpb, 0, sizeof(cpb));
     1423
     1424        /*
     1425         * For SFF 8020 compliance the command must be padded to 12 bytes.
     1426         */
     1427        cp->op_code = SCSI_CMD_START_STOP_UNIT;
     1428        cp->immed = 0;
     1429        cp->flags = flags;
     1430        cp->control = 0;
     1431
     1432        rc = ata_cmd_packet_nondata(device, cpb, sizeof(cpb));
     1433        if (rc != EOK)
     1434                return rc;
     1435
     1436        ata_msg_debug(device->chan, "ata_pcmd_start_stop_unit(): "
     1437            "ata_cmd_packet_nondata -> %d", rc);
    12991438
    13001439        return EOK;
     
    15291668         * exceed DMA buffer size.
    15301669         */
    1531         dma_maxnb = d->chan->params.max_dma_xfer / d->block_size;
    1532         if (dma_maxnb < maxnb)
    1533                 maxnb = dma_maxnb;
     1670        if (d->chan->params.use_dma) {
     1671                dma_maxnb = d->chan->params.max_dma_xfer / d->block_size;
     1672                if (dma_maxnb < maxnb)
     1673                        maxnb = dma_maxnb;
     1674        }
    15341675
    15351676        return maxnb;
Note: See TracChangeset for help on using the changeset viewer.