diff options
author | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2009-03-31 14:15:15 -0400 |
---|---|---|
committer | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2009-03-31 14:15:15 -0400 |
commit | c7ec89994fec4353d5b4251213bdfa7b1a68c26b (patch) | |
tree | 117b7909e069b3bc971071cf76a3544af69e8f91 /drivers/ide | |
parent | 8652b31ab211b6fe2a4994cc47b61d7038c3489c (diff) |
ide-cd: use scatterlists for PIO transfers (non-fs requests) (v2)
Convert ide-cd to use scatterlists for PIO transfers and get rid of
partial completions (except on error) also for non-fs requests.
v2:
Do not map dataless commands to an sg since it oopses on the virt_to_page()
translation check when DEBUG_VIRTUAL is enabled. (from Borislav Petkov,
reported/bisected-by Tetsuo Handa).
Cc: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Acked-by: Borislav Petkov <petkovbb@gmail.com>
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Diffstat (limited to 'drivers/ide')
-rw-r--r-- | drivers/ide/ide-cd.c | 100 |
1 files changed, 30 insertions, 70 deletions
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index cf0707fe87e8..7fdfb55011a6 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c | |||
@@ -509,8 +509,10 @@ static int ide_cd_check_ireason(ide_drive_t *drive, struct request *rq, | |||
509 | return -1; | 509 | return -1; |
510 | } | 510 | } |
511 | 511 | ||
512 | static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct request *rq) | 512 | static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct ide_cmd *cmd) |
513 | { | 513 | { |
514 | struct request *rq = cmd->rq; | ||
515 | |||
514 | ide_debug_log(IDE_DBG_FUNC, "rq->cmd[0]: 0x%x", rq->cmd[0]); | 516 | ide_debug_log(IDE_DBG_FUNC, "rq->cmd[0]: 0x%x", rq->cmd[0]); |
515 | 517 | ||
516 | /* | 518 | /* |
@@ -518,11 +520,14 @@ static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct request *rq) | |||
518 | * and some drives don't send them. Sigh. | 520 | * and some drives don't send them. Sigh. |
519 | */ | 521 | */ |
520 | if (rq->cmd[0] == GPCMD_REQUEST_SENSE && | 522 | if (rq->cmd[0] == GPCMD_REQUEST_SENSE && |
521 | rq->data_len > 0 && rq->data_len <= 5) | 523 | cmd->nleft > 0 && cmd->nleft <= 5) { |
522 | while (rq->data_len > 0) { | 524 | unsigned int ofs = cmd->nbytes - cmd->nleft; |
523 | *(u8 *)rq->data++ = 0; | 525 | |
524 | --rq->data_len; | 526 | while (cmd->nleft > 0) { |
527 | *((u8 *)rq->data + ofs++) = 0; | ||
528 | cmd->nleft--; | ||
525 | } | 529 | } |
530 | } | ||
526 | } | 531 | } |
527 | 532 | ||
528 | int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd, | 533 | int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd, |
@@ -613,22 +618,11 @@ static void ide_cd_error_cmd(ide_drive_t *drive, struct ide_cmd *cmd) | |||
613 | ide_complete_rq(drive, 0, nr_bytes); | 618 | ide_complete_rq(drive, 0, nr_bytes); |
614 | } | 619 | } |
615 | 620 | ||
616 | /* | ||
617 | * Called from blk_end_request_callback() after the data of the request is | ||
618 | * completed and before the request itself is completed. By returning value '1', | ||
619 | * blk_end_request_callback() returns immediately without completing it. | ||
620 | */ | ||
621 | static int cdrom_newpc_intr_dummy_cb(struct request *rq) | ||
622 | { | ||
623 | return 1; | ||
624 | } | ||
625 | |||
626 | static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) | 621 | static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) |
627 | { | 622 | { |
628 | ide_hwif_t *hwif = drive->hwif; | 623 | ide_hwif_t *hwif = drive->hwif; |
629 | struct ide_cmd *cmd = &hwif->cmd; | 624 | struct ide_cmd *cmd = &hwif->cmd; |
630 | struct request *rq = hwif->rq; | 625 | struct request *rq = hwif->rq; |
631 | xfer_func_t *xferfunc; | ||
632 | ide_expiry_t *expiry = NULL; | 626 | ide_expiry_t *expiry = NULL; |
633 | int dma_error = 0, dma, stat, thislen, uptodate = 0; | 627 | int dma_error = 0, dma, stat, thislen, uptodate = 0; |
634 | int write = (rq_data_dir(rq) == WRITE) ? 1 : 0, rc, nsectors; | 628 | int write = (rq_data_dir(rq) == WRITE) ? 1 : 0, rc, nsectors; |
@@ -678,7 +672,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) | |||
678 | 672 | ||
679 | ide_read_bcount_and_ireason(drive, &len, &ireason); | 673 | ide_read_bcount_and_ireason(drive, &len, &ireason); |
680 | 674 | ||
681 | thislen = blk_fs_request(rq) ? len : rq->data_len; | 675 | thislen = blk_fs_request(rq) ? len : cmd->nleft; |
682 | if (thislen > len) | 676 | if (thislen > len) |
683 | thislen = len; | 677 | thislen = len; |
684 | 678 | ||
@@ -702,9 +696,9 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) | |||
702 | uptodate = 0; | 696 | uptodate = 0; |
703 | } | 697 | } |
704 | } else if (!blk_pc_request(rq)) { | 698 | } else if (!blk_pc_request(rq)) { |
705 | ide_cd_request_sense_fixup(drive, rq); | 699 | ide_cd_request_sense_fixup(drive, cmd); |
706 | /* complain if we still have data left to transfer */ | 700 | /* complain if we still have data left to transfer */ |
707 | uptodate = rq->data_len ? 0 : 1; | 701 | uptodate = cmd->nleft ? 0 : 1; |
708 | if (uptodate == 0) | 702 | if (uptodate == 0) |
709 | rq->cmd_flags |= REQ_FAILED; | 703 | rq->cmd_flags |= REQ_FAILED; |
710 | } | 704 | } |
@@ -718,35 +712,15 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) | |||
718 | 712 | ||
719 | cmd->last_xfer_len = 0; | 713 | cmd->last_xfer_len = 0; |
720 | 714 | ||
721 | if (ireason == 0) { | ||
722 | write = 1; | ||
723 | xferfunc = hwif->tp_ops->output_data; | ||
724 | } else { | ||
725 | write = 0; | ||
726 | xferfunc = hwif->tp_ops->input_data; | ||
727 | } | ||
728 | |||
729 | ide_debug_log(IDE_DBG_PC, "data transfer, rq->cmd_type: 0x%x, " | 715 | ide_debug_log(IDE_DBG_PC, "data transfer, rq->cmd_type: 0x%x, " |
730 | "ireason: 0x%x", | 716 | "ireason: 0x%x", |
731 | rq->cmd_type, ireason); | 717 | rq->cmd_type, ireason); |
732 | 718 | ||
733 | /* transfer data */ | 719 | /* transfer data */ |
734 | while (thislen > 0) { | 720 | while (thislen > 0) { |
735 | u8 *ptr = blk_fs_request(rq) ? NULL : rq->data; | 721 | int blen = min_t(int, thislen, cmd->nleft); |
736 | int blen = rq->data_len; | ||
737 | |||
738 | /* bio backed? */ | ||
739 | if (rq->bio) { | ||
740 | if (blk_fs_request(rq)) { | ||
741 | blen = min_t(int, thislen, cmd->nleft); | ||
742 | } else { | ||
743 | ptr = bio_data(rq->bio); | ||
744 | blen = bio_iovec(rq->bio)->bv_len; | ||
745 | } | ||
746 | } | ||
747 | 722 | ||
748 | if ((blk_fs_request(rq) && cmd->nleft == 0) || | 723 | if (cmd->nleft == 0) { |
749 | (blk_fs_request(rq) == 0 && ptr == NULL)) { | ||
750 | if (blk_fs_request(rq) && !write) | 724 | if (blk_fs_request(rq) && !write) |
751 | /* | 725 | /* |
752 | * If the buffers are full, pipe the rest into | 726 | * If the buffers are full, pipe the rest into |
@@ -763,33 +737,12 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) | |||
763 | break; | 737 | break; |
764 | } | 738 | } |
765 | 739 | ||
766 | if (blen > thislen) | 740 | ide_pio_bytes(drive, cmd, write, blen); |
767 | blen = thislen; | 741 | cmd->last_xfer_len += blen; |
768 | |||
769 | if (blk_fs_request(rq)) { | ||
770 | ide_pio_bytes(drive, cmd, write, blen); | ||
771 | cmd->last_xfer_len += blen; | ||
772 | } else | ||
773 | xferfunc(drive, NULL, ptr, blen); | ||
774 | 742 | ||
775 | thislen -= blen; | 743 | thislen -= blen; |
776 | len -= blen; | 744 | len -= blen; |
777 | 745 | ||
778 | if (blk_fs_request(rq) == 0) { | ||
779 | rq->data_len -= blen; | ||
780 | |||
781 | /* | ||
782 | * The request can't be completed until DRQ is cleared. | ||
783 | * So complete the data, but don't complete the request | ||
784 | * using the dummy function for the callback feature | ||
785 | * of blk_end_request_callback(). | ||
786 | */ | ||
787 | if (rq->bio) | ||
788 | blk_end_request_callback(rq, 0, blen, | ||
789 | cdrom_newpc_intr_dummy_cb); | ||
790 | else | ||
791 | rq->data += blen; | ||
792 | } | ||
793 | if (sense && write == 0) | 746 | if (sense && write == 0) |
794 | rq->sense_len += blen; | 747 | rq->sense_len += blen; |
795 | } | 748 | } |
@@ -814,8 +767,7 @@ out_end: | |||
814 | if (blk_pc_request(rq) && rc == 0) { | 767 | if (blk_pc_request(rq) && rc == 0) { |
815 | unsigned int dlen = rq->data_len; | 768 | unsigned int dlen = rq->data_len; |
816 | 769 | ||
817 | if (dma) | 770 | rq->data_len = 0; |
818 | rq->data_len = 0; | ||
819 | 771 | ||
820 | if (blk_end_request(rq, 0, dlen)) | 772 | if (blk_end_request(rq, 0, dlen)) |
821 | BUG(); | 773 | BUG(); |
@@ -828,13 +780,14 @@ out_end: | |||
828 | if (blk_fs_request(rq)) { | 780 | if (blk_fs_request(rq)) { |
829 | if (cmd->nleft == 0) | 781 | if (cmd->nleft == 0) |
830 | uptodate = 1; | 782 | uptodate = 1; |
831 | if (uptodate == 0) | ||
832 | ide_cd_error_cmd(drive, cmd); | ||
833 | } else { | 783 | } else { |
834 | if (uptodate <= 0 && rq->errors == 0) | 784 | if (uptodate <= 0 && rq->errors == 0) |
835 | rq->errors = -EIO; | 785 | rq->errors = -EIO; |
836 | } | 786 | } |
837 | 787 | ||
788 | if (uptodate == 0) | ||
789 | ide_cd_error_cmd(drive, cmd); | ||
790 | |||
838 | /* make sure it's fully ended */ | 791 | /* make sure it's fully ended */ |
839 | if (blk_pc_request(rq)) | 792 | if (blk_pc_request(rq)) |
840 | nsectors = (rq->data_len + 511) >> 9; | 793 | nsectors = (rq->data_len + 511) >> 9; |
@@ -844,6 +797,12 @@ out_end: | |||
844 | if (nsectors == 0) | 797 | if (nsectors == 0) |
845 | nsectors = 1; | 798 | nsectors = 1; |
846 | 799 | ||
800 | if (blk_fs_request(rq) == 0) { | ||
801 | rq->data_len -= (cmd->nbytes - cmd->nleft); | ||
802 | if (uptodate == 0 && (cmd->tf_flags & IDE_TFLAG_WRITE)) | ||
803 | rq->data_len += cmd->last_xfer_len; | ||
804 | } | ||
805 | |||
847 | ide_complete_rq(drive, uptodate ? 0 : -EIO, nsectors << 9); | 806 | ide_complete_rq(drive, uptodate ? 0 : -EIO, nsectors << 9); |
848 | 807 | ||
849 | if (sense && rc == 2) | 808 | if (sense && rc == 2) |
@@ -971,8 +930,9 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq, | |||
971 | 930 | ||
972 | cmd.rq = rq; | 931 | cmd.rq = rq; |
973 | 932 | ||
974 | if (blk_fs_request(rq)) { | 933 | if (blk_fs_request(rq) || rq->data_len) { |
975 | ide_init_sg_cmd(&cmd, rq->nr_sectors << 9); | 934 | ide_init_sg_cmd(&cmd, blk_fs_request(rq) ? (rq->nr_sectors << 9) |
935 | : rq->data_len); | ||
976 | ide_map_sg(drive, &cmd); | 936 | ide_map_sg(drive, &cmd); |
977 | } | 937 | } |
978 | 938 | ||