Changeset 1787e527 in mainline for uspace/srv/bd/ata_bd/ata_bd.c
- Timestamp:
- 2009-11-16T21:22:54Z (15 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 5ebdf94
- Parents:
- fcbd1be (diff), 9c70ed6 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/bd/ata_bd/ata_bd.c
rfcbd1be r1787e527 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 … … 50 56 #include <as.h> 51 57 #include <fibril_sync.h> 58 #include <string.h> 52 59 #include <devmap.h> 53 60 #include <sys/types.h> … … 55 62 #include <bool.h> 56 63 #include <task.h> 64 #include <macros.h> 57 65 58 66 #include "ata_bd.h" … … 79 87 static int ata_bd_init(void); 80 88 static void ata_bd_connection(ipc_callid_t iid, ipc_call_t *icall); 81 static int ata_bd_r dwr(int disk_id, ipcarg_t method, off_t offset, size_t size,89 static int ata_bd_read_blocks(int disk_id, uint64_t ba, size_t cnt, 82 90 void *buf); 83 static int ata_bd_read_block(int disk_id, uint64_t blk_idx, size_t blk_cnt, 91 static int ata_bd_write_blocks(int disk_id, uint64_t ba, size_t cnt, 92 const void *buf); 93 static int ata_bd_read_block(int disk_id, uint64_t ba, size_t cnt, 84 94 void *buf); 85 static int ata_bd_write_block(int disk_id, uint64_t b lk_idx, size_t blk_cnt,95 static int ata_bd_write_block(int disk_id, uint64_t ba, size_t cnt, 86 96 const void *buf); 87 static int drive_identify(int drive_id, disk_t *d); 97 static int disk_init(disk_t *d, int disk_id); 98 static int drive_identify(int drive_id, void *buf); 99 static void disk_print_summary(disk_t *d); 100 static int coord_calc(disk_t *d, uint64_t ba, block_coord_t *bc); 101 static void coord_sc_program(const block_coord_t *bc, uint16_t scnt); 88 102 static int wait_status(unsigned set, unsigned n_reset, uint8_t *pstatus, 89 103 unsigned timeout); … … 97 111 printf(NAME ": ATA disk driver\n"); 98 112 99 printf("I/O address 0x% x\n", cmd_physical);113 printf("I/O address 0x%p/0x%p\n", ctl_physical, cmd_physical); 100 114 101 115 if (ata_bd_init() != EOK) … … 106 120 fflush(stdout); 107 121 108 rc = d rive_identify(i, &disk[i]);122 rc = disk_init(&disk[i], i); 109 123 110 124 if (rc == EOK) { 111 printf("%u cylinders, %u heads, %u sectors\n", 112 disk[i].cylinders, disk[i].heads, disk[i].sectors); 125 disk_print_summary(&disk[i]); 113 126 } else { 114 127 printf("Not found.\n"); … … 147 160 } 148 161 162 /** Print one-line device summary. */ 163 static void disk_print_summary(disk_t *d) 164 { 165 uint64_t mbytes; 166 167 printf("%s: ", d->model); 168 169 switch (d->amode) { 170 case am_chs: 171 printf("CHS %u cylinders, %u heads, %u sectors", 172 disk->geom.cylinders, disk->geom.heads, disk->geom.sectors); 173 break; 174 case am_lba28: 175 printf("LBA-28"); 176 break; 177 case am_lba48: 178 printf("LBA-48"); 179 break; 180 } 181 182 printf(" %llu blocks", d->blocks, d->blocks / (2 * 1024)); 183 184 mbytes = d->blocks / (2 * 1024); 185 if (mbytes > 0) 186 printf(" %llu MB.", mbytes); 187 188 printf("\n"); 189 } 149 190 150 191 /** Register driver and enable device I/O. */ … … 190 231 int flags; 191 232 int retval; 192 off_t idx;193 size_t size;233 uint64_t ba; 234 size_t cnt; 194 235 int disk_id, i; 195 236 … … 211 252 ipc_answer_0(iid, EOK); 212 253 213 if (! ipc_share_out_receive(&callid, &comm_size, &flags)) {254 if (!async_share_out_receive(&callid, &comm_size, &flags)) { 214 255 ipc_answer_0(callid, EHANGUP); 215 256 return; … … 222 263 } 223 264 224 (void) ipc_share_out_finalize(callid, fs_va);265 (void) async_share_out_finalize(callid, fs_va); 225 266 226 267 while (1) { … … 232 273 ipc_answer_0(callid, EOK); 233 274 return; 234 case BD_READ_BLOCK :235 case BD_WRITE_BLOCK:236 idx = IPC_GET_ARG1(call);237 size = IPC_GET_ARG2(call);238 if ( size > comm_size) {239 retval = E INVAL;275 case BD_READ_BLOCKS: 276 ba = MERGE_LOUP32(IPC_GET_ARG1(call), 277 IPC_GET_ARG2(call)); 278 cnt = IPC_GET_ARG3(call); 279 if (cnt * block_size > comm_size) { 280 retval = ELIMIT; 240 281 break; 241 282 } 242 retval = ata_bd_rdwr(disk_id, method, idx, 243 size, fs_va); 283 retval = ata_bd_read_blocks(disk_id, ba, cnt, fs_va); 244 284 break; 285 case BD_WRITE_BLOCKS: 286 ba = MERGE_LOUP32(IPC_GET_ARG1(call), 287 IPC_GET_ARG2(call)); 288 cnt = IPC_GET_ARG3(call); 289 if (cnt * block_size > comm_size) { 290 retval = ELIMIT; 291 break; 292 } 293 retval = ata_bd_write_blocks(disk_id, ba, cnt, fs_va); 294 break; 295 case BD_GET_BLOCK_SIZE: 296 ipc_answer_1(callid, EOK, block_size); 297 continue; 245 298 default: 246 299 retval = EINVAL; … … 251 304 } 252 305 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 */ 263 static int ata_bd_rdwr(int disk_id, ipcarg_t method, off_t blk_idx, size_t size, 264 void *buf) 265 { 306 /** Initialize a disk. 307 * 308 * Probes for a disk, determines its parameters and initializes 309 * the disk structure. 310 */ 311 static int disk_init(disk_t *d, int disk_id) 312 { 313 identify_data_t idata; 314 uint8_t model[40]; 315 uint16_t w; 316 uint8_t c; 317 size_t pos, len; 266 318 int rc; 267 size_t now; 268 269 while (size > 0) { 270 now = size < block_size ? size : block_size; 271 if (now != block_size) 272 return EINVAL; 273 274 if (method == BD_READ_BLOCK) 275 rc = ata_bd_read_block(disk_id, blk_idx, 1, buf); 276 else 277 rc = ata_bd_write_block(disk_id, blk_idx, 1, buf); 278 319 unsigned i; 320 321 rc = drive_identify(disk_id, &idata); 322 if (rc != EOK) { 323 d->present = false; 324 return rc; 325 } 326 327 if ((idata.caps & cap_lba) == 0) { 328 /* Device only supports CHS addressing. */ 329 d->amode = am_chs; 330 331 d->geom.cylinders = idata.cylinders; 332 d->geom.heads = idata.heads; 333 d->geom.sectors = idata.sectors; 334 335 d->blocks = d->geom.cylinders * d->geom.heads * d->geom.sectors; 336 } else if ((idata.cmd_set1 & cs1_addr48) == 0) { 337 /* Device only supports LBA-28 addressing. */ 338 d->amode = am_lba28; 339 340 d->geom.cylinders = 0; 341 d->geom.heads = 0; 342 d->geom.sectors = 0; 343 344 d->blocks = 345 (uint32_t) idata.total_lba28_0 | 346 ((uint32_t) idata.total_lba28_1 << 16); 347 } else { 348 /* Device supports LBA-48 addressing. */ 349 d->amode = am_lba48; 350 351 d->geom.cylinders = 0; 352 d->geom.heads = 0; 353 d->geom.sectors = 0; 354 355 d->blocks = 356 (uint64_t) idata.total_lba48_0 | 357 ((uint64_t) idata.total_lba48_1 << 16) | 358 ((uint64_t) idata.total_lba48_2 << 32) | 359 ((uint64_t) idata.total_lba48_3 << 48); 360 } 361 362 /* 363 * Convert model name to string representation. 364 */ 365 for (i = 0; i < 20; i++) { 366 w = idata.model_name[i]; 367 model[2 * i] = w >> 8; 368 model[2 * i + 1] = w & 0x00ff; 369 } 370 371 len = 40; 372 while (len > 0 && model[len - 1] == 0x20) 373 --len; 374 375 pos = 0; 376 for (i = 0; i < len; ++i) { 377 c = model[i]; 378 if (c >= 0x80) c = '?'; 379 380 chr_encode(c, d->model, &pos, 40); 381 } 382 d->model[pos] = '\0'; 383 384 d->present = true; 385 fibril_mutex_initialize(&d->lock); 386 387 return EOK; 388 } 389 390 /** Read multiple blocks from the device. */ 391 static int ata_bd_read_blocks(int disk_id, uint64_t ba, size_t cnt, 392 void *buf) { 393 394 int rc; 395 396 while (cnt > 0) { 397 rc = ata_bd_read_block(disk_id, ba, 1, buf); 279 398 if (rc != EOK) 280 399 return rc; 281 400 401 ++ba; 402 --cnt; 282 403 buf += block_size; 283 blk_idx++; 284 285 if (size > block_size) 286 size -= block_size; 287 else 288 size = 0; 404 } 405 406 return EOK; 407 } 408 409 /** Write multiple blocks to the device. */ 410 static int ata_bd_write_blocks(int disk_id, uint64_t ba, size_t cnt, 411 const void *buf) { 412 413 int rc; 414 415 while (cnt > 0) { 416 rc = ata_bd_write_block(disk_id, ba, 1, buf); 417 if (rc != EOK) 418 return rc; 419 420 ++ba; 421 --cnt; 422 buf += block_size; 289 423 } 290 424 … … 294 428 /** Issue IDENTIFY command. 295 429 * 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.430 * Reads @c identify data into the provided buffer. This is used to detect 431 * whether an ATA device is present and if so, to determine its parameters. 298 432 * 299 433 * @param disk_id Device ID, 0 or 1. 300 * @param d Device structure to store parameters in.301 */ 302 static int drive_identify(int disk_id, disk_t *d)434 * @param buf Pointer to a 512-byte buffer. 435 */ 436 static int drive_identify(int disk_id, void *buf) 303 437 { 304 438 uint16_t data; … … 308 442 309 443 drv_head = ((disk_id != 0) ? DHR_DRV : 0); 310 d->present = false;311 444 312 445 if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) … … 330 463 331 464 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 */368 static int ata_bd_read_block(int disk_id, uint64_t blk_idx, size_t blk_cnt,369 void *buf)370 {371 size_t i;372 uint16_t data;373 uint8_t status;374 uint64_t c, h, s;375 uint64_t idx;376 uint8_t drv_head;377 disk_t *d;378 379 d = &disk[disk_id];380 381 /* Check device bounds. */382 if (blk_idx >= d->blocks)383 return EINVAL;384 385 /* Compute CHS. */386 c = blk_idx / (d->heads * d->sectors);387 idx = blk_idx % (d->heads * d->sectors);388 389 h = idx / d->sectors;390 s = 1 + (idx % d->sectors);391 392 /* New value for Drive/Head register */393 drv_head =394 ((disk_id != 0) ? DHR_DRV : 0) |395 (h & 0x0f);396 397 fibril_mutex_lock(&d->lock);398 399 /* Program a Read Sectors operation. */400 401 if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_BSY) != EOK) {402 fibril_mutex_unlock(&d->lock);403 return EIO;404 }405 406 pio_write_8(&cmd->drive_head, drv_head);407 408 if (wait_status(SR_DRDY, ~SR_BSY, NULL, TIMEOUT_DRDY) != EOK) {409 fibril_mutex_unlock(&d->lock);410 return EIO;411 }412 413 pio_write_8(&cmd->sector_count, 1);414 pio_write_8(&cmd->sector_number, s);415 pio_write_8(&cmd->cylinder_low, c & 0xff);416 pio_write_8(&cmd->cylinder_high, c >> 16);417 418 pio_write_8(&cmd->command, CMD_READ_SECTORS);419 420 if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {421 fibril_mutex_unlock(&d->lock);422 return EIO;423 }424 425 if ((status & SR_DRQ) != 0) {426 /* Read data from the device buffer. */427 428 465 for (i = 0; i < block_size / 2; i++) { 429 466 data = pio_read_16(&cmd->data_port); … … 435 472 return EIO; 436 473 437 fibril_mutex_unlock(&d->lock); 438 return EOK; 439 } 440 441 /** Write a physical block to the device. 474 return EOK; 475 } 476 477 /** Read a physical from the device. 442 478 * 443 479 * @param disk_id Device index (0 or 1) 444 * @param b lk_idx Index ofthe first block.445 * @param blk_cntNumber of blocks to transfer.446 * @param buf Buffer holding the data to write.480 * @param ba Address the first block. 481 * @param cnt Number of blocks to transfer. 482 * @param buf Buffer for holding the data. 447 483 * 448 484 * @return EOK on success, EIO on error. 449 485 */ 450 static int ata_bd_ write_block(int disk_id, uint64_t blk_idx, size_t blk_cnt,451 constvoid *buf)486 static int ata_bd_read_block(int disk_id, uint64_t ba, size_t blk_cnt, 487 void *buf) 452 488 { 453 489 size_t i; 490 uint16_t data; 454 491 uint8_t status; 455 uint64_t c, h, s;456 uint64_t idx;457 492 uint8_t drv_head; 458 493 disk_t *d; 494 block_coord_t bc; 459 495 460 496 d = &disk[disk_id]; 461 462 /* Check device bounds. */ 463 if (blk_idx >= d->blocks) 497 bc.h = 0; /* Silence warning. */ 498 499 /* Compute block coordinates. */ 500 if (coord_calc(d, ba, &bc) != EOK) 464 501 return EINVAL; 465 466 /* Compute CHS. */467 c = blk_idx / (d->heads * d->sectors);468 idx = blk_idx % (d->heads * d->sectors);469 470 h = idx / d->sectors;471 s = 1 + (idx % d->sectors);472 502 473 503 /* New value for Drive/Head register */ 474 504 drv_head = 475 505 ((disk_id != 0) ? DHR_DRV : 0) | 476 (h & 0x0f); 506 ((d->amode != am_chs) ? DHR_LBA : 0) | 507 (bc.h & 0x0f); 477 508 478 509 fibril_mutex_lock(&d->lock); 479 510 480 /* Program a WriteSectors operation. */511 /* Program a Read Sectors operation. */ 481 512 482 513 if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_BSY) != EOK) { … … 492 523 } 493 524 494 pio_write_8(&cmd->sector_count, 1); 495 pio_write_8(&cmd->sector_number, s); 496 pio_write_8(&cmd->cylinder_low, c & 0xff); 497 pio_write_8(&cmd->cylinder_high, c >> 16); 498 499 pio_write_8(&cmd->command, CMD_WRITE_SECTORS); 525 /* Program block coordinates into the device. */ 526 coord_sc_program(&bc, 1); 527 528 pio_write_8(&cmd->command, d->amode == am_lba48 ? 529 CMD_READ_SECTORS_EXT : CMD_READ_SECTORS); 530 531 if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) { 532 fibril_mutex_unlock(&d->lock); 533 return EIO; 534 } 535 536 if ((status & SR_DRQ) != 0) { 537 /* Read data from the device buffer. */ 538 539 for (i = 0; i < block_size / 2; i++) { 540 data = pio_read_16(&cmd->data_port); 541 ((uint16_t *) buf)[i] = data; 542 } 543 } 544 545 if ((status & SR_ERR) != 0) 546 return EIO; 547 548 fibril_mutex_unlock(&d->lock); 549 return EOK; 550 } 551 552 /** Write a physical block to the device. 553 * 554 * @param disk_id Device index (0 or 1) 555 * @param ba Address of the first block. 556 * @param cnt Number of blocks to transfer. 557 * @param buf Buffer holding the data to write. 558 * 559 * @return EOK on success, EIO on error. 560 */ 561 static int ata_bd_write_block(int disk_id, uint64_t ba, size_t cnt, 562 const void *buf) 563 { 564 size_t i; 565 uint8_t status; 566 uint8_t drv_head; 567 disk_t *d; 568 block_coord_t bc; 569 570 d = &disk[disk_id]; 571 bc.h = 0; /* Silence warning. */ 572 573 /* Compute block coordinates. */ 574 if (coord_calc(d, ba, &bc) != EOK) 575 return EINVAL; 576 577 /* New value for Drive/Head register */ 578 drv_head = 579 ((disk_id != 0) ? DHR_DRV : 0) | 580 ((d->amode != am_chs) ? DHR_LBA : 0) | 581 (bc.h & 0x0f); 582 583 fibril_mutex_lock(&d->lock); 584 585 /* Program a Write Sectors operation. */ 586 587 if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_BSY) != EOK) { 588 fibril_mutex_unlock(&d->lock); 589 return EIO; 590 } 591 592 pio_write_8(&cmd->drive_head, drv_head); 593 594 if (wait_status(SR_DRDY, ~SR_BSY, NULL, TIMEOUT_DRDY) != EOK) { 595 fibril_mutex_unlock(&d->lock); 596 return EIO; 597 } 598 599 /* Program block coordinates into the device. */ 600 coord_sc_program(&bc, 1); 601 602 pio_write_8(&cmd->command, d->amode == am_lba48 ? 603 CMD_WRITE_SECTORS_EXT : CMD_WRITE_SECTORS); 500 604 501 605 if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) { … … 518 622 519 623 return EOK; 624 } 625 626 /** Calculate block coordinates. 627 * 628 * Calculates block coordinates in the best coordinate system supported 629 * by the device. These can be later programmed into the device using 630 * @c coord_sc_program(). 631 * 632 * @return EOK on success or EINVAL if block index is past end of device. 633 */ 634 static int coord_calc(disk_t *d, uint64_t ba, block_coord_t *bc) 635 { 636 uint64_t c; 637 uint64_t idx; 638 639 /* Check device bounds. */ 640 if (ba >= d->blocks) 641 return EINVAL; 642 643 bc->amode = d->amode; 644 645 switch (d->amode) { 646 case am_chs: 647 /* Compute CHS coordinates. */ 648 c = ba / (d->geom.heads * d->geom.sectors); 649 idx = ba % (d->geom.heads * d->geom.sectors); 650 651 bc->cyl_lo = c & 0xff; 652 bc->cyl_hi = (c >> 8) & 0xff; 653 bc->h = (idx / d->geom.sectors) & 0x0f; 654 bc->sector = (1 + (idx % d->geom.sectors)) & 0xff; 655 break; 656 657 case am_lba28: 658 /* Compute LBA-28 coordinates. */ 659 bc->c0 = ba & 0xff; /* bits 0-7 */ 660 bc->c1 = (ba >> 8) & 0xff; /* bits 8-15 */ 661 bc->c2 = (ba >> 16) & 0xff; /* bits 16-23 */ 662 bc->h = (ba >> 24) & 0x0f; /* bits 24-27 */ 663 break; 664 665 case am_lba48: 666 /* Compute LBA-48 coordinates. */ 667 bc->c0 = ba & 0xff; /* bits 0-7 */ 668 bc->c1 = (ba >> 8) & 0xff; /* bits 8-15 */ 669 bc->c2 = (ba >> 16) & 0xff; /* bits 16-23 */ 670 bc->c3 = (ba >> 24) & 0xff; /* bits 24-31 */ 671 bc->c4 = (ba >> 32) & 0xff; /* bits 32-39 */ 672 bc->c5 = (ba >> 40) & 0xff; /* bits 40-47 */ 673 bc->h = 0; 674 break; 675 } 676 677 return EOK; 678 } 679 680 /** Program block coordinates and sector count into ATA registers. 681 * 682 * Note that bc->h must be programmed separately into the device/head register. 683 */ 684 static void coord_sc_program(const block_coord_t *bc, uint16_t scnt) 685 { 686 if (bc->amode == am_lba48) { 687 /* Write high-order bits. */ 688 pio_write_8(&cmd->sector_count, scnt >> 8); 689 pio_write_8(&cmd->sector_number, bc->c3); 690 pio_write_8(&cmd->cylinder_low, bc->c4); 691 pio_write_8(&cmd->cylinder_high, bc->c5); 692 } 693 694 /* Write low-order bits. */ 695 pio_write_8(&cmd->sector_count, scnt & 0x00ff); 696 pio_write_8(&cmd->sector_number, bc->c0); 697 pio_write_8(&cmd->cylinder_low, bc->c1); 698 pio_write_8(&cmd->cylinder_high, bc->c2); 520 699 } 521 700
Note:
See TracChangeset
for help on using the changeset viewer.