Changeset eb522e8 in mainline for uspace/srv/bd/ata_bd/ata_bd.c
- Timestamp:
- 2011-06-01T08:43:42Z (14 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 8d6c1f1
- Parents:
- 9e2e715 (diff), e51a514 (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
r9e2e715 reb522e8 51 51 #include <libarch/ddi.h> 52 52 #include <ddi.h> 53 #include <ipc/ipc.h>54 53 #include <ipc/bd.h> 55 54 #include <async.h> 56 55 #include <as.h> 57 56 #include <fibril_synch.h> 57 #include <stdint.h> 58 58 #include <str.h> 59 59 #include <devmap.h> … … 62 62 #include <errno.h> 63 63 #include <bool.h> 64 #include <byteorder.h> 64 65 #include <task.h> 65 66 #include <macros.h> 66 67 68 #include "ata_hw.h" 67 69 #include "ata_bd.h" 68 70 … … 70 72 #define NAMESPACE "bd" 71 73 72 /** Physical block size. Should be always 512. */ 73 static const size_t block_size = 512; 74 /** Number of defined legacy controller base addresses. */ 75 #define LEGACY_CTLS 4 76 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; 74 82 75 83 /** Size of the communication area. */ … … 77 85 78 86 /** I/O base address of the command registers. */ 79 static uintptr_t cmd_physical = 0x1f0;87 static uintptr_t cmd_physical; 80 88 /** I/O base address of the control registers. */ 81 static uintptr_t ctl_physical = 0x170; 89 static uintptr_t ctl_physical; 90 91 /** I/O base addresses for legacy (ISA-compatible) controllers. */ 92 static ata_base_t legacy_base[LEGACY_CTLS] = { 93 { 0x1f0, 0x3f0 }, 94 { 0x170, 0x370 }, 95 { 0x1e8, 0x3e8 }, 96 { 0x168, 0x368 } 97 }; 82 98 83 99 static ata_cmd_t *cmd; … … 87 103 static disk_t disk[MAX_DISKS]; 88 104 105 static void print_syntax(void); 89 106 static int ata_bd_init(void); 90 107 static void ata_bd_connection(ipc_callid_t iid, ipc_call_t *icall); … … 93 110 static int ata_bd_write_blocks(int disk_id, uint64_t ba, size_t cnt, 94 111 const void *buf); 95 static int ata_ bd_read_block(int disk_id, uint64_t ba, size_t cnt,112 static int ata_rcmd_read(int disk_id, uint64_t ba, size_t cnt, 96 113 void *buf); 97 static int ata_ bd_write_block(int disk_id, uint64_t ba, size_t cnt,114 static int ata_rcmd_write(int disk_id, uint64_t ba, size_t cnt, 98 115 const void *buf); 99 116 static int disk_init(disk_t *d, int disk_id); 100 117 static 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); 101 124 static void disk_print_summary(disk_t *d); 102 125 static int coord_calc(disk_t *d, uint64_t ba, block_coord_t *bc); … … 110 133 int i, rc; 111 134 int n_disks; 135 unsigned ctl_num; 136 char *eptr; 112 137 113 138 printf(NAME ": ATA disk driver\n"); 114 139 115 printf("I/O address %p/%p\n", ctl_physical, cmd_physical); 140 if (argc > 1) { 141 ctl_num = strtoul(argv[1], &eptr, 0); 142 if (*eptr != '\0' || ctl_num == 0 || ctl_num > 4) { 143 printf("Invalid argument.\n"); 144 print_syntax(); 145 return -1; 146 } 147 } else { 148 ctl_num = 1; 149 } 150 151 cmd_physical = legacy_base[ctl_num - 1].cmd; 152 ctl_physical = legacy_base[ctl_num - 1].ctl; 153 154 printf("I/O address %p/%p\n", (void *) cmd_physical, 155 (void *) ctl_physical); 116 156 117 157 if (ata_bd_init() != EOK) … … 138 178 continue; 139 179 140 snprintf(name, 16, "%s/ disk%d", NAMESPACE, i);141 rc = devmap_device_register(name, &disk[i].dev _handle);180 snprintf(name, 16, "%s/ata%udisk%d", NAMESPACE, ctl_num, i); 181 rc = devmap_device_register(name, &disk[i].devmap_handle); 142 182 if (rc != EOK) { 143 devmap_hangup_phone(DEVMAP_DRIVER);144 183 printf(NAME ": Unable to register device %s.\n", name); 145 184 return rc; … … 161 200 } 162 201 202 203 static void print_syntax(void) 204 { 205 printf("Syntax: " NAME " <controller_number>\n"); 206 printf("Controller number = 1..4\n"); 207 } 208 163 209 /** Print one-line device summary. */ 164 210 static void disk_print_summary(disk_t *d) … … 168 214 printf("%s: ", d->model); 169 215 170 switch (d->amode) { 171 case am_chs: 172 printf("CHS %u cylinders, %u heads, %u sectors", 173 disk->geom.cylinders, disk->geom.heads, disk->geom.sectors); 174 break; 175 case am_lba28: 176 printf("LBA-28"); 177 break; 178 case am_lba48: 179 printf("LBA-48"); 180 break; 181 } 182 183 printf(" %" PRIu64 " blocks", d->blocks, d->blocks / (2 * 1024)); 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"); 232 } 233 234 printf(" %" PRIu64 " blocks", d->blocks); 184 235 185 236 mbytes = d->blocks / (2 * 1024); … … 228 279 ipc_callid_t callid; 229 280 ipc_call_t call; 230 ipcarg_t method;231 dev _handle_t dh;232 int flags;281 sysarg_t method; 282 devmap_handle_t dh; 283 unsigned int flags; 233 284 int retval; 234 285 uint64_t ba; … … 242 293 disk_id = -1; 243 294 for (i = 0; i < MAX_DISKS; i++) 244 if (disk[i].dev _handle == dh)295 if (disk[i].devmap_handle == dh) 245 296 disk_id = i; 246 297 247 298 if (disk_id < 0 || disk[disk_id].present == false) { 248 ipc_answer_0(iid, EINVAL);299 async_answer_0(iid, EINVAL); 249 300 return; 250 301 } 251 302 252 303 /* Answer the IPC_M_CONNECT_ME_TO call. */ 253 ipc_answer_0(iid, EOK);304 async_answer_0(iid, EOK); 254 305 255 306 if (!async_share_out_receive(&callid, &comm_size, &flags)) { 256 ipc_answer_0(callid, EHANGUP);307 async_answer_0(callid, EHANGUP); 257 308 return; 258 309 } … … 260 311 fs_va = as_get_mappable_page(comm_size); 261 312 if (fs_va == NULL) { 262 ipc_answer_0(callid, EHANGUP);313 async_answer_0(callid, EHANGUP); 263 314 return; 264 315 } … … 268 319 while (1) { 269 320 callid = async_get_call(&call); 270 method = IPC_GET_ METHOD(call);321 method = IPC_GET_IMETHOD(call); 271 322 switch (method) { 272 323 case IPC_M_PHONE_HUNGUP: 273 324 /* The other side has hung up. */ 274 ipc_answer_0(callid, EOK);325 async_answer_0(callid, EOK); 275 326 return; 276 327 case BD_READ_BLOCKS: … … 278 329 IPC_GET_ARG2(call)); 279 330 cnt = IPC_GET_ARG3(call); 280 if (cnt * block_size > comm_size) {331 if (cnt * disk[disk_id].block_size > comm_size) { 281 332 retval = ELIMIT; 282 333 break; … … 288 339 IPC_GET_ARG2(call)); 289 340 cnt = IPC_GET_ARG3(call); 290 if (cnt * block_size > comm_size) {341 if (cnt * disk[disk_id].block_size > comm_size) { 291 342 retval = ELIMIT; 292 343 break; … … 295 346 break; 296 347 case BD_GET_BLOCK_SIZE: 297 ipc_answer_1(callid, EOK,block_size);348 async_answer_1(callid, EOK, disk[disk_id].block_size); 298 349 continue; 299 350 case BD_GET_NUM_BLOCKS: 300 ipc_answer_2(callid, EOK, LOWER32(disk[disk_id].blocks),351 async_answer_2(callid, EOK, LOWER32(disk[disk_id].blocks), 301 352 UPPER32(disk[disk_id].blocks)); 302 353 continue; … … 305 356 break; 306 357 } 307 ipc_answer_0(callid, retval);358 async_answer_0(callid, retval); 308 359 } 309 360 } … … 318 369 identify_data_t idata; 319 370 uint8_t model[40]; 371 ata_inquiry_data_t inq_data; 320 372 uint16_t w; 321 373 uint8_t c; 374 uint16_t bc; 322 375 size_t pos, len; 323 376 int rc; 324 377 unsigned i; 325 378 379 d->present = false; 380 fibril_mutex_initialize(&d->lock); 381 382 /* Try identify command. */ 326 383 rc = drive_identify(disk_id, &idata); 327 if (rc != EOK) { 328 d->present = false; 329 return rc; 330 } 331 332 if ((idata.caps & cap_lba) == 0) { 384 if (rc == EOK) { 385 /* Success. It's a register (non-packet) device. */ 386 printf("ATA register-only device found.\n"); 387 d->dev_type = ata_reg_dev; 388 } else if (rc == EIO) { 389 /* 390 * There is something, but not a register device. Check to see 391 * whether the IDENTIFY command left the packet signature in 392 * the registers in case this is a packet device. 393 * 394 * According to the ATA specification, the LBA low and 395 * interrupt reason registers should be set to 0x01. However, 396 * there are many devices that do not follow this and only set 397 * the byte count registers. So, only check these. 398 */ 399 bc = ((uint16_t)pio_read_8(&cmd->cylinder_high) << 8) | 400 pio_read_8(&cmd->cylinder_low); 401 402 if (bc == PDEV_SIGNATURE_BC) { 403 rc = identify_pkt_dev(disk_id, &idata); 404 if (rc == EOK) { 405 /* We have a packet device. */ 406 d->dev_type = ata_pkt_dev; 407 } else { 408 return EIO; 409 } 410 } else { 411 /* Nope. Something's there, but not recognized. */ 412 return EIO; 413 } 414 } else { 415 /* Operation timed out. That means there is no device there. */ 416 return EIO; 417 } 418 419 if (d->dev_type == ata_pkt_dev) { 420 /* Packet device */ 421 d->amode = 0; 422 423 d->geom.cylinders = 0; 424 d->geom.heads = 0; 425 d->geom.sectors = 0; 426 427 d->blocks = 0; 428 } else if ((idata.caps & rd_cap_lba) == 0) { 333 429 /* Device only supports CHS addressing. */ 334 430 d->amode = am_chs; … … 387 483 d->model[pos] = '\0'; 388 484 485 if (d->dev_type == ata_pkt_dev) { 486 /* Send inquiry. */ 487 rc = ata_pcmd_inquiry(0, &inq_data, sizeof(inq_data)); 488 if (rc != EOK) { 489 printf("Device inquiry failed.\n"); 490 d->present = false; 491 return EIO; 492 } 493 494 /* Check device type. */ 495 if (INQUIRY_PDEV_TYPE(inq_data.pdev_type) != PDEV_TYPE_CDROM) 496 printf("Warning: Peripheral device type is not CD-ROM.\n"); 497 498 /* Assume 2k block size for now. */ 499 d->block_size = 2048; 500 } else { 501 /* Assume register Read always uses 512-byte blocks. */ 502 d->block_size = 512; 503 } 504 389 505 d->present = true; 390 fibril_mutex_initialize(&d->lock);391 392 506 return EOK; 393 507 } … … 400 514 401 515 while (cnt > 0) { 402 rc = ata_bd_read_block(disk_id, ba, 1, buf); 516 if (disk[disk_id].dev_type == ata_reg_dev) 517 rc = ata_rcmd_read(disk_id, ba, 1, buf); 518 else 519 rc = ata_pcmd_read_12(disk_id, ba, 1, buf, 520 disk[disk_id].block_size); 521 403 522 if (rc != EOK) 404 523 return rc; … … 406 525 ++ba; 407 526 --cnt; 408 buf += block_size;527 buf += disk[disk_id].block_size; 409 528 } 410 529 … … 418 537 int rc; 419 538 539 if (disk[disk_id].dev_type != ata_reg_dev) 540 return ENOTSUP; 541 420 542 while (cnt > 0) { 421 rc = ata_ bd_write_block(disk_id, ba, 1, buf);543 rc = ata_rcmd_write(disk_id, ba, 1, buf); 422 544 if (rc != EOK) 423 545 return rc; … … 425 547 ++ba; 426 548 --cnt; 427 buf += block_size;549 buf += disk[disk_id].block_size; 428 550 } 429 551 … … 438 560 * @param disk_id Device ID, 0 or 1. 439 561 * @param buf Pointer to a 512-byte buffer. 562 * 563 * @return ETIMEOUT on timeout (this can mean the device is 564 * not present). EIO if device responds with error. 440 565 */ 441 566 static int drive_identify(int disk_id, void *buf) … … 449 574 450 575 if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) 451 return E IO;576 return ETIMEOUT; 452 577 453 578 pio_write_8(&cmd->drive_head, drv_head); 454 579 455 580 /* 456 * This is where we would most likely expect a non-existing device to 457 * show up by not setting SR_DRDY. 581 * Do not wait for DRDY to be set in case this is a packet device. 582 * We determine whether the device is present by waiting for DRQ to be 583 * set after issuing the command. 458 584 */ 459 if (wait_status( SR_DRDY, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)460 return E IO;585 if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) 586 return ETIMEOUT; 461 587 462 588 pio_write_8(&cmd->command, CMD_IDENTIFY_DRIVE); 463 589 464 590 if (wait_status(0, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK) 465 return EIO; 591 return ETIMEOUT; 592 593 /* 594 * If ERR is set, this may be a packet device, so return EIO to cause 595 * the caller to check for one. 596 */ 597 if ((status & SR_ERR) != 0) { 598 return EIO; 599 } 600 601 if (wait_status(SR_DRQ, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK) 602 return ETIMEOUT; 466 603 467 604 /* Read data from the disk buffer. */ 468 605 606 for (i = 0; i < identify_data_size / 2; i++) { 607 data = pio_read_16(&cmd->data_port); 608 ((uint16_t *) buf)[i] = data; 609 } 610 611 return EOK; 612 } 613 614 /** Issue Identify Packet Device command. 615 * 616 * Reads @c identify data into the provided buffer. This is used to detect 617 * whether an ATAPI device is present and if so, to determine its parameters. 618 * 619 * @param dev_idx Device index, 0 or 1. 620 * @param buf Pointer to a 512-byte buffer. 621 */ 622 static int identify_pkt_dev(int dev_idx, void *buf) 623 { 624 uint16_t data; 625 uint8_t status; 626 uint8_t drv_head; 627 size_t i; 628 629 drv_head = ((dev_idx != 0) ? DHR_DRV : 0); 630 631 if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) 632 return EIO; 633 634 pio_write_8(&cmd->drive_head, drv_head); 635 636 /* For ATAPI commands we do not need to wait for DRDY. */ 637 if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) 638 return EIO; 639 640 pio_write_8(&cmd->command, CMD_IDENTIFY_PKT_DEV); 641 642 if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) 643 return EIO; 644 645 /* Read data from the device buffer. */ 646 469 647 if ((status & SR_DRQ) != 0) { 470 for (i = 0; i < block_size / 2; i++) {648 for (i = 0; i < identify_data_size / 2; i++) { 471 649 data = pio_read_16(&cmd->data_port); 472 650 ((uint16_t *) buf)[i] = data; … … 476 654 if ((status & SR_ERR) != 0) 477 655 return EIO; 656 657 return EOK; 658 } 659 660 /** Issue packet command (i. e. write a command packet to the device). 661 * 662 * Only data-in commands are supported (e.g. inquiry, read). 663 * 664 * @param dev_idx Device index (0 or 1) 665 * @param obuf Buffer for storing data read from device 666 * @param obuf_size Size of obuf in bytes 667 * 668 * @return EOK on success, EIO on error. 669 */ 670 static int ata_cmd_packet(int dev_idx, const void *cpkt, size_t cpkt_size, 671 void *obuf, size_t obuf_size) 672 { 673 size_t i; 674 uint8_t status; 675 uint8_t drv_head; 676 disk_t *d; 677 size_t data_size; 678 uint16_t val; 679 680 d = &disk[dev_idx]; 681 fibril_mutex_lock(&d->lock); 682 683 /* New value for Drive/Head register */ 684 drv_head = 685 ((dev_idx != 0) ? DHR_DRV : 0); 686 687 if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) { 688 fibril_mutex_unlock(&d->lock); 689 return EIO; 690 } 691 692 pio_write_8(&cmd->drive_head, drv_head); 693 694 if (wait_status(0, ~(SR_BSY|SR_DRQ), NULL, TIMEOUT_BSY) != EOK) { 695 fibril_mutex_unlock(&d->lock); 696 return EIO; 697 } 698 699 /* Byte count <- max. number of bytes we can read in one transfer. */ 700 pio_write_8(&cmd->cylinder_low, 0xfe); 701 pio_write_8(&cmd->cylinder_high, 0xff); 702 703 pio_write_8(&cmd->command, CMD_PACKET); 704 705 if (wait_status(SR_DRQ, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) { 706 fibril_mutex_unlock(&d->lock); 707 return EIO; 708 } 709 710 /* Write command packet. */ 711 for (i = 0; i < (cpkt_size + 1) / 2; i++) 712 pio_write_16(&cmd->data_port, ((uint16_t *) cpkt)[i]); 713 714 if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) { 715 fibril_mutex_unlock(&d->lock); 716 return EIO; 717 } 718 719 if ((status & SR_DRQ) == 0) { 720 fibril_mutex_unlock(&d->lock); 721 return EIO; 722 } 723 724 /* Read byte count. */ 725 data_size = (uint16_t) pio_read_8(&cmd->cylinder_low) + 726 ((uint16_t) pio_read_8(&cmd->cylinder_high) << 8); 727 728 /* Check whether data fits into output buffer. */ 729 if (data_size > obuf_size) { 730 /* Output buffer is too small to store data. */ 731 fibril_mutex_unlock(&d->lock); 732 return EIO; 733 } 734 735 /* Read data from the device buffer. */ 736 for (i = 0; i < (data_size + 1) / 2; i++) { 737 val = pio_read_16(&cmd->data_port); 738 ((uint16_t *) obuf)[i] = val; 739 } 740 741 if (status & SR_ERR) { 742 fibril_mutex_unlock(&d->lock); 743 return EIO; 744 } 745 746 fibril_mutex_unlock(&d->lock); 747 748 return EOK; 749 } 750 751 /** Issue ATAPI Inquiry. 752 * 753 * @param dev_idx Device index (0 or 1) 754 * @param obuf Buffer for storing inquiry data read from device 755 * @param obuf_size Size of obuf in bytes 756 * 757 * @return EOK on success, EIO on error. 758 */ 759 static int ata_pcmd_inquiry(int dev_idx, void *obuf, size_t obuf_size) 760 { 761 ata_pcmd_inquiry_t cp; 762 int rc; 763 764 memset(&cp, 0, sizeof(cp)); 765 766 cp.opcode = PCMD_INQUIRY; 767 cp.alloc_len = min(obuf_size, 0xff); /* Allocation length */ 768 769 rc = ata_cmd_packet(0, &cp, sizeof(cp), obuf, obuf_size); 770 if (rc != EOK) 771 return rc; 772 773 return EOK; 774 } 775 776 /** Issue ATAPI read(12) command. 777 * 778 * Output buffer must be large enough to hold the data, otherwise the 779 * function will fail. 780 * 781 * @param dev_idx Device index (0 or 1) 782 * @param ba Starting block address 783 * @param cnt Number of blocks to read 784 * @param obuf Buffer for storing inquiry data read from device 785 * @param obuf_size Size of obuf in bytes 786 * 787 * @return EOK on success, EIO on error. 788 */ 789 static int ata_pcmd_read_12(int dev_idx, uint64_t ba, size_t cnt, 790 void *obuf, size_t obuf_size) 791 { 792 ata_pcmd_read_12_t cp; 793 int rc; 794 795 if (ba > UINT32_MAX) 796 return EINVAL; 797 798 memset(&cp, 0, sizeof(cp)); 799 800 cp.opcode = PCMD_READ_12; 801 cp.ba = host2uint32_t_be(ba); 802 cp.nblocks = host2uint32_t_be(cnt); 803 804 rc = ata_cmd_packet(0, &cp, sizeof(cp), obuf, obuf_size); 805 if (rc != EOK) 806 return rc; 478 807 479 808 return EOK; … … 489 818 * @return EOK on success, EIO on error. 490 819 */ 491 static int ata_ bd_read_block(int disk_id, uint64_t ba, size_t blk_cnt,820 static int ata_rcmd_read(int disk_id, uint64_t ba, size_t blk_cnt, 492 821 void *buf) 493 822 { … … 544 873 /* Read data from the device buffer. */ 545 874 546 for (i = 0; i < block_size / 2; i++) {875 for (i = 0; i < disk[disk_id].block_size / 2; i++) { 547 876 data = pio_read_16(&cmd->data_port); 548 877 ((uint16_t *) buf)[i] = data; … … 566 895 * @return EOK on success, EIO on error. 567 896 */ 568 static int ata_ bd_write_block(int disk_id, uint64_t ba, size_t cnt,897 static int ata_rcmd_write(int disk_id, uint64_t ba, size_t cnt, 569 898 const void *buf) 570 899 { … … 620 949 /* Write data to the device buffer. */ 621 950 622 for (i = 0; i < block_size / 2; i++) {951 for (i = 0; i < disk[disk_id].block_size / 2; i++) { 623 952 pio_write_16(&cmd->data_port, ((uint16_t *) buf)[i]); 624 953 }
Note:
See TracChangeset
for help on using the changeset viewer.