Changeset 04803bf in mainline for uspace/srv/bd/ata_bd/ata_bd.c
- Timestamp:
- 2011-03-21T22:00:17Z (15 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 143932e3
- Parents:
- b50b5af2 (diff), 7308e84 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)links above to see all the changes relative to each parent. - File:
-
- 1 edited
-
uspace/srv/bd/ata_bd/ata_bd.c (modified) (22 diffs)
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/bd/ata_bd/ata_bd.c
rb50b5af2 r04803bf 35 35 * @brief ATA disk driver 36 36 * 37 * This driver currently works only with CHS addressing and uses PIO. 38 * Currently based on the (now obsolete) ATA-1, ATA-2 standards. 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. 39 45 * 40 46 * The driver services a single controller which can have up to two disks … … 45 51 #include <libarch/ddi.h> 46 52 #include <ddi.h> 47 #include <ipc/ipc.h>48 53 #include <ipc/bd.h> 49 54 #include <async.h> 50 55 #include <as.h> 51 #include <fibril_sync.h> 56 #include <fibril_synch.h> 57 #include <stdint.h> 58 #include <str.h> 52 59 #include <devmap.h> 53 60 #include <sys/types.h> 61 #include <inttypes.h> 54 62 #include <errno.h> 55 63 #include <bool.h> 64 #include <byteorder.h> 56 65 #include <task.h> 57 66 #include <macros.h> 67 68 #include "ata_hw.h" 58 69 #include "ata_bd.h" 59 70 60 #define NAME "ata_bd" 61 62 /** Physical block size. Should be always 512. */ 63 static const size_t block_size = 512; 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 */ 81 static const size_t identify_data_size = 512; 64 82 65 83 /** Size of the communication area. */ … … 67 85 68 86 /** I/O base address of the command registers. */ 69 static uintptr_t cmd_physical = 0x1f0;87 static uintptr_t cmd_physical; 70 88 /** I/O base address of the control registers. */ 71 static uintptr_t ctl_physical = 0x170; 89 static uintptr_t ctl_physical; 90 91 /** I/O base addresses for legacy (ISA-compatible) controllers. */ 92 static ata_base_t legacy_base[LEGACY_CTLS] = { 93 { 0x1f0, 0x3f0 }, 94 { 0x170, 0x370 }, 95 { 0x1e8, 0x3e8 }, 96 { 0x168, 0x368 } 97 }; 72 98 73 99 static ata_cmd_t *cmd; … … 77 103 static disk_t disk[MAX_DISKS]; 78 104 105 static void print_syntax(void); 79 106 static int ata_bd_init(void); 80 107 static void ata_bd_connection(ipc_callid_t iid, ipc_call_t *icall); 81 static int ata_bd_r dwr(int disk_id, ipcarg_t method, off_t offset, size_t size,108 static int ata_bd_read_blocks(int disk_id, uint64_t ba, size_t cnt, 82 109 void *buf); 83 static int ata_bd_read_block(int disk_id, uint64_t blk_idx, size_t blk_cnt, 110 static int ata_bd_write_blocks(int disk_id, uint64_t ba, size_t cnt, 111 const void *buf); 112 static int ata_rcmd_read(int disk_id, uint64_t ba, size_t cnt, 84 113 void *buf); 85 static int ata_ bd_write_block(int disk_id, uint64_t blk_idx, size_t blk_cnt,114 static int ata_rcmd_write(int disk_id, uint64_t ba, size_t cnt, 86 115 const void *buf); 87 static int drive_identify(int drive_id, disk_t *d); 116 static int disk_init(disk_t *d, int disk_id); 117 static int drive_identify(int drive_id, void *buf); 118 static int identify_pkt_dev(int dev_idx, void *buf); 119 static int ata_cmd_packet(int dev_idx, const void *cpkt, size_t cpkt_size, 120 void *obuf, size_t obuf_size); 121 static int ata_pcmd_inquiry(int dev_idx, void *obuf, size_t obuf_size); 122 static int ata_pcmd_read_12(int dev_idx, uint64_t ba, size_t cnt, 123 void *obuf, size_t obuf_size); 124 static void disk_print_summary(disk_t *d); 125 static int coord_calc(disk_t *d, uint64_t ba, block_coord_t *bc); 126 static void coord_sc_program(const block_coord_t *bc, uint16_t scnt); 88 127 static int wait_status(unsigned set, unsigned n_reset, uint8_t *pstatus, 89 128 unsigned timeout); … … 94 133 int i, rc; 95 134 int n_disks; 135 unsigned ctl_num; 136 char *eptr; 96 137 97 138 printf(NAME ": ATA disk driver\n"); 98 139 99 printf("I/O address 0x%x\n", cmd_physical); 140 if (argc > 1) { 141 ctl_num = strtoul(argv[1], &eptr, 0); 142 if (*eptr != '\0' || ctl_num == 0 || ctl_num > 4) { 143 printf("Invalid argument.\n"); 144 print_syntax(); 145 return -1; 146 } 147 } else { 148 ctl_num = 1; 149 } 150 151 cmd_physical = legacy_base[ctl_num - 1].cmd; 152 ctl_physical = legacy_base[ctl_num - 1].ctl; 153 154 printf("I/O address %p/%p\n", (void *) cmd_physical, 155 (void *) ctl_physical); 100 156 101 157 if (ata_bd_init() != EOK) … … 106 162 fflush(stdout); 107 163 108 rc = d rive_identify(i, &disk[i]);164 rc = disk_init(&disk[i], i); 109 165 110 166 if (rc == EOK) { 111 printf("%u cylinders, %u heads, %u sectors\n", 112 disk[i].cylinders, disk[i].heads, disk[i].sectors); 167 disk_print_summary(&disk[i]); 113 168 } else { 114 169 printf("Not found.\n"); … … 122 177 if (disk[i].present == false) 123 178 continue; 124 125 snprintf(name, 16, " disk%d", i);126 rc = devmap_device_register(name, &disk[i].dev _handle);179 180 snprintf(name, 16, "%s/ata%udisk%d", NAMESPACE, ctl_num, i); 181 rc = devmap_device_register(name, &disk[i].devmap_handle); 127 182 if (rc != EOK) { 128 devmap_hangup_phone(DEVMAP_DRIVER); 129 printf(NAME ": Unable to register device %s.\n", 130 name); 183 printf(NAME ": Unable to register device %s.\n", name); 131 184 return rc; 132 185 } … … 147 200 } 148 201 202 203 static void print_syntax(void) 204 { 205 printf("Syntax: " NAME " <controller_number>\n"); 206 printf("Controller number = 1..4\n"); 207 } 208 209 /** Print one-line device summary. */ 210 static void disk_print_summary(disk_t *d) 211 { 212 uint64_t mbytes; 213 214 printf("%s: ", d->model); 215 216 if (d->dev_type == ata_reg_dev) { 217 switch (d->amode) { 218 case am_chs: 219 printf("CHS %u cylinders, %u heads, %u sectors", 220 disk->geom.cylinders, disk->geom.heads, 221 disk->geom.sectors); 222 break; 223 case am_lba28: 224 printf("LBA-28"); 225 break; 226 case am_lba48: 227 printf("LBA-48"); 228 break; 229 } 230 } else { 231 printf("PACKET"); 232 } 233 234 printf(" %" PRIu64 " blocks", d->blocks); 235 236 mbytes = d->blocks / (2 * 1024); 237 if (mbytes > 0) 238 printf(" %" PRIu64 " MB.", mbytes); 239 240 printf("\n"); 241 } 149 242 150 243 /** Register driver and enable device I/O. */ … … 186 279 ipc_callid_t callid; 187 280 ipc_call_t call; 188 ipcarg_t method;189 dev _handle_t dh;190 int flags;281 sysarg_t method; 282 devmap_handle_t dh; 283 unsigned int flags; 191 284 int retval; 192 off_t idx;193 size_t size;285 uint64_t ba; 286 size_t cnt; 194 287 int disk_id, i; 195 288 … … 200 293 disk_id = -1; 201 294 for (i = 0; i < MAX_DISKS; i++) 202 if (disk[i].dev _handle == dh)295 if (disk[i].devmap_handle == dh) 203 296 disk_id = i; 204 297 205 298 if (disk_id < 0 || disk[disk_id].present == false) { 206 ipc_answer_0(iid, EINVAL);299 async_answer_0(iid, EINVAL); 207 300 return; 208 301 } 209 302 210 303 /* Answer the IPC_M_CONNECT_ME_TO call. */ 211 ipc_answer_0(iid, EOK);212 213 if (! ipc_share_out_receive(&callid, &comm_size, &flags)) {214 ipc_answer_0(callid, EHANGUP);304 async_answer_0(iid, EOK); 305 306 if (!async_share_out_receive(&callid, &comm_size, &flags)) { 307 async_answer_0(callid, EHANGUP); 215 308 return; 216 309 } … … 218 311 fs_va = as_get_mappable_page(comm_size); 219 312 if (fs_va == NULL) { 220 ipc_answer_0(callid, EHANGUP);313 async_answer_0(callid, EHANGUP); 221 314 return; 222 315 } 223 316 224 (void) ipc_share_out_finalize(callid, fs_va);317 (void) async_share_out_finalize(callid, fs_va); 225 318 226 319 while (1) { 227 320 callid = async_get_call(&call); 228 method = IPC_GET_ METHOD(call);321 method = IPC_GET_IMETHOD(call); 229 322 switch (method) { 230 323 case IPC_M_PHONE_HUNGUP: 231 324 /* The other side has hung up. */ 232 ipc_answer_0(callid, EOK);325 async_answer_0(callid, EOK); 233 326 return; 234 case BD_READ_BLOCK :235 case BD_WRITE_BLOCK:236 idx = IPC_GET_ARG1(call);237 size = IPC_GET_ARG2(call);238 if ( size > comm_size) {239 retval = E INVAL;327 case BD_READ_BLOCKS: 328 ba = MERGE_LOUP32(IPC_GET_ARG1(call), 329 IPC_GET_ARG2(call)); 330 cnt = IPC_GET_ARG3(call); 331 if (cnt * disk[disk_id].block_size > comm_size) { 332 retval = ELIMIT; 240 333 break; 241 334 } 242 retval = ata_bd_rdwr(disk_id, method, idx, 243 size, fs_va); 335 retval = ata_bd_read_blocks(disk_id, ba, cnt, fs_va); 244 336 break; 337 case BD_WRITE_BLOCKS: 338 ba = MERGE_LOUP32(IPC_GET_ARG1(call), 339 IPC_GET_ARG2(call)); 340 cnt = IPC_GET_ARG3(call); 341 if (cnt * disk[disk_id].block_size > comm_size) { 342 retval = ELIMIT; 343 break; 344 } 345 retval = ata_bd_write_blocks(disk_id, ba, cnt, fs_va); 346 break; 347 case BD_GET_BLOCK_SIZE: 348 async_answer_1(callid, EOK, disk[disk_id].block_size); 349 continue; 350 case BD_GET_NUM_BLOCKS: 351 async_answer_2(callid, EOK, LOWER32(disk[disk_id].blocks), 352 UPPER32(disk[disk_id].blocks)); 353 continue; 245 354 default: 246 355 retval = EINVAL; 247 356 break; 248 357 } 249 ipc_answer_0(callid, retval);250 } 251 } 252 253 /** Transfer a logical block from/to the device.254 * 255 * @param disk_id Device index (0 or 1)256 * @param method @c BD_READ_BLOCK or @c BD_WRITE_BLOCK257 * @param blk_idx Index of the first block.258 * @param size Size of the logical block. 259 * @param buf Data buffer. 260 * 261 * @return EOK on success, EIO on error. 262 */ 263 static int ata_bd_rdwr(int disk_id, ipcarg_t method, off_t blk_idx, size_t size, 264 void *buf) 265 { 358 async_answer_0(callid, retval); 359 } 360 } 361 362 /** Initialize a disk. 363 * 364 * Probes for a disk, determines its parameters and initializes 365 * the disk structure. 366 */ 367 static int disk_init(disk_t *d, int disk_id) 368 { 369 identify_data_t idata; 370 uint8_t model[40]; 371 ata_inquiry_data_t inq_data; 372 uint16_t w; 373 uint8_t c; 374 size_t pos, len; 266 375 int rc; 267 size_t now; 268 269 while (size > 0) { 270 now = size < block_size ? size : block_size; 271 if (now != block_size) 272 return EINVAL; 273 274 if (method == BD_READ_BLOCK) 275 rc = ata_bd_read_block(disk_id, blk_idx, 1, buf); 376 unsigned i; 377 378 d->present = false; 379 fibril_mutex_initialize(&d->lock); 380 381 /* Try identify command. */ 382 rc = drive_identify(disk_id, &idata); 383 if (rc == EOK) { 384 /* Success. It's a register (non-packet) device. */ 385 printf("ATA register-only device found.\n"); 386 d->dev_type = ata_reg_dev; 387 } else if (rc == EIO) { 388 /* 389 * There is something, but not a register device. 390 * It could be a packet device. 391 */ 392 rc = identify_pkt_dev(disk_id, &idata); 393 if (rc == EOK) { 394 /* We have a packet device. */ 395 d->dev_type = ata_pkt_dev; 396 } else { 397 /* Nope. Something's there, but not recognized. */ 398 return EIO; 399 } 400 } else { 401 /* Operation timed out. That means there is no device there. */ 402 return EIO; 403 } 404 405 printf("device caps: 0x%04x\n", idata.caps); 406 if (d->dev_type == ata_pkt_dev) { 407 /* Packet device */ 408 d->amode = 0; 409 410 d->geom.cylinders = 0; 411 d->geom.heads = 0; 412 d->geom.sectors = 0; 413 414 d->blocks = 0; 415 } else if ((idata.caps & rd_cap_lba) == 0) { 416 /* Device only supports CHS addressing. */ 417 d->amode = am_chs; 418 419 d->geom.cylinders = idata.cylinders; 420 d->geom.heads = idata.heads; 421 d->geom.sectors = idata.sectors; 422 423 d->blocks = d->geom.cylinders * d->geom.heads * d->geom.sectors; 424 } else if ((idata.cmd_set1 & cs1_addr48) == 0) { 425 /* Device only supports LBA-28 addressing. */ 426 d->amode = am_lba28; 427 428 d->geom.cylinders = 0; 429 d->geom.heads = 0; 430 d->geom.sectors = 0; 431 432 d->blocks = 433 (uint32_t) idata.total_lba28_0 | 434 ((uint32_t) idata.total_lba28_1 << 16); 435 } else { 436 /* Device supports LBA-48 addressing. */ 437 d->amode = am_lba48; 438 439 d->geom.cylinders = 0; 440 d->geom.heads = 0; 441 d->geom.sectors = 0; 442 443 d->blocks = 444 (uint64_t) idata.total_lba48_0 | 445 ((uint64_t) idata.total_lba48_1 << 16) | 446 ((uint64_t) idata.total_lba48_2 << 32) | 447 ((uint64_t) idata.total_lba48_3 << 48); 448 } 449 450 /* 451 * Convert model name to string representation. 452 */ 453 for (i = 0; i < 20; i++) { 454 w = idata.model_name[i]; 455 model[2 * i] = w >> 8; 456 model[2 * i + 1] = w & 0x00ff; 457 } 458 459 len = 40; 460 while (len > 0 && model[len - 1] == 0x20) 461 --len; 462 463 pos = 0; 464 for (i = 0; i < len; ++i) { 465 c = model[i]; 466 if (c >= 0x80) c = '?'; 467 468 chr_encode(c, d->model, &pos, 40); 469 } 470 d->model[pos] = '\0'; 471 472 if (d->dev_type == ata_pkt_dev) { 473 /* Send inquiry. */ 474 rc = ata_pcmd_inquiry(0, &inq_data, sizeof(inq_data)); 475 if (rc != EOK) { 476 printf("Device inquiry failed.\n"); 477 d->present = false; 478 return EIO; 479 } 480 481 /* Check device type. */ 482 if (INQUIRY_PDEV_TYPE(inq_data.pdev_type) != PDEV_TYPE_CDROM) 483 printf("Warning: Peripheral device type is not CD-ROM.\n"); 484 485 /* Assume 2k block size for now. */ 486 d->block_size = 2048; 487 } else { 488 /* Assume register Read always uses 512-byte blocks. */ 489 d->block_size = 512; 490 } 491 492 d->present = true; 493 return EOK; 494 } 495 496 /** Read multiple blocks from the device. */ 497 static int ata_bd_read_blocks(int disk_id, uint64_t ba, size_t cnt, 498 void *buf) { 499 500 int rc; 501 502 while (cnt > 0) { 503 if (disk[disk_id].dev_type == ata_reg_dev) 504 rc = ata_rcmd_read(disk_id, ba, 1, buf); 276 505 else 277 rc = ata_bd_write_block(disk_id, blk_idx, 1, buf); 506 rc = ata_pcmd_read_12(disk_id, ba, 1, buf, 507 disk[disk_id].block_size); 278 508 279 509 if (rc != EOK) 280 510 return rc; 281 511 282 buf += block_size; 283 blk_idx++; 284 285 if (size > block_size) 286 size -= block_size; 287 else 288 size = 0; 512 ++ba; 513 --cnt; 514 buf += disk[disk_id].block_size; 515 } 516 517 return EOK; 518 } 519 520 /** Write multiple blocks to the device. */ 521 static int ata_bd_write_blocks(int disk_id, uint64_t ba, size_t cnt, 522 const void *buf) { 523 524 int rc; 525 526 if (disk[disk_id].dev_type != ata_reg_dev) 527 return ENOTSUP; 528 529 while (cnt > 0) { 530 rc = ata_rcmd_write(disk_id, ba, 1, buf); 531 if (rc != EOK) 532 return rc; 533 534 ++ba; 535 --cnt; 536 buf += disk[disk_id].block_size; 289 537 } 290 538 … … 294 542 /** Issue IDENTIFY command. 295 543 * 296 * This is used to detect whether an ATA device is present and if so,297 * to determine its parameters. The parameters are written to @a d.544 * Reads @c identify data into the provided buffer. This is used to detect 545 * whether an ATA device is present and if so, to determine its parameters. 298 546 * 299 547 * @param disk_id Device ID, 0 or 1. 300 * @param d Device structure to store parameters in. 301 */ 302 static int drive_identify(int disk_id, disk_t *d) 548 * @param buf Pointer to a 512-byte buffer. 549 * 550 * @return ETIMEOUT on timeout (this can mean the device is 551 * not present). EIO if device responds with error. 552 */ 553 static int drive_identify(int disk_id, void *buf) 303 554 { 304 555 uint16_t data; … … 308 559 309 560 drv_head = ((disk_id != 0) ? DHR_DRV : 0); 310 d->present = false;311 561 312 562 if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) 313 return E IO;563 return ETIMEOUT; 314 564 315 565 pio_write_8(&cmd->drive_head, drv_head); … … 320 570 */ 321 571 if (wait_status(SR_DRDY, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) 322 return E IO;572 return ETIMEOUT; 323 573 324 574 pio_write_8(&cmd->command, CMD_IDENTIFY_DRIVE); 325 575 326 576 if (wait_status(0, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK) 327 return E IO;577 return ETIMEOUT; 328 578 329 579 /* Read data from the disk buffer. */ 330 580 331 581 if ((status & SR_DRQ) != 0) { 332 // for (i = 0; i < block_size / 2; i++) { 333 // data = pio_read_16(&cmd->data_port); 334 // ((uint16_t *) buf)[i] = data; 335 // } 336 337 for (i = 0; i < block_size / 2; i++) { 582 for (i = 0; i < identify_data_size / 2; i++) { 338 583 data = pio_read_16(&cmd->data_port); 339 340 switch (i) { 341 case 1: d->cylinders = data; break; 342 case 3: d->heads = data; break; 343 case 6: d->sectors = data; break; 344 } 584 ((uint16_t *) buf)[i] = data; 345 585 } 346 586 } 347 587 588 if ((status & SR_ERR) != 0) { 589 return EIO; 590 } 591 592 return EOK; 593 } 594 595 /** Issue Identify Packet Device command. 596 * 597 * Reads @c identify data into the provided buffer. This is used to detect 598 * whether an ATAPI device is present and if so, to determine its parameters. 599 * 600 * @param dev_idx Device index, 0 or 1. 601 * @param buf Pointer to a 512-byte buffer. 602 */ 603 static int identify_pkt_dev(int dev_idx, void *buf) 604 { 605 uint16_t data; 606 uint8_t status; 607 uint8_t drv_head; 608 size_t i; 609 610 drv_head = ((dev_idx != 0) ? DHR_DRV : 0); 611 612 if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) 613 return EIO; 614 615 pio_write_8(&cmd->drive_head, drv_head); 616 617 /* For ATAPI commands we do not need to wait for DRDY. */ 618 if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) 619 return EIO; 620 621 pio_write_8(&cmd->command, CMD_IDENTIFY_PKT_DEV); 622 623 if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) 624 return EIO; 625 626 /* Read data from the device buffer. */ 627 628 if ((status & SR_DRQ) != 0) { 629 for (i = 0; i < identify_data_size / 2; i++) { 630 data = pio_read_16(&cmd->data_port); 631 ((uint16_t *) buf)[i] = data; 632 } 633 } 634 348 635 if ((status & SR_ERR) != 0) 349 636 return EIO; 350 637 351 d->blocks = d->cylinders * d->heads * d->sectors; 352 353 d->present = true; 354 fibril_mutex_initialize(&d->lock); 638 return EOK; 639 } 640 641 /** Issue packet command (i. e. write a command packet to the device). 642 * 643 * Only data-in commands are supported (e.g. inquiry, read). 644 * 645 * @param dev_idx Device index (0 or 1) 646 * @param obuf Buffer for storing data read from device 647 * @param obuf_size Size of obuf in bytes 648 * 649 * @return EOK on success, EIO on error. 650 */ 651 static int ata_cmd_packet(int dev_idx, const void *cpkt, size_t cpkt_size, 652 void *obuf, size_t obuf_size) 653 { 654 size_t i; 655 uint8_t status; 656 uint8_t drv_head; 657 disk_t *d; 658 size_t data_size; 659 uint16_t val; 660 661 d = &disk[dev_idx]; 662 fibril_mutex_lock(&d->lock); 663 664 /* New value for Drive/Head register */ 665 drv_head = 666 ((dev_idx != 0) ? DHR_DRV : 0); 667 668 if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) { 669 fibril_mutex_unlock(&d->lock); 670 return EIO; 671 } 672 673 pio_write_8(&cmd->drive_head, drv_head); 674 675 if (wait_status(0, ~(SR_BSY|SR_DRQ), NULL, TIMEOUT_BSY) != EOK) { 676 fibril_mutex_unlock(&d->lock); 677 return EIO; 678 } 679 680 /* Byte count <- max. number of bytes we can read in one transfer. */ 681 pio_write_8(&cmd->cylinder_low, 0xfe); 682 pio_write_8(&cmd->cylinder_high, 0xff); 683 684 pio_write_8(&cmd->command, CMD_PACKET); 685 686 if (wait_status(SR_DRQ, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) { 687 fibril_mutex_unlock(&d->lock); 688 return EIO; 689 } 690 691 /* Write command packet. */ 692 for (i = 0; i < (cpkt_size + 1) / 2; i++) 693 pio_write_16(&cmd->data_port, ((uint16_t *) cpkt)[i]); 694 695 if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) { 696 fibril_mutex_unlock(&d->lock); 697 return EIO; 698 } 699 700 if ((status & SR_DRQ) == 0) { 701 fibril_mutex_unlock(&d->lock); 702 return EIO; 703 } 704 705 /* Read byte count. */ 706 data_size = (uint16_t) pio_read_8(&cmd->cylinder_low) + 707 ((uint16_t) pio_read_8(&cmd->cylinder_high) << 8); 708 709 /* Check whether data fits into output buffer. */ 710 if (data_size > obuf_size) { 711 /* Output buffer is too small to store data. */ 712 fibril_mutex_unlock(&d->lock); 713 return EIO; 714 } 715 716 /* Read data from the device buffer. */ 717 for (i = 0; i < (data_size + 1) / 2; i++) { 718 val = pio_read_16(&cmd->data_port); 719 ((uint16_t *) obuf)[i] = val; 720 } 721 722 if (status & SR_ERR) { 723 fibril_mutex_unlock(&d->lock); 724 return EIO; 725 } 726 727 fibril_mutex_unlock(&d->lock); 728 729 return EOK; 730 } 731 732 /** Issue ATAPI Inquiry. 733 * 734 * @param dev_idx Device index (0 or 1) 735 * @param obuf Buffer for storing inquiry data read from device 736 * @param obuf_size Size of obuf in bytes 737 * 738 * @return EOK on success, EIO on error. 739 */ 740 static int ata_pcmd_inquiry(int dev_idx, void *obuf, size_t obuf_size) 741 { 742 ata_pcmd_inquiry_t cp; 743 int rc; 744 745 memset(&cp, 0, sizeof(cp)); 746 747 cp.opcode = PCMD_INQUIRY; 748 cp.alloc_len = min(obuf_size, 0xff); /* Allocation length */ 749 750 rc = ata_cmd_packet(0, &cp, sizeof(cp), obuf, obuf_size); 751 if (rc != EOK) 752 return rc; 753 754 return EOK; 755 } 756 757 /** Issue ATAPI read(12) command. 758 * 759 * Output buffer must be large enough to hold the data, otherwise the 760 * function will fail. 761 * 762 * @param dev_idx Device index (0 or 1) 763 * @param ba Starting block address 764 * @param cnt Number of blocks to read 765 * @param obuf Buffer for storing inquiry data read from device 766 * @param obuf_size Size of obuf in bytes 767 * 768 * @return EOK on success, EIO on error. 769 */ 770 static int ata_pcmd_read_12(int dev_idx, uint64_t ba, size_t cnt, 771 void *obuf, size_t obuf_size) 772 { 773 ata_pcmd_read_12_t cp; 774 int rc; 775 776 if (ba > UINT32_MAX) 777 return EINVAL; 778 779 memset(&cp, 0, sizeof(cp)); 780 781 cp.opcode = PCMD_READ_12; 782 cp.ba = host2uint32_t_be(ba); 783 cp.nblocks = host2uint32_t_be(cnt); 784 785 rc = ata_cmd_packet(0, &cp, sizeof(cp), obuf, obuf_size); 786 if (rc != EOK) 787 return rc; 355 788 356 789 return EOK; … … 360 793 * 361 794 * @param disk_id Device index (0 or 1) 362 * @param b lk_idx Index ofthe first block.363 * @param blk_cntNumber of blocks to transfer.795 * @param ba Address the first block. 796 * @param cnt Number of blocks to transfer. 364 797 * @param buf Buffer for holding the data. 365 798 * 366 799 * @return EOK on success, EIO on error. 367 800 */ 368 static int ata_ bd_read_block(int disk_id, uint64_t blk_idx, size_t blk_cnt,801 static int ata_rcmd_read(int disk_id, uint64_t ba, size_t blk_cnt, 369 802 void *buf) 370 803 { … … 372 805 uint16_t data; 373 806 uint8_t status; 374 uint64_t c, h, s;375 uint64_t idx;376 807 uint8_t drv_head; 377 808 disk_t *d; 809 block_coord_t bc; 378 810 379 811 d = &disk[disk_id]; 380 381 /* Check device bounds. */ 382 if (blk_idx >= d->blocks) 812 813 /* Silence warning. */ 814 memset(&bc, 0, sizeof(bc)); 815 816 /* Compute block coordinates. */ 817 if (coord_calc(d, ba, &bc) != EOK) 383 818 return EINVAL; 384 385 /* Compute CHS. */386 c = blk_idx / (d->heads * d->sectors);387 idx = blk_idx % (d->heads * d->sectors);388 389 h = idx / d->sectors;390 s = 1 + (idx % d->sectors);391 819 392 820 /* New value for Drive/Head register */ 393 821 drv_head = 394 822 ((disk_id != 0) ? DHR_DRV : 0) | 395 (h & 0x0f); 823 ((d->amode != am_chs) ? DHR_LBA : 0) | 824 (bc.h & 0x0f); 396 825 397 826 fibril_mutex_lock(&d->lock); … … 411 840 } 412 841 413 pio_write_8(&cmd->sector_count, 1); 414 pio_write_8(&cmd->sector_number, s); 415 pio_write_8(&cmd->cylinder_low, c & 0xff); 416 pio_write_8(&cmd->cylinder_high, c >> 16); 417 418 pio_write_8(&cmd->command, CMD_READ_SECTORS); 842 /* Program block coordinates into the device. */ 843 coord_sc_program(&bc, 1); 844 845 pio_write_8(&cmd->command, d->amode == am_lba48 ? 846 CMD_READ_SECTORS_EXT : CMD_READ_SECTORS); 419 847 420 848 if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) { … … 426 854 /* Read data from the device buffer. */ 427 855 428 for (i = 0; i < block_size / 2; i++) {856 for (i = 0; i < disk[disk_id].block_size / 2; i++) { 429 857 data = pio_read_16(&cmd->data_port); 430 858 ((uint16_t *) buf)[i] = data; … … 442 870 * 443 871 * @param disk_id Device index (0 or 1) 444 * @param b lk_idx Indexof the first block.445 * @param blk_cntNumber of blocks to transfer.872 * @param ba Address of the first block. 873 * @param cnt Number of blocks to transfer. 446 874 * @param buf Buffer holding the data to write. 447 875 * 448 876 * @return EOK on success, EIO on error. 449 877 */ 450 static int ata_ bd_write_block(int disk_id, uint64_t blk_idx, size_t blk_cnt,878 static int ata_rcmd_write(int disk_id, uint64_t ba, size_t cnt, 451 879 const void *buf) 452 880 { 453 881 size_t i; 454 882 uint8_t status; 455 uint64_t c, h, s;456 uint64_t idx;457 883 uint8_t drv_head; 458 884 disk_t *d; 885 block_coord_t bc; 459 886 460 887 d = &disk[disk_id]; 461 462 /* Check device bounds. */ 463 if (blk_idx >= d->blocks) 888 889 /* Silence warning. */ 890 memset(&bc, 0, sizeof(bc)); 891 892 /* Compute block coordinates. */ 893 if (coord_calc(d, ba, &bc) != EOK) 464 894 return EINVAL; 465 466 /* Compute CHS. */467 c = blk_idx / (d->heads * d->sectors);468 idx = blk_idx % (d->heads * d->sectors);469 470 h = idx / d->sectors;471 s = 1 + (idx % d->sectors);472 895 473 896 /* New value for Drive/Head register */ 474 897 drv_head = 475 898 ((disk_id != 0) ? DHR_DRV : 0) | 476 (h & 0x0f); 899 ((d->amode != am_chs) ? DHR_LBA : 0) | 900 (bc.h & 0x0f); 477 901 478 902 fibril_mutex_lock(&d->lock); … … 492 916 } 493 917 494 pio_write_8(&cmd->sector_count, 1); 495 pio_write_8(&cmd->sector_number, s); 496 pio_write_8(&cmd->cylinder_low, c & 0xff); 497 pio_write_8(&cmd->cylinder_high, c >> 16); 498 499 pio_write_8(&cmd->command, CMD_WRITE_SECTORS); 918 /* Program block coordinates into the device. */ 919 coord_sc_program(&bc, 1); 920 921 pio_write_8(&cmd->command, d->amode == am_lba48 ? 922 CMD_WRITE_SECTORS_EXT : CMD_WRITE_SECTORS); 500 923 501 924 if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) { … … 507 930 /* Write data to the device buffer. */ 508 931 509 for (i = 0; i < block_size / 2; i++) {932 for (i = 0; i < disk[disk_id].block_size / 2; i++) { 510 933 pio_write_16(&cmd->data_port, ((uint16_t *) buf)[i]); 511 934 } … … 518 941 519 942 return EOK; 943 } 944 945 /** Calculate block coordinates. 946 * 947 * Calculates block coordinates in the best coordinate system supported 948 * by the device. These can be later programmed into the device using 949 * @c coord_sc_program(). 950 * 951 * @return EOK on success or EINVAL if block index is past end of device. 952 */ 953 static int coord_calc(disk_t *d, uint64_t ba, block_coord_t *bc) 954 { 955 uint64_t c; 956 uint64_t idx; 957 958 /* Check device bounds. */ 959 if (ba >= d->blocks) 960 return EINVAL; 961 962 bc->amode = d->amode; 963 964 switch (d->amode) { 965 case am_chs: 966 /* Compute CHS coordinates. */ 967 c = ba / (d->geom.heads * d->geom.sectors); 968 idx = ba % (d->geom.heads * d->geom.sectors); 969 970 bc->cyl_lo = c & 0xff; 971 bc->cyl_hi = (c >> 8) & 0xff; 972 bc->h = (idx / d->geom.sectors) & 0x0f; 973 bc->sector = (1 + (idx % d->geom.sectors)) & 0xff; 974 break; 975 976 case am_lba28: 977 /* Compute LBA-28 coordinates. */ 978 bc->c0 = ba & 0xff; /* bits 0-7 */ 979 bc->c1 = (ba >> 8) & 0xff; /* bits 8-15 */ 980 bc->c2 = (ba >> 16) & 0xff; /* bits 16-23 */ 981 bc->h = (ba >> 24) & 0x0f; /* bits 24-27 */ 982 break; 983 984 case am_lba48: 985 /* Compute LBA-48 coordinates. */ 986 bc->c0 = ba & 0xff; /* bits 0-7 */ 987 bc->c1 = (ba >> 8) & 0xff; /* bits 8-15 */ 988 bc->c2 = (ba >> 16) & 0xff; /* bits 16-23 */ 989 bc->c3 = (ba >> 24) & 0xff; /* bits 24-31 */ 990 bc->c4 = (ba >> 32) & 0xff; /* bits 32-39 */ 991 bc->c5 = (ba >> 40) & 0xff; /* bits 40-47 */ 992 bc->h = 0; 993 break; 994 } 995 996 return EOK; 997 } 998 999 /** Program block coordinates and sector count into ATA registers. 1000 * 1001 * Note that bc->h must be programmed separately into the device/head register. 1002 */ 1003 static void coord_sc_program(const block_coord_t *bc, uint16_t scnt) 1004 { 1005 if (bc->amode == am_lba48) { 1006 /* Write high-order bits. */ 1007 pio_write_8(&cmd->sector_count, scnt >> 8); 1008 pio_write_8(&cmd->sector_number, bc->c3); 1009 pio_write_8(&cmd->cylinder_low, bc->c4); 1010 pio_write_8(&cmd->cylinder_high, bc->c5); 1011 } 1012 1013 /* Write low-order bits. */ 1014 pio_write_8(&cmd->sector_count, scnt & 0x00ff); 1015 pio_write_8(&cmd->sector_number, bc->c0); 1016 pio_write_8(&cmd->cylinder_low, bc->c1); 1017 pio_write_8(&cmd->cylinder_high, bc->c2); 520 1018 } 521 1019
Note:
See TracChangeset
for help on using the changeset viewer.
