source: mainline/uspace/srv/bd/ata_bd/ata_bd.c@ 4daee7a

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

Standards-compliant boolean type.

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