Changes in / [c5f0bff:40fb017] in mainline


Ignore:
Location:
uspace/srv/bd/ata_bd
Files:
3 edited

Legend:

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

    rc5f0bff r40fb017  
    5555#include <as.h>
    5656#include <fibril_synch.h>
    57 #include <stdint.h>
    5857#include <str.h>
    5958#include <devmap.h>
     
    6261#include <errno.h>
    6362#include <bool.h>
    64 #include <byteorder.h>
    6563#include <task.h>
    6664#include <macros.h>
     
    7573#define LEGACY_CTLS 4
    7674
    77 /**
    78  * Size of data returned from Identify Device or Identify Packet Device
    79  * command.
    80  */
    81 static const size_t identify_data_size = 512;
     75/** Physical block size. Should be always 512. */
     76static const size_t block_size = 512;
    8277
    8378/** Size of the communication area. */
     
    110105static int ata_bd_write_blocks(int disk_id, uint64_t ba, size_t cnt,
    111106    const void *buf);
    112 static int ata_rcmd_read(int disk_id, uint64_t ba, size_t cnt,
     107static int ata_bd_read_block(int disk_id, uint64_t ba, size_t cnt,
    113108    void *buf);
    114 static int ata_rcmd_write(int disk_id, uint64_t ba, size_t cnt,
     109static int ata_bd_write_block(int disk_id, uint64_t ba, size_t cnt,
    115110    const void *buf);
    116111static int disk_init(disk_t *d, int disk_id);
    117112static int drive_identify(int drive_id, void *buf);
    118 static int identify_pkt_dev(int dev_idx, void *buf);
    119 static int ata_cmd_packet(int dev_idx, const void *cpkt, size_t cpkt_size,
    120     void *obuf, size_t obuf_size);
    121 static int ata_pcmd_inquiry(int dev_idx, void *obuf, size_t obuf_size);
    122 static int ata_pcmd_read_12(int dev_idx, uint64_t ba, size_t cnt,
    123     void *obuf, size_t obuf_size);
    124113static void disk_print_summary(disk_t *d);
    125114static int coord_calc(disk_t *d, uint64_t ba, block_coord_t *bc);
     
    214203        printf("%s: ", d->model);
    215204
    216         if (d->dev_type == ata_reg_dev) {
    217                 switch (d->amode) {
    218                 case am_chs:
    219                         printf("CHS %u cylinders, %u heads, %u sectors",
    220                             disk->geom.cylinders, disk->geom.heads,
    221                             disk->geom.sectors);
    222                         break;
    223                 case am_lba28:
    224                         printf("LBA-28");
    225                         break;
    226                 case am_lba48:
    227                         printf("LBA-48");
    228                         break;
    229                 }
    230         } else {
    231                 printf("PACKET");
     205        switch (d->amode) {
     206        case am_chs:
     207                printf("CHS %u cylinders, %u heads, %u sectors",
     208                    disk->geom.cylinders, disk->geom.heads, disk->geom.sectors);
     209                break;
     210        case am_lba28:
     211                printf("LBA-28");
     212                break;
     213        case am_lba48:
     214                printf("LBA-48");
     215                break;
    232216        }
    233217
     
    329313                            IPC_GET_ARG2(call));
    330314                        cnt = IPC_GET_ARG3(call);
    331                         if (cnt * disk[disk_id].block_size > comm_size) {
     315                        if (cnt * block_size > comm_size) {
    332316                                retval = ELIMIT;
    333317                                break;
     
    339323                            IPC_GET_ARG2(call));
    340324                        cnt = IPC_GET_ARG3(call);
    341                         if (cnt * disk[disk_id].block_size > comm_size) {
     325                        if (cnt * block_size > comm_size) {
    342326                                retval = ELIMIT;
    343327                                break;
     
    346330                        break;
    347331                case BD_GET_BLOCK_SIZE:
    348                         async_answer_1(callid, EOK, disk[disk_id].block_size);
     332                        async_answer_1(callid, EOK, block_size);
    349333                        continue;
    350334                case BD_GET_NUM_BLOCKS:
     
    369353        identify_data_t idata;
    370354        uint8_t model[40];
    371         ata_inquiry_data_t inq_data;
    372355        uint16_t w;
    373356        uint8_t c;
     
    376359        unsigned i;
    377360
    378         d->present = false;
    379         fibril_mutex_initialize(&d->lock);
    380 
    381         /* Try identify command. */
    382361        rc = drive_identify(disk_id, &idata);
    383         if (rc == EOK) {
    384                 /* Success. It's a register (non-packet) device. */
    385                 printf("ATA register-only device found.\n");
    386                 d->dev_type = ata_reg_dev;
    387         } else if (rc == EIO) {
    388                 /*
    389                  * There is something, but not a register device.
    390                  * It could be a packet device.
    391                  */
    392                 rc = identify_pkt_dev(disk_id, &idata);
    393                 if (rc == EOK) {
    394                         /* We have a packet device. */
    395                         d->dev_type = ata_pkt_dev;
    396                 } else {
    397                         /* Nope. Something's there, but not recognized. */
    398                         return EIO;
    399                 }
    400         } else {
    401                 /* Operation timed out. That means there is no device there. */
    402                 return EIO;
    403         }
    404 
    405         printf("device caps: 0x%04x\n", idata.caps);
    406         if (d->dev_type == ata_pkt_dev) {
    407                 /* Packet device */
    408                 d->amode = 0;
    409 
    410                 d->geom.cylinders = 0;
    411                 d->geom.heads = 0;
    412                 d->geom.sectors = 0;
    413 
    414                 d->blocks = 0;
    415         } else if ((idata.caps & rd_cap_lba) == 0) {
     362        if (rc != EOK) {
     363                d->present = false;
     364                return rc;
     365        }
     366
     367        if ((idata.caps & cap_lba) == 0) {
    416368                /* Device only supports CHS addressing. */
    417369                d->amode = am_chs;
     
    470422        d->model[pos] = '\0';
    471423
    472         if (d->dev_type == ata_pkt_dev) {
    473                 /* Send inquiry. */
    474                 rc = ata_pcmd_inquiry(0, &inq_data, sizeof(inq_data));
    475                 if (rc != EOK) {
    476                         printf("Device inquiry failed.\n");
    477                         d->present = false;
    478                         return EIO;
    479                 }
    480 
    481                 /* Check device type. */
    482                 if (INQUIRY_PDEV_TYPE(inq_data.pdev_type) != PDEV_TYPE_CDROM)
    483                         printf("Warning: Peripheral device type is not CD-ROM.\n");
    484 
    485                 /* Assume 2k block size for now. */
    486                 d->block_size = 2048;
    487         } else {
    488                 /* Assume register Read always uses 512-byte blocks. */
    489                 d->block_size = 512;
    490         }
    491 
    492424        d->present = true;
     425        fibril_mutex_initialize(&d->lock);
     426
    493427        return EOK;
    494428}
     
    501435
    502436        while (cnt > 0) {
    503                 if (disk[disk_id].dev_type == ata_reg_dev)
    504                         rc = ata_rcmd_read(disk_id, ba, 1, buf);
    505                 else
    506                         rc = ata_pcmd_read_12(disk_id, ba, 1, buf,
    507                             disk[disk_id].block_size);
    508 
     437                rc = ata_bd_read_block(disk_id, ba, 1, buf);
    509438                if (rc != EOK)
    510439                        return rc;
     
    512441                ++ba;
    513442                --cnt;
    514                 buf += disk[disk_id].block_size;
     443                buf += block_size;
    515444        }
    516445
     
    524453        int rc;
    525454
    526         if (disk[disk_id].dev_type != ata_reg_dev)
    527                 return ENOTSUP;
    528 
    529455        while (cnt > 0) {
    530                 rc = ata_rcmd_write(disk_id, ba, 1, buf);
     456                rc = ata_bd_write_block(disk_id, ba, 1, buf);
    531457                if (rc != EOK)
    532458                        return rc;
     
    534460                ++ba;
    535461                --cnt;
    536                 buf += disk[disk_id].block_size;
     462                buf += block_size;
    537463        }
    538464
     
    547473 * @param disk_id       Device ID, 0 or 1.
    548474 * @param buf           Pointer to a 512-byte buffer.
    549  *
    550  * @return              ETIMEOUT on timeout (this can mean the device is
    551  *                      not present). EIO if device responds with error.
    552475 */
    553476static int drive_identify(int disk_id, void *buf)
     
    561484
    562485        if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
    563                 return ETIMEOUT;
     486                return EIO;
    564487
    565488        pio_write_8(&cmd->drive_head, drv_head);
     
    570493         */
    571494        if (wait_status(SR_DRDY, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
    572                 return ETIMEOUT;
     495                return EIO;
    573496
    574497        pio_write_8(&cmd->command, CMD_IDENTIFY_DRIVE);
    575498
    576499        if (wait_status(0, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK)
    577                 return ETIMEOUT;
     500                return EIO;
    578501
    579502        /* Read data from the disk buffer. */
    580503
    581504        if ((status & SR_DRQ) != 0) {
    582                 for (i = 0; i < identify_data_size / 2; i++) {
     505                for (i = 0; i < block_size / 2; i++) {
    583506                        data = pio_read_16(&cmd->data_port);
    584507                        ((uint16_t *) buf)[i] = data;
     
    586509        }
    587510
    588         if ((status & SR_ERR) != 0) {
    589                 return EIO;
    590         }
    591 
    592         return EOK;
    593 }
    594 
    595 /** Issue Identify Packet Device command.
    596  *
    597  * Reads @c identify data into the provided buffer. This is used to detect
    598  * whether an ATAPI device is present and if so, to determine its parameters.
    599  *
    600  * @param dev_idx       Device index, 0 or 1.
    601  * @param buf           Pointer to a 512-byte buffer.
    602  */
    603 static int identify_pkt_dev(int dev_idx, void *buf)
    604 {
    605         uint16_t data;
    606         uint8_t status;
    607         uint8_t drv_head;
    608         size_t i;
    609 
    610         drv_head = ((dev_idx != 0) ? DHR_DRV : 0);
    611 
    612         if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
    613                 return EIO;
    614 
    615         pio_write_8(&cmd->drive_head, drv_head);
    616 
    617         /* For ATAPI commands we do not need to wait for DRDY. */
    618         if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
    619                 return EIO;
    620 
    621         pio_write_8(&cmd->command, CMD_IDENTIFY_PKT_DEV);
    622 
    623         if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK)
    624                 return EIO;
    625 
    626         /* Read data from the device buffer. */
    627 
    628         if ((status & SR_DRQ) != 0) {
    629                 for (i = 0; i < identify_data_size / 2; i++) {
    630                         data = pio_read_16(&cmd->data_port);
    631                         ((uint16_t *) buf)[i] = data;
    632                 }
    633         }
    634 
    635511        if ((status & SR_ERR) != 0)
    636512                return EIO;
    637 
    638         return EOK;
    639 }
    640 
    641 /** Issue packet command (i. e. write a command packet to the device).
    642  *
    643  * Only data-in commands are supported (e.g. inquiry, read).
    644  *
    645  * @param dev_idx       Device index (0 or 1)
    646  * @param obuf          Buffer for storing data read from device
    647  * @param obuf_size     Size of obuf in bytes
    648  *
    649  * @return EOK on success, EIO on error.
    650  */
    651 static int ata_cmd_packet(int dev_idx, const void *cpkt, size_t cpkt_size,
    652     void *obuf, size_t obuf_size)
    653 {
    654         size_t i;
    655         uint8_t status;
    656         uint8_t drv_head;
    657         disk_t *d;
    658         size_t data_size;
    659         uint16_t val;
    660 
    661         d = &disk[dev_idx];
    662         fibril_mutex_lock(&d->lock);
    663 
    664         /* New value for Drive/Head register */
    665         drv_head =
    666             ((dev_idx != 0) ? DHR_DRV : 0);
    667 
    668         if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) {
    669                 fibril_mutex_unlock(&d->lock);
    670                 return EIO;
    671         }
    672 
    673         pio_write_8(&cmd->drive_head, drv_head);
    674 
    675         if (wait_status(0, ~(SR_BSY|SR_DRQ), NULL, TIMEOUT_BSY) != EOK) {
    676                 fibril_mutex_unlock(&d->lock);
    677                 return EIO;
    678         }
    679 
    680         /* Byte count <- max. number of bytes we can read in one transfer. */
    681         pio_write_8(&cmd->cylinder_low, 0xfe);
    682         pio_write_8(&cmd->cylinder_high, 0xff);
    683 
    684         pio_write_8(&cmd->command, CMD_PACKET);
    685 
    686         if (wait_status(SR_DRQ, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
    687                 fibril_mutex_unlock(&d->lock);
    688                 return EIO;
    689         }
    690 
    691         /* Write command packet. */
    692         for (i = 0; i < (cpkt_size + 1) / 2; i++)
    693                 pio_write_16(&cmd->data_port, ((uint16_t *) cpkt)[i]);
    694 
    695         if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
    696                 fibril_mutex_unlock(&d->lock);
    697                 return EIO;
    698         }
    699 
    700         if ((status & SR_DRQ) == 0) {
    701                 fibril_mutex_unlock(&d->lock);
    702                 return EIO;
    703         }
    704 
    705         /* Read byte count. */
    706         data_size = (uint16_t) pio_read_8(&cmd->cylinder_low) +
    707             ((uint16_t) pio_read_8(&cmd->cylinder_high) << 8);
    708 
    709         /* Check whether data fits into output buffer. */
    710         if (data_size > obuf_size) {
    711                 /* Output buffer is too small to store data. */
    712                 fibril_mutex_unlock(&d->lock);
    713                 return EIO;
    714         }
    715 
    716         /* Read data from the device buffer. */
    717         for (i = 0; i < (data_size + 1) / 2; i++) {
    718                 val = pio_read_16(&cmd->data_port);
    719                 ((uint16_t *) obuf)[i] = val;
    720         }
    721 
    722         if (status & SR_ERR) {
    723                 fibril_mutex_unlock(&d->lock);
    724                 return EIO;
    725         }
    726 
    727         fibril_mutex_unlock(&d->lock);
    728 
    729         return EOK;
    730 }
    731 
    732 /** Issue ATAPI Inquiry.
    733  *
    734  * @param dev_idx       Device index (0 or 1)
    735  * @param obuf          Buffer for storing inquiry data read from device
    736  * @param obuf_size     Size of obuf in bytes
    737  *
    738  * @return EOK on success, EIO on error.
    739  */
    740 static int ata_pcmd_inquiry(int dev_idx, void *obuf, size_t obuf_size)
    741 {
    742         ata_pcmd_inquiry_t cp;
    743         int rc;
    744 
    745         memset(&cp, 0, sizeof(cp));
    746 
    747         cp.opcode = PCMD_INQUIRY;
    748         cp.alloc_len = min(obuf_size, 0xff); /* Allocation length */
    749 
    750         rc = ata_cmd_packet(0, &cp, sizeof(cp), obuf, obuf_size);
    751         if (rc != EOK)
    752                 return rc;
    753 
    754         return EOK;
    755 }
    756 
    757 /** Issue ATAPI read(12) command.
    758  *
    759  * Output buffer must be large enough to hold the data, otherwise the
    760  * function will fail.
    761  *
    762  * @param dev_idx       Device index (0 or 1)
    763  * @param ba            Starting block address
    764  * @param cnt           Number of blocks to read
    765  * @param obuf          Buffer for storing inquiry data read from device
    766  * @param obuf_size     Size of obuf in bytes
    767  *
    768  * @return EOK on success, EIO on error.
    769  */
    770 static int ata_pcmd_read_12(int dev_idx, uint64_t ba, size_t cnt,
    771     void *obuf, size_t obuf_size)
    772 {
    773         ata_pcmd_read_12_t cp;
    774         int rc;
    775 
    776         if (ba > UINT32_MAX)
    777                 return EINVAL;
    778 
    779         memset(&cp, 0, sizeof(cp));
    780 
    781         cp.opcode = PCMD_READ_12;
    782         cp.ba = host2uint32_t_be(ba);
    783         cp.nblocks = host2uint32_t_be(cnt);
    784 
    785         rc = ata_cmd_packet(0, &cp, sizeof(cp), obuf, obuf_size);
    786         if (rc != EOK)
    787                 return rc;
    788513
    789514        return EOK;
     
    799524 * @return EOK on success, EIO on error.
    800525 */
    801 static int ata_rcmd_read(int disk_id, uint64_t ba, size_t blk_cnt,
     526static int ata_bd_read_block(int disk_id, uint64_t ba, size_t blk_cnt,
    802527    void *buf)
    803528{
     
    854579                /* Read data from the device buffer. */
    855580
    856                 for (i = 0; i < disk[disk_id].block_size / 2; i++) {
     581                for (i = 0; i < block_size / 2; i++) {
    857582                        data = pio_read_16(&cmd->data_port);
    858583                        ((uint16_t *) buf)[i] = data;
     
    876601 * @return EOK on success, EIO on error.
    877602 */
    878 static int ata_rcmd_write(int disk_id, uint64_t ba, size_t cnt,
     603static int ata_bd_write_block(int disk_id, uint64_t ba, size_t cnt,
    879604    const void *buf)
    880605{
     
    930655                /* Write data to the device buffer. */
    931656
    932                 for (i = 0; i < disk[disk_id].block_size / 2; i++) {
     657                for (i = 0; i < block_size / 2; i++) {
    933658                        pio_write_16(&cmd->data_port, ((uint16_t *) buf)[i]);
    934659                }
  • uspace/srv/bd/ata_bd/ata_bd.h

    rc5f0bff r40fb017  
    5353};
    5454
    55 enum ata_dev_type {
    56         ata_reg_dev,    /* Register device (no packet feature set support) */
    57         ata_pkt_dev     /* Packet device (supports packet feature set). */
    58 };
    59 
    60 /** Register device block addressing mode. */
    61 enum rd_addr_mode {
     55/** Block addressing mode. */
     56enum addr_mode {
    6257        am_chs,         /**< CHS block addressing */
    6358        am_lba28,       /**< LBA-28 block addressing */
     
    6762/** Block coordinates */
    6863typedef struct {
    69         enum rd_addr_mode amode;
     64        /** Addressing mode used */
     65        enum addr_mode amode;
    7066
    7167        union {
     
    9490typedef struct {
    9591        bool present;
    96 
    97         /** Device type */
    98         enum ata_dev_type dev_type;
    99 
    100         /** Addressing mode to use (if register device) */
    101         enum rd_addr_mode amode;
     92        enum addr_mode amode;
    10293
    10394        /*
     
    111102
    112103        uint64_t blocks;
    113         size_t block_size;
    114104
    115105        char model[STR_BOUNDS(40) + 1];
  • uspace/srv/bd/ata_bd/ata_hw.h

    rc5f0bff r40fb017  
    134134        CMD_WRITE_SECTORS       = 0x30,
    135135        CMD_WRITE_SECTORS_EXT   = 0x34,
    136         CMD_PACKET              = 0xA0,
    137         CMD_IDENTIFY_PKT_DEV    = 0xA1,
    138136        CMD_IDENTIFY_DRIVE      = 0xEC
    139137};
    140138
    141 /** Data returned from identify device and identify packet device command. */
     139/** Data returned from @c identify command. */
    142140typedef struct {
    143141        uint16_t gen_conf;
     
    161159        uint16_t max_rw_multiple;
    162160        uint16_t _res48;
    163         uint16_t caps;          /* Different meaning for packet device */
     161        uint16_t caps;
    164162        uint16_t _res50;
    165163        uint16_t pio_timing;
     
    216214} identify_data_t;
    217215
    218 /** Capability bits for register device. */
    219 enum ata_regdev_caps {
    220         rd_cap_iordy            = 0x0800,
    221         rd_cap_iordy_cbd        = 0x0400,
    222         rd_cap_lba              = 0x0200,
    223         rd_cap_dma              = 0x0100
    224 };
    225 
    226 /** Capability bits for packet device. */
    227 enum ata_pktdev_caps {
    228         pd_cap_ildma            = 0x8000,
    229         pd_cap_cmdqueue         = 0x4000,
    230         pd_cap_overlap          = 0x2000,
    231         pd_cap_need_softreset   = 0x1000,       /* Obsolete (ATAPI-6) */
    232         pd_cap_iordy            = 0x0800,
    233         pd_cap_iordy_dis        = 0x0400,
    234         pd_cap_lba              = 0x0200,       /* Must be on */
    235         pd_cap_dma              = 0x0100
     216enum ata_caps {
     217        cap_iordy       = 0x0800,
     218        cap_iordy_cbd   = 0x0400,
     219        cap_lba         = 0x0200,
     220        cap_dma         = 0x0100
    236221};
    237222
     
    241226};
    242227
    243 /** ATA packet command codes. */
    244 enum ata_pkt_command {
    245         PCMD_INQUIRY            = 0x12,
    246         PCMD_READ_12            = 0xa8
    247 };
    248 
    249 /** ATAPI Inquiry command */
    250 typedef struct {
    251         uint8_t opcode;         /**< Operation code (PCMD_INQUIRY) */
    252         uint8_t _res0;
    253         uint8_t _res1;
    254         uint8_t _res2;
    255         uint8_t alloc_len;      /**< Allocation length */
    256         uint8_t _res3;
    257         uint8_t _res4;
    258         uint8_t _res5;
    259         uint32_t _res6;
    260 } __attribute__ ((packed)) ata_pcmd_inquiry_t;
    261 
    262 /** ATAPI Read(12) command */
    263 typedef struct {
    264         uint8_t opcode;         /**< Operation code (PCMD_READ_12) */
    265         uint8_t _res0;
    266         uint32_t ba;            /**< Starting block address */
    267         uint32_t nblocks;       /**< Number of blocks to transfer */
    268         uint8_t _res1;
    269         uint8_t _res2;
    270 } __attribute__ ((packed)) ata_pcmd_read_12_t;
    271 
    272 /** Data returned from Inquiry command (mandatory part) */
    273 typedef struct {
    274         uint8_t pdev_type;      /** Reserved, Peripheral device type */
    275         uint8_t rmb;            /** RMB, Reserved */
    276         uint8_t std_version;    /** ISO version, ECMA version, ANSI version */
    277         uint8_t atapi_ver_rdf;  /** ATAPI version, Response data format */
    278         uint8_t additional_len; /** Additional length */
    279         uint8_t _res0;
    280         uint8_t _res1;
    281         uint8_t _res2;
    282         uint8_t vendor_id[8];   /** Vendor ID */
    283         uint8_t product_id[8];  /** Product ID */
    284         uint8_t product_rev[4]; /** Product revision level */
    285 } ata_inquiry_data_t;
    286 
    287 /** Extract value of ata_inquiry_data_t.pdev_type */
    288 #define INQUIRY_PDEV_TYPE(val) ((val) & 0x1f)
    289 
    290 /** Values for ata_inquiry_data_t.pdev_type */
    291 enum ata_pdev_type {
    292         PDEV_TYPE_CDROM         = 0x05
    293 };
    294 
    295228#endif
    296229
Note: See TracChangeset for help on using the changeset viewer.