source: mainline/uspace/srv/bd/ata_bd/ata_bd.c@ 0d247f5

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

Implement ATAPI read(12) command.

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