Changes in / [22af3af:21d8020] in mainline
- Location:
- uspace/srv/bd/ata_bd
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/bd/ata_bd/ata_bd.c
r22af3af r21d8020 35 35 * @brief ATA disk driver 36 36 * 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. 39 45 * 40 46 * The driver services a single controller which can have up to two disks … … 89 95 static int drive_identify(int drive_id, void *buf); 90 96 static void disk_print_summary(disk_t *d); 97 static int coord_calc(disk_t *d, uint64_t blk_idx, block_coord_t *bc); 98 static void coord_sc_program(const block_coord_t *bc, uint16_t scnt); 91 99 static int wait_status(unsigned set, unsigned n_reset, uint8_t *pstatus, 92 100 unsigned timeout); … … 100 108 printf(NAME ": ATA disk driver\n"); 101 109 102 printf("I/O address 0x% x\n", cmd_physical);110 printf("I/O address 0x%p/0x%p\n", ctl_physical, cmd_physical); 103 111 104 112 if (ata_bd_init() != EOK) … … 156 164 printf("%s: ", d->model); 157 165 158 if (d->amode == am_chs) { 166 switch (d->amode) { 167 case am_chs: 159 168 printf("CHS %u cylinders, %u heads, %u sectors", 160 169 disk->geom.cylinders, disk->geom.heads, disk->geom.sectors); 161 } else { 170 break; 171 case am_lba28: 162 172 printf("LBA-28"); 173 break; 174 case am_lba48: 175 printf("LBA-48"); 176 break; 163 177 } 164 178 … … 288 302 size_t pos, len; 289 303 int rc; 290 inti;304 unsigned i; 291 305 292 306 rc = drive_identify(disk_id, &idata); … … 305 319 306 320 d->blocks = d->geom.cylinders * d->geom.heads * d->geom.sectors; 307 } else {308 /* Device supports LBA-28. */321 } else if ((idata.cmd_set1 & cs1_addr48) == 0) { 322 /* Device only supports LBA-28 addressing. */ 309 323 d->amode = am_lba28; 310 324 … … 314 328 315 329 d->blocks = 316 (uint32_t) idata.total_lba_sec0 | 317 ((uint32_t) idata.total_lba_sec1 << 16); 330 (uint32_t) idata.total_lba28_0 | 331 ((uint32_t) idata.total_lba28_1 << 16); 332 } else { 333 /* Device supports LBA-48 addressing. */ 334 d->amode = am_lba48; 335 336 d->geom.cylinders = 0; 337 d->geom.heads = 0; 338 d->geom.sectors = 0; 339 340 d->blocks = 341 (uint64_t) idata.total_lba48_0 | 342 ((uint64_t) idata.total_lba48_1 << 16) | 343 ((uint64_t) idata.total_lba48_2 << 32) | 344 ((uint64_t) idata.total_lba48_3 << 48); 318 345 } 319 346 … … 451 478 uint16_t data; 452 479 uint8_t status; 453 uint64_t c, h, s;454 uint64_t idx;455 480 uint8_t drv_head; 456 481 disk_t *d; 482 block_coord_t bc; 457 483 458 484 d = &disk[disk_id]; 459 460 /* Check device bounds. */ 461 if (blk_idx >= d->blocks) 485 bc.h = 0; /* Silence warning. */ 486 487 /* Compute block coordinates. */ 488 if (coord_calc(d, blk_idx, &bc) != EOK) 462 489 return EINVAL; 463 464 if (d->amode == am_chs) {465 /* Compute CHS coordinates. */466 c = blk_idx / (d->geom.heads * d->geom.sectors);467 idx = blk_idx % (d->geom.heads * d->geom.sectors);468 469 h = idx / d->geom.sectors;470 s = 1 + (idx % d->geom.sectors);471 } else {472 /* Compute LBA-28 coordinates. */473 s = blk_idx & 0xff; /* bits 0-7 */474 c = (blk_idx >> 8) & 0xffff; /* bits 8-23 */475 h = (blk_idx >> 24) & 0x0f; /* bits 24-27 */476 }477 490 478 491 /* New value for Drive/Head register */ … … 480 493 ((disk_id != 0) ? DHR_DRV : 0) | 481 494 ((d->amode != am_chs) ? DHR_LBA : 0) | 482 ( h & 0x0f);495 (bc.h & 0x0f); 483 496 484 497 fibril_mutex_lock(&d->lock); … … 498 511 } 499 512 500 pio_write_8(&cmd->sector_count, 1); 501 pio_write_8(&cmd->sector_number, s); 502 pio_write_8(&cmd->cylinder_low, c & 0xff); 503 pio_write_8(&cmd->cylinder_high, c >> 16); 504 505 pio_write_8(&cmd->command, CMD_READ_SECTORS); 513 /* Program block coordinates into the device. */ 514 coord_sc_program(&bc, 1); 515 516 pio_write_8(&cmd->command, d->amode == am_lba48 ? 517 CMD_READ_SECTORS_EXT : CMD_READ_SECTORS); 506 518 507 519 if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) { … … 540 552 size_t i; 541 553 uint8_t status; 542 uint64_t c, h, s;543 uint64_t idx;544 554 uint8_t drv_head; 545 555 disk_t *d; 556 block_coord_t bc; 546 557 547 558 d = &disk[disk_id]; 548 549 /* Check device bounds. */ 550 if (blk_idx >= d->blocks) 559 bc.h = 0; /* Silence warning. */ 560 561 /* Compute block coordinates. */ 562 if (coord_calc(d, blk_idx, &bc) != EOK) 551 563 return EINVAL; 552 553 if (d->amode == am_chs) {554 /* Compute CHS coordinates. */555 c = blk_idx / (d->geom.heads * d->geom.sectors);556 idx = blk_idx % (d->geom.heads * d->geom.sectors);557 558 h = idx / d->geom.sectors;559 s = 1 + (idx % d->geom.sectors);560 } else {561 /* Compute LBA-28 coordinates. */562 s = blk_idx & 0xff; /* bits 0-7 */563 c = (blk_idx >> 8) & 0xffff; /* bits 8-23 */564 h = (blk_idx >> 24) & 0x0f; /* bits 24-27 */565 }566 564 567 565 /* New value for Drive/Head register */ … … 569 567 ((disk_id != 0) ? DHR_DRV : 0) | 570 568 ((d->amode != am_chs) ? DHR_LBA : 0) | 571 ( h & 0x0f);569 (bc.h & 0x0f); 572 570 573 571 fibril_mutex_lock(&d->lock); … … 587 585 } 588 586 589 pio_write_8(&cmd->sector_count, 1); 590 pio_write_8(&cmd->sector_number, s); 591 pio_write_8(&cmd->cylinder_low, c & 0xff); 592 pio_write_8(&cmd->cylinder_high, c >> 16); 593 594 pio_write_8(&cmd->command, CMD_WRITE_SECTORS); 587 /* Program block coordinates into the device. */ 588 coord_sc_program(&bc, 1); 589 590 pio_write_8(&cmd->command, d->amode == am_lba48 ? 591 CMD_WRITE_SECTORS_EXT : CMD_WRITE_SECTORS); 595 592 596 593 if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) { … … 613 610 614 611 return EOK; 612 } 613 614 /** Calculate block coordinates. 615 * 616 * Calculates block coordinates in the best coordinate system supported 617 * by the device. These can be later programmed into the device using 618 * @c coord_sc_program(). 619 * 620 * @return EOK on success or EINVAL if block index is past end of device. 621 */ 622 static int coord_calc(disk_t *d, uint64_t blk_idx, block_coord_t *bc) 623 { 624 uint64_t c; 625 uint64_t idx; 626 627 /* Check device bounds. */ 628 if (blk_idx >= d->blocks) 629 return EINVAL; 630 631 bc->amode = d->amode; 632 633 switch (d->amode) { 634 case am_chs: 635 /* Compute CHS coordinates. */ 636 c = blk_idx / (d->geom.heads * d->geom.sectors); 637 idx = blk_idx % (d->geom.heads * d->geom.sectors); 638 639 bc->cyl_lo = c & 0xff; 640 bc->cyl_hi = (c >> 8) & 0xff; 641 bc->h = (idx / d->geom.sectors) & 0x0f; 642 bc->sector = (1 + (idx % d->geom.sectors)) & 0xff; 643 break; 644 645 case am_lba28: 646 /* Compute LBA-28 coordinates. */ 647 bc->c0 = blk_idx & 0xff; /* bits 0-7 */ 648 bc->c1 = (blk_idx >> 8) & 0xff; /* bits 8-15 */ 649 bc->c2 = (blk_idx >> 16) & 0xff; /* bits 16-23 */ 650 bc->h = (blk_idx >> 24) & 0x0f; /* bits 24-27 */ 651 break; 652 653 case am_lba48: 654 /* Compute LBA-48 coordinates. */ 655 bc->c0 = blk_idx & 0xff; /* bits 0-7 */ 656 bc->c1 = (blk_idx >> 8) & 0xff; /* bits 8-15 */ 657 bc->c2 = (blk_idx >> 16) & 0xff; /* bits 16-23 */ 658 bc->c3 = (blk_idx >> 24) & 0xff; /* bits 24-31 */ 659 bc->c4 = (blk_idx >> 32) & 0xff; /* bits 32-39 */ 660 bc->c5 = (blk_idx >> 40) & 0xff; /* bits 40-47 */ 661 bc->h = 0; 662 break; 663 } 664 665 return EOK; 666 } 667 668 /** Program block coordinates and sector count into ATA registers. 669 * 670 * Note that bc->h must be programmed separately into the device/head register. 671 */ 672 static void coord_sc_program(const block_coord_t *bc, uint16_t scnt) 673 { 674 if (bc->amode == am_lba48) { 675 /* Write high-order bits. */ 676 pio_write_8(&cmd->sector_count, scnt >> 8); 677 pio_write_8(&cmd->sector_number, bc->c3); 678 pio_write_8(&cmd->cylinder_low, bc->c4); 679 pio_write_8(&cmd->cylinder_high, bc->c5); 680 } 681 682 /* Write low-order bits. */ 683 pio_write_8(&cmd->sector_count, scnt & 0x00ff); 684 pio_write_8(&cmd->sector_number, bc->c0); 685 pio_write_8(&cmd->cylinder_low, bc->c1); 686 pio_write_8(&cmd->cylinder_high, bc->c2); 615 687 } 616 688 -
uspace/srv/bd/ata_bd/ata_bd.h
r22af3af r21d8020 132 132 133 133 enum ata_command { 134 CMD_IDENTIFY_DRIVE = 0xEC,135 134 CMD_READ_SECTORS = 0x20, 136 CMD_WRITE_SECTORS = 0x30 135 CMD_READ_SECTORS_EXT = 0x24, 136 CMD_WRITE_SECTORS = 0x30, 137 CMD_WRITE_SECTORS_EXT = 0x34, 138 CMD_IDENTIFY_DRIVE = 0xEC 137 139 }; 138 140 … … 156 158 uint16_t _vs8; 157 159 uint16_t _vs9; 160 158 161 uint16_t serial_number[10]; 159 162 uint16_t _vs20; … … 162 165 uint16_t firmware_rev[4]; 163 166 uint16_t model_name[20]; 167 164 168 uint16_t max_rw_multiple; 165 169 uint16_t _res48; … … 168 172 uint16_t pio_timing; 169 173 uint16_t dma_timing; 174 170 175 uint16_t validity; 171 176 uint16_t cur_cyl; … … 175 180 uint16_t cur_capacity1; 176 181 uint16_t mss; 177 uint16_t total_lba _sec0;178 uint16_t total_lba _sec1;182 uint16_t total_lba28_0; 183 uint16_t total_lba28_1; 179 184 uint16_t sw_dma; 180 185 uint16_t mw_dma; … … 184 189 uint16_t min_raw_pio_cycle; 185 190 uint16_t min_iordy_pio_cycle; 191 186 192 uint16_t _res69; 187 193 uint16_t _res70; 188 uint16_t _res71[1 + 127 - 71]; 194 uint16_t _res71; 195 uint16_t _res72; 196 uint16_t _res73; 197 uint16_t _res74; 198 199 uint16_t queue_depth; 200 uint16_t _res76[1 + 79 - 76]; 201 uint16_t version_maj; 202 uint16_t version_min; 203 uint16_t cmd_set0; 204 uint16_t cmd_set1; 205 uint16_t csf_sup_ext; 206 uint16_t csf_enabled0; 207 uint16_t csf_enabled1; 208 uint16_t csf_default; 209 uint16_t udma; 210 211 uint16_t _res89[1 + 99 - 89]; 212 213 /* Total number of blocks in LBA-48 addressing */ 214 uint16_t total_lba48_0; 215 uint16_t total_lba48_1; 216 uint16_t total_lba48_2; 217 uint16_t total_lba48_3; 218 219 /* Note: more fields are defined in ATA/ATAPI-7 */ 220 uint16_t _res104[1 + 127 - 104]; 189 221 uint16_t _vs128[1 + 159 - 128]; 190 222 uint16_t _res160[1 + 255 - 160]; … … 198 230 }; 199 231 232 /** Bits of @c identify_data_t.cmd_set1 */ 233 enum ata_cs1 { 234 cs1_addr48 = 0x0400 /**< 48-bit address feature set */ 235 }; 236 200 237 /** Block addressing mode. */ 201 238 enum addr_mode { 202 am_chs, 203 am_lba28 204 }; 239 am_chs, /**< CHS block addressing */ 240 am_lba28, /**< LBA-28 block addressing */ 241 am_lba48 /**< LBA-48 block addressing */ 242 }; 243 244 /** Block coordinates */ 245 typedef struct { 246 /** Addressing mode used */ 247 enum addr_mode amode; 248 249 union { 250 /** CHS coordinates */ 251 struct { 252 uint8_t sector; 253 uint8_t cyl_lo; 254 uint8_t cyl_hi; 255 }; 256 /** LBA coordinates */ 257 struct { 258 uint8_t c0; 259 uint8_t c1; 260 uint8_t c2; 261 uint8_t c3; 262 uint8_t c4; 263 uint8_t c5; 264 }; 265 }; 266 267 /** Lower 4 bits for device/head register */ 268 uint8_t h; 269 } block_coord_t; 205 270 206 271 typedef struct {
Note:
See TracChangeset
for help on using the changeset viewer.