diff options
author | Mark Lord <liml@rtr.ca> | 2007-03-16 10:22:26 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-04-28 14:16:01 -0400 |
commit | 5a5dbd18a7496ed403f6f54bb20c955c65482fa5 (patch) | |
tree | 031eec40ab42ac4ab04e59db539b8126ac31fb6d | |
parent | 1234010684bb9cde51125ec3d1c71054a9f24f47 (diff) |
libata: add support for READ/WRITE LONG
The READ/WRITE LONG commands are theoretically obsolete,
but the majority of drives in existance still implement them.
The WRITE_LONG and WRITE_LONG_ONCE commands are of particular
interest for fault injection testing -- eg. creating "media errors"
at specific locations on a disk.
The fussy bit is that these commands require a non-standard
sector size, usually 520 bytes instead of 512.
This patch adds support to libata for READ/WRITE LONG commands
issued via SG_IO/ATA_16.
Signed-off-by: Mark Lord <mlord@pobox.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r-- | drivers/ata/libata-core.c | 20 | ||||
-rw-r--r-- | drivers/ata/libata-scsi.c | 12 | ||||
-rw-r--r-- | include/linux/ata.h | 6 | ||||
-rw-r--r-- | include/linux/libata.h | 2 |
4 files changed, 30 insertions, 10 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 971a737a8734..96bf86f67388 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c | |||
@@ -4106,10 +4106,10 @@ void ata_data_xfer_noirq(struct ata_device *adev, unsigned char *buf, | |||
4106 | 4106 | ||
4107 | 4107 | ||
4108 | /** | 4108 | /** |
4109 | * ata_pio_sector - Transfer ATA_SECT_SIZE (512 bytes) of data. | 4109 | * ata_pio_sector - Transfer a sector of data. |
4110 | * @qc: Command on going | 4110 | * @qc: Command on going |
4111 | * | 4111 | * |
4112 | * Transfer ATA_SECT_SIZE of data from/to the ATA device. | 4112 | * Transfer qc->sect_size bytes of data from/to the ATA device. |
4113 | * | 4113 | * |
4114 | * LOCKING: | 4114 | * LOCKING: |
4115 | * Inherited from caller. | 4115 | * Inherited from caller. |
@@ -4124,7 +4124,7 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) | |||
4124 | unsigned int offset; | 4124 | unsigned int offset; |
4125 | unsigned char *buf; | 4125 | unsigned char *buf; |
4126 | 4126 | ||
4127 | if (qc->curbytes == qc->nbytes - ATA_SECT_SIZE) | 4127 | if (qc->curbytes == qc->nbytes - qc->sect_size) |
4128 | ap->hsm_task_state = HSM_ST_LAST; | 4128 | ap->hsm_task_state = HSM_ST_LAST; |
4129 | 4129 | ||
4130 | page = sg[qc->cursg].page; | 4130 | page = sg[qc->cursg].page; |
@@ -4144,17 +4144,17 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) | |||
4144 | buf = kmap_atomic(page, KM_IRQ0); | 4144 | buf = kmap_atomic(page, KM_IRQ0); |
4145 | 4145 | ||
4146 | /* do the actual data transfer */ | 4146 | /* do the actual data transfer */ |
4147 | ap->ops->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write); | 4147 | ap->ops->data_xfer(qc->dev, buf + offset, qc->sect_size, do_write); |
4148 | 4148 | ||
4149 | kunmap_atomic(buf, KM_IRQ0); | 4149 | kunmap_atomic(buf, KM_IRQ0); |
4150 | local_irq_restore(flags); | 4150 | local_irq_restore(flags); |
4151 | } else { | 4151 | } else { |
4152 | buf = page_address(page); | 4152 | buf = page_address(page); |
4153 | ap->ops->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write); | 4153 | ap->ops->data_xfer(qc->dev, buf + offset, qc->sect_size, do_write); |
4154 | } | 4154 | } |
4155 | 4155 | ||
4156 | qc->curbytes += ATA_SECT_SIZE; | 4156 | qc->curbytes += qc->sect_size; |
4157 | qc->cursg_ofs += ATA_SECT_SIZE; | 4157 | qc->cursg_ofs += qc->sect_size; |
4158 | 4158 | ||
4159 | if (qc->cursg_ofs == (&sg[qc->cursg])->length) { | 4159 | if (qc->cursg_ofs == (&sg[qc->cursg])->length) { |
4160 | qc->cursg++; | 4160 | qc->cursg++; |
@@ -4163,10 +4163,10 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) | |||
4163 | } | 4163 | } |
4164 | 4164 | ||
4165 | /** | 4165 | /** |
4166 | * ata_pio_sectors - Transfer one or many 512-byte sectors. | 4166 | * ata_pio_sectors - Transfer one or many sectors. |
4167 | * @qc: Command on going | 4167 | * @qc: Command on going |
4168 | * | 4168 | * |
4169 | * Transfer one or many ATA_SECT_SIZE of data from/to the | 4169 | * Transfer one or many sectors of data from/to the |
4170 | * ATA device for the DRQ request. | 4170 | * ATA device for the DRQ request. |
4171 | * | 4171 | * |
4172 | * LOCKING: | 4172 | * LOCKING: |
@@ -4181,7 +4181,7 @@ static void ata_pio_sectors(struct ata_queued_cmd *qc) | |||
4181 | 4181 | ||
4182 | WARN_ON(qc->dev->multi_count == 0); | 4182 | WARN_ON(qc->dev->multi_count == 0); |
4183 | 4183 | ||
4184 | nsect = min((qc->nbytes - qc->curbytes) / ATA_SECT_SIZE, | 4184 | nsect = min((qc->nbytes - qc->curbytes) / qc->sect_size, |
4185 | qc->dev->multi_count); | 4185 | qc->dev->multi_count); |
4186 | while (nsect--) | 4186 | while (nsect--) |
4187 | ata_pio_sector(qc); | 4187 | ata_pio_sector(qc); |
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 7d41afe8ccbc..563ef0bfb038 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c | |||
@@ -2678,6 +2678,18 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) | |||
2678 | tf->device = qc->dev->devno ? | 2678 | tf->device = qc->dev->devno ? |
2679 | tf->device | ATA_DEV1 : tf->device & ~ATA_DEV1; | 2679 | tf->device | ATA_DEV1 : tf->device & ~ATA_DEV1; |
2680 | 2680 | ||
2681 | /* READ/WRITE LONG use a non-standard sect_size */ | ||
2682 | qc->sect_size = ATA_SECT_SIZE; | ||
2683 | switch (tf->command) { | ||
2684 | case ATA_CMD_READ_LONG: | ||
2685 | case ATA_CMD_READ_LONG_ONCE: | ||
2686 | case ATA_CMD_WRITE_LONG: | ||
2687 | case ATA_CMD_WRITE_LONG_ONCE: | ||
2688 | if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1) | ||
2689 | goto invalid_fld; | ||
2690 | qc->sect_size = scmd->request_bufflen; | ||
2691 | } | ||
2692 | |||
2681 | /* | 2693 | /* |
2682 | * Filter SET_FEATURES - XFER MODE command -- otherwise, | 2694 | * Filter SET_FEATURES - XFER MODE command -- otherwise, |
2683 | * SET_FEATURES - XFER MODE must be preceded/succeeded | 2695 | * SET_FEATURES - XFER MODE must be preceded/succeeded |
diff --git a/include/linux/ata.h b/include/linux/ata.h index 6caeb98e29dd..ffb6cdc5010d 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h | |||
@@ -164,6 +164,12 @@ enum { | |||
164 | /* READ_LOG_EXT pages */ | 164 | /* READ_LOG_EXT pages */ |
165 | ATA_LOG_SATA_NCQ = 0x10, | 165 | ATA_LOG_SATA_NCQ = 0x10, |
166 | 166 | ||
167 | /* READ/WRITE LONG (obsolete) */ | ||
168 | ATA_CMD_READ_LONG = 0x22, | ||
169 | ATA_CMD_READ_LONG_ONCE = 0x23, | ||
170 | ATA_CMD_WRITE_LONG = 0x32, | ||
171 | ATA_CMD_WRITE_LONG_ONCE = 0x33, | ||
172 | |||
167 | /* SETFEATURES stuff */ | 173 | /* SETFEATURES stuff */ |
168 | SETFEATURES_XFER = 0x03, | 174 | SETFEATURES_XFER = 0x03, |
169 | XFER_UDMA_7 = 0x47, | 175 | XFER_UDMA_7 = 0x47, |
diff --git a/include/linux/libata.h b/include/linux/libata.h index 5a40a8d95114..12237d4b9f9b 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h | |||
@@ -427,6 +427,7 @@ struct ata_queued_cmd { | |||
427 | int dma_dir; | 427 | int dma_dir; |
428 | 428 | ||
429 | unsigned int pad_len; | 429 | unsigned int pad_len; |
430 | unsigned int sect_size; | ||
430 | 431 | ||
431 | unsigned int nbytes; | 432 | unsigned int nbytes; |
432 | unsigned int curbytes; | 433 | unsigned int curbytes; |
@@ -1182,6 +1183,7 @@ static inline void ata_qc_reinit(struct ata_queued_cmd *qc) | |||
1182 | qc->n_elem = 0; | 1183 | qc->n_elem = 0; |
1183 | qc->err_mask = 0; | 1184 | qc->err_mask = 0; |
1184 | qc->pad_len = 0; | 1185 | qc->pad_len = 0; |
1186 | qc->sect_size = ATA_SECT_SIZE; | ||
1185 | 1187 | ||
1186 | ata_tf_init(qc->dev, &qc->tf); | 1188 | ata_tf_init(qc->dev, &qc->tf); |
1187 | 1189 | ||