source: mainline/uspace/drv/block/ata_bd/ata_bd.c@ f1c6975

Last change on this file since f1c6975 was eaf4e2fc, checked in by Jiri Svoboda <jiri@…>, 6 years ago

Make ATA driver less verbose

  • Property mode set to 100644
File size: 31.0 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
[c8ea6eca]29/** @addtogroup ata_bd
[f8ef660]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
[b7fd2a0]84static errno_t ata_bd_init_io(ata_ctrl_t *ctrl);
[66cb7a2]85static void ata_bd_fini_io(ata_ctrl_t *ctrl);
[4802dd7]86
[b7fd2a0]87static errno_t ata_bd_open(bd_srvs_t *, bd_srv_t *);
88static errno_t ata_bd_close(bd_srv_t *);
89static errno_t ata_bd_read_blocks(bd_srv_t *, uint64_t ba, size_t cnt, void *buf,
[4802dd7]90 size_t);
[b7fd2a0]91static errno_t ata_bd_read_toc(bd_srv_t *, uint8_t session, void *buf, size_t);
92static errno_t ata_bd_write_blocks(bd_srv_t *, uint64_t ba, size_t cnt,
[4802dd7]93 const void *buf, size_t);
[b7fd2a0]94static errno_t ata_bd_get_block_size(bd_srv_t *, size_t *);
95static errno_t ata_bd_get_num_blocks(bd_srv_t *, aoff64_t *);
96static errno_t ata_bd_sync_cache(bd_srv_t *, aoff64_t, size_t);
[4802dd7]97
[b7fd2a0]98static errno_t ata_rcmd_read(disk_t *disk, uint64_t ba, size_t cnt,
[f8ef660]99 void *buf);
[b7fd2a0]100static errno_t ata_rcmd_write(disk_t *disk, uint64_t ba, size_t cnt,
[d9f4c76]101 const void *buf);
[b7fd2a0]102static errno_t ata_rcmd_flush_cache(disk_t *disk);
103static errno_t disk_init(ata_ctrl_t *ctrl, disk_t *d, int disk_id);
104static errno_t ata_identify_dev(disk_t *disk, void *buf);
105static errno_t ata_identify_pkt_dev(disk_t *disk, void *buf);
106static errno_t 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);
[b7fd2a0]108static errno_t ata_pcmd_inquiry(disk_t *disk, void *obuf, size_t obuf_size,
[c2844735]109 size_t *rcvd_size);
[b7fd2a0]110static errno_t ata_pcmd_read_12(disk_t *disk, uint64_t ba, size_t cnt,
[0d247f5]111 void *obuf, size_t obuf_size);
[b7fd2a0]112static errno_t ata_pcmd_read_capacity(disk_t *disk, uint64_t *nblocks,
[c2844735]113 size_t *block_size);
[b7fd2a0]114static errno_t 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);
[b7fd2a0]117static errno_t 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);
[b7fd2a0]120static errno_t wait_status(ata_ctrl_t *ctrl, unsigned set, unsigned n_reset,
[96cbd18]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. */
[b7fd2a0]145errno_t ata_ctrl_init(ata_ctrl_t *ctrl, ata_base_t *res)
[f8ef660]146{
[d5c1051]147 int i;
[b7fd2a0]148 errno_t 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++) {
[eaf4e2fc]165 ddf_msg(LVL_DEBUG, "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 {
[eaf4e2fc]172 ddf_msg(LVL_DEBUG, "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.");
[eaf4e2fc]194 rc = ENOENT;
[66cb7a2]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. */
[b7fd2a0]211errno_t ata_ctrl_remove(ata_ctrl_t *ctrl)
[66cb7a2]212{
[d5c1051]213 int i;
[b7fd2a0]214 errno_t 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. */
[b7fd2a0]236errno_t ata_ctrl_gone(ata_ctrl_t *ctrl)
[e092dc5]237{
[d5c1051]238 int i;
[b7fd2a0]239 errno_t 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. */
[b7fd2a0]310static errno_t ata_bd_init_io(ata_ctrl_t *ctrl)
[f8ef660]311{
[b7fd2a0]312 errno_t 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 */
[b7fd2a0]346static errno_t 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;
[b7fd2a0]358 errno_t 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. */
[eaf4e2fc]370 ddf_msg(LVL_DEBUG, "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 =
[1433ecda]430 (uint32_t) idata.total_lba28_0 |
[a1f48f6]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 =
[1433ecda]441 (uint64_t) idata.total_lba48_0 |
[a1f48f6]442 ((uint64_t) idata.total_lba48_1 << 16) |
[1b20da0]443 ((uint64_t) idata.total_lba48_2 << 32) |
[a1f48f6]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];
[1433ecda]463 if (c >= 0x80)
464 c = '?';
[0e6dce8]465
466 chr_encode(c, d->model, &pos, 40);
467 }
468 d->model[pos] = '\0';
469
[88743b5]470 if (d->dev_type == ata_pkt_dev) {
471 /* Send inquiry. */
[c2844735]472 rc = ata_pcmd_inquiry(d, &inq_data, sizeof(inq_data), &isize);
473 if (rc != EOK || isize < sizeof(inq_data)) {
[9f391e9]474 ddf_msg(LVL_ERROR, "Device inquiry failed.");
[88743b5]475 d->present = false;
476 return EIO;
477 }
[0e6dce8]478
[88743b5]479 /* Check device type. */
[35b8bfe]480 if (INQUIRY_PDEV_TYPE(inq_data.pqual_devtype) != SCSI_DEV_CD_DVD)
[9f391e9]481 ddf_msg(LVL_WARN, "Peripheral device type is not CD-ROM.");
[0e6dce8]482
[c2844735]483 rc = ata_pcmd_read_capacity(d, &nblocks, &block_size);
484 if (rc != EOK) {
485 ddf_msg(LVL_ERROR, "Read capacity command failed.");
486 d->present = false;
487 return EIO;
488 }
489
490 d->blocks = nblocks;
491 d->block_size = block_size;
[0d247f5]492 } else {
493 /* Assume register Read always uses 512-byte blocks. */
494 d->block_size = 512;
[88743b5]495 }
496
497 d->present = true;
[0e6dce8]498 return EOK;
499}
500
[b7fd2a0]501static errno_t ata_bd_open(bd_srvs_t *bds, bd_srv_t *bd)
[4802dd7]502{
503 return EOK;
504}
505
[b7fd2a0]506static errno_t ata_bd_close(bd_srv_t *bd)
[4802dd7]507{
508 return EOK;
509}
[1ee00b7]510
[4802dd7]511/** Read multiple blocks from the device. */
[b7fd2a0]512static errno_t ata_bd_read_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt,
[4802dd7]513 void *buf, size_t size)
514{
515 disk_t *disk = bd_srv_disk(bd);
[b7fd2a0]516 errno_t rc;
[f8ef660]517
[4802dd7]518 if (size < cnt * disk->block_size)
519 return EINVAL;
520
[1ee00b7]521 while (cnt > 0) {
[a44abb3e]522 if (disk->dev_type == ata_reg_dev) {
523 rc = ata_rcmd_read(disk, ba, 1, buf);
524 } else {
525 rc = ata_pcmd_read_12(disk, ba, 1, buf,
[4802dd7]526 disk->block_size);
[a44abb3e]527 }
[0d247f5]528
[1ee00b7]529 if (rc != EOK)
530 return rc;
531
532 ++ba;
533 --cnt;
[4802dd7]534 buf += disk->block_size;
[1ee00b7]535 }
536
537 return EOK;
538}
539
[4802dd7]540/** Read TOC from device. */
[b7fd2a0]541static errno_t ata_bd_read_toc(bd_srv_t *bd, uint8_t session, void *buf, size_t size)
[4802dd7]542{
543 disk_t *disk = bd_srv_disk(bd);
544
[a44abb3e]545 return ata_pcmd_read_toc(disk, session, buf, size);
[4802dd7]546}
[f8ef660]547
[4802dd7]548/** Write multiple blocks to the device. */
[b7fd2a0]549static errno_t ata_bd_write_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt,
[4802dd7]550 const void *buf, size_t size)
551{
552 disk_t *disk = bd_srv_disk(bd);
[b7fd2a0]553 errno_t rc;
[f8ef660]554
[4802dd7]555 if (disk->dev_type != ata_reg_dev)
[0d247f5]556 return ENOTSUP;
557
[4802dd7]558 if (size < cnt * disk->block_size)
559 return EINVAL;
560
[1ee00b7]561 while (cnt > 0) {
[a44abb3e]562 rc = ata_rcmd_write(disk, ba, 1, buf);
[f8ef660]563 if (rc != EOK)
564 return rc;
565
[1ee00b7]566 ++ba;
567 --cnt;
[4802dd7]568 buf += disk->block_size;
[f8ef660]569 }
570
571 return EOK;
572}
573
[4802dd7]574/** Get device block size. */
[b7fd2a0]575static errno_t ata_bd_get_block_size(bd_srv_t *bd, size_t *rbsize)
[4802dd7]576{
577 disk_t *disk = bd_srv_disk(bd);
578
579 *rbsize = disk->block_size;
580 return EOK;
581}
582
583/** Get device number of blocks. */
[b7fd2a0]584static errno_t ata_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb)
[4802dd7]585{
586 disk_t *disk = bd_srv_disk(bd);
587
588 *rnb = disk->blocks;
589 return EOK;
590}
591
[4abe919]592/** Flush cache. */
[b7fd2a0]593static errno_t ata_bd_sync_cache(bd_srv_t *bd, uint64_t ba, size_t cnt)
[4abe919]594{
595 disk_t *disk = bd_srv_disk(bd);
596
597 /* ATA cannot flush just some blocks, we just flush everything. */
598 (void)ba;
599 (void)cnt;
600
601 return ata_rcmd_flush_cache(disk);
602}
603
[882bc4b]604/** PIO data-in command protocol. */
[b7fd2a0]605static errno_t ata_pio_data_in(disk_t *disk, void *obuf, size_t obuf_size,
[882bc4b]606 size_t blk_size, size_t nblocks)
607{
608 ata_ctrl_t *ctrl = disk->ctrl;
609 uint16_t data;
610 size_t i;
611 uint8_t status;
612
613 /* XXX Support multiple blocks */
614 assert(nblocks == 1);
615 assert(blk_size % 2 == 0);
616
617 if (wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK)
618 return EIO;
619
620 if ((status & SR_DRQ) != 0) {
621 /* Read data from the device buffer. */
622
623 for (i = 0; i < blk_size / 2; i++) {
624 data = pio_read_16(&ctrl->cmd->data_port);
625 ((uint16_t *) obuf)[i] = data;
626 }
627 }
628
629 if ((status & SR_ERR) != 0)
630 return EIO;
631
632 return EOK;
633}
634
635/** PIO data-out command protocol. */
[b7fd2a0]636static errno_t ata_pio_data_out(disk_t *disk, const void *buf, size_t buf_size,
[882bc4b]637 size_t blk_size, size_t nblocks)
638{
639 ata_ctrl_t *ctrl = disk->ctrl;
640 size_t i;
641 uint8_t status;
642
643 /* XXX Support multiple blocks */
644 assert(nblocks == 1);
645 assert(blk_size % 2 == 0);
646
647 if (wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK)
648 return EIO;
649
650 if ((status & SR_DRQ) != 0) {
651 /* Write data to the device buffer. */
652
653 for (i = 0; i < blk_size / 2; i++) {
654 pio_write_16(&ctrl->cmd->data_port, ((uint16_t *) buf)[i]);
655 }
656 }
657
658 if (status & SR_ERR)
659 return EIO;
660
661 return EOK;
662}
663
[4abe919]664/** PIO non-data command protocol. */
[b7fd2a0]665static errno_t ata_pio_nondata(disk_t *disk)
[4abe919]666{
667 ata_ctrl_t *ctrl = disk->ctrl;
668 uint8_t status;
669
670 if (wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK)
671 return EIO;
672
673 if (status & SR_ERR)
674 return EIO;
675
676 return EOK;
677}
678
[882bc4b]679/** Issue IDENTIFY DEVICE command.
[54d0ddc]680 *
[0e6dce8]681 * Reads @c identify data into the provided buffer. This is used to detect
682 * whether an ATA device is present and if so, to determine its parameters.
[54d0ddc]683 *
[a44abb3e]684 * @param disk Disk
[0e6dce8]685 * @param buf Pointer to a 512-byte buffer.
[7a56e33e]686 *
687 * @return ETIMEOUT on timeout (this can mean the device is
688 * not present). EIO if device responds with error.
[54d0ddc]689 */
[b7fd2a0]690static errno_t ata_identify_dev(disk_t *disk, void *buf)
[54d0ddc]691{
[96cbd18]692 ata_ctrl_t *ctrl = disk->ctrl;
[54d0ddc]693 uint8_t status;
694 uint8_t drv_head;
[f8ef660]695
[a44abb3e]696 drv_head = ((disk_dev_idx(disk) != 0) ? DHR_DRV : 0);
[54d0ddc]697
[96cbd18]698 if (wait_status(ctrl, 0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
[7a56e33e]699 return ETIMEOUT;
[31de325]700
[96cbd18]701 pio_write_8(&ctrl->cmd->drive_head, drv_head);
[54d0ddc]702
703 /*
[250dbef]704 * Do not wait for DRDY to be set in case this is a packet device.
705 * We determine whether the device is present by waiting for DRQ to be
706 * set after issuing the command.
[54d0ddc]707 */
[96cbd18]708 if (wait_status(ctrl, 0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
[7a56e33e]709 return ETIMEOUT;
[54d0ddc]710
[96cbd18]711 pio_write_8(&ctrl->cmd->command, CMD_IDENTIFY_DRIVE);
[54d0ddc]712
[96cbd18]713 if (wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK)
[7a56e33e]714 return ETIMEOUT;
[54d0ddc]715
[250dbef]716 /*
717 * If ERR is set, this may be a packet device, so return EIO to cause
718 * the caller to check for one.
719 */
[882bc4b]720 if ((status & SR_ERR) != 0)
[7a56e33e]721 return EIO;
722
[882bc4b]723 /*
724 * For probing purposes we need to wait for some status bit to become
725 * active - otherwise we could be fooled just by receiving all zeroes.
726 */
[96cbd18]727 if (wait_status(ctrl, SR_DRQ, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK)
[250dbef]728 return ETIMEOUT;
729
[882bc4b]730 return ata_pio_data_in(disk, buf, identify_data_size,
731 identify_data_size, 1);
[7a56e33e]732}
733
734/** Issue Identify Packet Device command.
735 *
736 * Reads @c identify data into the provided buffer. This is used to detect
737 * whether an ATAPI device is present and if so, to determine its parameters.
738 *
[a44abb3e]739 * @param disk Disk
[7a56e33e]740 * @param buf Pointer to a 512-byte buffer.
741 */
[b7fd2a0]742static errno_t ata_identify_pkt_dev(disk_t *disk, void *buf)
[7a56e33e]743{
[96cbd18]744 ata_ctrl_t *ctrl = disk->ctrl;
[7a56e33e]745 uint8_t drv_head;
746
[a44abb3e]747 drv_head = ((disk_dev_idx(disk) != 0) ? DHR_DRV : 0);
[7a56e33e]748
[96cbd18]749 if (wait_status(ctrl, 0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
[7a56e33e]750 return EIO;
751
[96cbd18]752 pio_write_8(&ctrl->cmd->drive_head, drv_head);
[7a56e33e]753
754 /* For ATAPI commands we do not need to wait for DRDY. */
[96cbd18]755 if (wait_status(ctrl, 0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
[7a56e33e]756 return EIO;
757
[96cbd18]758 pio_write_8(&ctrl->cmd->command, CMD_IDENTIFY_PKT_DEV);
[7a56e33e]759
[882bc4b]760 return ata_pio_data_in(disk, buf, identify_data_size,
761 identify_data_size, 1);
[54d0ddc]762}
763
[88743b5]764/** Issue packet command (i. e. write a command packet to the device).
765 *
766 * Only data-in commands are supported (e.g. inquiry, read).
767 *
[a44abb3e]768 * @param disk Disk
[88743b5]769 * @param obuf Buffer for storing data read from device
770 * @param obuf_size Size of obuf in bytes
[c2844735]771 * @param rcvd_size Place to store number of bytes read or @c NULL
[88743b5]772 *
773 * @return EOK on success, EIO on error.
774 */
[b7fd2a0]775static errno_t ata_cmd_packet(disk_t *disk, const void *cpkt, size_t cpkt_size,
[c2844735]776 void *obuf, size_t obuf_size, size_t *rcvd_size)
[88743b5]777{
[96cbd18]778 ata_ctrl_t *ctrl = disk->ctrl;
[88743b5]779 size_t i;
780 uint8_t status;
781 uint8_t drv_head;
782 size_t data_size;
783 uint16_t val;
784
[66cb7a2]785 fibril_mutex_lock(&ctrl->lock);
[88743b5]786
787 /* New value for Drive/Head register */
788 drv_head =
[a44abb3e]789 ((disk_dev_idx(disk) != 0) ? DHR_DRV : 0);
[88743b5]790
[96cbd18]791 if (wait_status(ctrl, 0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) {
[66cb7a2]792 fibril_mutex_unlock(&ctrl->lock);
[88743b5]793 return EIO;
794 }
795
[96cbd18]796 pio_write_8(&ctrl->cmd->drive_head, drv_head);
[88743b5]797
[1433ecda]798 if (wait_status(ctrl, 0, ~(SR_BSY | SR_DRQ), NULL, TIMEOUT_BSY) != EOK) {
[66cb7a2]799 fibril_mutex_unlock(&ctrl->lock);
[88743b5]800 return EIO;
801 }
802
803 /* Byte count <- max. number of bytes we can read in one transfer. */
[96cbd18]804 pio_write_8(&ctrl->cmd->cylinder_low, 0xfe);
805 pio_write_8(&ctrl->cmd->cylinder_high, 0xff);
[88743b5]806
[96cbd18]807 pio_write_8(&ctrl->cmd->command, CMD_PACKET);
[88743b5]808
[96cbd18]809 if (wait_status(ctrl, SR_DRQ, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
[66cb7a2]810 fibril_mutex_unlock(&ctrl->lock);
[88743b5]811 return EIO;
812 }
813
814 /* Write command packet. */
815 for (i = 0; i < (cpkt_size + 1) / 2; i++)
[96cbd18]816 pio_write_16(&ctrl->cmd->data_port, ((uint16_t *) cpkt)[i]);
[88743b5]817
[96cbd18]818 if (wait_status(ctrl, 0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
[66cb7a2]819 fibril_mutex_unlock(&ctrl->lock);
[88743b5]820 return EIO;
821 }
822
823 if ((status & SR_DRQ) == 0) {
[66cb7a2]824 fibril_mutex_unlock(&ctrl->lock);
[88743b5]825 return EIO;
826 }
827
828 /* Read byte count. */
[96cbd18]829 data_size = (uint16_t) pio_read_8(&ctrl->cmd->cylinder_low) +
830 ((uint16_t) pio_read_8(&ctrl->cmd->cylinder_high) << 8);
[88743b5]831
832 /* Check whether data fits into output buffer. */
833 if (data_size > obuf_size) {
834 /* Output buffer is too small to store data. */
[66cb7a2]835 fibril_mutex_unlock(&ctrl->lock);
[88743b5]836 return EIO;
837 }
838
839 /* Read data from the device buffer. */
840 for (i = 0; i < (data_size + 1) / 2; i++) {
[96cbd18]841 val = pio_read_16(&ctrl->cmd->data_port);
[88743b5]842 ((uint16_t *) obuf)[i] = val;
843 }
844
[66cb7a2]845 fibril_mutex_unlock(&ctrl->lock);
[88743b5]846
[66cb7a2]847 if (status & SR_ERR)
848 return EIO;
[88743b5]849
[c2844735]850 if (rcvd_size != NULL)
851 *rcvd_size = data_size;
[88743b5]852 return EOK;
853}
854
[aa893e0]855/** Issue ATAPI Inquiry.
[88743b5]856 *
[a44abb3e]857 * @param disk Disk
[88743b5]858 * @param obuf Buffer for storing inquiry data read from device
859 * @param obuf_size Size of obuf in bytes
860 *
861 * @return EOK on success, EIO on error.
862 */
[b7fd2a0]863static errno_t ata_pcmd_inquiry(disk_t *disk, void *obuf, size_t obuf_size,
[c2844735]864 size_t *rcvd_size)
[88743b5]865{
[35b8bfe]866 uint8_t cpb[12];
867 scsi_cdb_inquiry_t *cp = (scsi_cdb_inquiry_t *)cpb;
[b7fd2a0]868 errno_t rc;
[88743b5]869
[35b8bfe]870 memset(cpb, 0, sizeof(cpb));
871
872 /*
873 * For SFF 8020 compliance the inquiry must be padded to 12 bytes
874 * and allocation length must fit in one byte.
875 */
876 cp->op_code = SCSI_CMD_INQUIRY;
[bb0eab1]877
[35b8bfe]878 /* Allocation length */
879 cp->alloc_len = host2uint16_t_be(min(obuf_size, 0xff));
[88743b5]880
[35b8bfe]881 rc = ata_cmd_packet(disk, cpb, sizeof(cpb), obuf, obuf_size, rcvd_size);
[c2844735]882 if (rc != EOK)
883 return rc;
884
885 return EOK;
886}
887
888/** Issue ATAPI read capacity(10) command.
889 *
890 * @param disk Disk
891 * @param nblocks Place to store number of blocks
892 * @param block_size Place to store block size
893 *
894 * @return EOK on success, EIO on error.
895 */
[b7fd2a0]896static errno_t ata_pcmd_read_capacity(disk_t *disk, uint64_t *nblocks,
[c2844735]897 size_t *block_size)
898{
899 scsi_cdb_read_capacity_10_t cdb;
900 scsi_read_capacity_10_data_t data;
901 size_t rsize;
[b7fd2a0]902 errno_t rc;
[c2844735]903
904 memset(&cdb, 0, sizeof(cdb));
905 cdb.op_code = SCSI_CMD_READ_CAPACITY_10;
906
907 rc = ata_cmd_packet(disk, &cdb, sizeof(cdb), &data, sizeof(data), &rsize);
[88743b5]908 if (rc != EOK)
909 return rc;
910
[c2844735]911 if (rsize != sizeof(data))
912 return EIO;
913
914 *nblocks = uint32_t_be2host(data.last_lba) + 1;
915 *block_size = uint32_t_be2host(data.block_size);
916
[88743b5]917 return EOK;
918}
919
[aa893e0]920/** Issue ATAPI read(12) command.
921 *
922 * Output buffer must be large enough to hold the data, otherwise the
923 * function will fail.
924 *
[a44abb3e]925 * @param disk Disk
[aa893e0]926 * @param ba Starting block address
927 * @param cnt Number of blocks to read
928 * @param obuf Buffer for storing inquiry data read from device
929 * @param obuf_size Size of obuf in bytes
930 *
931 * @return EOK on success, EIO on error.
932 */
[b7fd2a0]933static errno_t ata_pcmd_read_12(disk_t *disk, uint64_t ba, size_t cnt,
[0d247f5]934 void *obuf, size_t obuf_size)
935{
[35b8bfe]936 scsi_cdb_read_12_t cp;
[b7fd2a0]937 errno_t rc;
[0d247f5]938
[bb0eab1]939 if (ba > UINT32_MAX)
[0d247f5]940 return EINVAL;
941
[bb0eab1]942 memset(&cp, 0, sizeof(cp));
[0d247f5]943
[35b8bfe]944 cp.op_code = SCSI_CMD_READ_12;
945 cp.lba = host2uint32_t_be(ba);
946 cp.xfer_len = host2uint32_t_be(cnt);
[0d247f5]947
[c2844735]948 rc = ata_cmd_packet(disk, &cp, sizeof(cp), obuf, obuf_size, NULL);
[0d247f5]949 if (rc != EOK)
950 return rc;
951
952 return EOK;
953}
954
[4046b2f4]955/** Issue ATAPI read TOC command.
956 *
957 * Read TOC in 'multi-session' format (first and last session number
958 * with last session LBA).
959 *
960 * http://suif.stanford.edu/~csapuntz/specs/INF-8020.PDF page 171
961 *
962 * Output buffer must be large enough to hold the data, otherwise the
963 * function will fail.
964 *
[a44abb3e]965 * @param disk Disk
[4046b2f4]966 * @param session Starting session
967 * @param obuf Buffer for storing inquiry data read from device
968 * @param obuf_size Size of obuf in bytes
969 *
970 * @return EOK on success, EIO on error.
971 */
[b7fd2a0]972static errno_t ata_pcmd_read_toc(disk_t *disk, uint8_t session, void *obuf,
[4046b2f4]973 size_t obuf_size)
974{
[35b8bfe]975 uint8_t cpb[12];
976 scsi_cdb_read_toc_t *cp = (scsi_cdb_read_toc_t *)cpb;
[b7fd2a0]977 errno_t rc;
[4046b2f4]978
[35b8bfe]979 memset(cpb, 0, sizeof(cpb));
[4046b2f4]980
[35b8bfe]981 cp->op_code = SCSI_CMD_READ_TOC;
982 cp->msf = 0;
983 cp->format = 0x01; /* 0x01 = multi-session mode */
984 cp->track_sess_no = session;
985 cp->alloc_len = host2uint16_t_be(obuf_size);
986 cp->control = 0x40; /* 0x01 = multi-session mode (shifted to MSB) */
987
988 rc = ata_cmd_packet(disk, cpb, sizeof(cpb), obuf, obuf_size, NULL);
[4046b2f4]989 if (rc != EOK)
990 return rc;
[35b8bfe]991
[4046b2f4]992 return EOK;
993}
994
[882bc4b]995/** Read a physical block from the device.
[54d0ddc]996 *
[a44abb3e]997 * @param disk Disk
[1ee00b7]998 * @param ba Address the first block.
999 * @param cnt Number of blocks to transfer.
[54d0ddc]1000 * @param buf Buffer for holding the data.
1001 *
1002 * @return EOK on success, EIO on error.
1003 */
[b7fd2a0]1004static errno_t ata_rcmd_read(disk_t *disk, uint64_t ba, size_t blk_cnt,
[f8ef660]1005 void *buf)
1006{
[96cbd18]1007 ata_ctrl_t *ctrl = disk->ctrl;
[f8ef660]1008 uint8_t drv_head;
[5048be7]1009 block_coord_t bc;
[b7fd2a0]1010 errno_t rc;
[1806e5d]1011
[36e9cd1]1012 /* Silence warning. */
1013 memset(&bc, 0, sizeof(bc));
[f8ef660]1014
[5048be7]1015 /* Compute block coordinates. */
[a44abb3e]1016 if (coord_calc(disk, ba, &bc) != EOK)
[f8ef660]1017 return EINVAL;
1018
1019 /* New value for Drive/Head register */
1020 drv_head =
[a44abb3e]1021 ((disk_dev_idx(disk) != 0) ? DHR_DRV : 0) |
1022 ((disk->amode != am_chs) ? DHR_LBA : 0) |
[5048be7]1023 (bc.h & 0x0f);
[f8ef660]1024
[66cb7a2]1025 fibril_mutex_lock(&ctrl->lock);
[f8ef660]1026
1027 /* Program a Read Sectors operation. */
1028
[96cbd18]1029 if (wait_status(ctrl, 0, ~SR_BSY, NULL, TIMEOUT_BSY) != EOK) {
[66cb7a2]1030 fibril_mutex_unlock(&ctrl->lock);
[31de325]1031 return EIO;
1032 }
1033
[96cbd18]1034 pio_write_8(&ctrl->cmd->drive_head, drv_head);
[a7de7907]1035
[96cbd18]1036 if (wait_status(ctrl, SR_DRDY, ~SR_BSY, NULL, TIMEOUT_DRDY) != EOK) {
[66cb7a2]1037 fibril_mutex_unlock(&ctrl->lock);
[31de325]1038 return EIO;
1039 }
1040
[5048be7]1041 /* Program block coordinates into the device. */
[96cbd18]1042 coord_sc_program(ctrl, &bc, 1);
[a7de7907]1043
[96cbd18]1044 pio_write_8(&ctrl->cmd->command, disk->amode == am_lba48 ?
[1c1657c]1045 CMD_READ_SECTORS_EXT : CMD_READ_SECTORS);
[f8ef660]1046
[882bc4b]1047 rc = ata_pio_data_in(disk, buf, blk_cnt * disk->block_size,
1048 disk->block_size, blk_cnt);
[f8ef660]1049
[66cb7a2]1050 fibril_mutex_unlock(&ctrl->lock);
1051
[882bc4b]1052 return rc;
[f8ef660]1053}
1054
[54d0ddc]1055/** Write a physical block to the device.
1056 *
[a44abb3e]1057 * @param disk Disk
[1ee00b7]1058 * @param ba Address of the first block.
1059 * @param cnt Number of blocks to transfer.
[54d0ddc]1060 * @param buf Buffer holding the data to write.
1061 *
1062 * @return EOK on success, EIO on error.
1063 */
[b7fd2a0]1064static errno_t ata_rcmd_write(disk_t *disk, uint64_t ba, size_t cnt,
[d9f4c76]1065 const void *buf)
1066{
[96cbd18]1067 ata_ctrl_t *ctrl = disk->ctrl;
[d9f4c76]1068 uint8_t drv_head;
[5048be7]1069 block_coord_t bc;
[b7fd2a0]1070 errno_t rc;
[d9f4c76]1071
[36e9cd1]1072 /* Silence warning. */
1073 memset(&bc, 0, sizeof(bc));
[d9f4c76]1074
[5048be7]1075 /* Compute block coordinates. */
[a44abb3e]1076 if (coord_calc(disk, ba, &bc) != EOK)
[d9f4c76]1077 return EINVAL;
1078
1079 /* New value for Drive/Head register */
1080 drv_head =
[a44abb3e]1081 ((disk_dev_idx(disk) != 0) ? DHR_DRV : 0) |
1082 ((disk->amode != am_chs) ? DHR_LBA : 0) |
[5048be7]1083 (bc.h & 0x0f);
[d9f4c76]1084
[66cb7a2]1085 fibril_mutex_lock(&ctrl->lock);
[d9f4c76]1086
[31de325]1087 /* Program a Write Sectors operation. */
1088
[96cbd18]1089 if (wait_status(ctrl, 0, ~SR_BSY, NULL, TIMEOUT_BSY) != EOK) {
[66cb7a2]1090 fibril_mutex_unlock(&ctrl->lock);
[31de325]1091 return EIO;
1092 }
[d9f4c76]1093
[96cbd18]1094 pio_write_8(&ctrl->cmd->drive_head, drv_head);
[a7de7907]1095
[96cbd18]1096 if (wait_status(ctrl, SR_DRDY, ~SR_BSY, NULL, TIMEOUT_DRDY) != EOK) {
[66cb7a2]1097 fibril_mutex_unlock(&ctrl->lock);
[31de325]1098 return EIO;
1099 }
1100
[5048be7]1101 /* Program block coordinates into the device. */
[96cbd18]1102 coord_sc_program(ctrl, &bc, 1);
[a7de7907]1103
[96cbd18]1104 pio_write_8(&ctrl->cmd->command, disk->amode == am_lba48 ?
[1c1657c]1105 CMD_WRITE_SECTORS_EXT : CMD_WRITE_SECTORS);
[d9f4c76]1106
[882bc4b]1107 rc = ata_pio_data_out(disk, buf, cnt * disk->block_size,
1108 disk->block_size, cnt);
[d9f4c76]1109
[66cb7a2]1110 fibril_mutex_unlock(&ctrl->lock);
[882bc4b]1111 return rc;
[d9f4c76]1112}
1113
[4abe919]1114/** Flush cached data to nonvolatile storage.
1115 *
1116 * @param disk Disk
1117 *
1118 * @return EOK on success, EIO on error.
1119 */
[b7fd2a0]1120static errno_t ata_rcmd_flush_cache(disk_t *disk)
[4abe919]1121{
1122 ata_ctrl_t *ctrl = disk->ctrl;
1123 uint8_t drv_head;
[b7fd2a0]1124 errno_t rc;
[4abe919]1125
1126 /* New value for Drive/Head register */
1127 drv_head =
1128 (disk_dev_idx(disk) != 0) ? DHR_DRV : 0;
1129
1130 fibril_mutex_lock(&ctrl->lock);
1131
1132 /* Program a Flush Cache operation. */
1133
1134 if (wait_status(ctrl, 0, ~SR_BSY, NULL, TIMEOUT_BSY) != EOK) {
1135 fibril_mutex_unlock(&ctrl->lock);
1136 return EIO;
1137 }
1138
1139 pio_write_8(&ctrl->cmd->drive_head, drv_head);
1140
1141 if (wait_status(ctrl, SR_DRDY, ~SR_BSY, NULL, TIMEOUT_DRDY) != EOK) {
1142 fibril_mutex_unlock(&ctrl->lock);
1143 return EIO;
1144 }
1145
1146 pio_write_8(&ctrl->cmd->command, CMD_FLUSH_CACHE);
1147
1148 rc = ata_pio_nondata(disk);
1149
1150 fibril_mutex_unlock(&ctrl->lock);
1151 return rc;
1152}
1153
[5048be7]1154/** Calculate block coordinates.
1155 *
1156 * Calculates block coordinates in the best coordinate system supported
1157 * by the device. These can be later programmed into the device using
1158 * @c coord_sc_program().
1159 *
1160 * @return EOK on success or EINVAL if block index is past end of device.
1161 */
[b7fd2a0]1162static errno_t coord_calc(disk_t *d, uint64_t ba, block_coord_t *bc)
[5048be7]1163{
1164 uint64_t c;
1165 uint64_t idx;
1166
1167 /* Check device bounds. */
[1ee00b7]1168 if (ba >= d->blocks)
[5048be7]1169 return EINVAL;
1170
1171 bc->amode = d->amode;
1172
1173 switch (d->amode) {
1174 case am_chs:
1175 /* Compute CHS coordinates. */
[1ee00b7]1176 c = ba / (d->geom.heads * d->geom.sectors);
1177 idx = ba % (d->geom.heads * d->geom.sectors);
[5048be7]1178
1179 bc->cyl_lo = c & 0xff;
1180 bc->cyl_hi = (c >> 8) & 0xff;
1181 bc->h = (idx / d->geom.sectors) & 0x0f;
1182 bc->sector = (1 + (idx % d->geom.sectors)) & 0xff;
1183 break;
1184
1185 case am_lba28:
1186 /* Compute LBA-28 coordinates. */
[1ee00b7]1187 bc->c0 = ba & 0xff; /* bits 0-7 */
1188 bc->c1 = (ba >> 8) & 0xff; /* bits 8-15 */
1189 bc->c2 = (ba >> 16) & 0xff; /* bits 16-23 */
1190 bc->h = (ba >> 24) & 0x0f; /* bits 24-27 */
[5048be7]1191 break;
1192
1193 case am_lba48:
1194 /* Compute LBA-48 coordinates. */
[1ee00b7]1195 bc->c0 = ba & 0xff; /* bits 0-7 */
1196 bc->c1 = (ba >> 8) & 0xff; /* bits 8-15 */
1197 bc->c2 = (ba >> 16) & 0xff; /* bits 16-23 */
1198 bc->c3 = (ba >> 24) & 0xff; /* bits 24-31 */
1199 bc->c4 = (ba >> 32) & 0xff; /* bits 32-39 */
1200 bc->c5 = (ba >> 40) & 0xff; /* bits 40-47 */
[5048be7]1201 bc->h = 0;
1202 break;
1203 }
1204
1205 return EOK;
1206}
1207
1208/** Program block coordinates and sector count into ATA registers.
1209 *
1210 * Note that bc->h must be programmed separately into the device/head register.
[96cbd18]1211 *
1212 * @param ctrl Controller
1213 * @param bc Block coordinates
1214 * @param scnt Sector count
[5048be7]1215 */
[96cbd18]1216static void coord_sc_program(ata_ctrl_t *ctrl, const block_coord_t *bc,
1217 uint16_t scnt)
[5048be7]1218{
[96cbd18]1219 ata_cmd_t *cmd = ctrl->cmd;
1220
[5048be7]1221 if (bc->amode == am_lba48) {
1222 /* Write high-order bits. */
1223 pio_write_8(&cmd->sector_count, scnt >> 8);
1224 pio_write_8(&cmd->sector_number, bc->c3);
1225 pio_write_8(&cmd->cylinder_low, bc->c4);
1226 pio_write_8(&cmd->cylinder_high, bc->c5);
1227 }
1228
1229 /* Write low-order bits. */
1230 pio_write_8(&cmd->sector_count, scnt & 0x00ff);
1231 pio_write_8(&cmd->sector_number, bc->c0);
1232 pio_write_8(&cmd->cylinder_low, bc->c1);
1233 pio_write_8(&cmd->cylinder_high, bc->c2);
1234}
1235
[31de325]1236/** Wait until some status bits are set and some are reset.
[54d0ddc]1237 *
[96cbd18]1238 * Example: wait_status(ctrl, SR_DRDY, ~SR_BSY, ...) waits for SR_DRDY to become
[54d0ddc]1239 * set and SR_BSY to become reset.
1240 *
[96cbd18]1241 * @param ctrl Controller
[54d0ddc]1242 * @param set Combination if bits which must be all set.
1243 * @param n_reset Negated combination of bits which must be all reset.
[31de325]1244 * @param pstatus Pointer where to store last read status or NULL.
1245 * @param timeout Timeout in 10ms units.
1246 *
1247 * @return EOK on success, EIO on timeout.
[54d0ddc]1248 */
[b7fd2a0]1249static errno_t wait_status(ata_ctrl_t *ctrl, unsigned set, unsigned n_reset,
[96cbd18]1250 uint8_t *pstatus, unsigned timeout)
[54d0ddc]1251{
1252 uint8_t status;
[31de325]1253 int cnt;
1254
[96cbd18]1255 status = pio_read_8(&ctrl->cmd->status);
[31de325]1256
1257 /*
1258 * This is crude, yet simple. First try with 1us delays
1259 * (most likely the device will respond very fast). If not,
1260 * start trying every 10 ms.
1261 */
1262
1263 cnt = 100;
1264 while ((status & ~n_reset) != 0 || (status & set) != set) {
1265 --cnt;
[1433ecda]1266 if (cnt <= 0)
1267 break;
[31de325]1268
[96cbd18]1269 status = pio_read_8(&ctrl->cmd->status);
[31de325]1270 }
1271
1272 cnt = timeout;
1273 while ((status & ~n_reset) != 0 || (status & set) != set) {
[5f97ef44]1274 fibril_usleep(10000);
[31de325]1275 --cnt;
[1433ecda]1276 if (cnt <= 0)
1277 break;
[54d0ddc]1278
[96cbd18]1279 status = pio_read_8(&ctrl->cmd->status);
[31de325]1280 }
1281
1282 if (pstatus)
1283 *pstatus = status;
[54d0ddc]1284
[31de325]1285 if (cnt == 0)
1286 return EIO;
1287
1288 return EOK;
[54d0ddc]1289}
1290
[f8ef660]1291/**
1292 * @}
1293 */
Note: See TracBrowser for help on using the repository browser.