diff options
author | Albert Lee <albertcc@tw.ibm.com> | 2006-03-25 04:48:02 -0500 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-03-29 17:21:54 -0500 |
commit | bb5cb290f095f17f88c912e3da35adf5b2d9500b (patch) | |
tree | cf8cbbfc3419988f869b4527c8be5d63361b3eb2 /drivers/scsi/libata-core.c | |
parent | 6912ccd5a4a095d71fd7215ef2abea877c8fed6f (diff) |
[PATCH] libata-dev: Let ata_hsm_move() work with both irq-pio and polling pio
Let ata_hsm_move() work with both irq-pio and polling pio codepath.
Changes:
- add a new parameter "in_wq" for polling pio
- add return value "poll_next" to tell polling pio task whether the HSM is finished
- merge code from ata_pio_first_block() to the HSM_ST_FIRST state.
- call ata_poll_qc_complete() if called from the workqueue
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/scsi/libata-core.c')
-rw-r--r-- | drivers/scsi/libata-core.c | 87 |
1 files changed, 81 insertions, 6 deletions
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 094c7907534a..33b39d3ce2d3 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c | |||
@@ -3805,11 +3805,36 @@ static void ata_pio_error(struct ata_port *ap) | |||
3805 | ata_poll_qc_complete(qc); | 3805 | ata_poll_qc_complete(qc); |
3806 | } | 3806 | } |
3807 | 3807 | ||
3808 | static void ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, | 3808 | /** |
3809 | u8 status) | 3809 | * ata_hsm_move - move the HSM to the next state. |
3810 | * @ap: the target ata_port | ||
3811 | * @qc: qc on going | ||
3812 | * @status: current device status | ||
3813 | * @in_wq: 1 if called from workqueue, 0 otherwise | ||
3814 | * | ||
3815 | * RETURNS: | ||
3816 | * 1 when poll next status needed, 0 otherwise. | ||
3817 | */ | ||
3818 | |||
3819 | static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, | ||
3820 | u8 status, int in_wq) | ||
3810 | { | 3821 | { |
3822 | unsigned long flags = 0; | ||
3823 | int poll_next; | ||
3824 | |||
3811 | WARN_ON((qc->flags & ATA_QCFLAG_ACTIVE) == 0); | 3825 | WARN_ON((qc->flags & ATA_QCFLAG_ACTIVE) == 0); |
3812 | 3826 | ||
3827 | /* Make sure ata_qc_issue_prot() does not throw things | ||
3828 | * like DMA polling into the workqueue. Notice that | ||
3829 | * in_wq is not equivalent to (qc->tf.flags & ATA_TFLAG_POLLING). | ||
3830 | */ | ||
3831 | WARN_ON(in_wq != ((qc->tf.flags & ATA_TFLAG_POLLING) || | ||
3832 | (ap->hsm_task_state == HSM_ST_FIRST && | ||
3833 | ((qc->tf.protocol == ATA_PROT_PIO && | ||
3834 | (qc->tf.flags & ATA_TFLAG_WRITE)) || | ||
3835 | (is_atapi_taskfile(&qc->tf) && | ||
3836 | !(qc->dev->flags & ATA_DFLAG_CDB_INTR)))))); | ||
3837 | |||
3813 | /* check error */ | 3838 | /* check error */ |
3814 | if (unlikely(status & (ATA_ERR | ATA_DF))) { | 3839 | if (unlikely(status & (ATA_ERR | ATA_DF))) { |
3815 | qc->err_mask |= AC_ERR_DEV; | 3840 | qc->err_mask |= AC_ERR_DEV; |
@@ -3819,6 +3844,14 @@ static void ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, | |||
3819 | fsm_start: | 3844 | fsm_start: |
3820 | switch (ap->hsm_task_state) { | 3845 | switch (ap->hsm_task_state) { |
3821 | case HSM_ST_FIRST: | 3846 | case HSM_ST_FIRST: |
3847 | /* Send first data block or PACKET CDB */ | ||
3848 | |||
3849 | /* If polling, we will stay in the work queue after | ||
3850 | * sending the data. Otherwise, interrupt handler | ||
3851 | * takes over after sending the data. | ||
3852 | */ | ||
3853 | poll_next = (qc->tf.flags & ATA_TFLAG_POLLING); | ||
3854 | |||
3822 | /* check device status */ | 3855 | /* check device status */ |
3823 | if (unlikely((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ)) { | 3856 | if (unlikely((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ)) { |
3824 | /* Wrong status. Let EH handle this */ | 3857 | /* Wrong status. Let EH handle this */ |
@@ -3827,8 +3860,36 @@ fsm_start: | |||
3827 | goto fsm_start; | 3860 | goto fsm_start; |
3828 | } | 3861 | } |
3829 | 3862 | ||
3830 | atapi_send_cdb(ap, qc); | 3863 | /* Send the CDB (atapi) or the first data block (ata pio out). |
3864 | * During the state transition, interrupt handler shouldn't | ||
3865 | * be invoked before the data transfer is complete and | ||
3866 | * hsm_task_state is changed. Hence, the following locking. | ||
3867 | */ | ||
3868 | if (in_wq) | ||
3869 | spin_lock_irqsave(&ap->host_set->lock, flags); | ||
3870 | |||
3871 | if (qc->tf.protocol == ATA_PROT_PIO) { | ||
3872 | /* PIO data out protocol. | ||
3873 | * send first data block. | ||
3874 | */ | ||
3831 | 3875 | ||
3876 | /* ata_pio_sectors() might change the state | ||
3877 | * to HSM_ST_LAST. so, the state is changed here | ||
3878 | * before ata_pio_sectors(). | ||
3879 | */ | ||
3880 | ap->hsm_task_state = HSM_ST; | ||
3881 | ata_pio_sectors(qc); | ||
3882 | ata_altstatus(ap); /* flush */ | ||
3883 | } else | ||
3884 | /* send CDB */ | ||
3885 | atapi_send_cdb(ap, qc); | ||
3886 | |||
3887 | if (in_wq) | ||
3888 | spin_unlock_irqrestore(&ap->host_set->lock, flags); | ||
3889 | |||
3890 | /* if polling, ata_pio_task() handles the rest. | ||
3891 | * otherwise, interrupt handler takes over from here. | ||
3892 | */ | ||
3832 | break; | 3893 | break; |
3833 | 3894 | ||
3834 | case HSM_ST: | 3895 | case HSM_ST: |
@@ -3868,6 +3929,7 @@ fsm_start: | |||
3868 | } | 3929 | } |
3869 | 3930 | ||
3870 | ata_altstatus(ap); /* flush */ | 3931 | ata_altstatus(ap); /* flush */ |
3932 | poll_next = 1; | ||
3871 | break; | 3933 | break; |
3872 | 3934 | ||
3873 | case HSM_ST_LAST: | 3935 | case HSM_ST_LAST: |
@@ -3886,7 +3948,12 @@ fsm_start: | |||
3886 | ap->hsm_task_state = HSM_ST_IDLE; | 3948 | ap->hsm_task_state = HSM_ST_IDLE; |
3887 | 3949 | ||
3888 | /* complete taskfile transaction */ | 3950 | /* complete taskfile transaction */ |
3889 | ata_qc_complete(qc); | 3951 | if (in_wq) |
3952 | ata_poll_qc_complete(qc); | ||
3953 | else | ||
3954 | ata_qc_complete(qc); | ||
3955 | |||
3956 | poll_next = 0; | ||
3890 | break; | 3957 | break; |
3891 | 3958 | ||
3892 | case HSM_ST_ERR: | 3959 | case HSM_ST_ERR: |
@@ -3900,12 +3967,20 @@ fsm_start: | |||
3900 | WARN_ON(qc->err_mask == 0); | 3967 | WARN_ON(qc->err_mask == 0); |
3901 | 3968 | ||
3902 | ap->hsm_task_state = HSM_ST_IDLE; | 3969 | ap->hsm_task_state = HSM_ST_IDLE; |
3903 | ata_qc_complete(qc); | 3970 | |
3971 | if (in_wq) | ||
3972 | ata_poll_qc_complete(qc); | ||
3973 | else | ||
3974 | ata_qc_complete(qc); | ||
3975 | |||
3976 | poll_next = 0; | ||
3904 | break; | 3977 | break; |
3905 | default: | 3978 | default: |
3979 | poll_next = 0; | ||
3906 | BUG(); | 3980 | BUG(); |
3907 | } | 3981 | } |
3908 | 3982 | ||
3983 | return poll_next; | ||
3909 | } | 3984 | } |
3910 | 3985 | ||
3911 | static void ata_pio_task(void *_data) | 3986 | static void ata_pio_task(void *_data) |
@@ -4423,7 +4498,7 @@ inline unsigned int ata_host_intr (struct ata_port *ap, | |||
4423 | /* ack bmdma irq events */ | 4498 | /* ack bmdma irq events */ |
4424 | ap->ops->irq_clear(ap); | 4499 | ap->ops->irq_clear(ap); |
4425 | 4500 | ||
4426 | ata_hsm_move(ap, qc, status); | 4501 | ata_hsm_move(ap, qc, status, 0); |
4427 | return 1; /* irq handled */ | 4502 | return 1; /* irq handled */ |
4428 | 4503 | ||
4429 | idle_irq: | 4504 | idle_irq: |