source: mainline/uspace/drv/block/ata_bd/ata_bd.c@ 66cb7a2

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

Convert ata_bd to DDF.

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