Changeset b50b5af2 in mainline for uspace/srv/bd/ata_bd/ata_bd.c
- Timestamp:
- 2009-08-22T10:48:00Z (15 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 04803bf
- Parents:
- 1ea99cc (diff), a71c158 (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
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/bd/ata_bd/ata_bd.c
r1ea99cc rb50b5af2 36 36 * 37 37 * This driver currently works only with CHS addressing and uses PIO. 38 * Currently based on the (now obsolete) ANSI X3.221-1994 (ATA-1) standard. 39 * At this point only reading is possible, not writing. 38 * Currently based on the (now obsolete) ATA-1, ATA-2 standards. 40 39 * 41 40 * The driver services a single controller which can have up to two disks … … 61 60 #define NAME "ata_bd" 62 61 62 /** Physical block size. Should be always 512. */ 63 63 static const size_t block_size = 512; 64 65 /** Size of the communication area. */ 64 66 static size_t comm_size; 65 67 68 /** I/O base address of the command registers. */ 66 69 static uintptr_t cmd_physical = 0x1f0; 70 /** I/O base address of the control registers. */ 67 71 static uintptr_t ctl_physical = 0x170; 72 68 73 static ata_cmd_t *cmd; 69 74 static ata_ctl_t *ctl; … … 81 86 const void *buf); 82 87 static int drive_identify(int drive_id, disk_t *d); 88 static int wait_status(unsigned set, unsigned n_reset, uint8_t *pstatus, 89 unsigned timeout); 83 90 84 91 int main(int argc, char **argv) 85 92 { 86 uint8_t status;87 93 char name[16]; 88 94 int i, rc; … … 96 102 return -1; 97 103 98 /* Put drives to reset, disable interrupts. */ 99 printf("Reset drives... "); 100 fflush(stdout); 101 102 pio_write_8(&ctl->device_control, DCR_SRST); 103 /* FIXME: Find out how to do this properly. */ 104 async_usleep(100); 105 pio_write_8(&ctl->device_control, 0); 106 107 do { 108 status = pio_read_8(&cmd->status); 109 } while ((status & SR_BSY) != 0); 110 printf("Done\n"); 111 112 (void) drive_identify(0, &disk[0]); 113 (void) drive_identify(1, &disk[1]); 104 for (i = 0; i < MAX_DISKS; i++) { 105 printf("Identify drive %d... ", i); 106 fflush(stdout); 107 108 rc = drive_identify(i, &disk[i]); 109 110 if (rc == EOK) { 111 printf("%u cylinders, %u heads, %u sectors\n", 112 disk[i].cylinders, disk[i].heads, disk[i].sectors); 113 } else { 114 printf("Not found.\n"); 115 } 116 } 114 117 115 118 n_disks = 0; … … 144 147 } 145 148 146 static int drive_identify(int disk_id, disk_t *d) 147 { 148 uint16_t data; 149 uint8_t status; 150 size_t i; 151 152 printf("Identify drive %d... ", disk_id); 153 fflush(stdout); 154 155 pio_write_8(&cmd->drive_head, ((disk_id != 0) ? DHR_DRV : 0)); 156 async_usleep(100); 157 pio_write_8(&cmd->command, CMD_IDENTIFY_DRIVE); 158 159 status = pio_read_8(&cmd->status); 160 161 d->present = false; 162 163 /* 164 * Detect if drive is present. This is Qemu only! Need to 165 * do the right thing to work with real drives. 166 */ 167 if ((status & SR_DRDY) == 0) { 168 printf("None attached.\n"); 169 return ENOENT; 170 } 171 172 for (i = 0; i < block_size / 2; i++) { 173 do { 174 status = pio_read_8(&cmd->status); 175 } while ((status & SR_DRDY) == 0); 176 177 data = pio_read_16(&cmd->data_port); 178 179 switch (i) { 180 case 1: d->cylinders = data; break; 181 case 3: d->heads = data; break; 182 case 6: d->sectors = data; break; 183 } 184 } 185 186 d->blocks = d->cylinders * d->heads * d->sectors; 187 188 printf("Geometry: %u cylinders, %u heads, %u sectors\n", 189 d->cylinders, d->heads, d->sectors); 190 191 d->present = true; 192 fibril_mutex_initialize(&d->lock); 193 194 return EOK; 195 } 196 149 150 /** Register driver and enable device I/O. */ 197 151 static int ata_bd_init(void) 198 152 { … … 226 180 } 227 181 182 /** Block device connection handler */ 228 183 static void ata_bd_connection(ipc_callid_t iid, ipc_call_t *icall) 229 184 { … … 296 251 } 297 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_BLOCK 257 * @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 */ 298 263 static int ata_bd_rdwr(int disk_id, ipcarg_t method, off_t blk_idx, size_t size, 299 264 void *buf) … … 327 292 } 328 293 329 294 /** Issue IDENTIFY command. 295 * 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. 298 * 299 * @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) 303 { 304 uint16_t data; 305 uint8_t status; 306 uint8_t drv_head; 307 size_t i; 308 309 drv_head = ((disk_id != 0) ? DHR_DRV : 0); 310 d->present = false; 311 312 if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) 313 return EIO; 314 315 pio_write_8(&cmd->drive_head, drv_head); 316 317 /* 318 * This is where we would most likely expect a non-existing device to 319 * show up by not setting SR_DRDY. 320 */ 321 if (wait_status(SR_DRDY, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK) 322 return EIO; 323 324 pio_write_8(&cmd->command, CMD_IDENTIFY_DRIVE); 325 326 if (wait_status(0, ~SR_BSY, &status, TIMEOUT_PROBE) != EOK) 327 return EIO; 328 329 /* Read data from the disk buffer. */ 330 331 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++) { 338 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 } 345 } 346 } 347 348 if ((status & SR_ERR) != 0) 349 return EIO; 350 351 d->blocks = d->cylinders * d->heads * d->sectors; 352 353 d->present = true; 354 fibril_mutex_initialize(&d->lock); 355 356 return EOK; 357 } 358 359 /** Read a physical from the device. 360 * 361 * @param disk_id Device index (0 or 1) 362 * @param blk_idx Index of the first block. 363 * @param blk_cnt Number of blocks to transfer. 364 * @param buf Buffer for holding the data. 365 * 366 * @return EOK on success, EIO on error. 367 */ 330 368 static int ata_bd_read_block(int disk_id, uint64_t blk_idx, size_t blk_cnt, 331 369 void *buf) … … 361 399 /* Program a Read Sectors operation. */ 362 400 401 if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_BSY) != EOK) { 402 fibril_mutex_unlock(&d->lock); 403 return EIO; 404 } 405 363 406 pio_write_8(&cmd->drive_head, drv_head); 407 408 if (wait_status(SR_DRDY, ~SR_BSY, NULL, TIMEOUT_DRDY) != EOK) { 409 fibril_mutex_unlock(&d->lock); 410 return EIO; 411 } 412 364 413 pio_write_8(&cmd->sector_count, 1); 365 414 pio_write_8(&cmd->sector_number, s); 366 415 pio_write_8(&cmd->cylinder_low, c & 0xff); 367 416 pio_write_8(&cmd->cylinder_high, c >> 16); 417 368 418 pio_write_8(&cmd->command, CMD_READ_SECTORS); 369 419 370 /* Read data from the disk buffer. */ 371 372 for (i = 0; i < block_size / 2; i++) { 373 do { 374 status = pio_read_8(&cmd->status); 375 } while ((status & SR_DRDY) == 0); 376 377 data = pio_read_16(&cmd->data_port); 378 ((uint16_t *) buf)[i] = data; 379 } 420 if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) { 421 fibril_mutex_unlock(&d->lock); 422 return EIO; 423 } 424 425 if ((status & SR_DRQ) != 0) { 426 /* Read data from the device buffer. */ 427 428 for (i = 0; i < block_size / 2; i++) { 429 data = pio_read_16(&cmd->data_port); 430 ((uint16_t *) buf)[i] = data; 431 } 432 } 433 434 if ((status & SR_ERR) != 0) 435 return EIO; 380 436 381 437 fibril_mutex_unlock(&d->lock); … … 383 439 } 384 440 441 /** Write a physical block to the device. 442 * 443 * @param disk_id Device index (0 or 1) 444 * @param blk_idx Index of the first block. 445 * @param blk_cnt Number of blocks to transfer. 446 * @param buf Buffer holding the data to write. 447 * 448 * @return EOK on success, EIO on error. 449 */ 385 450 static int ata_bd_write_block(int disk_id, uint64_t blk_idx, size_t blk_cnt, 386 451 const void *buf) … … 413 478 fibril_mutex_lock(&d->lock); 414 479 415 /* Program a Read Sectors operation. */ 480 /* Program a Write Sectors operation. */ 481 482 if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_BSY) != EOK) { 483 fibril_mutex_unlock(&d->lock); 484 return EIO; 485 } 416 486 417 487 pio_write_8(&cmd->drive_head, drv_head); 488 489 if (wait_status(SR_DRDY, ~SR_BSY, NULL, TIMEOUT_DRDY) != EOK) { 490 fibril_mutex_unlock(&d->lock); 491 return EIO; 492 } 493 418 494 pio_write_8(&cmd->sector_count, 1); 419 495 pio_write_8(&cmd->sector_number, s); 420 496 pio_write_8(&cmd->cylinder_low, c & 0xff); 421 497 pio_write_8(&cmd->cylinder_high, c >> 16); 498 422 499 pio_write_8(&cmd->command, CMD_WRITE_SECTORS); 423 500 424 /* Write data to the disk buffer. */ 425 426 for (i = 0; i < block_size / 2; i++) { 427 do { 428 status = pio_read_8(&cmd->status); 429 } while ((status & SR_DRDY) == 0); 430 431 pio_write_16(&cmd->data_port, ((uint16_t *) buf)[i]); 501 if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) { 502 fibril_mutex_unlock(&d->lock); 503 return EIO; 504 } 505 506 if ((status & SR_DRQ) != 0) { 507 /* Write data to the device buffer. */ 508 509 for (i = 0; i < block_size / 2; i++) { 510 pio_write_16(&cmd->data_port, ((uint16_t *) buf)[i]); 511 } 432 512 } 433 513 434 514 fibril_mutex_unlock(&d->lock); 515 516 if (status & SR_ERR) 517 return EIO; 518 435 519 return EOK; 436 520 } 437 521 522 /** Wait until some status bits are set and some are reset. 523 * 524 * Example: wait_status(SR_DRDY, ~SR_BSY) waits for SR_DRDY to become 525 * set and SR_BSY to become reset. 526 * 527 * @param set Combination if bits which must be all set. 528 * @param n_reset Negated combination of bits which must be all reset. 529 * @param pstatus Pointer where to store last read status or NULL. 530 * @param timeout Timeout in 10ms units. 531 * 532 * @return EOK on success, EIO on timeout. 533 */ 534 static int wait_status(unsigned set, unsigned n_reset, uint8_t *pstatus, 535 unsigned timeout) 536 { 537 uint8_t status; 538 int cnt; 539 540 status = pio_read_8(&cmd->status); 541 542 /* 543 * This is crude, yet simple. First try with 1us delays 544 * (most likely the device will respond very fast). If not, 545 * start trying every 10 ms. 546 */ 547 548 cnt = 100; 549 while ((status & ~n_reset) != 0 || (status & set) != set) { 550 async_usleep(1); 551 --cnt; 552 if (cnt <= 0) break; 553 554 status = pio_read_8(&cmd->status); 555 } 556 557 cnt = timeout; 558 while ((status & ~n_reset) != 0 || (status & set) != set) { 559 async_usleep(10000); 560 --cnt; 561 if (cnt <= 0) break; 562 563 status = pio_read_8(&cmd->status); 564 } 565 566 if (pstatus) 567 *pstatus = status; 568 569 if (cnt == 0) 570 return EIO; 571 572 return EOK; 573 } 438 574 439 575 /**
Note:
See TracChangeset
for help on using the changeset viewer.