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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a5bad72 was 79ae36dd, checked in by Martin Decky <martin@…>, 15 years ago

new async framework with integrated exchange tracking

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