source: mainline/uspace/drv/block/ata_bd/ata_bd.c@ 132ab5d1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 132ab5d1 was d5c1051, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 8 years ago

"Obviously harmless" error handling tweaks.

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