Changes in / [c5f0bff:40fb017] in mainline
- Location:
- uspace/srv/bd/ata_bd
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/bd/ata_bd/ata_bd.c
rc5f0bff r40fb017 55 55 #include <as.h> 56 56 #include <fibril_synch.h> 57 #include <stdint.h>58 57 #include <str.h> 59 58 #include <devmap.h> … … 62 61 #include <errno.h> 63 62 #include <bool.h> 64 #include <byteorder.h>65 63 #include <task.h> 66 64 #include <macros.h> … … 75 73 #define LEGACY_CTLS 4 76 74 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; 75 /** Physical block size. Should be always 512. */ 76 static const size_t block_size = 512; 82 77 83 78 /** Size of the communication area. */ … … 110 105 static int ata_bd_write_blocks(int disk_id, uint64_t ba, size_t cnt, 111 106 const void *buf); 112 static int ata_ rcmd_read(int disk_id, uint64_t ba, size_t cnt,107 static int ata_bd_read_block(int disk_id, uint64_t ba, size_t cnt, 113 108 void *buf); 114 static int ata_ rcmd_write(int disk_id, uint64_t ba, size_t cnt,109 static int ata_bd_write_block(int disk_id, uint64_t ba, size_t cnt, 115 110 const void *buf); 116 111 static int disk_init(disk_t *d, int disk_id); 117 112 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);124 113 static void disk_print_summary(disk_t *d); 125 114 static int coord_calc(disk_t *d, uint64_t ba, block_coord_t *bc); … … 214 203 printf("%s: ", d->model); 215 204 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"); 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; 232 216 } 233 217 … … 329 313 IPC_GET_ARG2(call)); 330 314 cnt = IPC_GET_ARG3(call); 331 if (cnt * disk[disk_id].block_size > comm_size) {315 if (cnt * block_size > comm_size) { 332 316 retval = ELIMIT; 333 317 break; … … 339 323 IPC_GET_ARG2(call)); 340 324 cnt = IPC_GET_ARG3(call); 341 if (cnt * disk[disk_id].block_size > comm_size) {325 if (cnt * block_size > comm_size) { 342 326 retval = ELIMIT; 343 327 break; … … 346 330 break; 347 331 case BD_GET_BLOCK_SIZE: 348 async_answer_1(callid, EOK, disk[disk_id].block_size);332 async_answer_1(callid, EOK, block_size); 349 333 continue; 350 334 case BD_GET_NUM_BLOCKS: … … 369 353 identify_data_t idata; 370 354 uint8_t model[40]; 371 ata_inquiry_data_t inq_data;372 355 uint16_t w; 373 356 uint8_t c; … … 376 359 unsigned i; 377 360 378 d->present = false;379 fibril_mutex_initialize(&d->lock);380 381 /* Try identify command. */382 361 rc = drive_identify(disk_id, &idata); 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) { 362 if (rc != EOK) { 363 d->present = false; 364 return rc; 365 } 366 367 if ((idata.caps & cap_lba) == 0) { 416 368 /* Device only supports CHS addressing. */ 417 369 d->amode = am_chs; … … 470 422 d->model[pos] = '\0'; 471 423 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 492 424 d->present = true; 425 fibril_mutex_initialize(&d->lock); 426 493 427 return EOK; 494 428 } … … 501 435 502 436 while (cnt > 0) { 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 437 rc = ata_bd_read_block(disk_id, ba, 1, buf); 509 438 if (rc != EOK) 510 439 return rc; … … 512 441 ++ba; 513 442 --cnt; 514 buf += disk[disk_id].block_size;443 buf += block_size; 515 444 } 516 445 … … 524 453 int rc; 525 454 526 if (disk[disk_id].dev_type != ata_reg_dev)527 return ENOTSUP;528 529 455 while (cnt > 0) { 530 rc = ata_ rcmd_write(disk_id, ba, 1, buf);456 rc = ata_bd_write_block(disk_id, ba, 1, buf); 531 457 if (rc != EOK) 532 458 return rc; … … 534 460 ++ba; 535 461 --cnt; 536 buf += disk[disk_id].block_size;462 buf += block_size; 537 463 } 538 464 … … 547 473 * @param disk_id Device ID, 0 or 1. 548 474 * @param buf Pointer to a 512-byte buffer. 549 *550 * @return ETIMEOUT on timeout (this can mean the device is551 * not present). EIO if device responds with error.552 475 */ 553 476 static int drive_identify(int disk_id, void *buf) … … 561 484 562 485 if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) 563 return E TIMEOUT;486 return EIO; 564 487 565 488 pio_write_8(&cmd->drive_head, drv_head); … … 570 493 */ 571 494 if (wait_status(SR_DRDY, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) 572 return E TIMEOUT;495 return EIO; 573 496 574 497 pio_write_8(&cmd->command, CMD_IDENTIFY_DRIVE); 575 498 576 499 if (wait_status(0, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK) 577 return E TIMEOUT;500 return EIO; 578 501 579 502 /* Read data from the disk buffer. */ 580 503 581 504 if ((status & SR_DRQ) != 0) { 582 for (i = 0; i < identify_data_size / 2; i++) {505 for (i = 0; i < block_size / 2; i++) { 583 506 data = pio_read_16(&cmd->data_port); 584 507 ((uint16_t *) buf)[i] = data; … … 586 509 } 587 510 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 detect598 * 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 635 511 if ((status & SR_ERR) != 0) 636 512 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 device647 * @param obuf_size Size of obuf in bytes648 *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 device736 * @param obuf_size Size of obuf in bytes737 *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 the760 * function will fail.761 *762 * @param dev_idx Device index (0 or 1)763 * @param ba Starting block address764 * @param cnt Number of blocks to read765 * @param obuf Buffer for storing inquiry data read from device766 * @param obuf_size Size of obuf in bytes767 *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;788 513 789 514 return EOK; … … 799 524 * @return EOK on success, EIO on error. 800 525 */ 801 static int ata_ rcmd_read(int disk_id, uint64_t ba, size_t blk_cnt,526 static int ata_bd_read_block(int disk_id, uint64_t ba, size_t blk_cnt, 802 527 void *buf) 803 528 { … … 854 579 /* Read data from the device buffer. */ 855 580 856 for (i = 0; i < disk[disk_id].block_size / 2; i++) {581 for (i = 0; i < block_size / 2; i++) { 857 582 data = pio_read_16(&cmd->data_port); 858 583 ((uint16_t *) buf)[i] = data; … … 876 601 * @return EOK on success, EIO on error. 877 602 */ 878 static int ata_ rcmd_write(int disk_id, uint64_t ba, size_t cnt,603 static int ata_bd_write_block(int disk_id, uint64_t ba, size_t cnt, 879 604 const void *buf) 880 605 { … … 930 655 /* Write data to the device buffer. */ 931 656 932 for (i = 0; i < disk[disk_id].block_size / 2; i++) {657 for (i = 0; i < block_size / 2; i++) { 933 658 pio_write_16(&cmd->data_port, ((uint16_t *) buf)[i]); 934 659 } -
uspace/srv/bd/ata_bd/ata_bd.h
rc5f0bff r40fb017 53 53 }; 54 54 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 { 55 /** Block addressing mode. */ 56 enum addr_mode { 62 57 am_chs, /**< CHS block addressing */ 63 58 am_lba28, /**< LBA-28 block addressing */ … … 67 62 /** Block coordinates */ 68 63 typedef struct { 69 enum rd_addr_mode amode; 64 /** Addressing mode used */ 65 enum addr_mode amode; 70 66 71 67 union { … … 94 90 typedef struct { 95 91 bool present; 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; 92 enum addr_mode amode; 102 93 103 94 /* … … 111 102 112 103 uint64_t blocks; 113 size_t block_size;114 104 115 105 char model[STR_BOUNDS(40) + 1]; -
uspace/srv/bd/ata_bd/ata_hw.h
rc5f0bff r40fb017 134 134 CMD_WRITE_SECTORS = 0x30, 135 135 CMD_WRITE_SECTORS_EXT = 0x34, 136 CMD_PACKET = 0xA0,137 CMD_IDENTIFY_PKT_DEV = 0xA1,138 136 CMD_IDENTIFY_DRIVE = 0xEC 139 137 }; 140 138 141 /** Data returned from identify device and identify packet devicecommand. */139 /** Data returned from @c identify command. */ 142 140 typedef struct { 143 141 uint16_t gen_conf; … … 161 159 uint16_t max_rw_multiple; 162 160 uint16_t _res48; 163 uint16_t caps; /* Different meaning for packet device */161 uint16_t caps; 164 162 uint16_t _res50; 165 163 uint16_t pio_timing; … … 216 214 } identify_data_t; 217 215 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 216 enum ata_caps { 217 cap_iordy = 0x0800, 218 cap_iordy_cbd = 0x0400, 219 cap_lba = 0x0200, 220 cap_dma = 0x0100 236 221 }; 237 222 … … 241 226 }; 242 227 243 /** ATA packet command codes. */244 enum ata_pkt_command {245 PCMD_INQUIRY = 0x12,246 PCMD_READ_12 = 0xa8247 };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 = 0x05293 };294 295 228 #endif 296 229
Note:
See TracChangeset
for help on using the changeset viewer.
