source: mainline/uspace/srv/bd/ata_bd/ata_bd.c@ 8930624

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 8930624 was a44abb3e, checked in by Jiri Svoboda <jiri@…>, 13 years ago

Favor disk_t pointer over disk_id in ata_bd.

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