source: mainline/uspace/drv/block/ata_bd/ata_bd.c@ 95feb3e9

Last change on this file since 95feb3e9 was d7f7a4a, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 3 years ago

Replace some license headers with SPDX identifier

Headers are replaced using tools/transorm-copyright.sh only
when it can be matched verbatim with the license header used
throughout most of the codebase.

  • Property mode set to 100644
File size: 29.7 KB
RevLine 
[f8ef660]1/*
[d7f7a4a]2 * SPDX-FileCopyrightText: 2013 Jiri Svoboda
[f8ef660]3 *
[d7f7a4a]4 * SPDX-License-Identifier: BSD-3-Clause
[f8ef660]5 */
6
[c8ea6eca]7/** @addtogroup ata_bd
[f8ef660]8 * @{
9 */
10
11/**
12 * @file
13 * @brief ATA disk driver
14 *
[96cbd18]15 * This driver supports CHS, 28-bit and 48-bit LBA addressing, as well as
16 * PACKET devices. It only uses PIO transfers. There is no support DMA
17 * or any other fancy features such as S.M.A.R.T, removable devices, etc.
[a1f48f6]18 *
19 * This driver is based on the ATA-1, ATA-2, ATA-3 and ATA/ATAPI-4 through 7
20 * standards, as published by the ANSI, NCITS and INCITS standards bodies,
21 * which are freely available. This driver contains no vendor-specific
22 * code at this moment.
[12956e57]23 *
24 * The driver services a single controller which can have up to two disks
25 * attached.
[f8ef660]26 */
27
28#include <ddi.h>
[9f391e9]29#include <ddf/log.h>
[f8ef660]30#include <async.h>
31#include <as.h>
[4802dd7]32#include <bd_srv.h>
[1e4cada]33#include <fibril_synch.h>
[35b8bfe]34#include <scsi/mmc.h>
[c2844735]35#include <scsi/sbc.h>
[35b8bfe]36#include <scsi/spc.h>
[bb0eab1]37#include <stdint.h>
[8d2dd7f2]38#include <stdbool.h>
39#include <stdio.h>
40#include <stddef.h>
[19f857a]41#include <str.h>
[fb6f1a5]42#include <inttypes.h>
[f8ef660]43#include <errno.h>
[bb0eab1]44#include <byteorder.h>
[1ee00b7]45#include <macros.h>
[f8ef660]46
[d770deb]47#include "ata_hw.h"
[4f5caea]48#include "ata_bd.h"
[66cb7a2]49#include "main.h"
[f8ef660]50
[1313ee9]51#define NAME "ata_bd"
[1806e5d]52
[e092dc5]53/** Number of defined legacy controller base addresses. */
54#define LEGACY_CTLS 4
55
[0d247f5]56/**
57 * Size of data returned from Identify Device or Identify Packet Device
58 * command.
59 */
60static const size_t identify_data_size = 512;
[54d0ddc]61
[b7fd2a0]62static errno_t ata_bd_init_io(ata_ctrl_t *ctrl);
[66cb7a2]63static void ata_bd_fini_io(ata_ctrl_t *ctrl);
[4802dd7]64
[b7fd2a0]65static errno_t ata_bd_open(bd_srvs_t *, bd_srv_t *);
66static errno_t ata_bd_close(bd_srv_t *);
67static errno_t ata_bd_read_blocks(bd_srv_t *, uint64_t ba, size_t cnt, void *buf,
[4802dd7]68 size_t);
[b7fd2a0]69static errno_t ata_bd_read_toc(bd_srv_t *, uint8_t session, void *buf, size_t);
70static errno_t ata_bd_write_blocks(bd_srv_t *, uint64_t ba, size_t cnt,
[4802dd7]71 const void *buf, size_t);
[b7fd2a0]72static errno_t ata_bd_get_block_size(bd_srv_t *, size_t *);
73static errno_t ata_bd_get_num_blocks(bd_srv_t *, aoff64_t *);
74static errno_t ata_bd_sync_cache(bd_srv_t *, aoff64_t, size_t);
[4802dd7]75
[b7fd2a0]76static errno_t ata_rcmd_read(disk_t *disk, uint64_t ba, size_t cnt,
[f8ef660]77 void *buf);
[b7fd2a0]78static errno_t ata_rcmd_write(disk_t *disk, uint64_t ba, size_t cnt,
[d9f4c76]79 const void *buf);
[b7fd2a0]80static errno_t ata_rcmd_flush_cache(disk_t *disk);
81static errno_t disk_init(ata_ctrl_t *ctrl, disk_t *d, int disk_id);
82static errno_t ata_identify_dev(disk_t *disk, void *buf);
83static errno_t ata_identify_pkt_dev(disk_t *disk, void *buf);
84static errno_t ata_cmd_packet(disk_t *disk, const void *cpkt, size_t cpkt_size,
[c2844735]85 void *obuf, size_t obuf_size, size_t *rcvd_size);
[b7fd2a0]86static errno_t ata_pcmd_inquiry(disk_t *disk, void *obuf, size_t obuf_size,
[c2844735]87 size_t *rcvd_size);
[b7fd2a0]88static errno_t ata_pcmd_read_12(disk_t *disk, uint64_t ba, size_t cnt,
[0d247f5]89 void *obuf, size_t obuf_size);
[b7fd2a0]90static errno_t ata_pcmd_read_capacity(disk_t *disk, uint64_t *nblocks,
[c2844735]91 size_t *block_size);
[b7fd2a0]92static errno_t ata_pcmd_read_toc(disk_t *disk, uint8_t ses,
[4046b2f4]93 void *obuf, size_t obuf_size);
[a99cf073]94static void disk_print_summary(disk_t *d);
[b7fd2a0]95static errno_t coord_calc(disk_t *d, uint64_t ba, block_coord_t *bc);
[96cbd18]96static void coord_sc_program(ata_ctrl_t *ctrl, const block_coord_t *bc,
97 uint16_t scnt);
[b7fd2a0]98static errno_t wait_status(ata_ctrl_t *ctrl, unsigned set, unsigned n_reset,
[96cbd18]99 uint8_t *pstatus, unsigned timeout);
[f8ef660]100
[66cb7a2]101bd_ops_t ata_bd_ops = {
[4802dd7]102 .open = ata_bd_open,
103 .close = ata_bd_close,
104 .read_blocks = ata_bd_read_blocks,
105 .read_toc = ata_bd_read_toc,
106 .write_blocks = ata_bd_write_blocks,
107 .get_block_size = ata_bd_get_block_size,
[4abe919]108 .get_num_blocks = ata_bd_get_num_blocks,
109 .sync_cache = ata_bd_sync_cache
[4802dd7]110};
111
112static disk_t *bd_srv_disk(bd_srv_t *bd)
113{
[135486d]114 return (disk_t *)bd->srvs->sarg;
[4802dd7]115}
116
[a44abb3e]117static int disk_dev_idx(disk_t *disk)
118{
119 return (disk->disk_id & 1);
120}
121
[66cb7a2]122/** Initialize ATA controller. */
[b7fd2a0]123errno_t ata_ctrl_init(ata_ctrl_t *ctrl, ata_base_t *res)
[f8ef660]124{
[d5c1051]125 int i;
[b7fd2a0]126 errno_t rc;
[1806e5d]127 int n_disks;
[f8ef660]128
[9f391e9]129 ddf_msg(LVL_DEBUG, "ata_ctrl_init()");
[f8ef660]130
[66cb7a2]131 fibril_mutex_initialize(&ctrl->lock);
[3de67b4c]132 ctrl->cmd_physical = res->cmd;
133 ctrl->ctl_physical = res->ctl;
[e092dc5]134
[9f391e9]135 ddf_msg(LVL_NOTE, "I/O address %p/%p", (void *) ctrl->cmd_physical,
[96cbd18]136 (void *) ctrl->ctl_physical);
[f8ef660]137
[66cb7a2]138 rc = ata_bd_init_io(ctrl);
139 if (rc != EOK)
140 return rc;
[f8ef660]141
[31de325]142 for (i = 0; i < MAX_DISKS; i++) {
[eaf4e2fc]143 ddf_msg(LVL_DEBUG, "Identify drive %d...", i);
[31de325]144
[96cbd18]145 rc = disk_init(ctrl, &ctrl->disk[i], i);
[31de325]146
147 if (rc == EOK) {
[96cbd18]148 disk_print_summary(&ctrl->disk[i]);
[31de325]149 } else {
[eaf4e2fc]150 ddf_msg(LVL_DEBUG, "Not found.");
[31de325]151 }
152 }
[1806e5d]153
154 n_disks = 0;
155
156 for (i = 0; i < MAX_DISKS; i++) {
157 /* Skip unattached drives. */
[96cbd18]158 if (ctrl->disk[i].present == false)
[1806e5d]159 continue;
[66cb7a2]160
161 rc = ata_fun_create(&ctrl->disk[i]);
[1806e5d]162 if (rc != EOK) {
[9f391e9]163 ddf_msg(LVL_ERROR, "Unable to create function for "
164 "disk %d.", i);
[66cb7a2]165 goto error;
[1806e5d]166 }
167 ++n_disks;
168 }
169
170 if (n_disks == 0) {
[9f391e9]171 ddf_msg(LVL_WARN, "No disks detected.");
[eaf4e2fc]172 rc = ENOENT;
[66cb7a2]173 goto error;
[1806e5d]174 }
175
[66cb7a2]176 return EOK;
177error:
178 for (i = 0; i < MAX_DISKS; i++) {
179 if (ata_fun_remove(&ctrl->disk[i]) != EOK) {
[9f391e9]180 ddf_msg(LVL_ERROR, "Unable to clean up function for "
181 "disk %d.", i);
[66cb7a2]182 }
183 }
184 ata_bd_fini_io(ctrl);
185 return rc;
[1806e5d]186}
187
[66cb7a2]188/** Remove ATA controller. */
[b7fd2a0]189errno_t ata_ctrl_remove(ata_ctrl_t *ctrl)
[66cb7a2]190{
[d5c1051]191 int i;
[b7fd2a0]192 errno_t rc;
[66cb7a2]193
[9f391e9]194 ddf_msg(LVL_DEBUG, ": ata_ctrl_remove()");
[e092dc5]195
[66cb7a2]196 fibril_mutex_lock(&ctrl->lock);
197
198 for (i = 0; i < MAX_DISKS; i++) {
199 rc = ata_fun_remove(&ctrl->disk[i]);
200 if (rc != EOK) {
[9f391e9]201 ddf_msg(LVL_ERROR, "Unable to clean up function for "
202 "disk %d.", i);
[66cb7a2]203 return rc;
204 }
205 }
206
207 ata_bd_fini_io(ctrl);
208 fibril_mutex_unlock(&ctrl->lock);
209
210 return EOK;
211}
212
213/** Surprise removal of ATA controller. */
[b7fd2a0]214errno_t ata_ctrl_gone(ata_ctrl_t *ctrl)
[e092dc5]215{
[d5c1051]216 int i;
[b7fd2a0]217 errno_t rc;
[66cb7a2]218
[9f391e9]219 ddf_msg(LVL_DEBUG, "ata_ctrl_gone()");
[66cb7a2]220
221 fibril_mutex_lock(&ctrl->lock);
222
223 for (i = 0; i < MAX_DISKS; i++) {
224 rc = ata_fun_unbind(&ctrl->disk[i]);
225 if (rc != EOK) {
[9f391e9]226 ddf_msg(LVL_ERROR, "Unable to clean up function for "
227 "disk %d.", i);
[66cb7a2]228 return rc;
229 }
230 }
231
232 ata_bd_fini_io(ctrl);
233 fibril_mutex_unlock(&ctrl->lock);
234
235 return EOK;
[e092dc5]236}
237
[a99cf073]238/** Print one-line device summary. */
239static void disk_print_summary(disk_t *d)
240{
[4ef117f8]241 uint64_t mbytes;
[9f391e9]242 char *atype = NULL;
243 char *cap = NULL;
244 int rc;
[a99cf073]245
[7a56e33e]246 if (d->dev_type == ata_reg_dev) {
247 switch (d->amode) {
248 case am_chs:
[9f391e9]249 rc = asprintf(&atype, "CHS %u cylinders, %u heads, "
250 "%u sectors", d->geom.cylinders, d->geom.heads,
[4802dd7]251 d->geom.sectors);
[9f391e9]252 if (rc < 0) {
253 /* Out of memory */
254 atype = NULL;
255 }
[7a56e33e]256 break;
257 case am_lba28:
[9f391e9]258 atype = str_dup("LBA-28");
[7a56e33e]259 break;
260 case am_lba48:
[9f391e9]261 atype = str_dup("LBA-48");
[7a56e33e]262 break;
263 }
264 } else {
[9f391e9]265 atype = str_dup("PACKET");
[a99cf073]266 }
267
[9f391e9]268 if (atype == NULL)
269 return;
[4ef117f8]270
271 mbytes = d->blocks / (2 * 1024);
[9f391e9]272 if (mbytes > 0) {
273 rc = asprintf(&cap, " %" PRIu64 " MB.", mbytes);
274 if (rc < 0) {
275 cap = NULL;
276 goto cleanup;
277 }
278 }
[4ef117f8]279
[9f391e9]280 ddf_msg(LVL_NOTE, "%s: %s %" PRIu64 " blocks%s", d->model, atype,
281 d->blocks, cap);
282cleanup:
283 free(atype);
284 free(cap);
[a99cf073]285}
[f8ef660]286
[66cb7a2]287/** Enable device I/O. */
[b7fd2a0]288static errno_t ata_bd_init_io(ata_ctrl_t *ctrl)
[f8ef660]289{
[b7fd2a0]290 errno_t rc;
[b16e77d]291 void *vaddr;
[66cb7a2]292
[96cbd18]293 rc = pio_enable((void *) ctrl->cmd_physical, sizeof(ata_cmd_t), &vaddr);
[f8ef660]294 if (rc != EOK) {
[9f391e9]295 ddf_msg(LVL_ERROR, "Cannot initialize device I/O space.");
[f8ef660]296 return rc;
297 }
[66cb7a2]298
[96cbd18]299 ctrl->cmd = vaddr;
[66cb7a2]300
[96cbd18]301 rc = pio_enable((void *) ctrl->ctl_physical, sizeof(ata_ctl_t), &vaddr);
[f8ef660]302 if (rc != EOK) {
[9f391e9]303 ddf_msg(LVL_ERROR, "Cannot initialize device I/O space.");
[f8ef660]304 return rc;
305 }
[66cb7a2]306
[96cbd18]307 ctrl->ctl = vaddr;
[66cb7a2]308
[f8ef660]309 return EOK;
310}
311
[66cb7a2]312/** Clean up device I/O. */
313static void ata_bd_fini_io(ata_ctrl_t *ctrl)
[f8ef660]314{
[66cb7a2]315 (void) ctrl;
316 /* XXX TODO */
[f8ef660]317}
318
[0e6dce8]319/** Initialize a disk.
320 *
321 * Probes for a disk, determines its parameters and initializes
322 * the disk structure.
323 */
[b7fd2a0]324static errno_t disk_init(ata_ctrl_t *ctrl, disk_t *d, int disk_id)
[0e6dce8]325{
[b94334f]326 identify_data_t idata;
[0e6dce8]327 uint8_t model[40];
[35b8bfe]328 scsi_std_inquiry_data_t inq_data;
[c2844735]329 size_t isize;
[0e6dce8]330 uint16_t w;
[029b13c]331 uint8_t c;
332 uint16_t bc;
[c2844735]333 uint64_t nblocks;
334 size_t block_size;
[0e6dce8]335 size_t pos, len;
[b7fd2a0]336 errno_t rc;
[a1f48f6]337 unsigned i;
[0e6dce8]338
[96cbd18]339 d->ctrl = ctrl;
[4802dd7]340 d->disk_id = disk_id;
[7a56e33e]341 d->present = false;
[66cb7a2]342 d->afun = NULL;
[4802dd7]343
[7a56e33e]344 /* Try identify command. */
[882bc4b]345 rc = ata_identify_dev(d, &idata);
[7a56e33e]346 if (rc == EOK) {
347 /* Success. It's a register (non-packet) device. */
[eaf4e2fc]348 ddf_msg(LVL_DEBUG, "ATA register-only device found.");
[7a56e33e]349 d->dev_type = ata_reg_dev;
350 } else if (rc == EIO) {
351 /*
[250dbef]352 * There is something, but not a register device. Check to see
353 * whether the IDENTIFY command left the packet signature in
354 * the registers in case this is a packet device.
355 *
356 * According to the ATA specification, the LBA low and
357 * interrupt reason registers should be set to 0x01. However,
358 * there are many devices that do not follow this and only set
359 * the byte count registers. So, only check these.
[7a56e33e]360 */
[96cbd18]361 bc = ((uint16_t)pio_read_8(&ctrl->cmd->cylinder_high) << 8) |
362 pio_read_8(&ctrl->cmd->cylinder_low);
[250dbef]363
[029b13c]364 if (bc == PDEV_SIGNATURE_BC) {
[882bc4b]365 rc = ata_identify_pkt_dev(d, &idata);
[250dbef]366 if (rc == EOK) {
367 /* We have a packet device. */
368 d->dev_type = ata_pkt_dev;
369 } else {
370 return EIO;
371 }
[7a56e33e]372 } else {
373 /* Nope. Something's there, but not recognized. */
[88743b5]374 return EIO;
[7a56e33e]375 }
376 } else {
377 /* Operation timed out. That means there is no device there. */
378 return EIO;
[0e6dce8]379 }
380
[7a56e33e]381 if (d->dev_type == ata_pkt_dev) {
382 /* Packet device */
383 d->amode = 0;
384
385 d->geom.cylinders = 0;
386 d->geom.heads = 0;
387 d->geom.sectors = 0;
388
389 d->blocks = 0;
390 } else if ((idata.caps & rd_cap_lba) == 0) {
[a99cf073]391 /* Device only supports CHS addressing. */
392 d->amode = am_chs;
393
394 d->geom.cylinders = idata.cylinders;
395 d->geom.heads = idata.heads;
396 d->geom.sectors = idata.sectors;
397
398 d->blocks = d->geom.cylinders * d->geom.heads * d->geom.sectors;
[a1f48f6]399 } else if ((idata.cmd_set1 & cs1_addr48) == 0) {
400 /* Device only supports LBA-28 addressing. */
[a99cf073]401 d->amode = am_lba28;
[0e6dce8]402
[a99cf073]403 d->geom.cylinders = 0;
404 d->geom.heads = 0;
405 d->geom.sectors = 0;
406
407 d->blocks =
[1433ecda]408 (uint32_t) idata.total_lba28_0 |
[a1f48f6]409 ((uint32_t) idata.total_lba28_1 << 16);
410 } else {
411 /* Device supports LBA-48 addressing. */
412 d->amode = am_lba48;
413
414 d->geom.cylinders = 0;
415 d->geom.heads = 0;
416 d->geom.sectors = 0;
417
418 d->blocks =
[1433ecda]419 (uint64_t) idata.total_lba48_0 |
[a1f48f6]420 ((uint64_t) idata.total_lba48_1 << 16) |
[1b20da0]421 ((uint64_t) idata.total_lba48_2 << 32) |
[a1f48f6]422 ((uint64_t) idata.total_lba48_3 << 48);
[a99cf073]423 }
[0e6dce8]424
425 /*
426 * Convert model name to string representation.
427 */
428 for (i = 0; i < 20; i++) {
[b94334f]429 w = idata.model_name[i];
[0e6dce8]430 model[2 * i] = w >> 8;
431 model[2 * i + 1] = w & 0x00ff;
432 }
433
434 len = 40;
435 while (len > 0 && model[len - 1] == 0x20)
436 --len;
437
438 pos = 0;
439 for (i = 0; i < len; ++i) {
440 c = model[i];
[1433ecda]441 if (c >= 0x80)
442 c = '?';
[0e6dce8]443
444 chr_encode(c, d->model, &pos, 40);
445 }
446 d->model[pos] = '\0';
447
[88743b5]448 if (d->dev_type == ata_pkt_dev) {
449 /* Send inquiry. */
[c2844735]450 rc = ata_pcmd_inquiry(d, &inq_data, sizeof(inq_data), &isize);
451 if (rc != EOK || isize < sizeof(inq_data)) {
[9f391e9]452 ddf_msg(LVL_ERROR, "Device inquiry failed.");
[88743b5]453 d->present = false;
454 return EIO;
455 }
[0e6dce8]456
[88743b5]457 /* Check device type. */
[35b8bfe]458 if (INQUIRY_PDEV_TYPE(inq_data.pqual_devtype) != SCSI_DEV_CD_DVD)
[9f391e9]459 ddf_msg(LVL_WARN, "Peripheral device type is not CD-ROM.");
[0e6dce8]460
[c2844735]461 rc = ata_pcmd_read_capacity(d, &nblocks, &block_size);
462 if (rc != EOK) {
463 ddf_msg(LVL_ERROR, "Read capacity command failed.");
464 d->present = false;
465 return EIO;
466 }
467
468 d->blocks = nblocks;
469 d->block_size = block_size;
[0d247f5]470 } else {
471 /* Assume register Read always uses 512-byte blocks. */
472 d->block_size = 512;
[88743b5]473 }
474
475 d->present = true;
[0e6dce8]476 return EOK;
477}
478
[b7fd2a0]479static errno_t ata_bd_open(bd_srvs_t *bds, bd_srv_t *bd)
[4802dd7]480{
481 return EOK;
482}
483
[b7fd2a0]484static errno_t ata_bd_close(bd_srv_t *bd)
[4802dd7]485{
486 return EOK;
487}
[1ee00b7]488
[4802dd7]489/** Read multiple blocks from the device. */
[b7fd2a0]490static errno_t ata_bd_read_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt,
[4802dd7]491 void *buf, size_t size)
492{
493 disk_t *disk = bd_srv_disk(bd);
[b7fd2a0]494 errno_t rc;
[f8ef660]495
[4802dd7]496 if (size < cnt * disk->block_size)
497 return EINVAL;
498
[1ee00b7]499 while (cnt > 0) {
[a44abb3e]500 if (disk->dev_type == ata_reg_dev) {
501 rc = ata_rcmd_read(disk, ba, 1, buf);
502 } else {
503 rc = ata_pcmd_read_12(disk, ba, 1, buf,
[4802dd7]504 disk->block_size);
[a44abb3e]505 }
[0d247f5]506
[1ee00b7]507 if (rc != EOK)
508 return rc;
509
510 ++ba;
511 --cnt;
[4802dd7]512 buf += disk->block_size;
[1ee00b7]513 }
514
515 return EOK;
516}
517
[4802dd7]518/** Read TOC from device. */
[b7fd2a0]519static errno_t ata_bd_read_toc(bd_srv_t *bd, uint8_t session, void *buf, size_t size)
[4802dd7]520{
521 disk_t *disk = bd_srv_disk(bd);
522
[a44abb3e]523 return ata_pcmd_read_toc(disk, session, buf, size);
[4802dd7]524}
[f8ef660]525
[4802dd7]526/** Write multiple blocks to the device. */
[b7fd2a0]527static errno_t ata_bd_write_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt,
[4802dd7]528 const void *buf, size_t size)
529{
530 disk_t *disk = bd_srv_disk(bd);
[b7fd2a0]531 errno_t rc;
[f8ef660]532
[4802dd7]533 if (disk->dev_type != ata_reg_dev)
[0d247f5]534 return ENOTSUP;
535
[4802dd7]536 if (size < cnt * disk->block_size)
537 return EINVAL;
538
[1ee00b7]539 while (cnt > 0) {
[a44abb3e]540 rc = ata_rcmd_write(disk, ba, 1, buf);
[f8ef660]541 if (rc != EOK)
542 return rc;
543
[1ee00b7]544 ++ba;
545 --cnt;
[4802dd7]546 buf += disk->block_size;
[f8ef660]547 }
548
549 return EOK;
550}
551
[4802dd7]552/** Get device block size. */
[b7fd2a0]553static errno_t ata_bd_get_block_size(bd_srv_t *bd, size_t *rbsize)
[4802dd7]554{
555 disk_t *disk = bd_srv_disk(bd);
556
557 *rbsize = disk->block_size;
558 return EOK;
559}
560
561/** Get device number of blocks. */
[b7fd2a0]562static errno_t ata_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb)
[4802dd7]563{
564 disk_t *disk = bd_srv_disk(bd);
565
566 *rnb = disk->blocks;
567 return EOK;
568}
569
[4abe919]570/** Flush cache. */
[b7fd2a0]571static errno_t ata_bd_sync_cache(bd_srv_t *bd, uint64_t ba, size_t cnt)
[4abe919]572{
573 disk_t *disk = bd_srv_disk(bd);
574
575 /* ATA cannot flush just some blocks, we just flush everything. */
576 (void)ba;
577 (void)cnt;
578
579 return ata_rcmd_flush_cache(disk);
580}
581
[882bc4b]582/** PIO data-in command protocol. */
[b7fd2a0]583static errno_t ata_pio_data_in(disk_t *disk, void *obuf, size_t obuf_size,
[882bc4b]584 size_t blk_size, size_t nblocks)
585{
586 ata_ctrl_t *ctrl = disk->ctrl;
587 uint16_t data;
588 size_t i;
589 uint8_t status;
590
591 /* XXX Support multiple blocks */
592 assert(nblocks == 1);
593 assert(blk_size % 2 == 0);
594
595 if (wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK)
596 return EIO;
597
598 if ((status & SR_DRQ) != 0) {
599 /* Read data from the device buffer. */
600
601 for (i = 0; i < blk_size / 2; i++) {
602 data = pio_read_16(&ctrl->cmd->data_port);
603 ((uint16_t *) obuf)[i] = data;
604 }
605 }
606
607 if ((status & SR_ERR) != 0)
608 return EIO;
609
610 return EOK;
611}
612
613/** PIO data-out command protocol. */
[b7fd2a0]614static errno_t ata_pio_data_out(disk_t *disk, const void *buf, size_t buf_size,
[882bc4b]615 size_t blk_size, size_t nblocks)
616{
617 ata_ctrl_t *ctrl = disk->ctrl;
618 size_t i;
619 uint8_t status;
620
621 /* XXX Support multiple blocks */
622 assert(nblocks == 1);
623 assert(blk_size % 2 == 0);
624
625 if (wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK)
626 return EIO;
627
628 if ((status & SR_DRQ) != 0) {
629 /* Write data to the device buffer. */
630
631 for (i = 0; i < blk_size / 2; i++) {
632 pio_write_16(&ctrl->cmd->data_port, ((uint16_t *) buf)[i]);
633 }
634 }
635
636 if (status & SR_ERR)
637 return EIO;
638
639 return EOK;
640}
641
[4abe919]642/** PIO non-data command protocol. */
[b7fd2a0]643static errno_t ata_pio_nondata(disk_t *disk)
[4abe919]644{
645 ata_ctrl_t *ctrl = disk->ctrl;
646 uint8_t status;
647
648 if (wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK)
649 return EIO;
650
651 if (status & SR_ERR)
652 return EIO;
653
654 return EOK;
655}
656
[882bc4b]657/** Issue IDENTIFY DEVICE command.
[54d0ddc]658 *
[0e6dce8]659 * Reads @c identify data into the provided buffer. This is used to detect
660 * whether an ATA device is present and if so, to determine its parameters.
[54d0ddc]661 *
[a44abb3e]662 * @param disk Disk
[0e6dce8]663 * @param buf Pointer to a 512-byte buffer.
[7a56e33e]664 *
665 * @return ETIMEOUT on timeout (this can mean the device is
666 * not present). EIO if device responds with error.
[54d0ddc]667 */
[b7fd2a0]668static errno_t ata_identify_dev(disk_t *disk, void *buf)
[54d0ddc]669{
[96cbd18]670 ata_ctrl_t *ctrl = disk->ctrl;
[54d0ddc]671 uint8_t status;
672 uint8_t drv_head;
[f8ef660]673
[a44abb3e]674 drv_head = ((disk_dev_idx(disk) != 0) ? DHR_DRV : 0);
[54d0ddc]675
[96cbd18]676 if (wait_status(ctrl, 0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
[7a56e33e]677 return ETIMEOUT;
[31de325]678
[96cbd18]679 pio_write_8(&ctrl->cmd->drive_head, drv_head);
[54d0ddc]680
681 /*
[250dbef]682 * Do not wait for DRDY to be set in case this is a packet device.
683 * We determine whether the device is present by waiting for DRQ to be
684 * set after issuing the command.
[54d0ddc]685 */
[96cbd18]686 if (wait_status(ctrl, 0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
[7a56e33e]687 return ETIMEOUT;
[54d0ddc]688
[96cbd18]689 pio_write_8(&ctrl->cmd->command, CMD_IDENTIFY_DRIVE);
[54d0ddc]690
[96cbd18]691 if (wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK)
[7a56e33e]692 return ETIMEOUT;
[54d0ddc]693
[250dbef]694 /*
695 * If ERR is set, this may be a packet device, so return EIO to cause
696 * the caller to check for one.
697 */
[882bc4b]698 if ((status & SR_ERR) != 0)
[7a56e33e]699 return EIO;
700
[882bc4b]701 /*
702 * For probing purposes we need to wait for some status bit to become
703 * active - otherwise we could be fooled just by receiving all zeroes.
704 */
[96cbd18]705 if (wait_status(ctrl, SR_DRQ, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK)
[250dbef]706 return ETIMEOUT;
707
[882bc4b]708 return ata_pio_data_in(disk, buf, identify_data_size,
709 identify_data_size, 1);
[7a56e33e]710}
711
712/** Issue Identify Packet Device command.
713 *
714 * Reads @c identify data into the provided buffer. This is used to detect
715 * whether an ATAPI device is present and if so, to determine its parameters.
716 *
[a44abb3e]717 * @param disk Disk
[7a56e33e]718 * @param buf Pointer to a 512-byte buffer.
719 */
[b7fd2a0]720static errno_t ata_identify_pkt_dev(disk_t *disk, void *buf)
[7a56e33e]721{
[96cbd18]722 ata_ctrl_t *ctrl = disk->ctrl;
[7a56e33e]723 uint8_t drv_head;
724
[a44abb3e]725 drv_head = ((disk_dev_idx(disk) != 0) ? DHR_DRV : 0);
[7a56e33e]726
[96cbd18]727 if (wait_status(ctrl, 0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
[7a56e33e]728 return EIO;
729
[96cbd18]730 pio_write_8(&ctrl->cmd->drive_head, drv_head);
[7a56e33e]731
732 /* For ATAPI commands we do not need to wait for DRDY. */
[96cbd18]733 if (wait_status(ctrl, 0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
[7a56e33e]734 return EIO;
735
[96cbd18]736 pio_write_8(&ctrl->cmd->command, CMD_IDENTIFY_PKT_DEV);
[7a56e33e]737
[882bc4b]738 return ata_pio_data_in(disk, buf, identify_data_size,
739 identify_data_size, 1);
[54d0ddc]740}
741
[88743b5]742/** Issue packet command (i. e. write a command packet to the device).
743 *
744 * Only data-in commands are supported (e.g. inquiry, read).
745 *
[a44abb3e]746 * @param disk Disk
[88743b5]747 * @param obuf Buffer for storing data read from device
748 * @param obuf_size Size of obuf in bytes
[c2844735]749 * @param rcvd_size Place to store number of bytes read or @c NULL
[88743b5]750 *
751 * @return EOK on success, EIO on error.
752 */
[b7fd2a0]753static errno_t ata_cmd_packet(disk_t *disk, const void *cpkt, size_t cpkt_size,
[c2844735]754 void *obuf, size_t obuf_size, size_t *rcvd_size)
[88743b5]755{
[96cbd18]756 ata_ctrl_t *ctrl = disk->ctrl;
[88743b5]757 size_t i;
758 uint8_t status;
759 uint8_t drv_head;
760 size_t data_size;
761 uint16_t val;
762
[66cb7a2]763 fibril_mutex_lock(&ctrl->lock);
[88743b5]764
765 /* New value for Drive/Head register */
766 drv_head =
[a44abb3e]767 ((disk_dev_idx(disk) != 0) ? DHR_DRV : 0);
[88743b5]768
[96cbd18]769 if (wait_status(ctrl, 0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) {
[66cb7a2]770 fibril_mutex_unlock(&ctrl->lock);
[88743b5]771 return EIO;
772 }
773
[96cbd18]774 pio_write_8(&ctrl->cmd->drive_head, drv_head);
[88743b5]775
[1433ecda]776 if (wait_status(ctrl, 0, ~(SR_BSY | SR_DRQ), NULL, TIMEOUT_BSY) != EOK) {
[66cb7a2]777 fibril_mutex_unlock(&ctrl->lock);
[88743b5]778 return EIO;
779 }
780
781 /* Byte count <- max. number of bytes we can read in one transfer. */
[96cbd18]782 pio_write_8(&ctrl->cmd->cylinder_low, 0xfe);
783 pio_write_8(&ctrl->cmd->cylinder_high, 0xff);
[88743b5]784
[96cbd18]785 pio_write_8(&ctrl->cmd->command, CMD_PACKET);
[88743b5]786
[96cbd18]787 if (wait_status(ctrl, SR_DRQ, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
[66cb7a2]788 fibril_mutex_unlock(&ctrl->lock);
[88743b5]789 return EIO;
790 }
791
792 /* Write command packet. */
793 for (i = 0; i < (cpkt_size + 1) / 2; i++)
[96cbd18]794 pio_write_16(&ctrl->cmd->data_port, ((uint16_t *) cpkt)[i]);
[88743b5]795
[96cbd18]796 if (wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
[66cb7a2]797 fibril_mutex_unlock(&ctrl->lock);
[88743b5]798 return EIO;
799 }
800
801 if ((status & SR_DRQ) == 0) {
[66cb7a2]802 fibril_mutex_unlock(&ctrl->lock);
[88743b5]803 return EIO;
804 }
805
806 /* Read byte count. */
[96cbd18]807 data_size = (uint16_t) pio_read_8(&ctrl->cmd->cylinder_low) +
808 ((uint16_t) pio_read_8(&ctrl->cmd->cylinder_high) << 8);
[88743b5]809
810 /* Check whether data fits into output buffer. */
811 if (data_size > obuf_size) {
812 /* Output buffer is too small to store data. */
[66cb7a2]813 fibril_mutex_unlock(&ctrl->lock);
[88743b5]814 return EIO;
815 }
816
817 /* Read data from the device buffer. */
818 for (i = 0; i < (data_size + 1) / 2; i++) {
[96cbd18]819 val = pio_read_16(&ctrl->cmd->data_port);
[88743b5]820 ((uint16_t *) obuf)[i] = val;
821 }
822
[66cb7a2]823 fibril_mutex_unlock(&ctrl->lock);
[88743b5]824
[66cb7a2]825 if (status & SR_ERR)
826 return EIO;
[88743b5]827
[c2844735]828 if (rcvd_size != NULL)
829 *rcvd_size = data_size;
[88743b5]830 return EOK;
831}
832
[aa893e0]833/** Issue ATAPI Inquiry.
[88743b5]834 *
[a44abb3e]835 * @param disk Disk
[88743b5]836 * @param obuf Buffer for storing inquiry data read from device
837 * @param obuf_size Size of obuf in bytes
838 *
839 * @return EOK on success, EIO on error.
840 */
[b7fd2a0]841static errno_t ata_pcmd_inquiry(disk_t *disk, void *obuf, size_t obuf_size,
[c2844735]842 size_t *rcvd_size)
[88743b5]843{
[35b8bfe]844 uint8_t cpb[12];
845 scsi_cdb_inquiry_t *cp = (scsi_cdb_inquiry_t *)cpb;
[b7fd2a0]846 errno_t rc;
[88743b5]847
[35b8bfe]848 memset(cpb, 0, sizeof(cpb));
849
850 /*
851 * For SFF 8020 compliance the inquiry must be padded to 12 bytes
852 * and allocation length must fit in one byte.
853 */
854 cp->op_code = SCSI_CMD_INQUIRY;
[bb0eab1]855
[35b8bfe]856 /* Allocation length */
857 cp->alloc_len = host2uint16_t_be(min(obuf_size, 0xff));
[88743b5]858
[35b8bfe]859 rc = ata_cmd_packet(disk, cpb, sizeof(cpb), obuf, obuf_size, rcvd_size);
[c2844735]860 if (rc != EOK)
861 return rc;
862
863 return EOK;
864}
865
866/** Issue ATAPI read capacity(10) command.
867 *
868 * @param disk Disk
869 * @param nblocks Place to store number of blocks
870 * @param block_size Place to store block size
871 *
872 * @return EOK on success, EIO on error.
873 */
[b7fd2a0]874static errno_t ata_pcmd_read_capacity(disk_t *disk, uint64_t *nblocks,
[c2844735]875 size_t *block_size)
876{
877 scsi_cdb_read_capacity_10_t cdb;
878 scsi_read_capacity_10_data_t data;
879 size_t rsize;
[b7fd2a0]880 errno_t rc;
[c2844735]881
882 memset(&cdb, 0, sizeof(cdb));
883 cdb.op_code = SCSI_CMD_READ_CAPACITY_10;
884
885 rc = ata_cmd_packet(disk, &cdb, sizeof(cdb), &data, sizeof(data), &rsize);
[88743b5]886 if (rc != EOK)
887 return rc;
888
[c2844735]889 if (rsize != sizeof(data))
890 return EIO;
891
892 *nblocks = uint32_t_be2host(data.last_lba) + 1;
893 *block_size = uint32_t_be2host(data.block_size);
894
[88743b5]895 return EOK;
896}
897
[aa893e0]898/** Issue ATAPI read(12) command.
899 *
900 * Output buffer must be large enough to hold the data, otherwise the
901 * function will fail.
902 *
[a44abb3e]903 * @param disk Disk
[aa893e0]904 * @param ba Starting block address
905 * @param cnt Number of blocks to read
906 * @param obuf Buffer for storing inquiry data read from device
907 * @param obuf_size Size of obuf in bytes
908 *
909 * @return EOK on success, EIO on error.
910 */
[b7fd2a0]911static errno_t ata_pcmd_read_12(disk_t *disk, uint64_t ba, size_t cnt,
[0d247f5]912 void *obuf, size_t obuf_size)
913{
[35b8bfe]914 scsi_cdb_read_12_t cp;
[b7fd2a0]915 errno_t rc;
[0d247f5]916
[bb0eab1]917 if (ba > UINT32_MAX)
[0d247f5]918 return EINVAL;
919
[bb0eab1]920 memset(&cp, 0, sizeof(cp));
[0d247f5]921
[35b8bfe]922 cp.op_code = SCSI_CMD_READ_12;
923 cp.lba = host2uint32_t_be(ba);
924 cp.xfer_len = host2uint32_t_be(cnt);
[0d247f5]925
[c2844735]926 rc = ata_cmd_packet(disk, &cp, sizeof(cp), obuf, obuf_size, NULL);
[0d247f5]927 if (rc != EOK)
928 return rc;
929
930 return EOK;
931}
932
[4046b2f4]933/** Issue ATAPI read TOC command.
934 *
935 * Read TOC in 'multi-session' format (first and last session number
936 * with last session LBA).
937 *
938 * http://suif.stanford.edu/~csapuntz/specs/INF-8020.PDF page 171
939 *
940 * Output buffer must be large enough to hold the data, otherwise the
941 * function will fail.
942 *
[a44abb3e]943 * @param disk Disk
[4046b2f4]944 * @param session Starting session
945 * @param obuf Buffer for storing inquiry data read from device
946 * @param obuf_size Size of obuf in bytes
947 *
948 * @return EOK on success, EIO on error.
949 */
[b7fd2a0]950static errno_t ata_pcmd_read_toc(disk_t *disk, uint8_t session, void *obuf,
[4046b2f4]951 size_t obuf_size)
952{
[35b8bfe]953 uint8_t cpb[12];
954 scsi_cdb_read_toc_t *cp = (scsi_cdb_read_toc_t *)cpb;
[b7fd2a0]955 errno_t rc;
[4046b2f4]956
[35b8bfe]957 memset(cpb, 0, sizeof(cpb));
[4046b2f4]958
[35b8bfe]959 cp->op_code = SCSI_CMD_READ_TOC;
960 cp->msf = 0;
961 cp->format = 0x01; /* 0x01 = multi-session mode */
962 cp->track_sess_no = session;
963 cp->alloc_len = host2uint16_t_be(obuf_size);
964 cp->control = 0x40; /* 0x01 = multi-session mode (shifted to MSB) */
965
966 rc = ata_cmd_packet(disk, cpb, sizeof(cpb), obuf, obuf_size, NULL);
[4046b2f4]967 if (rc != EOK)
968 return rc;
[35b8bfe]969
[4046b2f4]970 return EOK;
971}
972
[882bc4b]973/** Read a physical block from the device.
[54d0ddc]974 *
[a44abb3e]975 * @param disk Disk
[1ee00b7]976 * @param ba Address the first block.
977 * @param cnt Number of blocks to transfer.
[54d0ddc]978 * @param buf Buffer for holding the data.
979 *
980 * @return EOK on success, EIO on error.
981 */
[b7fd2a0]982static errno_t ata_rcmd_read(disk_t *disk, uint64_t ba, size_t blk_cnt,
[f8ef660]983 void *buf)
984{
[96cbd18]985 ata_ctrl_t *ctrl = disk->ctrl;
[f8ef660]986 uint8_t drv_head;
[5048be7]987 block_coord_t bc;
[b7fd2a0]988 errno_t rc;
[1806e5d]989
[36e9cd1]990 /* Silence warning. */
991 memset(&bc, 0, sizeof(bc));
[f8ef660]992
[5048be7]993 /* Compute block coordinates. */
[a44abb3e]994 if (coord_calc(disk, ba, &bc) != EOK)
[f8ef660]995 return EINVAL;
996
997 /* New value for Drive/Head register */
998 drv_head =
[a44abb3e]999 ((disk_dev_idx(disk) != 0) ? DHR_DRV : 0) |
1000 ((disk->amode != am_chs) ? DHR_LBA : 0) |
[5048be7]1001 (bc.h & 0x0f);
[f8ef660]1002
[66cb7a2]1003 fibril_mutex_lock(&ctrl->lock);
[f8ef660]1004
1005 /* Program a Read Sectors operation. */
1006
[96cbd18]1007 if (wait_status(ctrl, 0, ~SR_BSY, NULL, TIMEOUT_BSY) != EOK) {
[66cb7a2]1008 fibril_mutex_unlock(&ctrl->lock);
[31de325]1009 return EIO;
1010 }
1011
[96cbd18]1012 pio_write_8(&ctrl->cmd->drive_head, drv_head);
[a7de7907]1013
[96cbd18]1014 if (wait_status(ctrl, SR_DRDY, ~SR_BSY, NULL, TIMEOUT_DRDY) != EOK) {
[66cb7a2]1015 fibril_mutex_unlock(&ctrl->lock);
[31de325]1016 return EIO;
1017 }
1018
[5048be7]1019 /* Program block coordinates into the device. */
[96cbd18]1020 coord_sc_program(ctrl, &bc, 1);
[a7de7907]1021
[96cbd18]1022 pio_write_8(&ctrl->cmd->command, disk->amode == am_lba48 ?
[1c1657c]1023 CMD_READ_SECTORS_EXT : CMD_READ_SECTORS);
[f8ef660]1024
[882bc4b]1025 rc = ata_pio_data_in(disk, buf, blk_cnt * disk->block_size,
1026 disk->block_size, blk_cnt);
[f8ef660]1027
[66cb7a2]1028 fibril_mutex_unlock(&ctrl->lock);
1029
[882bc4b]1030 return rc;
[f8ef660]1031}
1032
[54d0ddc]1033/** Write a physical block to the device.
1034 *
[a44abb3e]1035 * @param disk Disk
[1ee00b7]1036 * @param ba Address of the first block.
1037 * @param cnt Number of blocks to transfer.
[54d0ddc]1038 * @param buf Buffer holding the data to write.
1039 *
1040 * @return EOK on success, EIO on error.
1041 */
[b7fd2a0]1042static errno_t ata_rcmd_write(disk_t *disk, uint64_t ba, size_t cnt,
[d9f4c76]1043 const void *buf)
1044{
[96cbd18]1045 ata_ctrl_t *ctrl = disk->ctrl;
[d9f4c76]1046 uint8_t drv_head;
[5048be7]1047 block_coord_t bc;
[b7fd2a0]1048 errno_t rc;
[d9f4c76]1049
[36e9cd1]1050 /* Silence warning. */
1051 memset(&bc, 0, sizeof(bc));
[d9f4c76]1052
[5048be7]1053 /* Compute block coordinates. */
[a44abb3e]1054 if (coord_calc(disk, ba, &bc) != EOK)
[d9f4c76]1055 return EINVAL;
1056
1057 /* New value for Drive/Head register */
1058 drv_head =
[a44abb3e]1059 ((disk_dev_idx(disk) != 0) ? DHR_DRV : 0) |
1060 ((disk->amode != am_chs) ? DHR_LBA : 0) |
[5048be7]1061 (bc.h & 0x0f);
[d9f4c76]1062
[66cb7a2]1063 fibril_mutex_lock(&ctrl->lock);
[d9f4c76]1064
[31de325]1065 /* Program a Write Sectors operation. */
1066
[96cbd18]1067 if (wait_status(ctrl, 0, ~SR_BSY, NULL, TIMEOUT_BSY) != EOK) {
[66cb7a2]1068 fibril_mutex_unlock(&ctrl->lock);
[31de325]1069 return EIO;
1070 }
[d9f4c76]1071
[96cbd18]1072 pio_write_8(&ctrl->cmd->drive_head, drv_head);
[a7de7907]1073
[96cbd18]1074 if (wait_status(ctrl, SR_DRDY, ~SR_BSY, NULL, TIMEOUT_DRDY) != EOK) {
[66cb7a2]1075 fibril_mutex_unlock(&ctrl->lock);
[31de325]1076 return EIO;
1077 }
1078
[5048be7]1079 /* Program block coordinates into the device. */
[96cbd18]1080 coord_sc_program(ctrl, &bc, 1);
[a7de7907]1081
[96cbd18]1082 pio_write_8(&ctrl->cmd->command, disk->amode == am_lba48 ?
[1c1657c]1083 CMD_WRITE_SECTORS_EXT : CMD_WRITE_SECTORS);
[d9f4c76]1084
[882bc4b]1085 rc = ata_pio_data_out(disk, buf, cnt * disk->block_size,
1086 disk->block_size, cnt);
[d9f4c76]1087
[66cb7a2]1088 fibril_mutex_unlock(&ctrl->lock);
[882bc4b]1089 return rc;
[d9f4c76]1090}
1091
[4abe919]1092/** Flush cached data to nonvolatile storage.
1093 *
1094 * @param disk Disk
1095 *
1096 * @return EOK on success, EIO on error.
1097 */
[b7fd2a0]1098static errno_t ata_rcmd_flush_cache(disk_t *disk)
[4abe919]1099{
1100 ata_ctrl_t *ctrl = disk->ctrl;
1101 uint8_t drv_head;
[b7fd2a0]1102 errno_t rc;
[4abe919]1103
1104 /* New value for Drive/Head register */
1105 drv_head =
1106 (disk_dev_idx(disk) != 0) ? DHR_DRV : 0;
1107
1108 fibril_mutex_lock(&ctrl->lock);
1109
1110 /* Program a Flush Cache operation. */
1111
1112 if (wait_status(ctrl, 0, ~SR_BSY, NULL, TIMEOUT_BSY) != EOK) {
1113 fibril_mutex_unlock(&ctrl->lock);
1114 return EIO;
1115 }
1116
1117 pio_write_8(&ctrl->cmd->drive_head, drv_head);
1118
1119 if (wait_status(ctrl, SR_DRDY, ~SR_BSY, NULL, TIMEOUT_DRDY) != EOK) {
1120 fibril_mutex_unlock(&ctrl->lock);
1121 return EIO;
1122 }
1123
1124 pio_write_8(&ctrl->cmd->command, CMD_FLUSH_CACHE);
1125
1126 rc = ata_pio_nondata(disk);
1127
1128 fibril_mutex_unlock(&ctrl->lock);
1129 return rc;
1130}
1131
[5048be7]1132/** Calculate block coordinates.
1133 *
1134 * Calculates block coordinates in the best coordinate system supported
1135 * by the device. These can be later programmed into the device using
1136 * @c coord_sc_program().
1137 *
1138 * @return EOK on success or EINVAL if block index is past end of device.
1139 */
[b7fd2a0]1140static errno_t coord_calc(disk_t *d, uint64_t ba, block_coord_t *bc)
[5048be7]1141{
1142 uint64_t c;
1143 uint64_t idx;
1144
1145 /* Check device bounds. */
[1ee00b7]1146 if (ba >= d->blocks)
[5048be7]1147 return EINVAL;
1148
1149 bc->amode = d->amode;
1150
1151 switch (d->amode) {
1152 case am_chs:
1153 /* Compute CHS coordinates. */
[1ee00b7]1154 c = ba / (d->geom.heads * d->geom.sectors);
1155 idx = ba % (d->geom.heads * d->geom.sectors);
[5048be7]1156
1157 bc->cyl_lo = c & 0xff;
1158 bc->cyl_hi = (c >> 8) & 0xff;
1159 bc->h = (idx / d->geom.sectors) & 0x0f;
1160 bc->sector = (1 + (idx % d->geom.sectors)) & 0xff;
1161 break;
1162
1163 case am_lba28:
1164 /* Compute LBA-28 coordinates. */
[1ee00b7]1165 bc->c0 = ba & 0xff; /* bits 0-7 */
1166 bc->c1 = (ba >> 8) & 0xff; /* bits 8-15 */
1167 bc->c2 = (ba >> 16) & 0xff; /* bits 16-23 */
1168 bc->h = (ba >> 24) & 0x0f; /* bits 24-27 */
[5048be7]1169 break;
1170
1171 case am_lba48:
1172 /* Compute LBA-48 coordinates. */
[1ee00b7]1173 bc->c0 = ba & 0xff; /* bits 0-7 */
1174 bc->c1 = (ba >> 8) & 0xff; /* bits 8-15 */
1175 bc->c2 = (ba >> 16) & 0xff; /* bits 16-23 */
1176 bc->c3 = (ba >> 24) & 0xff; /* bits 24-31 */
1177 bc->c4 = (ba >> 32) & 0xff; /* bits 32-39 */
1178 bc->c5 = (ba >> 40) & 0xff; /* bits 40-47 */
[5048be7]1179 bc->h = 0;
1180 break;
1181 }
1182
1183 return EOK;
1184}
1185
1186/** Program block coordinates and sector count into ATA registers.
1187 *
1188 * Note that bc->h must be programmed separately into the device/head register.
[96cbd18]1189 *
1190 * @param ctrl Controller
1191 * @param bc Block coordinates
1192 * @param scnt Sector count
[5048be7]1193 */
[96cbd18]1194static void coord_sc_program(ata_ctrl_t *ctrl, const block_coord_t *bc,
1195 uint16_t scnt)
[5048be7]1196{
[96cbd18]1197 ata_cmd_t *cmd = ctrl->cmd;
1198
[5048be7]1199 if (bc->amode == am_lba48) {
1200 /* Write high-order bits. */
1201 pio_write_8(&cmd->sector_count, scnt >> 8);
1202 pio_write_8(&cmd->sector_number, bc->c3);
1203 pio_write_8(&cmd->cylinder_low, bc->c4);
1204 pio_write_8(&cmd->cylinder_high, bc->c5);
1205 }
1206
1207 /* Write low-order bits. */
1208 pio_write_8(&cmd->sector_count, scnt & 0x00ff);
1209 pio_write_8(&cmd->sector_number, bc->c0);
1210 pio_write_8(&cmd->cylinder_low, bc->c1);
1211 pio_write_8(&cmd->cylinder_high, bc->c2);
1212}
1213
[31de325]1214/** Wait until some status bits are set and some are reset.
[54d0ddc]1215 *
[96cbd18]1216 * Example: wait_status(ctrl, SR_DRDY, ~SR_BSY, ...) waits for SR_DRDY to become
[54d0ddc]1217 * set and SR_BSY to become reset.
1218 *
[96cbd18]1219 * @param ctrl Controller
[54d0ddc]1220 * @param set Combination if bits which must be all set.
1221 * @param n_reset Negated combination of bits which must be all reset.
[31de325]1222 * @param pstatus Pointer where to store last read status or NULL.
1223 * @param timeout Timeout in 10ms units.
1224 *
1225 * @return EOK on success, EIO on timeout.
[54d0ddc]1226 */
[b7fd2a0]1227static errno_t wait_status(ata_ctrl_t *ctrl, unsigned set, unsigned n_reset,
[96cbd18]1228 uint8_t *pstatus, unsigned timeout)
[54d0ddc]1229{
1230 uint8_t status;
[31de325]1231 int cnt;
1232
[96cbd18]1233 status = pio_read_8(&ctrl->cmd->status);
[31de325]1234
1235 /*
1236 * This is crude, yet simple. First try with 1us delays
1237 * (most likely the device will respond very fast). If not,
1238 * start trying every 10 ms.
1239 */
1240
1241 cnt = 100;
1242 while ((status & ~n_reset) != 0 || (status & set) != set) {
1243 --cnt;
[1433ecda]1244 if (cnt <= 0)
1245 break;
[31de325]1246
[96cbd18]1247 status = pio_read_8(&ctrl->cmd->status);
[31de325]1248 }
1249
1250 cnt = timeout;
1251 while ((status & ~n_reset) != 0 || (status & set) != set) {
[5f97ef44]1252 fibril_usleep(10000);
[31de325]1253 --cnt;
[1433ecda]1254 if (cnt <= 0)
1255 break;
[54d0ddc]1256
[96cbd18]1257 status = pio_read_8(&ctrl->cmd->status);
[31de325]1258 }
1259
1260 if (pstatus)
1261 *pstatus = status;
[54d0ddc]1262
[31de325]1263 if (cnt == 0)
1264 return EIO;
1265
1266 return EOK;
[54d0ddc]1267}
1268
[f8ef660]1269/**
1270 * @}
1271 */
Note: See TracBrowser for help on using the repository browser.