Changeset 9739b5a in mainline


Ignore:
Timestamp:
2024-06-11T09:32:59Z (3 weeks ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
master
Children:
c4ed9fa
Parents:
a38d504
git-author:
Jiri Svoboda <jiri@…> (2024-06-10 18:32:24)
git-committer:
Jiri Svoboda <jiri@…> (2024-06-11 09:32:59)
Message:

Add DMA support to PACKET command

Location:
uspace/lib/ata
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/ata/include/ata/ata_hw.h

    ra38d504 r9739b5a  
    105105#define REG_STATUS offsetof(ata_cmd_t, status)
    106106#define REG_COMMAND offsetof(ata_cmd_t, command)
     107#define REG_FEATURES offsetof(ata_cmd_t, features)
    107108
    108109enum devctl_bits {
  • uspace/lib/ata/src/ata.c

    ra38d504 r9739b5a  
    878878                rc = wait_status(chan, 0, ~SR_BSY, &status, TIMEOUT_BSY);
    879879
     880        /* Tear down DMA channel */
     881        ata_dma_chan_teardown(device);
     882
    880883        if (rc != EOK) {
    881884                ata_msg_debug(chan, "wait_irq/wait_status failed");
    882885                return EIO;
    883886        }
    884 
    885         /* Tear down DMA channel */
    886         ata_dma_chan_teardown(device);
    887887
    888888        if ((status & SR_ERR) != 0) {
     
    973973}
    974974
    975 /** Issue packet command (i. e. write a command packet to the device).
    976  *
    977  * Only data-in commands are supported (e.g. inquiry, read).
    978  *
    979  * @param device        Device
    980  * @param obuf          Buffer for storing data read from device
    981  * @param obuf_size     Size of obuf in bytes
    982  * @param rcvd_size     Place to store number of bytes read or @c NULL
    983  *
    984  * @return EOK on success, EIO on error.
    985  */
    986 static errno_t ata_cmd_packet(ata_device_t *device, const void *cpkt, size_t cpkt_size,
    987     void *obuf, size_t obuf_size, size_t *rcvd_size)
     975/** Read data using PIO during a PACKET command.
     976 *
     977 * @param device Device
     978 * @param obuf Output buffer
     979 * @param obuf_size Output buffer size
     980 * @param rcvd_size Place to store number of bytes actually transferred
     981 *                  or @c NULL
     982 */
     983static errno_t ata_packet_pio_data_in(ata_device_t *device, void *obuf,
     984    size_t obuf_size, size_t *rcvd_size)
    988985{
    989986        ata_channel_t *chan = device->chan;
    990         uint8_t status;
    991         uint8_t drv_head;
    992987        size_t data_size;
    993988        size_t remain;
    994         errno_t rc;
    995 
    996         fibril_mutex_lock(&chan->lock);
    997 
    998         /* New value for Drive/Head register */
    999         drv_head =
    1000             ((disk_dev_idx(device) != 0) ? DHR_DRV : 0);
    1001 
    1002         if (wait_status(chan, 0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) {
    1003                 fibril_mutex_unlock(&chan->lock);
    1004                 return EIO;
    1005         }
    1006 
    1007         ata_write_cmd_8(chan, REG_DRIVE_HEAD, drv_head);
    1008 
    1009         if (wait_status(chan, 0, ~(SR_BSY | SR_DRQ), NULL, TIMEOUT_BSY) != EOK) {
    1010                 fibril_mutex_unlock(&chan->lock);
    1011                 return EIO;
    1012         }
    1013 
    1014         /* Byte count <- max. number of bytes we can read in one transfer. */
    1015         ata_write_cmd_8(chan, REG_CYLINDER_LOW, 0xfe);
    1016         ata_write_cmd_8(chan, REG_CYLINDER_HIGH, 0xff);
    1017 
    1018         ata_write_cmd_8(chan, REG_COMMAND, CMD_PACKET);
    1019 
    1020         if (wait_status(chan, SR_DRQ, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
    1021                 fibril_mutex_unlock(&chan->lock);
    1022                 return EIO;
    1023         }
    1024 
    1025         /* Write command packet. */
    1026         ata_write_data_16(chan, ((uint16_t *) cpkt), (cpkt_size + 1) / 2);
     989        uint8_t status;
     990        errno_t rc;
    1027991
    1028992        remain = obuf_size;
     
    10641028                rc = wait_status(chan, 0, ~SR_BSY, &status, TIMEOUT_BSY);
    10651029
    1066         fibril_mutex_unlock(&chan->lock);
    1067 
    10681030        if (status & SR_ERR)
    10691031                return EIO;
     
    10711033        if (rcvd_size != NULL)
    10721034                *rcvd_size = obuf_size - remain;
     1035
     1036        return EOK;
     1037}
     1038
     1039static errno_t ata_packet_dma(ata_device_t *device, void *buf, size_t buf_size,
     1040    ata_dma_dir_t dir)
     1041{
     1042        ata_channel_t *chan = device->chan;
     1043        uint8_t status;
     1044        errno_t rc;
     1045
     1046        if (chan->params.have_irq)
     1047                rc = wait_irq(chan, &status, TIMEOUT_BSY);
     1048        else
     1049                rc = wait_status(chan, 0, ~SR_BSY, &status, TIMEOUT_BSY);
     1050
     1051        if (rc != EOK) {
     1052                ata_msg_debug(chan, "wait_irq/wait_status failed");
     1053                return EIO;
     1054        }
     1055
     1056        if ((status & SR_ERR) != 0) {
     1057                ata_msg_debug(chan, "status & SR_ERR != 0");
     1058                return EIO;
     1059        }
     1060
     1061        return EOK;
     1062}
     1063
     1064/** Issue packet command (i. e. write a command packet to the device).
     1065 *
     1066 * Only data-in commands are supported (e.g. inquiry, read).
     1067 *
     1068 * @param device        Device
     1069 * @param obuf          Buffer for storing data read from device
     1070 * @param obuf_size     Size of obuf in bytes
     1071 * @param rcvd_size     Place to store number of bytes read or @c NULL
     1072 *
     1073 * @return EOK on success, EIO on error.
     1074 */
     1075static errno_t ata_cmd_packet(ata_device_t *device, const void *cpkt, size_t cpkt_size,
     1076    void *obuf, size_t obuf_size, size_t *rcvd_size)
     1077{
     1078        ata_channel_t *chan = device->chan;
     1079        uint8_t status;
     1080        uint8_t drv_head;
     1081        errno_t rc;
     1082
     1083        fibril_mutex_lock(&chan->lock);
     1084
     1085        /* New value for Drive/Head register */
     1086        drv_head =
     1087            ((disk_dev_idx(device) != 0) ? DHR_DRV : 0);
     1088
     1089        if (wait_status(chan, 0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) {
     1090                fibril_mutex_unlock(&chan->lock);
     1091                return EIO;
     1092        }
     1093
     1094        ata_write_cmd_8(chan, REG_DRIVE_HEAD, drv_head);
     1095
     1096        if (wait_status(chan, 0, ~(SR_BSY | SR_DRQ), NULL, TIMEOUT_BSY) != EOK) {
     1097                fibril_mutex_unlock(&chan->lock);
     1098                return EIO;
     1099        }
     1100
     1101        if (chan->params.use_dma) {
     1102                /* Set up DMA channel */
     1103                ata_dma_chan_setup(device, obuf, obuf_size, ata_dma_read);
     1104                ata_write_cmd_8(chan, REG_FEATURES, 0x01); // XXX
     1105        } else {
     1106                /*
     1107                 * Byte count <- max. number of bytes we can read in one
     1108                 * PIO transfer.
     1109                 */
     1110                ata_write_cmd_8(chan, REG_CYLINDER_LOW, 0xfe);
     1111                ata_write_cmd_8(chan, REG_CYLINDER_HIGH, 0xff);
     1112        }
     1113
     1114        ata_write_cmd_8(chan, REG_COMMAND, CMD_PACKET);
     1115
     1116        if (wait_status(chan, SR_DRQ, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
     1117                if (chan->params.use_dma)
     1118                        ata_dma_chan_teardown(device);
     1119                fibril_mutex_unlock(&chan->lock);
     1120                return EIO;
     1121        }
     1122
     1123        /* Write command packet. */
     1124        ata_write_data_16(chan, ((uint16_t *) cpkt), (cpkt_size + 1) / 2);
     1125
     1126        if (chan->params.use_dma) {
     1127                /* Read data using DMA */
     1128                rc = ata_packet_dma(device, obuf, obuf_size, ata_dma_read);
     1129                if (rc == EOK && rcvd_size != NULL)
     1130                        *rcvd_size = obuf_size;
     1131                ata_dma_chan_teardown(device);
     1132        } else {
     1133                /* Read data using PIO */
     1134                rc = ata_packet_pio_data_in(device, obuf, obuf_size, rcvd_size);
     1135        }
     1136
     1137        fibril_mutex_unlock(&chan->lock);
     1138
     1139        if (rc != EOK)
     1140                return rc;
     1141
    10731142        return EOK;
    10741143}
Note: See TracChangeset for help on using the changeset viewer.