Changeset c5f0bff in mainline
- Timestamp:
- 2011-02-01T20:22:05Z (14 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 1e00216
- Parents:
- 40fb017 (diff), aa893e0 (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. - Location:
- uspace/srv/bd/ata_bd
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/bd/ata_bd/ata_bd.c
r40fb017 rc5f0bff 55 55 #include <as.h> 56 56 #include <fibril_synch.h> 57 #include <stdint.h> 57 58 #include <str.h> 58 59 #include <devmap.h> … … 61 62 #include <errno.h> 62 63 #include <bool.h> 64 #include <byteorder.h> 63 65 #include <task.h> 64 66 #include <macros.h> … … 73 75 #define LEGACY_CTLS 4 74 76 75 /** Physical block size. Should be always 512. */ 76 static const size_t block_size = 512; 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; 77 82 78 83 /** Size of the communication area. */ … … 105 110 static int ata_bd_write_blocks(int disk_id, uint64_t ba, size_t cnt, 106 111 const void *buf); 107 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, 108 113 void *buf); 109 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, 110 115 const void *buf); 111 116 static int disk_init(disk_t *d, int disk_id); 112 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); 113 124 static void disk_print_summary(disk_t *d); 114 125 static int coord_calc(disk_t *d, uint64_t ba, block_coord_t *bc); … … 203 214 printf("%s: ", d->model); 204 215 205 switch (d->amode) { 206 case am_chs: 207 printf("CHS %u cylinders, %u heads, %u sectors", 208 disk->geom.cylinders, disk->geom.heads, disk->geom.sectors); 209 break; 210 case am_lba28: 211 printf("LBA-28"); 212 break; 213 case am_lba48: 214 printf("LBA-48"); 215 break; 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"); 216 232 } 217 233 … … 313 329 IPC_GET_ARG2(call)); 314 330 cnt = IPC_GET_ARG3(call); 315 if (cnt * block_size > comm_size) {331 if (cnt * disk[disk_id].block_size > comm_size) { 316 332 retval = ELIMIT; 317 333 break; … … 323 339 IPC_GET_ARG2(call)); 324 340 cnt = IPC_GET_ARG3(call); 325 if (cnt * block_size > comm_size) {341 if (cnt * disk[disk_id].block_size > comm_size) { 326 342 retval = ELIMIT; 327 343 break; … … 330 346 break; 331 347 case BD_GET_BLOCK_SIZE: 332 async_answer_1(callid, EOK, block_size);348 async_answer_1(callid, EOK, disk[disk_id].block_size); 333 349 continue; 334 350 case BD_GET_NUM_BLOCKS: … … 353 369 identify_data_t idata; 354 370 uint8_t model[40]; 371 ata_inquiry_data_t inq_data; 355 372 uint16_t w; 356 373 uint8_t c; … … 359 376 unsigned i; 360 377 378 d->present = false; 379 fibril_mutex_initialize(&d->lock); 380 381 /* Try identify command. */ 361 382 rc = drive_identify(disk_id, &idata); 362 if (rc != EOK) { 363 d->present = false; 364 return rc; 365 } 366 367 if ((idata.caps & cap_lba) == 0) { 383 if (rc == EOK) { 384 /* Success. It's a register (non-packet) device. */ 385 printf("ATA register-only device found.\n"); 386 d->dev_type = ata_reg_dev; 387 } else if (rc == EIO) { 388 /* 389 * There is something, but not a register device. 390 * It could be a packet device. 391 */ 392 rc = identify_pkt_dev(disk_id, &idata); 393 if (rc == EOK) { 394 /* We have a packet device. */ 395 d->dev_type = ata_pkt_dev; 396 } else { 397 /* Nope. Something's there, but not recognized. */ 398 return EIO; 399 } 400 } else { 401 /* Operation timed out. That means there is no device there. */ 402 return EIO; 403 } 404 405 printf("device caps: 0x%04x\n", idata.caps); 406 if (d->dev_type == ata_pkt_dev) { 407 /* Packet device */ 408 d->amode = 0; 409 410 d->geom.cylinders = 0; 411 d->geom.heads = 0; 412 d->geom.sectors = 0; 413 414 d->blocks = 0; 415 } else if ((idata.caps & rd_cap_lba) == 0) { 368 416 /* Device only supports CHS addressing. */ 369 417 d->amode = am_chs; … … 422 470 d->model[pos] = '\0'; 423 471 472 if (d->dev_type == ata_pkt_dev) { 473 /* Send inquiry. */ 474 rc = ata_pcmd_inquiry(0, &inq_data, sizeof(inq_data)); 475 if (rc != EOK) { 476 printf("Device inquiry failed.\n"); 477 d->present = false; 478 return EIO; 479 } 480 481 /* Check device type. */ 482 if (INQUIRY_PDEV_TYPE(inq_data.pdev_type) != PDEV_TYPE_CDROM) 483 printf("Warning: Peripheral device type is not CD-ROM.\n"); 484 485 /* Assume 2k block size for now. */ 486 d->block_size = 2048; 487 } else { 488 /* Assume register Read always uses 512-byte blocks. */ 489 d->block_size = 512; 490 } 491 424 492 d->present = true; 425 fibril_mutex_initialize(&d->lock);426 427 493 return EOK; 428 494 } … … 435 501 436 502 while (cnt > 0) { 437 rc = ata_bd_read_block(disk_id, ba, 1, buf); 503 if (disk[disk_id].dev_type == ata_reg_dev) 504 rc = ata_rcmd_read(disk_id, ba, 1, buf); 505 else 506 rc = ata_pcmd_read_12(disk_id, ba, 1, buf, 507 disk[disk_id].block_size); 508 438 509 if (rc != EOK) 439 510 return rc; … … 441 512 ++ba; 442 513 --cnt; 443 buf += block_size;514 buf += disk[disk_id].block_size; 444 515 } 445 516 … … 453 524 int rc; 454 525 526 if (disk[disk_id].dev_type != ata_reg_dev) 527 return ENOTSUP; 528 455 529 while (cnt > 0) { 456 rc = ata_ bd_write_block(disk_id, ba, 1, buf);530 rc = ata_rcmd_write(disk_id, ba, 1, buf); 457 531 if (rc != EOK) 458 532 return rc; … … 460 534 ++ba; 461 535 --cnt; 462 buf += block_size;536 buf += disk[disk_id].block_size; 463 537 } 464 538 … … 473 547 * @param disk_id Device ID, 0 or 1. 474 548 * @param buf Pointer to a 512-byte buffer. 549 * 550 * @return ETIMEOUT on timeout (this can mean the device is 551 * not present). EIO if device responds with error. 475 552 */ 476 553 static int drive_identify(int disk_id, void *buf) … … 484 561 485 562 if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) 486 return E IO;563 return ETIMEOUT; 487 564 488 565 pio_write_8(&cmd->drive_head, drv_head); … … 493 570 */ 494 571 if (wait_status(SR_DRDY, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) 495 return E IO;572 return ETIMEOUT; 496 573 497 574 pio_write_8(&cmd->command, CMD_IDENTIFY_DRIVE); 498 575 499 576 if (wait_status(0, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK) 500 return E IO;577 return ETIMEOUT; 501 578 502 579 /* Read data from the disk buffer. */ 503 580 504 581 if ((status & SR_DRQ) != 0) { 505 for (i = 0; i < block_size / 2; i++) {582 for (i = 0; i < identify_data_size / 2; i++) { 506 583 data = pio_read_16(&cmd->data_port); 507 584 ((uint16_t *) buf)[i] = data; … … 509 586 } 510 587 588 if ((status & SR_ERR) != 0) { 589 return EIO; 590 } 591 592 return EOK; 593 } 594 595 /** Issue Identify Packet Device command. 596 * 597 * Reads @c identify data into the provided buffer. This is used to detect 598 * whether an ATAPI device is present and if so, to determine its parameters. 599 * 600 * @param dev_idx Device index, 0 or 1. 601 * @param buf Pointer to a 512-byte buffer. 602 */ 603 static int identify_pkt_dev(int dev_idx, void *buf) 604 { 605 uint16_t data; 606 uint8_t status; 607 uint8_t drv_head; 608 size_t i; 609 610 drv_head = ((dev_idx != 0) ? DHR_DRV : 0); 611 612 if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) 613 return EIO; 614 615 pio_write_8(&cmd->drive_head, drv_head); 616 617 /* For ATAPI commands we do not need to wait for DRDY. */ 618 if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) 619 return EIO; 620 621 pio_write_8(&cmd->command, CMD_IDENTIFY_PKT_DEV); 622 623 if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) 624 return EIO; 625 626 /* Read data from the device buffer. */ 627 628 if ((status & SR_DRQ) != 0) { 629 for (i = 0; i < identify_data_size / 2; i++) { 630 data = pio_read_16(&cmd->data_port); 631 ((uint16_t *) buf)[i] = data; 632 } 633 } 634 511 635 if ((status & SR_ERR) != 0) 512 636 return EIO; 637 638 return EOK; 639 } 640 641 /** Issue packet command (i. e. write a command packet to the device). 642 * 643 * Only data-in commands are supported (e.g. inquiry, read). 644 * 645 * @param dev_idx Device index (0 or 1) 646 * @param obuf Buffer for storing data read from device 647 * @param obuf_size Size of obuf in bytes 648 * 649 * @return EOK on success, EIO on error. 650 */ 651 static int ata_cmd_packet(int dev_idx, const void *cpkt, size_t cpkt_size, 652 void *obuf, size_t obuf_size) 653 { 654 size_t i; 655 uint8_t status; 656 uint8_t drv_head; 657 disk_t *d; 658 size_t data_size; 659 uint16_t val; 660 661 d = &disk[dev_idx]; 662 fibril_mutex_lock(&d->lock); 663 664 /* New value for Drive/Head register */ 665 drv_head = 666 ((dev_idx != 0) ? DHR_DRV : 0); 667 668 if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) { 669 fibril_mutex_unlock(&d->lock); 670 return EIO; 671 } 672 673 pio_write_8(&cmd->drive_head, drv_head); 674 675 if (wait_status(0, ~(SR_BSY|SR_DRQ), NULL, TIMEOUT_BSY) != EOK) { 676 fibril_mutex_unlock(&d->lock); 677 return EIO; 678 } 679 680 /* Byte count <- max. number of bytes we can read in one transfer. */ 681 pio_write_8(&cmd->cylinder_low, 0xfe); 682 pio_write_8(&cmd->cylinder_high, 0xff); 683 684 pio_write_8(&cmd->command, CMD_PACKET); 685 686 if (wait_status(SR_DRQ, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) { 687 fibril_mutex_unlock(&d->lock); 688 return EIO; 689 } 690 691 /* Write command packet. */ 692 for (i = 0; i < (cpkt_size + 1) / 2; i++) 693 pio_write_16(&cmd->data_port, ((uint16_t *) cpkt)[i]); 694 695 if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) { 696 fibril_mutex_unlock(&d->lock); 697 return EIO; 698 } 699 700 if ((status & SR_DRQ) == 0) { 701 fibril_mutex_unlock(&d->lock); 702 return EIO; 703 } 704 705 /* Read byte count. */ 706 data_size = (uint16_t) pio_read_8(&cmd->cylinder_low) + 707 ((uint16_t) pio_read_8(&cmd->cylinder_high) << 8); 708 709 /* Check whether data fits into output buffer. */ 710 if (data_size > obuf_size) { 711 /* Output buffer is too small to store data. */ 712 fibril_mutex_unlock(&d->lock); 713 return EIO; 714 } 715 716 /* Read data from the device buffer. */ 717 for (i = 0; i < (data_size + 1) / 2; i++) { 718 val = pio_read_16(&cmd->data_port); 719 ((uint16_t *) obuf)[i] = val; 720 } 721 722 if (status & SR_ERR) { 723 fibril_mutex_unlock(&d->lock); 724 return EIO; 725 } 726 727 fibril_mutex_unlock(&d->lock); 728 729 return EOK; 730 } 731 732 /** Issue ATAPI Inquiry. 733 * 734 * @param dev_idx Device index (0 or 1) 735 * @param obuf Buffer for storing inquiry data read from device 736 * @param obuf_size Size of obuf in bytes 737 * 738 * @return EOK on success, EIO on error. 739 */ 740 static int ata_pcmd_inquiry(int dev_idx, void *obuf, size_t obuf_size) 741 { 742 ata_pcmd_inquiry_t cp; 743 int rc; 744 745 memset(&cp, 0, sizeof(cp)); 746 747 cp.opcode = PCMD_INQUIRY; 748 cp.alloc_len = min(obuf_size, 0xff); /* Allocation length */ 749 750 rc = ata_cmd_packet(0, &cp, sizeof(cp), obuf, obuf_size); 751 if (rc != EOK) 752 return rc; 753 754 return EOK; 755 } 756 757 /** Issue ATAPI read(12) command. 758 * 759 * Output buffer must be large enough to hold the data, otherwise the 760 * function will fail. 761 * 762 * @param dev_idx Device index (0 or 1) 763 * @param ba Starting block address 764 * @param cnt Number of blocks to read 765 * @param obuf Buffer for storing inquiry data read from device 766 * @param obuf_size Size of obuf in bytes 767 * 768 * @return EOK on success, EIO on error. 769 */ 770 static int ata_pcmd_read_12(int dev_idx, uint64_t ba, size_t cnt, 771 void *obuf, size_t obuf_size) 772 { 773 ata_pcmd_read_12_t cp; 774 int rc; 775 776 if (ba > UINT32_MAX) 777 return EINVAL; 778 779 memset(&cp, 0, sizeof(cp)); 780 781 cp.opcode = PCMD_READ_12; 782 cp.ba = host2uint32_t_be(ba); 783 cp.nblocks = host2uint32_t_be(cnt); 784 785 rc = ata_cmd_packet(0, &cp, sizeof(cp), obuf, obuf_size); 786 if (rc != EOK) 787 return rc; 513 788 514 789 return EOK; … … 524 799 * @return EOK on success, EIO on error. 525 800 */ 526 static int ata_ bd_read_block(int disk_id, uint64_t ba, size_t blk_cnt,801 static int ata_rcmd_read(int disk_id, uint64_t ba, size_t blk_cnt, 527 802 void *buf) 528 803 { … … 579 854 /* Read data from the device buffer. */ 580 855 581 for (i = 0; i < block_size / 2; i++) {856 for (i = 0; i < disk[disk_id].block_size / 2; i++) { 582 857 data = pio_read_16(&cmd->data_port); 583 858 ((uint16_t *) buf)[i] = data; … … 601 876 * @return EOK on success, EIO on error. 602 877 */ 603 static int ata_ bd_write_block(int disk_id, uint64_t ba, size_t cnt,878 static int ata_rcmd_write(int disk_id, uint64_t ba, size_t cnt, 604 879 const void *buf) 605 880 { … … 655 930 /* Write data to the device buffer. */ 656 931 657 for (i = 0; i < block_size / 2; i++) {932 for (i = 0; i < disk[disk_id].block_size / 2; i++) { 658 933 pio_write_16(&cmd->data_port, ((uint16_t *) buf)[i]); 659 934 } -
uspace/srv/bd/ata_bd/ata_bd.h
r40fb017 rc5f0bff 53 53 }; 54 54 55 /** Block addressing mode. */ 56 enum addr_mode { 55 enum ata_dev_type { 56 ata_reg_dev, /* Register device (no packet feature set support) */ 57 ata_pkt_dev /* Packet device (supports packet feature set). */ 58 }; 59 60 /** Register device block addressing mode. */ 61 enum rd_addr_mode { 57 62 am_chs, /**< CHS block addressing */ 58 63 am_lba28, /**< LBA-28 block addressing */ … … 62 67 /** Block coordinates */ 63 68 typedef struct { 64 /** Addressing mode used */ 65 enum addr_mode amode; 69 enum rd_addr_mode amode; 66 70 67 71 union { … … 90 94 typedef struct { 91 95 bool present; 92 enum addr_mode amode; 96 97 /** Device type */ 98 enum ata_dev_type dev_type; 99 100 /** Addressing mode to use (if register device) */ 101 enum rd_addr_mode amode; 93 102 94 103 /* … … 102 111 103 112 uint64_t blocks; 113 size_t block_size; 104 114 105 115 char model[STR_BOUNDS(40) + 1]; -
uspace/srv/bd/ata_bd/ata_hw.h
r40fb017 rc5f0bff 134 134 CMD_WRITE_SECTORS = 0x30, 135 135 CMD_WRITE_SECTORS_EXT = 0x34, 136 CMD_PACKET = 0xA0, 137 CMD_IDENTIFY_PKT_DEV = 0xA1, 136 138 CMD_IDENTIFY_DRIVE = 0xEC 137 139 }; 138 140 139 /** Data returned from @c identifycommand. */141 /** Data returned from identify device and identify packet device command. */ 140 142 typedef struct { 141 143 uint16_t gen_conf; … … 159 161 uint16_t max_rw_multiple; 160 162 uint16_t _res48; 161 uint16_t caps; 163 uint16_t caps; /* Different meaning for packet device */ 162 164 uint16_t _res50; 163 165 uint16_t pio_timing; … … 214 216 } identify_data_t; 215 217 216 enum ata_caps { 217 cap_iordy = 0x0800, 218 cap_iordy_cbd = 0x0400, 219 cap_lba = 0x0200, 220 cap_dma = 0x0100 218 /** Capability bits for register device. */ 219 enum ata_regdev_caps { 220 rd_cap_iordy = 0x0800, 221 rd_cap_iordy_cbd = 0x0400, 222 rd_cap_lba = 0x0200, 223 rd_cap_dma = 0x0100 224 }; 225 226 /** Capability bits for packet device. */ 227 enum ata_pktdev_caps { 228 pd_cap_ildma = 0x8000, 229 pd_cap_cmdqueue = 0x4000, 230 pd_cap_overlap = 0x2000, 231 pd_cap_need_softreset = 0x1000, /* Obsolete (ATAPI-6) */ 232 pd_cap_iordy = 0x0800, 233 pd_cap_iordy_dis = 0x0400, 234 pd_cap_lba = 0x0200, /* Must be on */ 235 pd_cap_dma = 0x0100 221 236 }; 222 237 … … 226 241 }; 227 242 243 /** ATA packet command codes. */ 244 enum ata_pkt_command { 245 PCMD_INQUIRY = 0x12, 246 PCMD_READ_12 = 0xa8 247 }; 248 249 /** ATAPI Inquiry command */ 250 typedef struct { 251 uint8_t opcode; /**< Operation code (PCMD_INQUIRY) */ 252 uint8_t _res0; 253 uint8_t _res1; 254 uint8_t _res2; 255 uint8_t alloc_len; /**< Allocation length */ 256 uint8_t _res3; 257 uint8_t _res4; 258 uint8_t _res5; 259 uint32_t _res6; 260 } __attribute__ ((packed)) ata_pcmd_inquiry_t; 261 262 /** ATAPI Read(12) command */ 263 typedef struct { 264 uint8_t opcode; /**< Operation code (PCMD_READ_12) */ 265 uint8_t _res0; 266 uint32_t ba; /**< Starting block address */ 267 uint32_t nblocks; /**< Number of blocks to transfer */ 268 uint8_t _res1; 269 uint8_t _res2; 270 } __attribute__ ((packed)) ata_pcmd_read_12_t; 271 272 /** Data returned from Inquiry command (mandatory part) */ 273 typedef struct { 274 uint8_t pdev_type; /** Reserved, Peripheral device type */ 275 uint8_t rmb; /** RMB, Reserved */ 276 uint8_t std_version; /** ISO version, ECMA version, ANSI version */ 277 uint8_t atapi_ver_rdf; /** ATAPI version, Response data format */ 278 uint8_t additional_len; /** Additional length */ 279 uint8_t _res0; 280 uint8_t _res1; 281 uint8_t _res2; 282 uint8_t vendor_id[8]; /** Vendor ID */ 283 uint8_t product_id[8]; /** Product ID */ 284 uint8_t product_rev[4]; /** Product revision level */ 285 } ata_inquiry_data_t; 286 287 /** Extract value of ata_inquiry_data_t.pdev_type */ 288 #define INQUIRY_PDEV_TYPE(val) ((val) & 0x1f) 289 290 /** Values for ata_inquiry_data_t.pdev_type */ 291 enum ata_pdev_type { 292 PDEV_TYPE_CDROM = 0x05 293 }; 294 228 295 #endif 229 296
Note:
See TracChangeset
for help on using the changeset viewer.