source: mainline/uspace/srv/bd/ata_bd/ata_bd.c@ 96cbd18

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

Encapsulate controller state in ata_bd.

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