Changeset 2791fbb7 in mainline
- Timestamp:
- 2024-05-16T16:17:49Z (4 months ago)
- Branches:
- master
- Children:
- 59c0f478
- Parents:
- 64cf7a3
- Location:
- uspace
- Files:
-
- 3 added
- 6 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/block/ata_bd/ata_bd.c
r64cf7a3 r2791fbb7 33 33 /** 34 34 * @file 35 * @brief ATA disk driver 36 * 37 * This driver supports CHS, 28-bit and 48-bit LBA addressing, as well as 38 * PACKET devices. It only uses PIO transfers. There is no support DMA 39 * or any other 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. 45 * 46 * The driver services a single controller which can have up to two disks 47 * attached. 35 * @brief ISA ATA driver 36 * 37 * The driver services a single IDE channel. 48 38 */ 49 39 … … 53 43 #include <async.h> 54 44 #include <as.h> 55 #include <bd_srv.h>56 45 #include <fibril_synch.h> 57 #include <scsi/mmc.h>58 #include <scsi/sbc.h>59 #include <scsi/spc.h>60 46 #include <stdint.h> 61 47 #include <stdbool.h> … … 65 51 #include <inttypes.h> 66 52 #include <errno.h> 67 #include <byteorder.h> 68 #include <macros.h> 69 70 #include "ata_hw.h" 53 71 54 #include "ata_bd.h" 72 55 #include "main.h" 73 56 74 57 #define NAME "ata_bd" 75 76 /**77 * Size of data returned from Identify Device or Identify Packet Device78 * command.79 */80 static const size_t identify_data_size = 512;81 58 82 59 static errno_t ata_bd_init_io(ata_ctrl_t *ctrl); … … 84 61 static errno_t ata_bd_init_irq(ata_ctrl_t *ctrl); 85 62 static void ata_bd_fini_irq(ata_ctrl_t *ctrl); 86 87 static errno_t ata_bd_open(bd_srvs_t *, bd_srv_t *);88 static errno_t ata_bd_close(bd_srv_t *);89 static errno_t ata_bd_read_blocks(bd_srv_t *, uint64_t ba, size_t cnt, void *buf,90 size_t);91 static errno_t ata_bd_read_toc(bd_srv_t *, uint8_t session, void *buf, size_t);92 static errno_t ata_bd_write_blocks(bd_srv_t *, uint64_t ba, size_t cnt,93 const void *buf, size_t);94 static errno_t ata_bd_get_block_size(bd_srv_t *, size_t *);95 static errno_t ata_bd_get_num_blocks(bd_srv_t *, aoff64_t *);96 static errno_t ata_bd_sync_cache(bd_srv_t *, aoff64_t, size_t);97 98 static errno_t ata_rcmd_read(disk_t *disk, uint64_t ba, size_t cnt,99 void *buf);100 static errno_t ata_rcmd_write(disk_t *disk, uint64_t ba, size_t cnt,101 const void *buf);102 static errno_t ata_rcmd_flush_cache(disk_t *disk);103 static errno_t disk_init(ata_ctrl_t *ctrl, disk_t *d, int disk_id);104 static errno_t ata_identify_dev(disk_t *disk, void *buf);105 static errno_t ata_identify_pkt_dev(disk_t *disk, void *buf);106 static errno_t ata_cmd_packet(disk_t *disk, const void *cpkt, size_t cpkt_size,107 void *obuf, size_t obuf_size, size_t *rcvd_size);108 static errno_t ata_pcmd_inquiry(disk_t *disk, void *obuf, size_t obuf_size,109 size_t *rcvd_size);110 static errno_t ata_pcmd_read_12(disk_t *disk, uint64_t ba, size_t cnt,111 void *obuf, size_t obuf_size);112 static errno_t ata_pcmd_read_capacity(disk_t *disk, uint64_t *nblocks,113 size_t *block_size);114 static errno_t ata_pcmd_read_toc(disk_t *disk, uint8_t ses,115 void *obuf, size_t obuf_size);116 static void disk_print_summary(disk_t *d);117 static size_t ata_disk_maxnb(disk_t *d);118 static errno_t coord_calc(disk_t *d, uint64_t ba, block_coord_t *bc);119 static void coord_sc_program(ata_ctrl_t *ctrl, const block_coord_t *bc,120 uint16_t scnt);121 static errno_t wait_status(ata_ctrl_t *ctrl, unsigned set, unsigned n_reset,122 uint8_t *pstatus, unsigned timeout);123 static errno_t wait_irq(ata_ctrl_t *ctrl, uint8_t *pstatus, unsigned timeout);124 63 static void ata_irq_handler(ipc_call_t *call, ddf_dev_t *dev); 125 64 126 bd_ops_t ata_bd_ops = { 127 .open = ata_bd_open, 128 .close = ata_bd_close, 129 .read_blocks = ata_bd_read_blocks, 130 .read_toc = ata_bd_read_toc, 131 .write_blocks = ata_bd_write_blocks, 132 .get_block_size = ata_bd_get_block_size, 133 .get_num_blocks = ata_bd_get_num_blocks, 134 .sync_cache = ata_bd_sync_cache 135 }; 65 static void ata_write_data_16(void *, uint16_t *, size_t); 66 static void ata_read_data_16(void *, uint16_t *, size_t); 67 static void ata_write_cmd_8(void *, uint16_t, uint8_t); 68 static uint8_t ata_read_cmd_8(void *, uint16_t); 69 static void ata_write_ctl_8(void *, uint16_t, uint8_t); 70 static uint8_t ata_read_ctl_8(void *, uint16_t); 71 static errno_t ata_irq_enable(void *); 72 static errno_t ata_irq_disable(void *); 73 static errno_t ata_add_device(void *, unsigned, void *); 74 static errno_t ata_remove_device(void *, unsigned); 75 static void ata_msg_debug(void *, char *); 76 static void ata_msg_note(void *, char *); 77 static void ata_msg_warn(void *, char *); 78 static void ata_msg_error(void *, char *); 136 79 137 80 static const irq_pio_range_t ata_irq_ranges[] = { … … 154 97 }; 155 98 156 static disk_t *bd_srv_disk(bd_srv_t *bd)157 {158 return (disk_t *)bd->srvs->sarg;159 }160 161 static int disk_dev_idx(disk_t *disk)162 {163 return (disk->disk_id & 1);164 }165 166 99 /** Initialize ATA controller. */ 167 100 errno_t ata_ctrl_init(ata_ctrl_t *ctrl, ata_hwres_t *res) 168 101 { 169 int i; 170 errno_t rc; 171 int n_disks; 102 errno_t rc; 172 103 bool irq_inited = false; 104 ata_params_t params; 173 105 174 106 ddf_msg(LVL_DEBUG, "ata_ctrl_init()"); 175 107 176 108 fibril_mutex_initialize(&ctrl->lock); 177 fibril_mutex_initialize(&ctrl->irq_lock);178 fibril_condvar_initialize(&ctrl->irq_cv);179 109 ctrl->cmd_physical = res->cmd; 180 110 ctrl->ctl_physical = res->ctl; … … 184 114 (void *) ctrl->ctl_physical); 185 115 116 ddf_msg(LVL_DEBUG, "Init I/O"); 186 117 rc = ata_bd_init_io(ctrl); 187 118 if (rc != EOK) 188 119 return rc; 189 120 121 ddf_msg(LVL_DEBUG, "Init IRQ"); 190 122 rc = ata_bd_init_irq(ctrl); 123 if (rc != EOK) { 124 ddf_msg(LVL_NOTE, "init IRQ failed"); 125 return rc; 126 } 127 128 irq_inited = true; 129 130 ddf_msg(LVL_DEBUG, "ata_ctrl_init(): Initialize ATA channel"); 131 132 params.arg = (void *)ctrl; 133 params.have_irq = (ctrl->irq >= 0) ? true : false; 134 params.write_data_16 = ata_write_data_16; 135 params.read_data_16 = ata_read_data_16; 136 params.write_cmd_8 = ata_write_cmd_8; 137 params.read_cmd_8 = ata_read_cmd_8; 138 params.write_ctl_8 = ata_write_ctl_8; 139 params.read_ctl_8 = ata_read_ctl_8; 140 params.irq_enable = ata_irq_enable; 141 params.irq_disable = ata_irq_disable; 142 params.add_device = ata_add_device; 143 params.remove_device = ata_remove_device; 144 params.msg_debug = ata_msg_debug; 145 params.msg_note = ata_msg_note; 146 params.msg_warn = ata_msg_warn; 147 params.msg_error = ata_msg_error; 148 149 rc = ata_channel_create(¶ms, &ctrl->channel); 191 150 if (rc != EOK) 192 return rc;193 194 irq_inited = true;195 196 for (i = 0; i < MAX_DISKS; i++) {197 ddf_msg(LVL_DEBUG, "Identify drive %d...", i);198 199 rc = disk_init(ctrl, &ctrl->disk[i], i);200 201 if (rc == EOK) {202 disk_print_summary(&ctrl->disk[i]);203 } else {204 ddf_msg(LVL_DEBUG, "Not found.");205 }206 }207 208 n_disks = 0;209 210 for (i = 0; i < MAX_DISKS; i++) {211 /* Skip unattached drives. */212 if (ctrl->disk[i].present == false)213 continue;214 215 rc = ata_fun_create(&ctrl->disk[i]);216 if (rc != EOK) {217 ddf_msg(LVL_ERROR, "Unable to create function for "218 "disk %d.", i);219 goto error;220 }221 ++n_disks;222 }223 224 if (n_disks == 0) {225 ddf_msg(LVL_WARN, "No disks detected.");226 rc = ENOENT;227 151 goto error; 228 } 229 152 153 rc = ata_channel_initialize(ctrl->channel); 154 if (rc != EOK) 155 goto error; 156 157 ddf_msg(LVL_DEBUG, "ata_ctrl_init: DONE"); 230 158 return EOK; 231 159 error: 232 for (i = 0; i < MAX_DISKS; i++) {233 if (ata_fun_remove(&ctrl->disk[i]) != EOK) {234 ddf_msg(LVL_ERROR, "Unable to clean up function for "235 "disk %d.", i);236 }237 }238 160 if (irq_inited) 239 161 ata_bd_fini_irq(ctrl); … … 245 167 errno_t ata_ctrl_remove(ata_ctrl_t *ctrl) 246 168 { 247 int i;248 169 errno_t rc; 249 170 … … 252 173 fibril_mutex_lock(&ctrl->lock); 253 174 254 for (i = 0; i < MAX_DISKS; i++) { 255 rc = ata_fun_remove(&ctrl->disk[i]); 256 if (rc != EOK) { 257 ddf_msg(LVL_ERROR, "Unable to clean up function for " 258 "disk %d.", i); 259 return rc; 260 } 175 rc = ata_channel_destroy(ctrl->channel); 176 if (rc != EOK) { 177 fibril_mutex_unlock(&ctrl->lock); 178 return rc; 261 179 } 262 180 … … 271 189 errno_t ata_ctrl_gone(ata_ctrl_t *ctrl) 272 190 { 273 int i;274 191 errno_t rc; 275 192 … … 278 195 fibril_mutex_lock(&ctrl->lock); 279 196 280 for (i = 0; i < MAX_DISKS; i++) { 281 rc = ata_fun_unbind(&ctrl->disk[i]); 282 if (rc != EOK) { 283 ddf_msg(LVL_ERROR, "Unable to clean up function for " 284 "disk %d.", i); 285 return rc; 286 } 197 rc = ata_channel_destroy(ctrl->channel); 198 if (rc != EOK) { 199 fibril_mutex_unlock(&ctrl->lock); 200 return rc; 287 201 } 288 202 … … 293 207 } 294 208 295 /** Print one-line device summary. */296 static void disk_print_summary(disk_t *d)297 {298 uint64_t mbytes;299 char *atype = NULL;300 char *cap = NULL;301 int rc;302 303 if (d->dev_type == ata_reg_dev) {304 switch (d->amode) {305 case am_chs:306 rc = asprintf(&atype, "CHS %u cylinders, %u heads, "307 "%u sectors", d->geom.cylinders, d->geom.heads,308 d->geom.sectors);309 if (rc < 0) {310 /* Out of memory */311 atype = NULL;312 }313 break;314 case am_lba28:315 atype = str_dup("LBA-28");316 break;317 case am_lba48:318 atype = str_dup("LBA-48");319 break;320 }321 } else {322 atype = str_dup("PACKET");323 }324 325 if (atype == NULL)326 return;327 328 mbytes = d->blocks / (2 * 1024);329 if (mbytes > 0) {330 rc = asprintf(&cap, " %" PRIu64 " MB.", mbytes);331 if (rc < 0) {332 cap = NULL;333 goto cleanup;334 }335 }336 337 ddf_msg(LVL_NOTE, "%s: %s %" PRIu64 " blocks%s", d->model, atype,338 d->blocks, cap);339 cleanup:340 free(atype);341 free(cap);342 }343 344 209 /** Enable device I/O. */ 345 210 static errno_t ata_bd_init_io(ata_ctrl_t *ctrl) … … 377 242 { 378 243 irq_code_t irq_code; 379 async_sess_t *parent_sess;380 244 irq_pio_range_t *ranges; 381 245 irq_cmd_t *cmds; … … 413 277 } 414 278 415 parent_sess = ddf_dev_parent_sess_get(ctrl->dev); 416 417 rc = hw_res_enable_interrupt(parent_sess, ctrl->irq); 418 if (rc != EOK) { 419 ddf_msg(LVL_ERROR, "Error enabling IRQ."); 420 (void) unregister_interrupt_handler(ctrl->dev, 421 ctrl->ihandle); 422 goto error; 423 } 424 279 ddf_msg(LVL_DEBUG, "Interrupt handler registered"); 425 280 free(ranges); 426 281 free(cmds); … … 447 302 } 448 303 449 /** Initialize a disk.450 *451 * Probes for a disk, determines its parameters and initializes452 * the disk structure.453 */454 static errno_t disk_init(ata_ctrl_t *ctrl, disk_t *d, int disk_id)455 {456 identify_data_t idata;457 uint8_t model[40];458 scsi_std_inquiry_data_t inq_data;459 size_t isize;460 uint16_t w;461 uint8_t c;462 uint16_t bc;463 uint64_t nblocks;464 size_t block_size;465 size_t pos, len;466 errno_t rc;467 unsigned i;468 469 d->ctrl = ctrl;470 d->disk_id = disk_id;471 d->present = false;472 d->afun = NULL;473 474 /* Try identify command. */475 rc = ata_identify_dev(d, &idata);476 if (rc == EOK) {477 /* Success. It's a register (non-packet) device. */478 ddf_msg(LVL_DEBUG, "ATA register-only device found.");479 d->dev_type = ata_reg_dev;480 } else if (rc == EIO) {481 /*482 * There is something, but not a register device. Check to see483 * whether the IDENTIFY command left the packet signature in484 * the registers in case this is a packet device.485 *486 * According to the ATA specification, the LBA low and487 * interrupt reason registers should be set to 0x01. However,488 * there are many devices that do not follow this and only set489 * the byte count registers. So, only check these.490 */491 bc = ((uint16_t)pio_read_8(&ctrl->cmd->cylinder_high) << 8) |492 pio_read_8(&ctrl->cmd->cylinder_low);493 494 if (bc == PDEV_SIGNATURE_BC) {495 rc = ata_identify_pkt_dev(d, &idata);496 if (rc == EOK) {497 /* We have a packet device. */498 d->dev_type = ata_pkt_dev;499 } else {500 return EIO;501 }502 } else {503 /* Nope. Something's there, but not recognized. */504 return EIO;505 }506 } else {507 /* Operation timed out. That means there is no device there. */508 return EIO;509 }510 511 if (d->dev_type == ata_pkt_dev) {512 /* Packet device */513 d->amode = 0;514 515 d->geom.cylinders = 0;516 d->geom.heads = 0;517 d->geom.sectors = 0;518 519 d->blocks = 0;520 } else if ((idata.caps & rd_cap_lba) == 0) {521 /* Device only supports CHS addressing. */522 d->amode = am_chs;523 524 d->geom.cylinders = idata.cylinders;525 d->geom.heads = idata.heads;526 d->geom.sectors = idata.sectors;527 528 d->blocks = d->geom.cylinders * d->geom.heads * d->geom.sectors;529 } else if ((idata.cmd_set1 & cs1_addr48) == 0) {530 /* Device only supports LBA-28 addressing. */531 d->amode = am_lba28;532 533 d->geom.cylinders = 0;534 d->geom.heads = 0;535 d->geom.sectors = 0;536 537 d->blocks =538 (uint32_t) idata.total_lba28_0 |539 ((uint32_t) idata.total_lba28_1 << 16);540 } else {541 /* Device supports LBA-48 addressing. */542 d->amode = am_lba48;543 544 d->geom.cylinders = 0;545 d->geom.heads = 0;546 d->geom.sectors = 0;547 548 d->blocks =549 (uint64_t) idata.total_lba48_0 |550 ((uint64_t) idata.total_lba48_1 << 16) |551 ((uint64_t) idata.total_lba48_2 << 32) |552 ((uint64_t) idata.total_lba48_3 << 48);553 }554 555 /*556 * Convert model name to string representation.557 */558 for (i = 0; i < 20; i++) {559 w = idata.model_name[i];560 model[2 * i] = w >> 8;561 model[2 * i + 1] = w & 0x00ff;562 }563 564 len = 40;565 while (len > 0 && model[len - 1] == 0x20)566 --len;567 568 pos = 0;569 for (i = 0; i < len; ++i) {570 c = model[i];571 if (c >= 0x80)572 c = '?';573 574 chr_encode(c, d->model, &pos, 40);575 }576 d->model[pos] = '\0';577 578 if (d->dev_type == ata_pkt_dev) {579 /* Send inquiry. */580 rc = ata_pcmd_inquiry(d, &inq_data, sizeof(inq_data), &isize);581 if (rc != EOK || isize < sizeof(inq_data)) {582 ddf_msg(LVL_ERROR, "Device inquiry failed.");583 d->present = false;584 return EIO;585 }586 587 /* Check device type. */588 if (INQUIRY_PDEV_TYPE(inq_data.pqual_devtype) != SCSI_DEV_CD_DVD)589 ddf_msg(LVL_WARN, "Peripheral device type is not CD-ROM.");590 591 rc = ata_pcmd_read_capacity(d, &nblocks, &block_size);592 if (rc != EOK) {593 ddf_msg(LVL_ERROR, "Read capacity command failed.");594 d->present = false;595 return EIO;596 }597 598 d->blocks = nblocks;599 d->block_size = block_size;600 } else {601 /* Assume register Read always uses 512-byte blocks. */602 d->block_size = 512;603 }604 605 d->present = true;606 return EOK;607 }608 609 static errno_t ata_bd_open(bd_srvs_t *bds, bd_srv_t *bd)610 {611 return EOK;612 }613 614 static errno_t ata_bd_close(bd_srv_t *bd)615 {616 return EOK;617 }618 619 /** Read multiple blocks from the device. */620 static errno_t ata_bd_read_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt,621 void *buf, size_t size)622 {623 disk_t *disk = bd_srv_disk(bd);624 size_t maxnb;625 size_t nb;626 errno_t rc;627 628 if (size < cnt * disk->block_size) {629 rc = EINVAL;630 goto error;631 }632 633 /* Maximum number of blocks to transfer at the same time */634 maxnb = ata_disk_maxnb(disk);635 while (cnt > 0) {636 nb = min(maxnb, cnt);637 if (disk->dev_type == ata_reg_dev) {638 rc = ata_rcmd_read(disk, ba, nb, buf);639 } else {640 rc = ata_pcmd_read_12(disk, ba, nb, buf,641 disk->block_size);642 }643 644 if (rc != EOK)645 goto error;646 647 ba += nb;648 cnt -= nb;649 buf += disk->block_size * nb;650 }651 652 return EOK;653 error:654 ddf_msg(LVL_DEBUG, "ata_bd_read_blocks: rc=%d", rc);655 return rc;656 }657 658 /** Read TOC from device. */659 static errno_t ata_bd_read_toc(bd_srv_t *bd, uint8_t session, void *buf, size_t size)660 {661 disk_t *disk = bd_srv_disk(bd);662 663 return ata_pcmd_read_toc(disk, session, buf, size);664 }665 666 /** Write multiple blocks to the device. */667 static errno_t ata_bd_write_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt,668 const void *buf, size_t size)669 {670 disk_t *disk = bd_srv_disk(bd);671 size_t maxnb;672 size_t nb;673 errno_t rc;674 675 if (disk->dev_type != ata_reg_dev)676 return ENOTSUP;677 678 if (size < cnt * disk->block_size)679 return EINVAL;680 681 /* Maximum number of blocks to transfer at the same time */682 maxnb = ata_disk_maxnb(disk);683 while (cnt > 0) {684 nb = min(maxnb, cnt);685 rc = ata_rcmd_write(disk, ba, nb, buf);686 if (rc != EOK)687 return rc;688 689 ba += nb;690 cnt -= nb;691 buf += disk->block_size * nb;692 }693 694 return EOK;695 }696 697 /** Get device block size. */698 static errno_t ata_bd_get_block_size(bd_srv_t *bd, size_t *rbsize)699 {700 disk_t *disk = bd_srv_disk(bd);701 702 *rbsize = disk->block_size;703 return EOK;704 }705 706 /** Get device number of blocks. */707 static errno_t ata_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb)708 {709 disk_t *disk = bd_srv_disk(bd);710 711 *rnb = disk->blocks;712 return EOK;713 }714 715 /** Flush cache. */716 static errno_t ata_bd_sync_cache(bd_srv_t *bd, uint64_t ba, size_t cnt)717 {718 disk_t *disk = bd_srv_disk(bd);719 720 /* ATA cannot flush just some blocks, we just flush everything. */721 (void)ba;722 (void)cnt;723 724 return ata_rcmd_flush_cache(disk);725 }726 727 /** PIO data-in command protocol. */728 static errno_t ata_pio_data_in(disk_t *disk, void *obuf, size_t obuf_size,729 size_t blk_size, size_t nblocks)730 {731 ata_ctrl_t *ctrl = disk->ctrl;732 uint16_t data;733 size_t i;734 size_t bidx;735 uint8_t status;736 errno_t rc;737 738 assert(nblocks > 0);739 assert(blk_size % 2 == 0);740 741 bidx = 0;742 while (nblocks > 0) {743 if (ctrl->irq >= 0)744 rc = wait_irq(ctrl, &status, TIMEOUT_BSY);745 else746 rc = wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY);747 748 if (rc != EOK) {749 ddf_msg(LVL_DEBUG, "wait_irq/wait_status failed");750 return EIO;751 }752 753 if ((status & SR_DRQ) == 0) {754 ddf_msg(LVL_DEBUG, "DRQ == 0");755 break;756 }757 758 /* Read data from the device buffer. */759 for (i = 0; i < blk_size / 2; i++) {760 data = pio_read_16(&ctrl->cmd->data_port);761 ((uint16_t *) obuf)[bidx++] = data;762 }763 764 --nblocks;765 }766 767 if ((status & SR_ERR) != 0) {768 ddf_msg(LVL_DEBUG, "status & SR_ERR != 0");769 return EIO;770 }771 if (nblocks > 0) {772 ddf_msg(LVL_DEBUG, "remaining nblocks = %zu", nblocks);773 return EIO;774 }775 776 return EOK;777 }778 779 /** PIO data-out command protocol. */780 static errno_t ata_pio_data_out(disk_t *disk, const void *buf, size_t buf_size,781 size_t blk_size, size_t nblocks)782 {783 ata_ctrl_t *ctrl = disk->ctrl;784 size_t i;785 size_t bidx;786 uint8_t status;787 errno_t rc;788 789 assert(nblocks > 0);790 assert(blk_size % 2 == 0);791 792 rc = wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY);793 if (rc != EOK)794 return EIO;795 796 bidx = 0;797 while (nblocks > 0) {798 if ((status & SR_DRQ) == 0) {799 ddf_msg(LVL_DEBUG, "pio_data_out: unexpected DRQ=0");800 break;801 }802 803 /* Write data to the device buffer. */804 for (i = 0; i < blk_size / 2; i++) {805 pio_write_16(&ctrl->cmd->data_port,806 ((uint16_t *) buf)[bidx++]);807 }808 809 if (ctrl->irq >= 0)810 rc = wait_irq(ctrl, &status, TIMEOUT_BSY);811 else812 rc = wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY);813 if (rc != EOK)814 return EIO;815 816 --nblocks;817 }818 819 if (status & SR_ERR)820 return EIO;821 if (nblocks > 0)822 return EIO;823 824 return EOK;825 }826 827 /** PIO non-data command protocol. */828 static errno_t ata_pio_nondata(disk_t *disk)829 {830 ata_ctrl_t *ctrl = disk->ctrl;831 uint8_t status;832 errno_t rc;833 834 if (ctrl->irq >= 0)835 rc = wait_irq(ctrl, &status, TIMEOUT_BSY);836 else837 rc = wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY);838 839 if (rc != EOK)840 return EIO;841 842 if (status & SR_ERR)843 return EIO;844 845 return EOK;846 }847 848 /** Issue IDENTIFY DEVICE command.849 *850 * Reads @c identify data into the provided buffer. This is used to detect851 * whether an ATA device is present and if so, to determine its parameters.852 *853 * @param disk Disk854 * @param buf Pointer to a 512-byte buffer.855 *856 * @return ETIMEOUT on timeout (this can mean the device is857 * not present). EIO if device responds with error.858 */859 static errno_t ata_identify_dev(disk_t *disk, void *buf)860 {861 ata_ctrl_t *ctrl = disk->ctrl;862 uint8_t status;863 uint8_t drv_head;864 865 drv_head = ((disk_dev_idx(disk) != 0) ? DHR_DRV : 0);866 867 if (wait_status(ctrl, 0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)868 return ETIMEOUT;869 870 pio_write_8(&ctrl->cmd->drive_head, drv_head);871 872 /*873 * Do not wait for DRDY to be set in case this is a packet device.874 * We determine whether the device is present by waiting for DRQ to be875 * set after issuing the command.876 */877 if (wait_status(ctrl, 0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)878 return ETIMEOUT;879 880 pio_write_8(&ctrl->cmd->command, CMD_IDENTIFY_DRIVE);881 882 /*883 * For probing purposes we need to wait for some status bit to become884 * active - otherwise we could be fooled just by receiving all zeroes.885 */886 if (wait_status(ctrl, SR_DRQ, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK) {887 if ((status & SR_ERR) == 0) {888 /* Probably no device at all */889 return ETIMEOUT;890 }891 }892 893 return ata_pio_data_in(disk, buf, identify_data_size,894 identify_data_size, 1);895 }896 897 /** Issue Identify Packet Device command.898 *899 * Reads @c identify data into the provided buffer. This is used to detect900 * whether an ATAPI device is present and if so, to determine its parameters.901 *902 * @param disk Disk903 * @param buf Pointer to a 512-byte buffer.904 */905 static errno_t ata_identify_pkt_dev(disk_t *disk, void *buf)906 {907 ata_ctrl_t *ctrl = disk->ctrl;908 uint8_t drv_head;909 910 drv_head = ((disk_dev_idx(disk) != 0) ? DHR_DRV : 0);911 912 if (wait_status(ctrl, 0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)913 return EIO;914 915 pio_write_8(&ctrl->cmd->drive_head, drv_head);916 917 /* For ATAPI commands we do not need to wait for DRDY. */918 if (wait_status(ctrl, 0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)919 return EIO;920 921 pio_write_8(&ctrl->cmd->command, CMD_IDENTIFY_PKT_DEV);922 923 return ata_pio_data_in(disk, buf, identify_data_size,924 identify_data_size, 1);925 }926 927 /** Issue packet command (i. e. write a command packet to the device).928 *929 * Only data-in commands are supported (e.g. inquiry, read).930 *931 * @param disk Disk932 * @param obuf Buffer for storing data read from device933 * @param obuf_size Size of obuf in bytes934 * @param rcvd_size Place to store number of bytes read or @c NULL935 *936 * @return EOK on success, EIO on error.937 */938 static errno_t ata_cmd_packet(disk_t *disk, const void *cpkt, size_t cpkt_size,939 void *obuf, size_t obuf_size, size_t *rcvd_size)940 {941 ata_ctrl_t *ctrl = disk->ctrl;942 size_t i;943 uint8_t status;944 uint8_t drv_head;945 size_t data_size;946 size_t remain;947 size_t bidx;948 uint16_t val;949 errno_t rc;950 951 fibril_mutex_lock(&ctrl->lock);952 953 /* New value for Drive/Head register */954 drv_head =955 ((disk_dev_idx(disk) != 0) ? DHR_DRV : 0);956 957 if (wait_status(ctrl, 0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) {958 fibril_mutex_unlock(&ctrl->lock);959 return EIO;960 }961 962 pio_write_8(&ctrl->cmd->drive_head, drv_head);963 964 if (wait_status(ctrl, 0, ~(SR_BSY | SR_DRQ), NULL, TIMEOUT_BSY) != EOK) {965 fibril_mutex_unlock(&ctrl->lock);966 return EIO;967 }968 969 /* Byte count <- max. number of bytes we can read in one transfer. */970 pio_write_8(&ctrl->cmd->cylinder_low, 0xfe);971 pio_write_8(&ctrl->cmd->cylinder_high, 0xff);972 973 pio_write_8(&ctrl->cmd->command, CMD_PACKET);974 975 if (wait_status(ctrl, SR_DRQ, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {976 fibril_mutex_unlock(&ctrl->lock);977 return EIO;978 }979 980 /* Write command packet. */981 for (i = 0; i < (cpkt_size + 1) / 2; i++)982 pio_write_16(&ctrl->cmd->data_port, ((uint16_t *) cpkt)[i]);983 984 bidx = 0;985 remain = obuf_size;986 while (remain > 0) {987 if (ctrl->irq >= 0)988 rc = wait_irq(ctrl, &status, TIMEOUT_BSY);989 else990 rc = wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY);991 992 if (rc != EOK) {993 fibril_mutex_unlock(&ctrl->lock);994 return EIO;995 }996 997 if ((status & SR_DRQ) == 0)998 break;999 1000 /* Read byte count. */1001 data_size = (uint16_t) pio_read_8(&ctrl->cmd->cylinder_low) +1002 ((uint16_t) pio_read_8(&ctrl->cmd->cylinder_high) << 8);1003 1004 /* Check whether data fits into output buffer. */1005 if (data_size > obuf_size) {1006 /* Output buffer is too small to store data. */1007 fibril_mutex_unlock(&ctrl->lock);1008 return EIO;1009 }1010 1011 /* Read data from the device buffer. */1012 for (i = 0; i < (data_size + 1) / 2; i++) {1013 val = pio_read_16(&ctrl->cmd->data_port);1014 ((uint16_t *) obuf)[bidx++] = val;1015 }1016 1017 remain -= data_size;1018 }1019 1020 if (ctrl->irq >= 0)1021 rc = wait_irq(ctrl, &status, TIMEOUT_BSY);1022 else1023 rc = wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY);1024 1025 fibril_mutex_unlock(&ctrl->lock);1026 1027 if (status & SR_ERR)1028 return EIO;1029 1030 if (rcvd_size != NULL)1031 *rcvd_size = obuf_size - remain;1032 return EOK;1033 }1034 1035 /** Issue ATAPI Inquiry.1036 *1037 * @param disk Disk1038 * @param obuf Buffer for storing inquiry data read from device1039 * @param obuf_size Size of obuf in bytes1040 *1041 * @return EOK on success, EIO on error.1042 */1043 static errno_t ata_pcmd_inquiry(disk_t *disk, void *obuf, size_t obuf_size,1044 size_t *rcvd_size)1045 {1046 uint8_t cpb[12];1047 scsi_cdb_inquiry_t *cp = (scsi_cdb_inquiry_t *)cpb;1048 errno_t rc;1049 1050 memset(cpb, 0, sizeof(cpb));1051 1052 /*1053 * For SFF 8020 compliance the inquiry must be padded to 12 bytes1054 * and allocation length must fit in one byte.1055 */1056 cp->op_code = SCSI_CMD_INQUIRY;1057 1058 /* Allocation length */1059 cp->alloc_len = host2uint16_t_be(min(obuf_size, 0xff));1060 1061 rc = ata_cmd_packet(disk, cpb, sizeof(cpb), obuf, obuf_size, rcvd_size);1062 if (rc != EOK)1063 return rc;1064 1065 return EOK;1066 }1067 1068 /** Issue ATAPI read capacity(10) command.1069 *1070 * @param disk Disk1071 * @param nblocks Place to store number of blocks1072 * @param block_size Place to store block size1073 *1074 * @return EOK on success, EIO on error.1075 */1076 static errno_t ata_pcmd_read_capacity(disk_t *disk, uint64_t *nblocks,1077 size_t *block_size)1078 {1079 scsi_cdb_read_capacity_10_t cdb;1080 scsi_read_capacity_10_data_t data;1081 size_t rsize;1082 errno_t rc;1083 1084 memset(&cdb, 0, sizeof(cdb));1085 cdb.op_code = SCSI_CMD_READ_CAPACITY_10;1086 1087 rc = ata_cmd_packet(disk, &cdb, sizeof(cdb), &data, sizeof(data), &rsize);1088 if (rc != EOK)1089 return rc;1090 1091 if (rsize != sizeof(data))1092 return EIO;1093 1094 *nblocks = uint32_t_be2host(data.last_lba) + 1;1095 *block_size = uint32_t_be2host(data.block_size);1096 1097 return EOK;1098 }1099 1100 /** Issue ATAPI read(12) command.1101 *1102 * Output buffer must be large enough to hold the data, otherwise the1103 * function will fail.1104 *1105 * @param disk Disk1106 * @param ba Starting block address1107 * @param cnt Number of blocks to read1108 * @param obuf Buffer for storing inquiry data read from device1109 * @param obuf_size Size of obuf in bytes1110 *1111 * @return EOK on success, EIO on error.1112 */1113 static errno_t ata_pcmd_read_12(disk_t *disk, uint64_t ba, size_t cnt,1114 void *obuf, size_t obuf_size)1115 {1116 scsi_cdb_read_12_t cp;1117 errno_t rc;1118 1119 if (ba > UINT32_MAX)1120 return EINVAL;1121 1122 memset(&cp, 0, sizeof(cp));1123 1124 cp.op_code = SCSI_CMD_READ_12;1125 cp.lba = host2uint32_t_be(ba);1126 cp.xfer_len = host2uint32_t_be(cnt);1127 1128 rc = ata_cmd_packet(disk, &cp, sizeof(cp), obuf, obuf_size, NULL);1129 if (rc != EOK)1130 return rc;1131 1132 return EOK;1133 }1134 1135 /** Issue ATAPI read TOC command.1136 *1137 * Read TOC in 'multi-session' format (first and last session number1138 * with last session LBA).1139 *1140 * http://suif.stanford.edu/~csapuntz/specs/INF-8020.PDF page 1711141 *1142 * Output buffer must be large enough to hold the data, otherwise the1143 * function will fail.1144 *1145 * @param disk Disk1146 * @param session Starting session1147 * @param obuf Buffer for storing inquiry data read from device1148 * @param obuf_size Size of obuf in bytes1149 *1150 * @return EOK on success, EIO on error.1151 */1152 static errno_t ata_pcmd_read_toc(disk_t *disk, uint8_t session, void *obuf,1153 size_t obuf_size)1154 {1155 uint8_t cpb[12];1156 scsi_cdb_read_toc_t *cp = (scsi_cdb_read_toc_t *)cpb;1157 errno_t rc;1158 1159 memset(cpb, 0, sizeof(cpb));1160 1161 cp->op_code = SCSI_CMD_READ_TOC;1162 cp->msf = 0;1163 cp->format = 0x01; /* 0x01 = multi-session mode */1164 cp->track_sess_no = session;1165 cp->alloc_len = host2uint16_t_be(obuf_size);1166 cp->control = 0x40; /* 0x01 = multi-session mode (shifted to MSB) */1167 1168 rc = ata_cmd_packet(disk, cpb, sizeof(cpb), obuf, obuf_size, NULL);1169 if (rc != EOK)1170 return rc;1171 1172 return EOK;1173 }1174 1175 /** Read a physical block from the device.1176 *1177 * @param disk Disk1178 * @param ba Address the first block.1179 * @param cnt Number of blocks to transfer.1180 * @param buf Buffer for holding the data.1181 *1182 * @return EOK on success, EIO on error.1183 */1184 static errno_t ata_rcmd_read(disk_t *disk, uint64_t ba, size_t blk_cnt,1185 void *buf)1186 {1187 ata_ctrl_t *ctrl = disk->ctrl;1188 uint8_t drv_head;1189 block_coord_t bc;1190 errno_t rc;1191 1192 /* Silence warning. */1193 memset(&bc, 0, sizeof(bc));1194 1195 /* Compute block coordinates. */1196 if (coord_calc(disk, ba, &bc) != EOK) {1197 ddf_msg(LVL_NOTE, "ata_rcmd_read() -> coord_calc failed");1198 return EINVAL;1199 }1200 1201 /* New value for Drive/Head register */1202 drv_head =1203 ((disk_dev_idx(disk) != 0) ? DHR_DRV : 0) |1204 ((disk->amode != am_chs) ? DHR_LBA : 0) |1205 (bc.h & 0x0f);1206 1207 fibril_mutex_lock(&ctrl->lock);1208 1209 /* Program a Read Sectors operation. */1210 1211 if (wait_status(ctrl, 0, ~SR_BSY, NULL, TIMEOUT_BSY) != EOK) {1212 fibril_mutex_unlock(&ctrl->lock);1213 ddf_msg(LVL_NOTE, "ata_rcmd_read() -> wait_status failed");1214 return EIO;1215 }1216 1217 pio_write_8(&ctrl->cmd->drive_head, drv_head);1218 1219 if (wait_status(ctrl, SR_DRDY, ~SR_BSY, NULL, TIMEOUT_DRDY) != EOK) {1220 fibril_mutex_unlock(&ctrl->lock);1221 ddf_msg(LVL_NOTE, "ata_rcmd_read() -> wait_status 2 failed");1222 return EIO;1223 }1224 1225 /* Program block coordinates into the device. */1226 coord_sc_program(ctrl, &bc, blk_cnt);1227 1228 pio_write_8(&ctrl->cmd->command, disk->amode == am_lba48 ?1229 CMD_READ_SECTORS_EXT : CMD_READ_SECTORS);1230 1231 rc = ata_pio_data_in(disk, buf, blk_cnt * disk->block_size,1232 disk->block_size, blk_cnt);1233 1234 fibril_mutex_unlock(&ctrl->lock);1235 1236 if (rc != EOK)1237 ddf_msg(LVL_NOTE, "ata_rcmd_read() -> pio_data_in->%d", rc);1238 return rc;1239 }1240 1241 /** Write a physical block to the device.1242 *1243 * @param disk Disk1244 * @param ba Address of the first block.1245 * @param cnt Number of blocks to transfer.1246 * @param buf Buffer holding the data to write.1247 *1248 * @return EOK on success, EIO on error.1249 */1250 static errno_t ata_rcmd_write(disk_t *disk, uint64_t ba, size_t cnt,1251 const void *buf)1252 {1253 ata_ctrl_t *ctrl = disk->ctrl;1254 uint8_t drv_head;1255 block_coord_t bc;1256 errno_t rc;1257 1258 /* Silence warning. */1259 memset(&bc, 0, sizeof(bc));1260 1261 /* Compute block coordinates. */1262 if (coord_calc(disk, ba, &bc) != EOK)1263 return EINVAL;1264 1265 /* New value for Drive/Head register */1266 drv_head =1267 ((disk_dev_idx(disk) != 0) ? DHR_DRV : 0) |1268 ((disk->amode != am_chs) ? DHR_LBA : 0) |1269 (bc.h & 0x0f);1270 1271 fibril_mutex_lock(&ctrl->lock);1272 1273 /* Program a Write Sectors operation. */1274 1275 if (wait_status(ctrl, 0, ~SR_BSY, NULL, TIMEOUT_BSY) != EOK) {1276 fibril_mutex_unlock(&ctrl->lock);1277 return EIO;1278 }1279 1280 pio_write_8(&ctrl->cmd->drive_head, drv_head);1281 1282 if (wait_status(ctrl, SR_DRDY, ~SR_BSY, NULL, TIMEOUT_DRDY) != EOK) {1283 fibril_mutex_unlock(&ctrl->lock);1284 return EIO;1285 }1286 1287 /* Program block coordinates into the device. */1288 coord_sc_program(ctrl, &bc, cnt);1289 1290 pio_write_8(&ctrl->cmd->command, disk->amode == am_lba48 ?1291 CMD_WRITE_SECTORS_EXT : CMD_WRITE_SECTORS);1292 1293 rc = ata_pio_data_out(disk, buf, cnt * disk->block_size,1294 disk->block_size, cnt);1295 1296 fibril_mutex_unlock(&ctrl->lock);1297 return rc;1298 }1299 1300 /** Flush cached data to nonvolatile storage.1301 *1302 * @param disk Disk1303 *1304 * @return EOK on success, EIO on error.1305 */1306 static errno_t ata_rcmd_flush_cache(disk_t *disk)1307 {1308 ata_ctrl_t *ctrl = disk->ctrl;1309 uint8_t drv_head;1310 errno_t rc;1311 1312 /* New value for Drive/Head register */1313 drv_head =1314 (disk_dev_idx(disk) != 0) ? DHR_DRV : 0;1315 1316 fibril_mutex_lock(&ctrl->lock);1317 1318 /* Program a Flush Cache operation. */1319 1320 if (wait_status(ctrl, 0, ~SR_BSY, NULL, TIMEOUT_BSY) != EOK) {1321 fibril_mutex_unlock(&ctrl->lock);1322 return EIO;1323 }1324 1325 pio_write_8(&ctrl->cmd->drive_head, drv_head);1326 1327 if (wait_status(ctrl, SR_DRDY, ~SR_BSY, NULL, TIMEOUT_DRDY) != EOK) {1328 fibril_mutex_unlock(&ctrl->lock);1329 return EIO;1330 }1331 1332 pio_write_8(&ctrl->cmd->command, CMD_FLUSH_CACHE);1333 1334 rc = ata_pio_nondata(disk);1335 1336 fibril_mutex_unlock(&ctrl->lock);1337 return rc;1338 }1339 1340 /** Get the maximum number of blocks to be transferred in one I/O1341 *1342 * @param d Disk1343 * @return Maximum number of blocks1344 */1345 static size_t ata_disk_maxnb(disk_t *d)1346 {1347 size_t maxnb;1348 1349 maxnb = 0;1350 1351 if (d->dev_type == ata_pkt_dev) {1352 /* Could be more depending on SCSI command support */1353 maxnb = 0x100;1354 } else {1355 switch (d->amode) {1356 case am_chs:1357 case am_lba28:1358 maxnb = 0x100;1359 break;1360 case am_lba48:1361 maxnb = 0x10000;1362 break;1363 }1364 }1365 1366 /*1367 * If using DMA, this needs to be further restricted not to1368 * exceed DMA buffer size.1369 */1370 return maxnb;1371 }1372 1373 /** Calculate block coordinates.1374 *1375 * Calculates block coordinates in the best coordinate system supported1376 * by the device. These can be later programmed into the device using1377 * @c coord_sc_program().1378 *1379 * @return EOK on success or EINVAL if block index is past end of device.1380 */1381 static errno_t coord_calc(disk_t *d, uint64_t ba, block_coord_t *bc)1382 {1383 uint64_t c;1384 uint64_t idx;1385 1386 /* Check device bounds. */1387 if (ba >= d->blocks)1388 return EINVAL;1389 1390 bc->amode = d->amode;1391 1392 switch (d->amode) {1393 case am_chs:1394 /* Compute CHS coordinates. */1395 c = ba / (d->geom.heads * d->geom.sectors);1396 idx = ba % (d->geom.heads * d->geom.sectors);1397 1398 bc->cyl_lo = c & 0xff;1399 bc->cyl_hi = (c >> 8) & 0xff;1400 bc->h = (idx / d->geom.sectors) & 0x0f;1401 bc->sector = (1 + (idx % d->geom.sectors)) & 0xff;1402 break;1403 1404 case am_lba28:1405 /* Compute LBA-28 coordinates. */1406 bc->c0 = ba & 0xff; /* bits 0-7 */1407 bc->c1 = (ba >> 8) & 0xff; /* bits 8-15 */1408 bc->c2 = (ba >> 16) & 0xff; /* bits 16-23 */1409 bc->h = (ba >> 24) & 0x0f; /* bits 24-27 */1410 break;1411 1412 case am_lba48:1413 /* Compute LBA-48 coordinates. */1414 bc->c0 = ba & 0xff; /* bits 0-7 */1415 bc->c1 = (ba >> 8) & 0xff; /* bits 8-15 */1416 bc->c2 = (ba >> 16) & 0xff; /* bits 16-23 */1417 bc->c3 = (ba >> 24) & 0xff; /* bits 24-31 */1418 bc->c4 = (ba >> 32) & 0xff; /* bits 32-39 */1419 bc->c5 = (ba >> 40) & 0xff; /* bits 40-47 */1420 bc->h = 0;1421 break;1422 }1423 1424 return EOK;1425 }1426 1427 /** Program block coordinates and sector count into ATA registers.1428 *1429 * Note that bc->h must be programmed separately into the device/head register.1430 *1431 * @param ctrl Controller1432 * @param bc Block coordinates1433 * @param scnt Sector count1434 */1435 static void coord_sc_program(ata_ctrl_t *ctrl, const block_coord_t *bc,1436 uint16_t scnt)1437 {1438 ata_cmd_t *cmd = ctrl->cmd;1439 1440 if (bc->amode == am_lba48) {1441 /* Write high-order bits. */1442 pio_write_8(&cmd->sector_count, scnt >> 8);1443 pio_write_8(&cmd->sector_number, bc->c3);1444 pio_write_8(&cmd->cylinder_low, bc->c4);1445 pio_write_8(&cmd->cylinder_high, bc->c5);1446 }1447 1448 /* Write low-order bits. */1449 pio_write_8(&cmd->sector_count, scnt & 0x00ff);1450 pio_write_8(&cmd->sector_number, bc->c0);1451 pio_write_8(&cmd->cylinder_low, bc->c1);1452 pio_write_8(&cmd->cylinder_high, bc->c2);1453 }1454 1455 /** Wait until some status bits are set and some are reset.1456 *1457 * Example: wait_status(ctrl, SR_DRDY, ~SR_BSY, ...) waits for SR_DRDY to become1458 * set and SR_BSY to become reset.1459 *1460 * @param ctrl Controller1461 * @param set Combination if bits which must be all set.1462 * @param n_reset Negated combination of bits which must be all reset.1463 * @param pstatus Pointer where to store last read status or NULL.1464 * @param timeout Timeout in 10ms units.1465 *1466 * @return EOK on success, EIO on timeout.1467 */1468 static errno_t wait_status(ata_ctrl_t *ctrl, unsigned set, unsigned n_reset,1469 uint8_t *pstatus, unsigned timeout)1470 {1471 uint8_t status;1472 int cnt;1473 1474 status = pio_read_8(&ctrl->cmd->status);1475 1476 /*1477 * This is crude, yet simple. First try with 1us delays1478 * (most likely the device will respond very fast). If not,1479 * start trying every 10 ms.1480 */1481 1482 cnt = 100;1483 while ((status & ~n_reset) != 0 || (status & set) != set) {1484 --cnt;1485 if (cnt <= 0)1486 break;1487 1488 status = pio_read_8(&ctrl->cmd->status);1489 }1490 1491 cnt = timeout;1492 while ((status & ~n_reset) != 0 || (status & set) != set) {1493 fibril_usleep(10000);1494 --cnt;1495 if (cnt <= 0)1496 break;1497 1498 status = pio_read_8(&ctrl->cmd->status);1499 }1500 1501 if (pstatus)1502 *pstatus = status;1503 1504 if (cnt == 0)1505 return EIO;1506 1507 return EOK;1508 }1509 1510 /** Wait for IRQ and return status.1511 *1512 * @param ctrl Controller1513 * @param pstatus Pointer where to store last read status or NULL.1514 * @param timeout Timeout in 10ms units.1515 *1516 * @return EOK on success, EIO on timeout.1517 */1518 static errno_t wait_irq(ata_ctrl_t *ctrl, uint8_t *pstatus, unsigned timeout)1519 {1520 fibril_mutex_lock(&ctrl->irq_lock);1521 while (!ctrl->irq_fired)1522 fibril_condvar_wait(&ctrl->irq_cv, &ctrl->irq_lock);1523 1524 ctrl->irq_fired = false;1525 *pstatus = ctrl->irq_status;1526 fibril_mutex_unlock(&ctrl->irq_lock);1527 return EOK;1528 }1529 1530 304 /** Interrupt handler. 1531 305 * … … 1540 314 1541 315 status = ipc_get_arg1(call); 1542 1543 fibril_mutex_lock(&ctrl->irq_lock); 1544 ctrl->irq_fired = true; 1545 ctrl->irq_status = status; 1546 fibril_mutex_unlock(&ctrl->irq_lock); 1547 fibril_condvar_broadcast(&ctrl->irq_cv); 316 ata_channel_irq(ctrl->channel, status); 1548 317 1549 318 parent_sess = ddf_dev_parent_sess_get(dev); … … 1551 320 } 1552 321 322 /** Write the data register callback handler. 323 * 324 * @param arg Argument (ata_ctrl_t *) 325 * @param data Data 326 * @param nwords Number of words to write 327 */ 328 static void ata_write_data_16(void *arg, uint16_t *data, size_t nwords) 329 { 330 ata_ctrl_t *ctrl = (ata_ctrl_t *)arg; 331 size_t i; 332 333 for (i = 0; i < nwords; i++) 334 pio_write_16(&ctrl->cmd->data_port, data[i]); 335 } 336 337 /** Read the data register callback handler. 338 * 339 * @param arg Argument (ata_ctrl_t *) 340 * @param buf Destination buffer 341 * @param nwords Number of words to read 342 */ 343 static void ata_read_data_16(void *arg, uint16_t *buf, size_t nwords) 344 { 345 ata_ctrl_t *ctrl = (ata_ctrl_t *)arg; 346 size_t i; 347 348 for (i = 0; i < nwords; i++) 349 buf[i] = pio_read_16(&ctrl->cmd->data_port); 350 } 351 352 /** Write command register callback handler. 353 * 354 * @param arg Argument (ata_ctrl_t *) 355 * @param off Register offset 356 * @param value Value to write to command register 357 */ 358 static void ata_write_cmd_8(void *arg, uint16_t off, uint8_t value) 359 { 360 ata_ctrl_t *ctrl = (ata_ctrl_t *)arg; 361 362 pio_write_8(((ioport8_t *)ctrl->cmd) + off, value); 363 } 364 365 /** Read command register callback handler. 366 * 367 * @param arg Argument (ata_ctrl_t *) 368 * @param off Register offset 369 * @return value Value read from command register 370 */ 371 static uint8_t ata_read_cmd_8(void *arg, uint16_t off) 372 { 373 ata_ctrl_t *ctrl = (ata_ctrl_t *)arg; 374 375 return pio_read_8(((ioport8_t *)ctrl->cmd) + off); 376 } 377 378 /** Write control register callback handler. 379 * 380 * @param arg Argument (ata_ctrl_t *) 381 * @param off Register offset 382 * @param value Value to write to control register 383 */ 384 static void ata_write_ctl_8(void *arg, uint16_t off, uint8_t value) 385 { 386 ata_ctrl_t *ctrl = (ata_ctrl_t *)arg; 387 388 pio_write_8(((ioport8_t *)ctrl->ctl) + off, value); 389 } 390 391 /** Read control register callback handler. 392 * 393 * @param arg Argument (ata_ctrl_t *) 394 * @param off Register offset 395 * @return value Value read from control register 396 */ 397 static uint8_t ata_read_ctl_8(void *arg, uint16_t off) 398 { 399 ata_ctrl_t *ctrl = (ata_ctrl_t *)arg; 400 401 return pio_read_8(((ioport8_t *)ctrl->ctl) + off); 402 } 403 404 /** Enable IRQ callback handler 405 * 406 * @param arg Argument (ata_ctrl_t *) 407 * @return EOK on success or an error code 408 */ 409 static errno_t ata_irq_enable(void *arg) 410 { 411 ata_ctrl_t *ctrl = (ata_ctrl_t *)arg; 412 async_sess_t *parent_sess; 413 errno_t rc; 414 415 ddf_msg(LVL_DEBUG, "Enable IRQ"); 416 417 parent_sess = ddf_dev_parent_sess_get(ctrl->dev); 418 419 rc = hw_res_enable_interrupt(parent_sess, ctrl->irq); 420 if (rc != EOK) { 421 ddf_msg(LVL_ERROR, "Error enabling IRQ."); 422 (void) unregister_interrupt_handler(ctrl->dev, 423 ctrl->ihandle); 424 return rc; 425 } 426 427 return EOK; 428 } 429 430 /** Disable IRQ callback handler 431 * 432 * @param arg Argument (ata_ctrl_t *) 433 * @return EOK on success or an error code 434 */ 435 static errno_t ata_irq_disable(void *arg) 436 { 437 ata_ctrl_t *ctrl = (ata_ctrl_t *)arg; 438 async_sess_t *parent_sess; 439 errno_t rc; 440 441 ddf_msg(LVL_DEBUG, "Disable IRQ"); 442 443 parent_sess = ddf_dev_parent_sess_get(ctrl->dev); 444 445 rc = hw_res_disable_interrupt(parent_sess, ctrl->irq); 446 if (rc != EOK) { 447 ddf_msg(LVL_ERROR, "Error enabling IRQ."); 448 (void) unregister_interrupt_handler(ctrl->dev, 449 ctrl->ihandle); 450 return rc; 451 } 452 453 return EOK; 454 } 455 456 /** Add ATA device callback handler. 457 * 458 * @param arg Argument (ata_ctrl_t *) 459 * @param idx Device index 460 * $param charg Connection handler argument 461 * @return EOK on success or an error code 462 */ 463 static errno_t ata_add_device(void *arg, unsigned idx, void *charg) 464 { 465 ata_ctrl_t *ctrl = (ata_ctrl_t *)arg; 466 return ata_fun_create(ctrl, idx, charg); 467 } 468 469 /** Remove ATA device callback handler. 470 * 471 * @param arg Argument (ata_ctrl_t *) 472 * @param idx Device index 473 * @return EOK on success or an error code 474 */ 475 static errno_t ata_remove_device(void *arg, unsigned idx) 476 { 477 ata_ctrl_t *ctrl = (ata_ctrl_t *)arg; 478 return ata_fun_remove(ctrl, idx); 479 } 480 481 /** Debug message callback handler. 482 * 483 * @param arg Argument (ata_ctrl_t *) 484 * @param msg Message 485 */ 486 static void ata_msg_debug(void *arg, char *msg) 487 { 488 (void)arg; 489 ddf_msg(LVL_DEBUG, "%s", msg); 490 } 491 492 /** Notice message callback handler. 493 * 494 * @param arg Argument (ata_ctrl_t *) 495 * @param msg Message 496 */ 497 static void ata_msg_note(void *arg, char *msg) 498 { 499 (void)arg; 500 ddf_msg(LVL_NOTE, "%s", msg); 501 } 502 503 /** Warning message callback handler. 504 * 505 * @param arg Argument (ata_ctrl_t *) 506 * @param msg Message 507 */ 508 static void ata_msg_warn(void *arg, char *msg) 509 { 510 (void)arg; 511 ddf_msg(LVL_WARN, "%s", msg); 512 } 513 514 /** Error message callback handler. 515 * 516 * @param arg Argument (ata_ctrl_t *) 517 * @param msg Message 518 */ 519 static void ata_msg_error(void *arg, char *msg) 520 { 521 (void)arg; 522 ddf_msg(LVL_ERROR, "%s", msg); 523 } 524 1553 525 /** 1554 526 * @} -
uspace/drv/block/ata_bd/ata_bd.h
r64cf7a3 r2791fbb7 36 36 #define __ATA_BD_H__ 37 37 38 #include <a sync.h>39 #include < bd_srv.h>38 #include <ata/ata.h> 39 #include <ata/ata_hw.h> 40 40 #include <ddf/driver.h> 41 41 #include <fibril_synch.h> 42 42 #include <stdbool.h> 43 #include <str.h>44 43 #include <stdint.h> 45 #include <stddef.h>46 #include "ata_hw.h"47 44 48 45 #define NAME "ata_bd" … … 54 51 int irq; /**< IRQ */ 55 52 } ata_hwres_t; 56 57 /** Timeout definitions. Unit is 10 ms. */58 enum ata_timeout {59 TIMEOUT_PROBE = 100, /* 1 s */60 TIMEOUT_BSY = 100, /* 1 s */61 TIMEOUT_DRDY = 1000 /* 10 s */62 };63 64 enum ata_dev_type {65 ata_reg_dev, /* Register device (no packet feature set support) */66 ata_pkt_dev /* Packet device (supports packet feature set). */67 };68 69 /** Register device block addressing mode. */70 enum rd_addr_mode {71 am_chs, /**< CHS block addressing */72 am_lba28, /**< LBA-28 block addressing */73 am_lba48 /**< LBA-48 block addressing */74 };75 76 /** Block coordinates */77 typedef struct {78 enum rd_addr_mode amode;79 80 union {81 /** CHS coordinates */82 struct {83 uint8_t sector;84 uint8_t cyl_lo;85 uint8_t cyl_hi;86 };87 /** LBA coordinates */88 struct {89 uint8_t c0;90 uint8_t c1;91 uint8_t c2;92 uint8_t c3;93 uint8_t c4;94 uint8_t c5;95 };96 };97 98 /** Lower 4 bits for device/head register */99 uint8_t h;100 } block_coord_t;101 102 /** ATA device state structure. */103 typedef struct {104 bool present;105 struct ata_ctrl *ctrl;106 struct ata_fun *afun;107 108 /** Device type */109 enum ata_dev_type dev_type;110 111 /** Addressing mode to use (if register device) */112 enum rd_addr_mode amode;113 114 /*115 * Geometry. Only valid if operating in CHS mode.116 */117 struct {118 unsigned heads;119 unsigned cylinders;120 unsigned sectors;121 } geom;122 123 uint64_t blocks;124 size_t block_size;125 126 char model[STR_BOUNDS(40) + 1];127 128 int disk_id;129 } disk_t;130 53 131 54 /** ATA controller */ … … 147 70 cap_irq_handle_t ihandle; 148 71 149 /** Per-disk state. */150 disk_t disk[MAX_DISKS];151 152 72 /** Synchronize controller access */ 153 73 fibril_mutex_t lock; 154 /** Synchronize access to irq_fired/irq_status */155 fibril_mutex_t irq_lock;156 /** Signalled by IRQ handler */157 fibril_condvar_t irq_cv;158 /** Set to true when interrupt occurs */159 bool irq_fired;160 74 /** Value of status register read by interrupt handler */ 161 75 uint8_t irq_status; 76 77 /** Libata ATA channel */ 78 ata_channel_t *channel; 79 struct ata_fun *fun[2]; 162 80 } ata_ctrl_t; 163 81 164 82 typedef struct ata_fun { 165 83 ddf_fun_t *fun; 166 disk_t *disk; 167 bd_srvs_t bds; 84 void *charg; 168 85 } ata_fun_t; 169 86 … … 172 89 extern errno_t ata_ctrl_gone(ata_ctrl_t *); 173 90 174 extern bd_ops_t ata_bd_ops;175 176 91 #endif 177 92 -
uspace/drv/block/ata_bd/main.c
r64cf7a3 r2791fbb7 157 157 } 158 158 159 static char *ata_fun_name( disk_t *disk)159 static char *ata_fun_name(unsigned idx) 160 160 { 161 161 char *fun_name; 162 162 163 if (asprintf(&fun_name, "d%u", disk->disk_id) < 0)163 if (asprintf(&fun_name, "d%u", idx) < 0) 164 164 return NULL; 165 165 … … 167 167 } 168 168 169 errno_t ata_fun_create(disk_t *disk) 170 { 171 ata_ctrl_t *ctrl = disk->ctrl; 169 errno_t ata_fun_create(ata_ctrl_t *ctrl, unsigned idx, void *charg) 170 { 172 171 errno_t rc; 173 172 char *fun_name = NULL; … … 176 175 bool bound = false; 177 176 178 fun_name = ata_fun_name( disk);177 fun_name = ata_fun_name(idx); 179 178 if (fun_name == NULL) { 180 179 ddf_msg(LVL_ERROR, "Out of memory."); … … 199 198 200 199 afun->fun = fun; 201 afun->disk = disk; 202 203 bd_srvs_init(&afun->bds); 204 afun->bds.ops = &ata_bd_ops; 205 afun->bds.sarg = disk; 200 afun->charg = charg; 206 201 207 202 /* Set up a connection handler. */ … … 225 220 226 221 free(fun_name); 227 disk->afun = afun;228 222 return EOK; 229 223 error: … … 238 232 } 239 233 240 errno_t ata_fun_remove( disk_t *disk)234 errno_t ata_fun_remove(ata_ctrl_t *ctrl, unsigned idx) 241 235 { 242 236 errno_t rc; 243 237 char *fun_name; 244 245 if (disk->afun == NULL) 246 return EOK; 247 248 fun_name = ata_fun_name(disk); 238 ata_fun_t *afun = ctrl->fun[idx]; 239 240 fun_name = ata_fun_name(idx); 249 241 if (fun_name == NULL) { 250 242 ddf_msg(LVL_ERROR, "Out of memory."); … … 253 245 } 254 246 255 ddf_msg(LVL_DEBUG, "ata_fun_remove(%p, '%s')", disk, fun_name);256 rc = ddf_fun_offline( disk->afun->fun);247 ddf_msg(LVL_DEBUG, "ata_fun_remove(%p, '%s')", afun, fun_name); 248 rc = ddf_fun_offline(afun->fun); 257 249 if (rc != EOK) { 258 250 ddf_msg(LVL_ERROR, "Error offlining function '%s'.", fun_name); … … 260 252 } 261 253 262 rc = ddf_fun_unbind( disk->afun->fun);254 rc = ddf_fun_unbind(afun->fun); 263 255 if (rc != EOK) { 264 256 ddf_msg(LVL_ERROR, "Failed unbinding function '%s'.", fun_name); … … 266 258 } 267 259 268 ddf_fun_destroy(disk->afun->fun); 269 disk->afun = NULL; 260 ddf_fun_destroy(afun->fun); 270 261 free(fun_name); 271 262 return EOK; … … 276 267 } 277 268 278 errno_t ata_fun_unbind( disk_t *disk)269 errno_t ata_fun_unbind(ata_ctrl_t *ctrl, unsigned idx) 279 270 { 280 271 errno_t rc; 281 272 char *fun_name; 282 283 if (disk->afun == NULL) 284 return EOK; 285 286 fun_name = ata_fun_name(disk); 273 ata_fun_t *afun = ctrl->fun[idx]; 274 275 fun_name = ata_fun_name(idx); 287 276 if (fun_name == NULL) { 288 277 ddf_msg(LVL_ERROR, "Out of memory."); … … 291 280 } 292 281 293 ddf_msg(LVL_DEBUG, "ata_fun_unbind(%p, '%s')", disk, fun_name);294 rc = ddf_fun_unbind( disk->afun->fun);282 ddf_msg(LVL_DEBUG, "ata_fun_unbind(%p, '%s')", afun, fun_name); 283 rc = ddf_fun_unbind(afun->fun); 295 284 if (rc != EOK) { 296 285 ddf_msg(LVL_ERROR, "Failed unbinding function '%s'.", fun_name); … … 298 287 } 299 288 300 ddf_fun_destroy(disk->afun->fun); 301 disk->afun = NULL; 289 ddf_fun_destroy(afun->fun); 302 290 free(fun_name); 303 291 return EOK; … … 338 326 } 339 327 340 /** Block device connection handler */341 328 static void ata_bd_connection(ipc_call_t *icall, void *arg) 342 329 { … … 344 331 345 332 afun = (ata_fun_t *) ddf_fun_data_get((ddf_fun_t *)arg); 346 bd_conn(icall, &afun->bds);333 ata_connection(icall, afun->charg); 347 334 } 348 335 -
uspace/drv/block/ata_bd/main.h
r64cf7a3 r2791fbb7 1 1 /* 2 * Copyright (c) 20 13Jiri Svoboda2 * Copyright (c) 2024 Jiri Svoboda 3 3 * All rights reserved. 4 4 * … … 38 38 #include "ata_bd.h" 39 39 40 extern errno_t ata_fun_create( disk_t*);41 extern errno_t ata_fun_remove( disk_t *);42 extern errno_t ata_fun_unbind( disk_t *);40 extern errno_t ata_fun_create(ata_ctrl_t *, unsigned, void *); 41 extern errno_t ata_fun_remove(ata_ctrl_t *, unsigned); 42 extern errno_t ata_fun_unbind(ata_ctrl_t *, unsigned); 43 43 44 44 #endif -
uspace/drv/block/ata_bd/meson.build
r64cf7a3 r2791fbb7 27 27 # 28 28 29 deps = [ ' scsi' ]29 deps = [ 'ata', 'scsi' ] 30 30 src = files('ata_bd.c', 'main.c') -
uspace/lib/ata/include/ata/ata_hw.h
r64cf7a3 r2791fbb7 1 1 /* 2 * Copyright (c) 20 09Jiri Svoboda2 * Copyright (c) 2024 Jiri Svoboda 3 3 * All rights reserved. 4 4 * … … 27 27 */ 28 28 29 /** @addtogroup ata_bd29 /** @addtogroup libata 30 30 * @{ 31 31 */ … … 33 33 */ 34 34 35 #ifndef __ATA_HW_H__ 36 #define __ATA_HW_H__ 37 35 #ifndef LIBATA_ATA_HW_H 36 #define LIBATA_ATA_HW_H 37 38 #include <stddef.h> 38 39 #include <stdint.h> 39 40 … … 48 49 49 50 enum { 50 MAX_D ISKS = 251 MAX_DEVICES = 2 51 52 }; 52 53 … … 96 97 }; 97 98 } ata_ctl_t; 99 100 #define REG_SECTOR_COUNT offsetof(ata_cmd_t, sector_count) 101 #define REG_SECTOR_NUMBER offsetof(ata_cmd_t, sector_number) 102 #define REG_CYLINDER_LOW offsetof(ata_cmd_t, cylinder_low) 103 #define REG_CYLINDER_HIGH offsetof(ata_cmd_t, cylinder_high) 104 #define REG_DRIVE_HEAD offsetof(ata_cmd_t, drive_head) 105 #define REG_STATUS offsetof(ata_cmd_t, status) 106 #define REG_COMMAND offsetof(ata_cmd_t, command) 98 107 99 108 enum devctl_bits { -
uspace/lib/meson.build
r64cf7a3 r2791fbb7 111 111 'virtio', 112 112 113 'ata', 113 114 'ieee80211', 114 115 'ddev',
Note:
See TracChangeset
for help on using the changeset viewer.