From 5a5dbd18a7496ed403f6f54bb20c955c65482fa5 Mon Sep 17 00:00:00 2001 From: Mark Lord Date: Fri, 16 Mar 2007 10:22:26 -0400 Subject: 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 Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 20 ++++++++++---------- drivers/ata/libata-scsi.c | 12 ++++++++++++ 2 files changed, 22 insertions(+), 10 deletions(-) (limited to 'drivers/ata') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 971a737a873..96bf86f6738 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, /** - * ata_pio_sector - Transfer ATA_SECT_SIZE (512 bytes) of data. + * ata_pio_sector - Transfer a sector of data. * @qc: Command on going * - * Transfer ATA_SECT_SIZE of data from/to the ATA device. + * Transfer qc->sect_size bytes of data from/to the ATA device. * * LOCKING: * Inherited from caller. @@ -4124,7 +4124,7 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) unsigned int offset; unsigned char *buf; - if (qc->curbytes == qc->nbytes - ATA_SECT_SIZE) + if (qc->curbytes == qc->nbytes - qc->sect_size) ap->hsm_task_state = HSM_ST_LAST; page = sg[qc->cursg].page; @@ -4144,17 +4144,17 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) buf = kmap_atomic(page, KM_IRQ0); /* do the actual data transfer */ - ap->ops->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write); + ap->ops->data_xfer(qc->dev, buf + offset, qc->sect_size, do_write); kunmap_atomic(buf, KM_IRQ0); local_irq_restore(flags); } else { buf = page_address(page); - ap->ops->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write); + ap->ops->data_xfer(qc->dev, buf + offset, qc->sect_size, do_write); } - qc->curbytes += ATA_SECT_SIZE; - qc->cursg_ofs += ATA_SECT_SIZE; + qc->curbytes += qc->sect_size; + qc->cursg_ofs += qc->sect_size; if (qc->cursg_ofs == (&sg[qc->cursg])->length) { qc->cursg++; @@ -4163,10 +4163,10 @@ static void ata_pio_sector(struct ata_queued_cmd *qc) } /** - * ata_pio_sectors - Transfer one or many 512-byte sectors. + * ata_pio_sectors - Transfer one or many sectors. * @qc: Command on going * - * Transfer one or many ATA_SECT_SIZE of data from/to the + * Transfer one or many sectors of data from/to the * ATA device for the DRQ request. * * LOCKING: @@ -4181,7 +4181,7 @@ static void ata_pio_sectors(struct ata_queued_cmd *qc) WARN_ON(qc->dev->multi_count == 0); - nsect = min((qc->nbytes - qc->curbytes) / ATA_SECT_SIZE, + nsect = min((qc->nbytes - qc->curbytes) / qc->sect_size, qc->dev->multi_count); while (nsect--) ata_pio_sector(qc); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 7d41afe8ccb..563ef0bfb03 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) tf->device = qc->dev->devno ? tf->device | ATA_DEV1 : tf->device & ~ATA_DEV1; + /* READ/WRITE LONG use a non-standard sect_size */ + qc->sect_size = ATA_SECT_SIZE; + switch (tf->command) { + case ATA_CMD_READ_LONG: + case ATA_CMD_READ_LONG_ONCE: + case ATA_CMD_WRITE_LONG: + case ATA_CMD_WRITE_LONG_ONCE: + if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1) + goto invalid_fld; + qc->sect_size = scmd->request_bufflen; + } + /* * Filter SET_FEATURES - XFER MODE command -- otherwise, * SET_FEATURES - XFER MODE must be preceded/succeeded -- cgit v1.2.3