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

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

Remove the two-phase way of creating virtual memory areas (first asking for a mappable address and then mapping it) which was prone to race conditions when two or more calls to as_get_mappable_page() and as_area_create() were interleaved. This for example caused the e1k driver to randomly fail.

The memory area related syscalls and IPC calls have all been altered to accept a special value (void *) -1, representing a demand to atomically search for a mappable address space "hole" and map to it.

Individual changes:

  • IPC_M_SHARE_OUT: the destination address space area is supplied by the kernel, the callee only specifies the lower bound

(the address is returned to the callee via a pointer in an IPC reply argument)

  • IPC_M_SHARE_IN: the destination address space ares is supplied by the kernel, the callee only specifies the lower bound

(the address is returned to the caller as usual via an IPC argument)

  • SYS_AS_GET_UNMAPPED_AREA was removed
  • dummy implementations of SYS_PHYSMEM_UNMAP and SYS_IOSPACE_DISABLE were added for the sake of symmetry (they do nothing yet)
  • SYS_PHYSMEM_MAP and SYS_DMAMEM_MAP were altered to accept (void *) -1 as address space area base and a lower bound
  • kernel as_area_create() and as_area_share() were altered to accept (void *) -1 as address space area base and a lower bound
  • uspace libraries and programs were altered to reflect the new API
  • Property mode set to 100644
File size: 27.0 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 <loc.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/** I/O base address of the command registers. */
84static uintptr_t cmd_physical;
85/** I/O base address of the control registers. */
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};
95
96static ata_cmd_t *cmd;
97static ata_ctl_t *ctl;
98
99/** Per-disk state. */
100static disk_t disk[MAX_DISKS];
101
102static void print_syntax(void);
103static int ata_bd_init(void);
104static void ata_bd_connection(ipc_callid_t iid, ipc_call_t *icall, void *);
105static int ata_bd_read_blocks(int disk_id, uint64_t ba, size_t cnt,
106 void *buf);
107static int ata_bd_write_blocks(int disk_id, uint64_t ba, size_t cnt,
108 const void *buf);
109static int ata_rcmd_read(int disk_id, uint64_t ba, size_t cnt,
110 void *buf);
111static int ata_rcmd_write(int disk_id, uint64_t ba, size_t cnt,
112 const void *buf);
113static int disk_init(disk_t *d, int disk_id);
114static int drive_identify(int drive_id, void *buf);
115static int identify_pkt_dev(int dev_idx, void *buf);
116static int ata_cmd_packet(int dev_idx, const void *cpkt, size_t cpkt_size,
117 void *obuf, size_t obuf_size);
118static int ata_pcmd_inquiry(int dev_idx, void *obuf, size_t obuf_size);
119static int ata_pcmd_read_12(int dev_idx, uint64_t ba, size_t cnt,
120 void *obuf, size_t obuf_size);
121static int ata_pcmd_read_toc(int dev_idx, uint8_t ses,
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 = loc_service_register(name, &disk[i].service_id);
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 = loc_server_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, void *arg)
276{
277 void *fs_va = NULL;
278 ipc_callid_t callid;
279 ipc_call_t call;
280 sysarg_t method;
281 service_id_t dsid;
282 size_t comm_size; /**< Size of the communication area. */
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 service ID. */
290 dsid = 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].service_id == dsid)
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 (void) async_share_out_finalize(callid, &fs_va);
312 if (fs_va == (void *) -1) {
313 async_answer_0(callid, EHANGUP);
314 return;
315 }
316
317 while (true) {
318 callid = async_get_call(&call);
319 method = IPC_GET_IMETHOD(call);
320
321 if (!method) {
322 /* The other side has hung up. */
323 async_answer_0(callid, EOK);
324 return;
325 }
326
327 switch (method) {
328 case BD_READ_BLOCKS:
329 ba = MERGE_LOUP32(IPC_GET_ARG1(call),
330 IPC_GET_ARG2(call));
331 cnt = IPC_GET_ARG3(call);
332 if (cnt * disk[disk_id].block_size > comm_size) {
333 retval = ELIMIT;
334 break;
335 }
336 retval = ata_bd_read_blocks(disk_id, ba, cnt, fs_va);
337 break;
338 case BD_WRITE_BLOCKS:
339 ba = MERGE_LOUP32(IPC_GET_ARG1(call),
340 IPC_GET_ARG2(call));
341 cnt = IPC_GET_ARG3(call);
342 if (cnt * disk[disk_id].block_size > comm_size) {
343 retval = ELIMIT;
344 break;
345 }
346 retval = ata_bd_write_blocks(disk_id, ba, cnt, fs_va);
347 break;
348 case BD_GET_BLOCK_SIZE:
349 async_answer_1(callid, EOK, disk[disk_id].block_size);
350 continue;
351 case BD_GET_NUM_BLOCKS:
352 async_answer_2(callid, EOK, LOWER32(disk[disk_id].blocks),
353 UPPER32(disk[disk_id].blocks));
354 continue;
355 case BD_READ_TOC:
356 cnt = IPC_GET_ARG1(call);
357 if (disk[disk_id].dev_type == ata_pkt_dev)
358 retval = ata_pcmd_read_toc(disk_id, cnt, fs_va,
359 disk[disk_id].block_size);
360 else
361 retval = EINVAL;
362 break;
363 default:
364 retval = EINVAL;
365 break;
366 }
367 async_answer_0(callid, retval);
368 }
369}
370
371/** Initialize a disk.
372 *
373 * Probes for a disk, determines its parameters and initializes
374 * the disk structure.
375 */
376static int disk_init(disk_t *d, int disk_id)
377{
378 identify_data_t idata;
379 uint8_t model[40];
380 ata_inquiry_data_t inq_data;
381 uint16_t w;
382 uint8_t c;
383 uint16_t bc;
384 size_t pos, len;
385 int rc;
386 unsigned i;
387
388 d->present = false;
389 fibril_mutex_initialize(&d->lock);
390
391 /* Try identify command. */
392 rc = drive_identify(disk_id, &idata);
393 if (rc == EOK) {
394 /* Success. It's a register (non-packet) device. */
395 printf("ATA register-only device found.\n");
396 d->dev_type = ata_reg_dev;
397 } else if (rc == EIO) {
398 /*
399 * There is something, but not a register device. Check to see
400 * whether the IDENTIFY command left the packet signature in
401 * the registers in case this is a packet device.
402 *
403 * According to the ATA specification, the LBA low and
404 * interrupt reason registers should be set to 0x01. However,
405 * there are many devices that do not follow this and only set
406 * the byte count registers. So, only check these.
407 */
408 bc = ((uint16_t)pio_read_8(&cmd->cylinder_high) << 8) |
409 pio_read_8(&cmd->cylinder_low);
410
411 if (bc == PDEV_SIGNATURE_BC) {
412 rc = identify_pkt_dev(disk_id, &idata);
413 if (rc == EOK) {
414 /* We have a packet device. */
415 d->dev_type = ata_pkt_dev;
416 } else {
417 return EIO;
418 }
419 } else {
420 /* Nope. Something's there, but not recognized. */
421 return EIO;
422 }
423 } else {
424 /* Operation timed out. That means there is no device there. */
425 return EIO;
426 }
427
428 if (d->dev_type == ata_pkt_dev) {
429 /* Packet device */
430 d->amode = 0;
431
432 d->geom.cylinders = 0;
433 d->geom.heads = 0;
434 d->geom.sectors = 0;
435
436 d->blocks = 0;
437 } else if ((idata.caps & rd_cap_lba) == 0) {
438 /* Device only supports CHS addressing. */
439 d->amode = am_chs;
440
441 d->geom.cylinders = idata.cylinders;
442 d->geom.heads = idata.heads;
443 d->geom.sectors = idata.sectors;
444
445 d->blocks = d->geom.cylinders * d->geom.heads * d->geom.sectors;
446 } else if ((idata.cmd_set1 & cs1_addr48) == 0) {
447 /* Device only supports LBA-28 addressing. */
448 d->amode = am_lba28;
449
450 d->geom.cylinders = 0;
451 d->geom.heads = 0;
452 d->geom.sectors = 0;
453
454 d->blocks =
455 (uint32_t) idata.total_lba28_0 |
456 ((uint32_t) idata.total_lba28_1 << 16);
457 } else {
458 /* Device supports LBA-48 addressing. */
459 d->amode = am_lba48;
460
461 d->geom.cylinders = 0;
462 d->geom.heads = 0;
463 d->geom.sectors = 0;
464
465 d->blocks =
466 (uint64_t) idata.total_lba48_0 |
467 ((uint64_t) idata.total_lba48_1 << 16) |
468 ((uint64_t) idata.total_lba48_2 << 32) |
469 ((uint64_t) idata.total_lba48_3 << 48);
470 }
471
472 /*
473 * Convert model name to string representation.
474 */
475 for (i = 0; i < 20; i++) {
476 w = idata.model_name[i];
477 model[2 * i] = w >> 8;
478 model[2 * i + 1] = w & 0x00ff;
479 }
480
481 len = 40;
482 while (len > 0 && model[len - 1] == 0x20)
483 --len;
484
485 pos = 0;
486 for (i = 0; i < len; ++i) {
487 c = model[i];
488 if (c >= 0x80) c = '?';
489
490 chr_encode(c, d->model, &pos, 40);
491 }
492 d->model[pos] = '\0';
493
494 if (d->dev_type == ata_pkt_dev) {
495 /* Send inquiry. */
496 rc = ata_pcmd_inquiry(0, &inq_data, sizeof(inq_data));
497 if (rc != EOK) {
498 printf("Device inquiry failed.\n");
499 d->present = false;
500 return EIO;
501 }
502
503 /* Check device type. */
504 if (INQUIRY_PDEV_TYPE(inq_data.pdev_type) != PDEV_TYPE_CDROM)
505 printf("Warning: Peripheral device type is not CD-ROM.\n");
506
507 /* Assume 2k block size for now. */
508 d->block_size = 2048;
509 } else {
510 /* Assume register Read always uses 512-byte blocks. */
511 d->block_size = 512;
512 }
513
514 d->present = true;
515 return EOK;
516}
517
518/** Read multiple blocks from the device. */
519static int ata_bd_read_blocks(int disk_id, uint64_t ba, size_t cnt,
520 void *buf) {
521
522 int rc;
523
524 while (cnt > 0) {
525 if (disk[disk_id].dev_type == ata_reg_dev)
526 rc = ata_rcmd_read(disk_id, ba, 1, buf);
527 else
528 rc = ata_pcmd_read_12(disk_id, ba, 1, buf,
529 disk[disk_id].block_size);
530
531 if (rc != EOK)
532 return rc;
533
534 ++ba;
535 --cnt;
536 buf += disk[disk_id].block_size;
537 }
538
539 return EOK;
540}
541
542/** Write multiple blocks to the device. */
543static int ata_bd_write_blocks(int disk_id, uint64_t ba, size_t cnt,
544 const void *buf) {
545
546 int rc;
547
548 if (disk[disk_id].dev_type != ata_reg_dev)
549 return ENOTSUP;
550
551 while (cnt > 0) {
552 rc = ata_rcmd_write(disk_id, ba, 1, buf);
553 if (rc != EOK)
554 return rc;
555
556 ++ba;
557 --cnt;
558 buf += disk[disk_id].block_size;
559 }
560
561 return EOK;
562}
563
564/** Issue IDENTIFY command.
565 *
566 * Reads @c identify data into the provided buffer. This is used to detect
567 * whether an ATA device is present and if so, to determine its parameters.
568 *
569 * @param disk_id Device ID, 0 or 1.
570 * @param buf Pointer to a 512-byte buffer.
571 *
572 * @return ETIMEOUT on timeout (this can mean the device is
573 * not present). EIO if device responds with error.
574 */
575static int drive_identify(int disk_id, void *buf)
576{
577 uint16_t data;
578 uint8_t status;
579 uint8_t drv_head;
580 size_t i;
581
582 drv_head = ((disk_id != 0) ? DHR_DRV : 0);
583
584 if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
585 return ETIMEOUT;
586
587 pio_write_8(&cmd->drive_head, drv_head);
588
589 /*
590 * Do not wait for DRDY to be set in case this is a packet device.
591 * We determine whether the device is present by waiting for DRQ to be
592 * set after issuing the command.
593 */
594 if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
595 return ETIMEOUT;
596
597 pio_write_8(&cmd->command, CMD_IDENTIFY_DRIVE);
598
599 if (wait_status(0, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK)
600 return ETIMEOUT;
601
602 /*
603 * If ERR is set, this may be a packet device, so return EIO to cause
604 * the caller to check for one.
605 */
606 if ((status & SR_ERR) != 0) {
607 return EIO;
608 }
609
610 if (wait_status(SR_DRQ, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK)
611 return ETIMEOUT;
612
613 /* Read data from the disk buffer. */
614
615 for (i = 0; i < identify_data_size / 2; i++) {
616 data = pio_read_16(&cmd->data_port);
617 ((uint16_t *) buf)[i] = data;
618 }
619
620 return EOK;
621}
622
623/** Issue Identify Packet Device command.
624 *
625 * Reads @c identify data into the provided buffer. This is used to detect
626 * whether an ATAPI device is present and if so, to determine its parameters.
627 *
628 * @param dev_idx Device index, 0 or 1.
629 * @param buf Pointer to a 512-byte buffer.
630 */
631static int identify_pkt_dev(int dev_idx, void *buf)
632{
633 uint16_t data;
634 uint8_t status;
635 uint8_t drv_head;
636 size_t i;
637
638 drv_head = ((dev_idx != 0) ? DHR_DRV : 0);
639
640 if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
641 return EIO;
642
643 pio_write_8(&cmd->drive_head, drv_head);
644
645 /* For ATAPI commands we do not need to wait for DRDY. */
646 if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
647 return EIO;
648
649 pio_write_8(&cmd->command, CMD_IDENTIFY_PKT_DEV);
650
651 if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK)
652 return EIO;
653
654 /* Read data from the device buffer. */
655
656 if ((status & SR_DRQ) != 0) {
657 for (i = 0; i < identify_data_size / 2; i++) {
658 data = pio_read_16(&cmd->data_port);
659 ((uint16_t *) buf)[i] = data;
660 }
661 }
662
663 if ((status & SR_ERR) != 0)
664 return EIO;
665
666 return EOK;
667}
668
669/** Issue packet command (i. e. write a command packet to the device).
670 *
671 * Only data-in commands are supported (e.g. inquiry, read).
672 *
673 * @param dev_idx Device index (0 or 1)
674 * @param obuf Buffer for storing data read from device
675 * @param obuf_size Size of obuf in bytes
676 *
677 * @return EOK on success, EIO on error.
678 */
679static int ata_cmd_packet(int dev_idx, const void *cpkt, size_t cpkt_size,
680 void *obuf, size_t obuf_size)
681{
682 size_t i;
683 uint8_t status;
684 uint8_t drv_head;
685 disk_t *d;
686 size_t data_size;
687 uint16_t val;
688
689 d = &disk[dev_idx];
690 fibril_mutex_lock(&d->lock);
691
692 /* New value for Drive/Head register */
693 drv_head =
694 ((dev_idx != 0) ? DHR_DRV : 0);
695
696 if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) {
697 fibril_mutex_unlock(&d->lock);
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) {
704 fibril_mutex_unlock(&d->lock);
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) {
715 fibril_mutex_unlock(&d->lock);
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) {
724 fibril_mutex_unlock(&d->lock);
725 return EIO;
726 }
727
728 if ((status & SR_DRQ) == 0) {
729 fibril_mutex_unlock(&d->lock);
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. */
740 fibril_mutex_unlock(&d->lock);
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) {
751 fibril_mutex_unlock(&d->lock);
752 return EIO;
753 }
754
755 fibril_mutex_unlock(&d->lock);
756
757 return EOK;
758}
759
760/** Issue ATAPI Inquiry.
761 *
762 * @param dev_idx Device index (0 or 1)
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 */
768static int ata_pcmd_inquiry(int dev_idx, void *obuf, size_t obuf_size)
769{
770 ata_pcmd_inquiry_t cp;
771 int rc;
772
773 memset(&cp, 0, sizeof(cp));
774
775 cp.opcode = PCMD_INQUIRY;
776 cp.alloc_len = min(obuf_size, 0xff); /* Allocation length */
777
778 rc = ata_cmd_packet(0, &cp, sizeof(cp), obuf, obuf_size);
779 if (rc != EOK)
780 return rc;
781
782 return EOK;
783}
784
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 *
790 * @param dev_idx Device index (0 or 1)
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 */
798static int ata_pcmd_read_12(int dev_idx, uint64_t ba, size_t cnt,
799 void *obuf, size_t obuf_size)
800{
801 ata_pcmd_read_12_t cp;
802 int rc;
803
804 if (ba > UINT32_MAX)
805 return EINVAL;
806
807 memset(&cp, 0, sizeof(cp));
808
809 cp.opcode = PCMD_READ_12;
810 cp.ba = host2uint32_t_be(ba);
811 cp.nblocks = host2uint32_t_be(cnt);
812
813 rc = ata_cmd_packet(0, &cp, sizeof(cp), obuf, obuf_size);
814 if (rc != EOK)
815 return rc;
816
817 return EOK;
818}
819
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 *
830 * @param dev_idx Device index (0 or 1)
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 */
837static int ata_pcmd_read_toc(int dev_idx, uint8_t session, void *obuf,
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
859/** Read a physical from the device.
860 *
861 * @param disk_id Device index (0 or 1)
862 * @param ba Address the first block.
863 * @param cnt Number of blocks to transfer.
864 * @param buf Buffer for holding the data.
865 *
866 * @return EOK on success, EIO on error.
867 */
868static int ata_rcmd_read(int disk_id, uint64_t ba, size_t blk_cnt,
869 void *buf)
870{
871 size_t i;
872 uint16_t data;
873 uint8_t status;
874 uint8_t drv_head;
875 disk_t *d;
876 block_coord_t bc;
877
878 d = &disk[disk_id];
879
880 /* Silence warning. */
881 memset(&bc, 0, sizeof(bc));
882
883 /* Compute block coordinates. */
884 if (coord_calc(d, ba, &bc) != EOK)
885 return EINVAL;
886
887 /* New value for Drive/Head register */
888 drv_head =
889 ((disk_id != 0) ? DHR_DRV : 0) |
890 ((d->amode != am_chs) ? DHR_LBA : 0) |
891 (bc.h & 0x0f);
892
893 fibril_mutex_lock(&d->lock);
894
895 /* Program a Read Sectors operation. */
896
897 if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_BSY) != EOK) {
898 fibril_mutex_unlock(&d->lock);
899 return EIO;
900 }
901
902 pio_write_8(&cmd->drive_head, drv_head);
903
904 if (wait_status(SR_DRDY, ~SR_BSY, NULL, TIMEOUT_DRDY) != EOK) {
905 fibril_mutex_unlock(&d->lock);
906 return EIO;
907 }
908
909 /* Program block coordinates into the device. */
910 coord_sc_program(&bc, 1);
911
912 pio_write_8(&cmd->command, d->amode == am_lba48 ?
913 CMD_READ_SECTORS_EXT : CMD_READ_SECTORS);
914
915 if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
916 fibril_mutex_unlock(&d->lock);
917 return EIO;
918 }
919
920 if ((status & SR_DRQ) != 0) {
921 /* Read data from the device buffer. */
922
923 for (i = 0; i < disk[disk_id].block_size / 2; i++) {
924 data = pio_read_16(&cmd->data_port);
925 ((uint16_t *) buf)[i] = data;
926 }
927 }
928
929 if ((status & SR_ERR) != 0)
930 return EIO;
931
932 fibril_mutex_unlock(&d->lock);
933 return EOK;
934}
935
936/** Write a physical block to the device.
937 *
938 * @param disk_id Device index (0 or 1)
939 * @param ba Address of the first block.
940 * @param cnt Number of blocks to transfer.
941 * @param buf Buffer holding the data to write.
942 *
943 * @return EOK on success, EIO on error.
944 */
945static int ata_rcmd_write(int disk_id, uint64_t ba, size_t cnt,
946 const void *buf)
947{
948 size_t i;
949 uint8_t status;
950 uint8_t drv_head;
951 disk_t *d;
952 block_coord_t bc;
953
954 d = &disk[disk_id];
955
956 /* Silence warning. */
957 memset(&bc, 0, sizeof(bc));
958
959 /* Compute block coordinates. */
960 if (coord_calc(d, ba, &bc) != EOK)
961 return EINVAL;
962
963 /* New value for Drive/Head register */
964 drv_head =
965 ((disk_id != 0) ? DHR_DRV : 0) |
966 ((d->amode != am_chs) ? DHR_LBA : 0) |
967 (bc.h & 0x0f);
968
969 fibril_mutex_lock(&d->lock);
970
971 /* Program a Write Sectors operation. */
972
973 if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_BSY) != EOK) {
974 fibril_mutex_unlock(&d->lock);
975 return EIO;
976 }
977
978 pio_write_8(&cmd->drive_head, drv_head);
979
980 if (wait_status(SR_DRDY, ~SR_BSY, NULL, TIMEOUT_DRDY) != EOK) {
981 fibril_mutex_unlock(&d->lock);
982 return EIO;
983 }
984
985 /* Program block coordinates into the device. */
986 coord_sc_program(&bc, 1);
987
988 pio_write_8(&cmd->command, d->amode == am_lba48 ?
989 CMD_WRITE_SECTORS_EXT : CMD_WRITE_SECTORS);
990
991 if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
992 fibril_mutex_unlock(&d->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[disk_id].block_size / 2; i++) {
1000 pio_write_16(&cmd->data_port, ((uint16_t *) buf)[i]);
1001 }
1002 }
1003
1004 fibril_mutex_unlock(&d->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 */
1070static void coord_sc_program(const block_coord_t *bc, uint16_t scnt)
1071{
1072 if (bc->amode == am_lba48) {
1073 /* Write high-order bits. */
1074 pio_write_8(&cmd->sector_count, scnt >> 8);
1075 pio_write_8(&cmd->sector_number, bc->c3);
1076 pio_write_8(&cmd->cylinder_low, bc->c4);
1077 pio_write_8(&cmd->cylinder_high, bc->c5);
1078 }
1079
1080 /* Write low-order bits. */
1081 pio_write_8(&cmd->sector_count, scnt & 0x00ff);
1082 pio_write_8(&cmd->sector_number, bc->c0);
1083 pio_write_8(&cmd->cylinder_low, bc->c1);
1084 pio_write_8(&cmd->cylinder_high, bc->c2);
1085}
1086
1087/** Wait until some status bits are set and some are reset.
1088 *
1089 * Example: wait_status(SR_DRDY, ~SR_BSY) waits for SR_DRDY to become
1090 * set and SR_BSY to become reset.
1091 *
1092 * @param set Combination if bits which must be all set.
1093 * @param n_reset Negated combination of bits which must be all reset.
1094 * @param pstatus Pointer where to store last read status or NULL.
1095 * @param timeout Timeout in 10ms units.
1096 *
1097 * @return EOK on success, EIO on timeout.
1098 */
1099static int wait_status(unsigned set, unsigned n_reset, uint8_t *pstatus,
1100 unsigned timeout)
1101{
1102 uint8_t status;
1103 int cnt;
1104
1105 status = pio_read_8(&cmd->status);
1106
1107 /*
1108 * This is crude, yet simple. First try with 1us delays
1109 * (most likely the device will respond very fast). If not,
1110 * start trying every 10 ms.
1111 */
1112
1113 cnt = 100;
1114 while ((status & ~n_reset) != 0 || (status & set) != set) {
1115 async_usleep(1);
1116 --cnt;
1117 if (cnt <= 0) break;
1118
1119 status = pio_read_8(&cmd->status);
1120 }
1121
1122 cnt = timeout;
1123 while ((status & ~n_reset) != 0 || (status & set) != set) {
1124 async_usleep(10000);
1125 --cnt;
1126 if (cnt <= 0) break;
1127
1128 status = pio_read_8(&cmd->status);
1129 }
1130
1131 if (pstatus)
1132 *pstatus = status;
1133
1134 if (cnt == 0)
1135 return EIO;
1136
1137 return EOK;
1138}
1139
1140/**
1141 * @}
1142 */
Note: See TracBrowser for help on using the repository browser.