diff options
author | Albert Lee <albertcc@tw.ibm.com> | 2005-11-01 06:33:20 -0500 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-11-09 01:22:19 -0500 |
commit | 07f6f7d074e68d56d82e7cc5c65096033ac8dc56 (patch) | |
tree | d420722be7721691e5c56dc5a0ff326e926a58e6 | |
parent | fbcdd80b0d5bde06f3483b9a13f9599a0452431c (diff) |
[PATCH] libata irq-pio: add read/write multiple support
- add is_multi_taskfile() to ata.h
- initialize ata_device->multi_count with device identify data
- use ata_pio_sectors() to support r/w multiple commands
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
========
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
-rw-r--r-- | drivers/scsi/libata-core.c | 44 | ||||
-rw-r--r-- | include/linux/ata.h | 8 |
2 files changed, 46 insertions, 6 deletions
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 2e0e6cca327c..59a4a26bc13f 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c | |||
@@ -1261,6 +1261,12 @@ retry: | |||
1261 | 1261 | ||
1262 | } | 1262 | } |
1263 | 1263 | ||
1264 | if (dev->id[59] & 0x100) { | ||
1265 | dev->multi_count = dev->id[59] & 0xff; | ||
1266 | DPRINTK("ata%u: dev %u multi count %u\n", | ||
1267 | ap->id, device, dev->multi_count); | ||
1268 | } | ||
1269 | |||
1264 | ap->host->max_cmd_len = 16; | 1270 | ap->host->max_cmd_len = 16; |
1265 | } | 1271 | } |
1266 | 1272 | ||
@@ -2804,7 +2810,7 @@ static int ata_pio_complete (struct ata_port *ap) | |||
2804 | * we enter, BSY will be cleared in a chk-status or two. If not, | 2810 | * we enter, BSY will be cleared in a chk-status or two. If not, |
2805 | * the drive is probably seeking or something. Snooze for a couple | 2811 | * the drive is probably seeking or something. Snooze for a couple |
2806 | * msecs, then chk-status again. If still busy, fall back to | 2812 | * msecs, then chk-status again. If still busy, fall back to |
2807 | * HSM_ST_POLL state. | 2813 | * HSM_ST_LAST_POLL state. |
2808 | */ | 2814 | */ |
2809 | drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10); | 2815 | drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10); |
2810 | if (drv_stat & (ATA_BUSY | ATA_DRQ)) { | 2816 | if (drv_stat & (ATA_BUSY | ATA_DRQ)) { |
@@ -3021,6 +3027,32 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) | |||
3021 | } | 3027 | } |
3022 | 3028 | ||
3023 | /** | 3029 | /** |
3030 | * ata_pio_sectors - Transfer one or many 512-byte sectors. | ||
3031 | * @qc: Command on going | ||
3032 | * | ||
3033 | * Transfer one or many ATA_SECT_SIZE of data from/to the | ||
3034 | * ATA device for the DRQ request. | ||
3035 | * | ||
3036 | * LOCKING: | ||
3037 | * Inherited from caller. | ||
3038 | */ | ||
3039 | |||
3040 | static void ata_pio_sectors(struct ata_queued_cmd *qc) | ||
3041 | { | ||
3042 | if (is_multi_taskfile(&qc->tf)) { | ||
3043 | /* READ/WRITE MULTIPLE */ | ||
3044 | unsigned int nsect; | ||
3045 | |||
3046 | assert(qc->dev->multi_count); | ||
3047 | |||
3048 | nsect = min(qc->nsect - qc->cursect, qc->dev->multi_count); | ||
3049 | while (nsect--) | ||
3050 | ata_pio_sector(qc); | ||
3051 | } else | ||
3052 | ata_pio_sector(qc); | ||
3053 | } | ||
3054 | |||
3055 | /** | ||
3024 | * atapi_send_cdb - Write CDB bytes to hardware | 3056 | * atapi_send_cdb - Write CDB bytes to hardware |
3025 | * @ap: Port to which ATAPI device is attached. | 3057 | * @ap: Port to which ATAPI device is attached. |
3026 | * @qc: Taskfile currently active | 3058 | * @qc: Taskfile currently active |
@@ -3118,11 +3150,11 @@ static int ata_pio_first_block(struct ata_port *ap) | |||
3118 | * send first data block. | 3150 | * send first data block. |
3119 | */ | 3151 | */ |
3120 | 3152 | ||
3121 | /* ata_pio_sector() might change the state to HSM_ST_LAST. | 3153 | /* ata_pio_sectors() might change the state to HSM_ST_LAST. |
3122 | * so, the state is changed here before ata_pio_sector(). | 3154 | * so, the state is changed here before ata_pio_sectors(). |
3123 | */ | 3155 | */ |
3124 | ap->hsm_task_state = HSM_ST; | 3156 | ap->hsm_task_state = HSM_ST; |
3125 | ata_pio_sector(qc); | 3157 | ata_pio_sectors(qc); |
3126 | ata_altstatus(ap); /* flush */ | 3158 | ata_altstatus(ap); /* flush */ |
3127 | } else | 3159 | } else |
3128 | /* send CDB */ | 3160 | /* send CDB */ |
@@ -3327,7 +3359,7 @@ static void ata_pio_block(struct ata_port *ap) | |||
3327 | return; | 3359 | return; |
3328 | } | 3360 | } |
3329 | 3361 | ||
3330 | ata_pio_sector(qc); | 3362 | ata_pio_sectors(qc); |
3331 | } | 3363 | } |
3332 | 3364 | ||
3333 | ata_altstatus(ap); /* flush */ | 3365 | ata_altstatus(ap); /* flush */ |
@@ -4213,7 +4245,7 @@ fsm_start: | |||
4213 | goto fsm_start; | 4245 | goto fsm_start; |
4214 | } | 4246 | } |
4215 | 4247 | ||
4216 | ata_pio_sector(qc); | 4248 | ata_pio_sectors(qc); |
4217 | 4249 | ||
4218 | if (ap->hsm_task_state == HSM_ST_LAST && | 4250 | if (ap->hsm_task_state == HSM_ST_LAST && |
4219 | (!(qc->tf.flags & ATA_TFLAG_WRITE))) { | 4251 | (!(qc->tf.flags & ATA_TFLAG_WRITE))) { |
diff --git a/include/linux/ata.h b/include/linux/ata.h index d54da3306d2c..f512104a1a3f 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h | |||
@@ -293,6 +293,14 @@ static inline int is_atapi_taskfile(const struct ata_taskfile *tf) | |||
293 | (tf->protocol == ATA_PROT_ATAPI_DMA); | 293 | (tf->protocol == ATA_PROT_ATAPI_DMA); |
294 | } | 294 | } |
295 | 295 | ||
296 | static inline int is_multi_taskfile(struct ata_taskfile *tf) | ||
297 | { | ||
298 | return (tf->command == ATA_CMD_READ_MULTI) || | ||
299 | (tf->command == ATA_CMD_WRITE_MULTI) || | ||
300 | (tf->command == ATA_CMD_READ_MULTI_EXT) || | ||
301 | (tf->command == ATA_CMD_WRITE_MULTI_EXT); | ||
302 | } | ||
303 | |||
296 | static inline int ata_ok(u8 status) | 304 | static inline int ata_ok(u8 status) |
297 | { | 305 | { |
298 | return ((status & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ | ATA_ERR)) | 306 | return ((status & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ | ATA_ERR)) |