Changes in / [21d8020:22af3af] in mainline
- Location:
- uspace/srv/bd/ata_bd
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/bd/ata_bd/ata_bd.c
r21d8020 r22af3af 35 35 * @brief ATA disk driver 36 36 * 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. 37 * This driver currently works only with CHS addressing and uses PIO. 38 * Currently based on the (now obsolete) ATA-1, ATA-2 standards. 45 39 * 46 40 * The driver services a single controller which can have up to two disks … … 95 89 static int drive_identify(int drive_id, void *buf); 96 90 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);99 91 static int wait_status(unsigned set, unsigned n_reset, uint8_t *pstatus, 100 92 unsigned timeout); … … 108 100 printf(NAME ": ATA disk driver\n"); 109 101 110 printf("I/O address 0x% p/0x%p\n", ctl_physical, cmd_physical);102 printf("I/O address 0x%x\n", cmd_physical); 111 103 112 104 if (ata_bd_init() != EOK) … … 164 156 printf("%s: ", d->model); 165 157 166 switch (d->amode) { 167 case am_chs: 158 if (d->amode == am_chs) { 168 159 printf("CHS %u cylinders, %u heads, %u sectors", 169 160 disk->geom.cylinders, disk->geom.heads, disk->geom.sectors); 170 break; 171 case am_lba28: 161 } else { 172 162 printf("LBA-28"); 173 break;174 case am_lba48:175 printf("LBA-48");176 break;177 163 } 178 164 … … 302 288 size_t pos, len; 303 289 int rc; 304 unsignedi;290 int i; 305 291 306 292 rc = drive_identify(disk_id, &idata); … … 319 305 320 306 d->blocks = d->geom.cylinders * d->geom.heads * d->geom.sectors; 321 } else if ((idata.cmd_set1 & cs1_addr48) == 0){322 /* Device only supports LBA-28 addressing. */307 } else { 308 /* Device supports LBA-28. */ 323 309 d->amode = am_lba28; 324 310 … … 328 314 329 315 d->blocks = 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); 316 (uint32_t) idata.total_lba_sec0 | 317 ((uint32_t) idata.total_lba_sec1 << 16); 345 318 } 346 319 … … 478 451 uint16_t data; 479 452 uint8_t status; 453 uint64_t c, h, s; 454 uint64_t idx; 480 455 uint8_t drv_head; 481 456 disk_t *d; 482 block_coord_t bc;483 457 484 458 d = &disk[disk_id]; 485 bc.h = 0; /* Silence warning. */ 486 487 /* Compute block coordinates. */ 488 if (coord_calc(d, blk_idx, &bc) != EOK) 459 460 /* Check device bounds. */ 461 if (blk_idx >= d->blocks) 489 462 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 } 490 477 491 478 /* New value for Drive/Head register */ … … 493 480 ((disk_id != 0) ? DHR_DRV : 0) | 494 481 ((d->amode != am_chs) ? DHR_LBA : 0) | 495 ( bc.h & 0x0f);482 (h & 0x0f); 496 483 497 484 fibril_mutex_lock(&d->lock); … … 511 498 } 512 499 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); 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); 518 506 519 507 if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) { … … 552 540 size_t i; 553 541 uint8_t status; 542 uint64_t c, h, s; 543 uint64_t idx; 554 544 uint8_t drv_head; 555 545 disk_t *d; 556 block_coord_t bc;557 546 558 547 d = &disk[disk_id]; 559 bc.h = 0; /* Silence warning. */ 560 561 /* Compute block coordinates. */ 562 if (coord_calc(d, blk_idx, &bc) != EOK) 548 549 /* Check device bounds. */ 550 if (blk_idx >= d->blocks) 563 551 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 } 564 566 565 567 /* New value for Drive/Head register */ … … 567 569 ((disk_id != 0) ? DHR_DRV : 0) | 568 570 ((d->amode != am_chs) ? DHR_LBA : 0) | 569 ( bc.h & 0x0f);571 (h & 0x0f); 570 572 571 573 fibril_mutex_lock(&d->lock); … … 585 587 } 586 588 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); 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); 592 595 593 596 if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) { … … 610 613 611 614 return EOK; 612 }613 614 /** Calculate block coordinates.615 *616 * Calculates block coordinates in the best coordinate system supported617 * by the device. These can be later programmed into the device using618 * @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);687 615 } 688 616 -
uspace/srv/bd/ata_bd/ata_bd.h
r21d8020 r22af3af 132 132 133 133 enum ata_command { 134 CMD_IDENTIFY_DRIVE = 0xEC, 134 135 CMD_READ_SECTORS = 0x20, 135 CMD_READ_SECTORS_EXT = 0x24, 136 CMD_WRITE_SECTORS = 0x30, 137 CMD_WRITE_SECTORS_EXT = 0x34, 138 CMD_IDENTIFY_DRIVE = 0xEC 136 CMD_WRITE_SECTORS = 0x30 139 137 }; 140 138 … … 158 156 uint16_t _vs8; 159 157 uint16_t _vs9; 160 161 158 uint16_t serial_number[10]; 162 159 uint16_t _vs20; … … 165 162 uint16_t firmware_rev[4]; 166 163 uint16_t model_name[20]; 167 168 164 uint16_t max_rw_multiple; 169 165 uint16_t _res48; … … 172 168 uint16_t pio_timing; 173 169 uint16_t dma_timing; 174 175 170 uint16_t validity; 176 171 uint16_t cur_cyl; … … 180 175 uint16_t cur_capacity1; 181 176 uint16_t mss; 182 uint16_t total_lba 28_0;183 uint16_t total_lba 28_1;177 uint16_t total_lba_sec0; 178 uint16_t total_lba_sec1; 184 179 uint16_t sw_dma; 185 180 uint16_t mw_dma; … … 189 184 uint16_t min_raw_pio_cycle; 190 185 uint16_t min_iordy_pio_cycle; 191 192 186 uint16_t _res69; 193 187 uint16_t _res70; 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]; 188 uint16_t _res71[1 + 127 - 71]; 221 189 uint16_t _vs128[1 + 159 - 128]; 222 190 uint16_t _res160[1 + 255 - 160]; … … 230 198 }; 231 199 232 /** Bits of @c identify_data_t.cmd_set1 */233 enum ata_cs1 {234 cs1_addr48 = 0x0400 /**< 48-bit address feature set */235 };236 237 200 /** Block addressing mode. */ 238 201 enum addr_mode { 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; 202 am_chs, 203 am_lba28 204 }; 270 205 271 206 typedef struct {
Note:
See TracChangeset
for help on using the changeset viewer.