diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-07-31 15:10:26 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-07-31 15:10:26 -0400 |
| commit | a5bc92cdf2ab27a15732976004b3755c40740f57 (patch) | |
| tree | ab7ee562f31ed9fddac78c1e17a2ba9eee6cb028 /drivers | |
| parent | 6eb80e00bff341dd09a7ec8b9dba6da8410448bf (diff) | |
| parent | cbb4f2646d77b536ed2b1500ef6641083228ed8f (diff) | |
Merge branch 'for-linus' of git://git.kernel.dk/linux-2.6-block
* 'for-linus' of git://git.kernel.dk/linux-2.6-block:
io context: fix ref counting
block: make the end_io functions be non-GPL exports
block: fix improper kobject release in blk_integrity_unregister
block: always assign default lock to queues
mg_disk: Add missing ready status check on mg_write()
mg_disk: fix issue with data integrity on error in mg_write()
mg_disk: fix reading invalid status when use polling driver
mg_disk: remove prohibited sleep operation
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/block/mg_disk.c | 101 |
1 files changed, 56 insertions, 45 deletions
diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c index f703f5478246..6d7fbaa92248 100644 --- a/drivers/block/mg_disk.c +++ b/drivers/block/mg_disk.c | |||
| @@ -36,7 +36,6 @@ | |||
| 36 | 36 | ||
| 37 | /* Register offsets */ | 37 | /* Register offsets */ |
| 38 | #define MG_BUFF_OFFSET 0x8000 | 38 | #define MG_BUFF_OFFSET 0x8000 |
| 39 | #define MG_STORAGE_BUFFER_SIZE 0x200 | ||
| 40 | #define MG_REG_OFFSET 0xC000 | 39 | #define MG_REG_OFFSET 0xC000 |
| 41 | #define MG_REG_FEATURE (MG_REG_OFFSET + 2) /* write case */ | 40 | #define MG_REG_FEATURE (MG_REG_OFFSET + 2) /* write case */ |
| 42 | #define MG_REG_ERROR (MG_REG_OFFSET + 2) /* read case */ | 41 | #define MG_REG_ERROR (MG_REG_OFFSET + 2) /* read case */ |
| @@ -219,6 +218,16 @@ static unsigned int mg_wait(struct mg_host *host, u32 expect, u32 msec) | |||
| 219 | host->error = MG_ERR_NONE; | 218 | host->error = MG_ERR_NONE; |
| 220 | expire = jiffies + msecs_to_jiffies(msec); | 219 | expire = jiffies + msecs_to_jiffies(msec); |
| 221 | 220 | ||
| 221 | /* These 2 times dummy status read prevents reading invalid | ||
| 222 | * status. A very little time (3 times of mflash operating clk) | ||
| 223 | * is required for busy bit is set. Use dummy read instead of | ||
| 224 | * busy wait, because mflash's PLL is machine dependent. | ||
| 225 | */ | ||
| 226 | if (prv_data->use_polling) { | ||
| 227 | status = inb((unsigned long)host->dev_base + MG_REG_STATUS); | ||
| 228 | status = inb((unsigned long)host->dev_base + MG_REG_STATUS); | ||
| 229 | } | ||
| 230 | |||
| 222 | status = inb((unsigned long)host->dev_base + MG_REG_STATUS); | 231 | status = inb((unsigned long)host->dev_base + MG_REG_STATUS); |
| 223 | 232 | ||
| 224 | do { | 233 | do { |
| @@ -245,8 +254,6 @@ static unsigned int mg_wait(struct mg_host *host, u32 expect, u32 msec) | |||
| 245 | mg_dump_status("not ready", status, host); | 254 | mg_dump_status("not ready", status, host); |
| 246 | return MG_ERR_INV_STAT; | 255 | return MG_ERR_INV_STAT; |
| 247 | } | 256 | } |
| 248 | if (prv_data->use_polling) | ||
| 249 | msleep(1); | ||
| 250 | 257 | ||
| 251 | status = inb((unsigned long)host->dev_base + MG_REG_STATUS); | 258 | status = inb((unsigned long)host->dev_base + MG_REG_STATUS); |
| 252 | } while (time_before(cur_jiffies, expire)); | 259 | } while (time_before(cur_jiffies, expire)); |
| @@ -469,9 +476,18 @@ static unsigned int mg_out(struct mg_host *host, | |||
| 469 | return MG_ERR_NONE; | 476 | return MG_ERR_NONE; |
| 470 | } | 477 | } |
| 471 | 478 | ||
| 479 | static void mg_read_one(struct mg_host *host, struct request *req) | ||
| 480 | { | ||
| 481 | u16 *buff = (u16 *)req->buffer; | ||
| 482 | u32 i; | ||
| 483 | |||
| 484 | for (i = 0; i < MG_SECTOR_SIZE >> 1; i++) | ||
| 485 | *buff++ = inw((unsigned long)host->dev_base + MG_BUFF_OFFSET + | ||
| 486 | (i << 1)); | ||
| 487 | } | ||
| 488 | |||
| 472 | static void mg_read(struct request *req) | 489 | static void mg_read(struct request *req) |
| 473 | { | 490 | { |
| 474 | u32 j; | ||
| 475 | struct mg_host *host = req->rq_disk->private_data; | 491 | struct mg_host *host = req->rq_disk->private_data; |
| 476 | 492 | ||
| 477 | if (mg_out(host, blk_rq_pos(req), blk_rq_sectors(req), | 493 | if (mg_out(host, blk_rq_pos(req), blk_rq_sectors(req), |
| @@ -482,49 +498,65 @@ static void mg_read(struct request *req) | |||
| 482 | blk_rq_sectors(req), blk_rq_pos(req), req->buffer); | 498 | blk_rq_sectors(req), blk_rq_pos(req), req->buffer); |
| 483 | 499 | ||
| 484 | do { | 500 | do { |
| 485 | u16 *buff = (u16 *)req->buffer; | ||
| 486 | |||
| 487 | if (mg_wait(host, ATA_DRQ, | 501 | if (mg_wait(host, ATA_DRQ, |
| 488 | MG_TMAX_WAIT_RD_DRQ) != MG_ERR_NONE) { | 502 | MG_TMAX_WAIT_RD_DRQ) != MG_ERR_NONE) { |
| 489 | mg_bad_rw_intr(host); | 503 | mg_bad_rw_intr(host); |
| 490 | return; | 504 | return; |
| 491 | } | 505 | } |
| 492 | for (j = 0; j < MG_SECTOR_SIZE >> 1; j++) | 506 | |
| 493 | *buff++ = inw((unsigned long)host->dev_base + | 507 | mg_read_one(host, req); |
| 494 | MG_BUFF_OFFSET + (j << 1)); | ||
| 495 | 508 | ||
| 496 | outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base + | 509 | outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base + |
| 497 | MG_REG_COMMAND); | 510 | MG_REG_COMMAND); |
| 498 | } while (mg_end_request(host, 0, MG_SECTOR_SIZE)); | 511 | } while (mg_end_request(host, 0, MG_SECTOR_SIZE)); |
| 499 | } | 512 | } |
| 500 | 513 | ||
| 514 | static void mg_write_one(struct mg_host *host, struct request *req) | ||
| 515 | { | ||
| 516 | u16 *buff = (u16 *)req->buffer; | ||
| 517 | u32 i; | ||
| 518 | |||
| 519 | for (i = 0; i < MG_SECTOR_SIZE >> 1; i++) | ||
| 520 | outw(*buff++, (unsigned long)host->dev_base + MG_BUFF_OFFSET + | ||
| 521 | (i << 1)); | ||
| 522 | } | ||
| 523 | |||
| 501 | static void mg_write(struct request *req) | 524 | static void mg_write(struct request *req) |
| 502 | { | 525 | { |
| 503 | u32 j; | ||
| 504 | struct mg_host *host = req->rq_disk->private_data; | 526 | struct mg_host *host = req->rq_disk->private_data; |
| 527 | unsigned int rem = blk_rq_sectors(req); | ||
| 505 | 528 | ||
| 506 | if (mg_out(host, blk_rq_pos(req), blk_rq_sectors(req), | 529 | if (mg_out(host, blk_rq_pos(req), rem, |
| 507 | MG_CMD_WR, NULL) != MG_ERR_NONE) { | 530 | MG_CMD_WR, NULL) != MG_ERR_NONE) { |
| 508 | mg_bad_rw_intr(host); | 531 | mg_bad_rw_intr(host); |
| 509 | return; | 532 | return; |
| 510 | } | 533 | } |
| 511 | 534 | ||
| 512 | MG_DBG("requested %d sects (from %ld), buffer=0x%p\n", | 535 | MG_DBG("requested %d sects (from %ld), buffer=0x%p\n", |
| 513 | blk_rq_sectors(req), blk_rq_pos(req), req->buffer); | 536 | rem, blk_rq_pos(req), req->buffer); |
| 537 | |||
| 538 | if (mg_wait(host, ATA_DRQ, | ||
| 539 | MG_TMAX_WAIT_WR_DRQ) != MG_ERR_NONE) { | ||
| 540 | mg_bad_rw_intr(host); | ||
| 541 | return; | ||
| 542 | } | ||
| 514 | 543 | ||
| 515 | do { | 544 | do { |
| 516 | u16 *buff = (u16 *)req->buffer; | 545 | mg_write_one(host, req); |
| 517 | 546 | ||
| 518 | if (mg_wait(host, ATA_DRQ, MG_TMAX_WAIT_WR_DRQ) != MG_ERR_NONE) { | 547 | outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base + |
| 548 | MG_REG_COMMAND); | ||
| 549 | |||
| 550 | rem--; | ||
| 551 | if (rem > 1 && mg_wait(host, ATA_DRQ, | ||
| 552 | MG_TMAX_WAIT_WR_DRQ) != MG_ERR_NONE) { | ||
| 553 | mg_bad_rw_intr(host); | ||
| 554 | return; | ||
| 555 | } else if (mg_wait(host, MG_STAT_READY, | ||
| 556 | MG_TMAX_WAIT_WR_DRQ) != MG_ERR_NONE) { | ||
| 519 | mg_bad_rw_intr(host); | 557 | mg_bad_rw_intr(host); |
| 520 | return; | 558 | return; |
| 521 | } | 559 | } |
| 522 | for (j = 0; j < MG_SECTOR_SIZE >> 1; j++) | ||
| 523 | outw(*buff++, (unsigned long)host->dev_base + | ||
| 524 | MG_BUFF_OFFSET + (j << 1)); | ||
| 525 | |||
| 526 | outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base + | ||
| 527 | MG_REG_COMMAND); | ||
| 528 | } while (mg_end_request(host, 0, MG_SECTOR_SIZE)); | 560 | } while (mg_end_request(host, 0, MG_SECTOR_SIZE)); |
| 529 | } | 561 | } |
| 530 | 562 | ||
| @@ -532,7 +564,6 @@ static void mg_read_intr(struct mg_host *host) | |||
| 532 | { | 564 | { |
| 533 | struct request *req = host->req; | 565 | struct request *req = host->req; |
| 534 | u32 i; | 566 | u32 i; |
| 535 | u16 *buff; | ||
| 536 | 567 | ||
| 537 | /* check status */ | 568 | /* check status */ |
| 538 | do { | 569 | do { |
| @@ -550,13 +581,7 @@ static void mg_read_intr(struct mg_host *host) | |||
| 550 | return; | 581 | return; |
| 551 | 582 | ||
| 552 | ok_to_read: | 583 | ok_to_read: |
| 553 | /* get current segment of request */ | 584 | mg_read_one(host, req); |
| 554 | buff = (u16 *)req->buffer; | ||
| 555 | |||
| 556 | /* read 1 sector */ | ||
| 557 | for (i = 0; i < MG_SECTOR_SIZE >> 1; i++) | ||
| 558 | *buff++ = inw((unsigned long)host->dev_base + MG_BUFF_OFFSET + | ||
| 559 | (i << 1)); | ||
| 560 | 585 | ||
| 561 | MG_DBG("sector %ld, remaining=%ld, buffer=0x%p\n", | 586 | MG_DBG("sector %ld, remaining=%ld, buffer=0x%p\n", |
| 562 | blk_rq_pos(req), blk_rq_sectors(req) - 1, req->buffer); | 587 | blk_rq_pos(req), blk_rq_sectors(req) - 1, req->buffer); |
| @@ -575,8 +600,7 @@ ok_to_read: | |||
| 575 | static void mg_write_intr(struct mg_host *host) | 600 | static void mg_write_intr(struct mg_host *host) |
| 576 | { | 601 | { |
| 577 | struct request *req = host->req; | 602 | struct request *req = host->req; |
| 578 | u32 i, j; | 603 | u32 i; |
| 579 | u16 *buff; | ||
| 580 | bool rem; | 604 | bool rem; |
| 581 | 605 | ||
| 582 | /* check status */ | 606 | /* check status */ |
| @@ -597,12 +621,7 @@ static void mg_write_intr(struct mg_host *host) | |||
| 597 | ok_to_write: | 621 | ok_to_write: |
| 598 | if ((rem = mg_end_request(host, 0, MG_SECTOR_SIZE))) { | 622 | if ((rem = mg_end_request(host, 0, MG_SECTOR_SIZE))) { |
| 599 | /* write 1 sector and set handler if remains */ | 623 | /* write 1 sector and set handler if remains */ |
| 600 | buff = (u16 *)req->buffer; | 624 | mg_write_one(host, req); |
| 601 | for (j = 0; j < MG_STORAGE_BUFFER_SIZE >> 1; j++) { | ||
| 602 | outw(*buff, (unsigned long)host->dev_base + | ||
| 603 | MG_BUFF_OFFSET + (j << 1)); | ||
| 604 | buff++; | ||
| 605 | } | ||
| 606 | MG_DBG("sector %ld, remaining=%ld, buffer=0x%p\n", | 625 | MG_DBG("sector %ld, remaining=%ld, buffer=0x%p\n", |
| 607 | blk_rq_pos(req), blk_rq_sectors(req), req->buffer); | 626 | blk_rq_pos(req), blk_rq_sectors(req), req->buffer); |
| 608 | host->mg_do_intr = mg_write_intr; | 627 | host->mg_do_intr = mg_write_intr; |
| @@ -667,9 +686,6 @@ static unsigned int mg_issue_req(struct request *req, | |||
| 667 | unsigned int sect_num, | 686 | unsigned int sect_num, |
| 668 | unsigned int sect_cnt) | 687 | unsigned int sect_cnt) |
| 669 | { | 688 | { |
| 670 | u16 *buff; | ||
| 671 | u32 i; | ||
| 672 | |||
| 673 | switch (rq_data_dir(req)) { | 689 | switch (rq_data_dir(req)) { |
| 674 | case READ: | 690 | case READ: |
| 675 | if (mg_out(host, sect_num, sect_cnt, MG_CMD_RD, &mg_read_intr) | 691 | if (mg_out(host, sect_num, sect_cnt, MG_CMD_RD, &mg_read_intr) |
| @@ -693,12 +709,7 @@ static unsigned int mg_issue_req(struct request *req, | |||
| 693 | mg_bad_rw_intr(host); | 709 | mg_bad_rw_intr(host); |
| 694 | return host->error; | 710 | return host->error; |
| 695 | } | 711 | } |
| 696 | buff = (u16 *)req->buffer; | 712 | mg_write_one(host, req); |
| 697 | for (i = 0; i < MG_SECTOR_SIZE >> 1; i++) { | ||
| 698 | outw(*buff, (unsigned long)host->dev_base + | ||
| 699 | MG_BUFF_OFFSET + (i << 1)); | ||
| 700 | buff++; | ||
| 701 | } | ||
| 702 | mod_timer(&host->timer, jiffies + 3 * HZ); | 713 | mod_timer(&host->timer, jiffies + 3 * HZ); |
| 703 | outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base + | 714 | outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base + |
| 704 | MG_REG_COMMAND); | 715 | MG_REG_COMMAND); |
