Changes in / [42cfd91:330965c] in mainline


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

Legend:

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

    r42cfd91 r330965c  
    6060#define NAME "ata_bd"
    6161
     62/** Physical block size. Should be always 512. */
    6263static const size_t block_size = 512;
     64
     65/** Size of the communication area. */
    6366static size_t comm_size;
    6467
     68/** I/O base address of the command registers. */
    6569static uintptr_t cmd_physical = 0x1f0;
     70/** I/O base address of the control registers. */
    6671static uintptr_t ctl_physical = 0x170;
     72
    6773static ata_cmd_t *cmd;
    6874static ata_ctl_t *ctl;
     
    8086    const void *buf);
    8187static int drive_identify(int drive_id, disk_t *d);
     88static int wait_status(unsigned set, unsigned n_reset, uint8_t *pstatus,
     89    unsigned timeout);
    8290
    8391int main(int argc, char **argv)
    8492{
    85         uint8_t status;
    8693        char name[16];
    8794        int i, rc;
     
    95102                return -1;
    96103
    97         (void) drive_identify(0, &disk[0]);
    98         (void) drive_identify(1, &disk[1]);
     104        for (i = 0; i < MAX_DISKS; i++) {
     105                printf("Identify drive %d... ", i);
     106                fflush(stdout);
     107
     108                rc = drive_identify(i, &disk[i]);
     109
     110                if (rc == EOK) {
     111                        printf("%u cylinders, %u heads, %u sectors\n",
     112                            disk[i].cylinders, disk[i].heads, disk[i].sectors);
     113                } else {
     114                        printf("Not found.\n");
     115                }
     116        }
    99117
    100118        n_disks = 0;
     
    129147}
    130148
    131 static int drive_identify(int disk_id, disk_t *d)
    132 {
    133         uint16_t data;
    134         uint8_t status;
    135         uint8_t drv_head;
    136         size_t i;
    137 
    138         printf("Identify drive %d... ", disk_id);
    139         fflush(stdout);
    140 
    141         drv_head = ((disk_id != 0) ? DHR_DRV : 0);
    142         d->present = false;
    143 
    144         do {
    145                 status = pio_read_8(&cmd->status);
    146         } while ((status & SR_BSY) != 0);
    147 
    148         pio_write_8(&cmd->drive_head, drv_head);
    149 
    150         /*
    151          * Detect if drive is present. This is Qemu only! Need to
    152          * do the right thing to work with real drives.
    153          */
    154         do {
    155                 status = pio_read_8(&cmd->status);
    156         } while ((status & SR_BSY) != 0);
    157 
    158         if ((status & SR_DRDY) == 0) {
    159                 printf("None attached.\n");
    160                 return ENOENT;
    161         }
    162         /***/
    163 
    164         do {
    165                 status = pio_read_8(&cmd->status);
    166         } while ((status & SR_BSY) != 0 || (status & SR_DRDY) == 0);
    167 
    168         pio_write_8(&cmd->command, CMD_IDENTIFY_DRIVE);
    169 
    170         do {
    171                 status = pio_read_8(&cmd->status);
    172         } while ((status & SR_BSY) != 0);
    173 
    174         /* Read data from the disk buffer. */
    175 
    176         if ((status & SR_DRQ) != 0) {
    177 //              for (i = 0; i < block_size / 2; i++) {
    178 //                      data = pio_read_16(&cmd->data_port);
    179 //                      ((uint16_t *) buf)[i] = data;
    180 //              }
    181 
    182                 for (i = 0; i < block_size / 2; i++) {
    183                         data = pio_read_16(&cmd->data_port);
    184 
    185                         switch (i) {
    186                         case 1: d->cylinders = data; break;
    187                         case 3: d->heads = data; break;
    188                         case 6: d->sectors = data; break;
    189                         }
    190                 }
    191         }
    192 
    193         if ((status & SR_ERR) != 0)
    194                 return EIO;
    195 
    196         d->blocks = d->cylinders * d->heads * d->sectors;
    197 
    198         printf("Geometry: %u cylinders, %u heads, %u sectors\n",
    199                 d->cylinders, d->heads, d->sectors);
    200 
    201         d->present = true;
    202         fibril_mutex_initialize(&d->lock);
    203 
    204         return EOK;
    205 }
    206 
     149
     150/** Register driver and enable device I/O. */
    207151static int ata_bd_init(void)
    208152{
     
    236180}
    237181
     182/** Block device connection handler */
    238183static void ata_bd_connection(ipc_callid_t iid, ipc_call_t *icall)
    239184{
     
    306251}
    307252
     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 */
    308263static int ata_bd_rdwr(int disk_id, ipcarg_t method, off_t blk_idx, size_t size,
    309264    void *buf)
     
    337292}
    338293
    339 
     294/** Issue IDENTIFY command.
     295 *
     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.
     298 *
     299 * @param disk_id       Device ID, 0 or 1.
     300 * @param d             Device structure to store parameters in.
     301 */
     302static int drive_identify(int disk_id, disk_t *d)
     303{
     304        uint16_t data;
     305        uint8_t status;
     306        uint8_t drv_head;
     307        size_t i;
     308
     309        drv_head = ((disk_id != 0) ? DHR_DRV : 0);
     310        d->present = false;
     311
     312        if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
     313                return EIO;
     314
     315        pio_write_8(&cmd->drive_head, drv_head);
     316
     317        /*
     318         * This is where we would most likely expect a non-existing device to
     319         * show up by not setting SR_DRDY.
     320         */
     321        if (wait_status(SR_DRDY, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
     322                return EIO;
     323
     324        pio_write_8(&cmd->command, CMD_IDENTIFY_DRIVE);
     325
     326        if (wait_status(0, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK)
     327                return EIO;
     328
     329        /* Read data from the disk buffer. */
     330
     331        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 */
    340368static int ata_bd_read_block(int disk_id, uint64_t blk_idx, size_t blk_cnt,
    341369    void *buf)
     
    371399        /* Program a Read Sectors operation. */
    372400
    373         do {
    374                 status = pio_read_8(&cmd->status);
    375         } while ((status & SR_BSY) != 0);
     401        if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_BSY) != EOK) {
     402                fibril_mutex_unlock(&d->lock);
     403                return EIO;
     404        }
    376405
    377406        pio_write_8(&cmd->drive_head, drv_head);
    378407
    379         do {
    380                 status = pio_read_8(&cmd->status);
    381         } while ((status & SR_BSY) != 0 || (status & SR_DRDY) == 0);
     408        if (wait_status(SR_DRDY, ~SR_BSY, NULL, TIMEOUT_DRDY) != EOK) {
     409                fibril_mutex_unlock(&d->lock);
     410                return EIO;
     411        }
    382412
    383413        pio_write_8(&cmd->sector_count, 1);
     
    388418        pio_write_8(&cmd->command, CMD_READ_SECTORS);
    389419
    390         do {
    391                 status = pio_read_8(&cmd->status);
    392         } while ((status & SR_BSY) != 0);
    393 
    394         /* Read data from the disk buffer. */
     420        if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
     421                fibril_mutex_unlock(&d->lock);
     422                return EIO;
     423        }
    395424
    396425        if ((status & SR_DRQ) != 0) {
     426                /* Read data from the device buffer. */
     427
    397428                for (i = 0; i < block_size / 2; i++) {
    398429                        data = pio_read_16(&cmd->data_port);
     
    408439}
    409440
     441/** Write a physical block to the device.
     442 *
     443 * @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.
     447 *
     448 * @return EOK on success, EIO on error.
     449 */
    410450static int ata_bd_write_block(int disk_id, uint64_t blk_idx, size_t blk_cnt,
    411451    const void *buf)
     
    438478        fibril_mutex_lock(&d->lock);
    439479
    440         /* Program a Read Sectors operation. */
    441 
    442         do {
    443                 status = pio_read_8(&cmd->status);
    444         } while ((status & SR_BSY) != 0);
    445        
     480        /* Program a Write Sectors operation. */
     481
     482        if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_BSY) != EOK) {
     483                fibril_mutex_unlock(&d->lock);
     484                return EIO;
     485        }
     486
    446487        pio_write_8(&cmd->drive_head, drv_head);
    447488
    448         do {
    449                 status = pio_read_8(&cmd->status);
    450         } while ((status & SR_BSY) != 0 || (status & SR_DRDY) == 0);
     489        if (wait_status(SR_DRDY, ~SR_BSY, NULL, TIMEOUT_DRDY) != EOK) {
     490                fibril_mutex_unlock(&d->lock);
     491                return EIO;
     492        }
    451493
    452494        pio_write_8(&cmd->sector_count, 1);
     
    457499        pio_write_8(&cmd->command, CMD_WRITE_SECTORS);
    458500
    459         do {
    460                 status = pio_read_8(&cmd->status);
    461         } while ((status & SR_BSY) != 0);
    462 
    463         /* Write data to the disk buffer. */
     501        if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
     502                fibril_mutex_unlock(&d->lock);
     503                return EIO;
     504        }
    464505
    465506        if ((status & SR_DRQ) != 0) {
     507                /* Write data to the device buffer. */
     508
    466509                for (i = 0; i < block_size / 2; i++) {
    467510                        pio_write_16(&cmd->data_port, ((uint16_t *) buf)[i]);
     
    477520}
    478521
     522/** Wait until some status bits are set and some are reset.
     523 *
     524 * Example: wait_status(SR_DRDY, ~SR_BSY) waits for SR_DRDY to become
     525 * set and SR_BSY to become reset.
     526 *
     527 * @param set           Combination if bits which must be all set.
     528 * @param n_reset       Negated combination of bits which must be all reset.
     529 * @param pstatus       Pointer where to store last read status or NULL.
     530 * @param timeout       Timeout in 10ms units.
     531 *
     532 * @return              EOK on success, EIO on timeout.
     533 */
     534static int wait_status(unsigned set, unsigned n_reset, uint8_t *pstatus,
     535    unsigned timeout)
     536{
     537        uint8_t status;
     538        int cnt;
     539
     540        status = pio_read_8(&cmd->status);
     541
     542        /*
     543         * This is crude, yet simple. First try with 1us delays
     544         * (most likely the device will respond very fast). If not,
     545         * start trying every 10 ms.
     546         */
     547
     548        cnt = 100;
     549        while ((status & ~n_reset) != 0 || (status & set) != set) {
     550                async_usleep(1);
     551                --cnt;
     552                if (cnt <= 0) break;
     553
     554                status = pio_read_8(&cmd->status);
     555        }
     556
     557        cnt = timeout;
     558        while ((status & ~n_reset) != 0 || (status & set) != set) {
     559                async_usleep(10000);
     560                --cnt;
     561                if (cnt <= 0) break;
     562
     563                status = pio_read_8(&cmd->status);
     564        }
     565
     566        if (pstatus)
     567                *pstatus = status;
     568
     569        if (cnt == 0)
     570                return EIO;
     571
     572        return EOK;
     573}
     574
    479575/**
    480576 * @}
  • uspace/srv/bd/ata_bd/ata_bd.h

    r42cfd91 r330965c  
    135135};
    136136
     137/** Timeout definitions. Unit is 10 ms. */
     138enum ata_timeout {
     139        TIMEOUT_PROBE   =  100, /*  1 s */
     140        TIMEOUT_BSY     =  100, /*  1 s */
     141        TIMEOUT_DRDY    = 1000  /* 10 s */
     142};
     143
    137144typedef struct {
    138145        bool present;
Note: See TracChangeset for help on using the changeset viewer.