From 6013efd8860bf15c1f86f365332642cfe557152f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 19 Nov 2009 15:36:45 +0900 Subject: libata: retry failed FLUSH if device didn't fail it If ATA device failed FLUSH, it means that the device failed to write out some amount of data and the error needs to be reported to upper layers. As retries can't recover the lost data, FLUSH failures need to be reported immediately in general. However, if FLUSH fails due to transmission errors, the FLUSH needs to be retried; otherwise, filesystems may switch to RO mode and/or raid array may drop a drive for a random transmission glitch. This condition can be rather easily reproduced on certain ahci controllers which go through a PHY event after powersave mode switch + ext4 combination. Powersave mode switch is often closely followed by flush from the filesystem failing the FLUSH with ATA bus error which makes the filesystem code believe that data is lost and drop to RO mode. This was reported in the following bugzilla bug. http://bugzilla.kernel.org/show_bug.cgi?id=14543 This patch makes libata EH retry FLUSH if it wasn't failed by the device. Signed-off-by: Tejun Heo Reported-by: Andrey Vihrov Signed-off-by: Jeff Garzik --- include/linux/libata.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/libata.h b/include/linux/libata.h index 87698640c091..ba07e84c9840 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -365,7 +365,7 @@ enum { /* This should match the actual table size of * ata_eh_cmd_timeout_table in libata-eh.c. */ - ATA_EH_CMD_TIMEOUT_TABLE_SIZE = 5, + ATA_EH_CMD_TIMEOUT_TABLE_SIZE = 6, /* Horkage types. May be set by libata or controller on drives (some horkage may be drive/controller pair dependant */ -- cgit v1.2.3 From 18f0f97850059303ed73b1f02084f55ca330a80c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 17 Nov 2009 10:00:47 -0500 Subject: libata: add translation for SCSI WRITE SAME (aka TRIM support) Add support for the ATA TRIM command in libata. We translate a WRITE SAME 16 command with the unmap bit set into an ATA TRIM command and export enough information in READ CAPACITY 16 and the block limits EVPD page so that the new SCSI layer discard support will driver this for us. Note that I hardcode the WRITE_SAME_16 opcode for now as the patch to introduce the symbolic is not in 2.6.32 yet but only in the SCSI tree - as soon as it is merged we can fix it up to properly use the symbolic name. Signed-off-by: Christoph Hellwig Signed-off-by: Jeff Garzik --- drivers/ata/libata-scsi.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++ include/linux/ata.h | 13 +++++++ 2 files changed, 111 insertions(+) (limited to 'include/linux') diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 512a3ee8caf6..340a616d226b 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -47,6 +47,7 @@ #include #include #include +#include #include "libata.h" @@ -1963,6 +1964,7 @@ static unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf) 0x80, /* page 0x80, unit serial no page */ 0x83, /* page 0x83, device ident page */ 0x89, /* page 0x89, ata info page */ + 0xb0, /* page 0xb0, block limits page */ 0xb1, /* page 0xb1, block device characteristics page */ }; @@ -2084,6 +2086,41 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf) return 0; } +static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf) +{ + u32 min_io_sectors; + + rbuf[1] = 0xb0; + rbuf[3] = 0x3c; /* required VPD size with unmap support */ + + /* + * Optimal transfer length granularity. + * + * This is always one physical block, but for disks with a smaller + * logical than physical sector size we need to figure out what the + * latter is. + */ + if (ata_id_has_large_logical_sectors(args->id)) + min_io_sectors = ata_id_logical_per_physical_sectors(args->id); + else + min_io_sectors = 1; + put_unaligned_be16(min_io_sectors, &rbuf[6]); + + /* + * Optimal unmap granularity. + * + * The ATA spec doesn't even know about a granularity or alignment + * for the TRIM command. We can leave away most of the unmap related + * VPD page entries, but we have specifify a granularity to signal + * that we support some form of unmap - in thise case via WRITE SAME + * with the unmap bit set. + */ + if (ata_id_has_trim(args->id)) + put_unaligned_be32(1, &rbuf[28]); + + return 0; +} + static unsigned int ata_scsiop_inq_b1(struct ata_scsi_args *args, u8 *rbuf) { int form_factor = ata_id_form_factor(args->id); @@ -2373,6 +2410,9 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf) rbuf[13] = log_per_phys; rbuf[14] = (lowest_aligned >> 8) & 0x3f; rbuf[15] = lowest_aligned; + + if (ata_id_has_trim(args->id)) + rbuf[14] |= 0x80; } return 0; @@ -2895,6 +2935,58 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) return 1; } +static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) +{ + struct ata_taskfile *tf = &qc->tf; + struct scsi_cmnd *scmd = qc->scsicmd; + struct ata_device *dev = qc->dev; + const u8 *cdb = scmd->cmnd; + u64 block; + u32 n_block; + u32 size; + void *buf; + + /* we may not issue DMA commands if no DMA mode is set */ + if (unlikely(!dev->dma_mode)) + goto invalid_fld; + + if (unlikely(scmd->cmd_len < 16)) + goto invalid_fld; + scsi_16_lba_len(cdb, &block, &n_block); + + /* for now we only support WRITE SAME with the unmap bit set */ + if (unlikely(!(cdb[1] & 0x8))) + goto invalid_fld; + + /* + * WRITE SAME always has a sector sized buffer as payload, this + * should never be a multiple entry S/G list. + */ + if (!scsi_sg_count(scmd)) + goto invalid_fld; + + buf = page_address(sg_page(scsi_sglist(scmd))); + size = ata_set_lba_range_entries(buf, 512 / 8, block, n_block); + + tf->protocol = ATA_PROT_DMA; + tf->hob_feature = 0; + tf->feature = ATA_DSM_TRIM; + tf->hob_nsect = (size / 512) >> 8; + tf->nsect = size / 512; + tf->command = ATA_CMD_DSM; + tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | + ATA_TFLAG_WRITE; + + ata_qc_set_pc_nbytes(qc); + + return 0; + + invalid_fld: + ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x00); + /* "Invalid field in cdb" */ + return 1; +} + /** * ata_get_xlat_func - check if SCSI to ATA translation is possible * @dev: ATA device @@ -2919,6 +3011,9 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd) case WRITE_16: return ata_scsi_rw_xlat; + case 0x93 /*WRITE_SAME_16*/: + return ata_scsi_write_same_xlat; + case SYNCHRONIZE_CACHE: if (ata_try_flush_cache(dev)) return ata_scsi_flush_xlat; @@ -3108,6 +3203,9 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd, case 0x89: ata_scsi_rbuf_fill(&args, ata_scsiop_inq_89); break; + case 0xb0: + ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b0); + break; case 0xb1: ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b1); break; diff --git a/include/linux/ata.h b/include/linux/ata.h index 4fb357312b3b..e2595e877e44 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -87,6 +87,7 @@ enum { ATA_ID_HW_CONFIG = 93, ATA_ID_SPG = 98, ATA_ID_LBA_CAPACITY_2 = 100, + ATA_ID_SECTOR_SIZE = 106, ATA_ID_LAST_LUN = 126, ATA_ID_DLF = 128, ATA_ID_CSFO = 129, @@ -638,6 +639,18 @@ static inline int ata_id_flush_ext_enabled(const u16 *id) return (id[ATA_ID_CFS_ENABLE_2] & 0x2400) == 0x2400; } +static inline int ata_id_has_large_logical_sectors(const u16 *id) +{ + if ((id[ATA_ID_SECTOR_SIZE] & 0xc000) != 0x4000) + return 0; + return id[ATA_ID_SECTOR_SIZE] & (1 << 13); +} + +static inline u8 ata_id_logical_per_physical_sectors(const u16 *id) +{ + return id[ATA_ID_SECTOR_SIZE] & 0xf; +} + static inline int ata_id_has_lba48(const u16 *id) { if ((id[ATA_ID_COMMAND_SET_2] & 0xC000) != 0x4000) -- cgit v1.2.3 From 8e182a90f91456335756d2ce304ad470795d98e1 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 30 Nov 2009 13:23:11 +0000 Subject: pata_piccolo: Driver for old Toshiba chipsets We were never able to get docs for this out of Toshiba for years. Dave Barnes produced a NetBSD driver however and from that we can fill in the needed tables. As we correct the PCI identifiers a bit also update the old ide generic driver at the same time so it stays compiling. Signed-off-by: Alan Cox Signed-off-by: Jeff Garzik --- drivers/ata/Kconfig | 9 +++ drivers/ata/Makefile | 1 + drivers/ata/ata_generic.c | 5 +- drivers/ata/pata_piccolo.c | 140 ++++++++++++++++++++++++++++++++++++++++++ drivers/ide/ide-pci-generic.c | 3 +- include/linux/pci_ids.h | 7 ++- 6 files changed, 160 insertions(+), 5 deletions(-) create mode 100644 drivers/ata/pata_piccolo.c (limited to 'include/linux') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index a47ca75aa078..676f08b004b3 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -667,6 +667,15 @@ config PATA_SIS If unsure, say N. +config PATA_TOSHIBA + tristate "Toshiba Piccolo support (Experimental)" + depends on PCI && EXPERIMENTAL + help + Support for the Toshiba Piccolo controllers. Currently only the + primary channel is supported by this driver. + + If unsure, say N. + config PATA_VIA tristate "VIA PATA support" depends on PCI diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 01e126f343b3..d909435e9d81 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -63,6 +63,7 @@ obj-$(CONFIG_PATA_RZ1000) += pata_rz1000.o obj-$(CONFIG_PATA_SC1200) += pata_sc1200.o obj-$(CONFIG_PATA_SERVERWORKS) += pata_serverworks.o obj-$(CONFIG_PATA_SIL680) += pata_sil680.o +obj-$(CONFIG_PATA_TOSHIBA) += pata_piccolo.o obj-$(CONFIG_PATA_VIA) += pata_via.o obj-$(CONFIG_PATA_WINBOND) += pata_sl82c105.o obj-$(CONFIG_PATA_WINBOND_VLB) += pata_winbond.o diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index ecfd22b4f1ce..12e26c3c68e3 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -168,9 +168,12 @@ static struct pci_device_id ata_generic[] = { { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561), }, { PCI_DEVICE(PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558), }, { PCI_DEVICE(PCI_VENDOR_ID_CENATEK,PCI_DEVICE_ID_CENATEK_IDE), }, - { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO), }, +#if !defined(CONFIG_PATA_TOSHIBA) && !defined(CONFIG_PATA_TOSHIBA_MODULE) { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1), }, { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2), }, + { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_3), }, + { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_5), }, +#endif /* Must come last. If you add entries adjust this table appropriately */ { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 1}, { 0, }, diff --git a/drivers/ata/pata_piccolo.c b/drivers/ata/pata_piccolo.c new file mode 100644 index 000000000000..bfe0180f3efa --- /dev/null +++ b/drivers/ata/pata_piccolo.c @@ -0,0 +1,140 @@ +/* + * pata_piccolo.c - Toshiba Piccolo PATA/SATA controller driver. + * + * This is basically an update to ata_generic.c to add Toshiba Piccolo support + * then split out to keep ata_generic "clean". + * + * Copyright 2005 Red Hat Inc, all rights reserved. + * + * Elements from ide/pci/generic.c + * Copyright (C) 2001-2002 Andre Hedrick + * Portions (C) Copyright 2002 Red Hat Inc + * + * May be copied or modified under the terms of the GNU General Public License + * + * The timing data tables/programming info are courtesy of the NetBSD driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "pata_piccolo" +#define DRV_VERSION "0.0.1" + + + +static void tosh_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + static const u16 pio[6] = { /* For reg 0x50 low word & E088 */ + 0x0566, 0x0433, 0x0311, 0x0201, 0x0200, 0x0100 + }; + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + u16 conf; + pci_read_config_word(pdev, 0x50, &conf); + conf &= 0xE088; + conf |= pio[adev->pio_mode - XFER_PIO_0]; + pci_write_config_word(pdev, 0x50, conf); +} + +static void tosh_set_dmamode(struct ata_port *ap, struct ata_device *adev) +{ + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + u32 conf; + pci_read_config_dword(pdev, 0x5C, &conf); + conf &= 0x78FFE088; /* Keep the other bits */ + if (adev->dma_mode >= XFER_UDMA_0) { + int udma = adev->dma_mode - XFER_UDMA_0; + conf |= 0x80000000; + conf |= (udma + 2) << 28; + conf |= (2 - udma) * 0x111; /* spread into three nibbles */ + } else { + static const u32 mwdma[4] = { + 0x0655, 0x0200, 0x0200, 0x0100 + }; + conf |= mwdma[adev->dma_mode - XFER_MW_DMA_0]; + } + pci_write_config_dword(pdev, 0x5C, conf); +} + + +static struct scsi_host_template tosh_sht = { + ATA_BMDMA_SHT(DRV_NAME), +}; + +static struct ata_port_operations tosh_port_ops = { + .inherits = &ata_bmdma_port_ops, + .cable_detect = ata_cable_unknown, + .set_piomode = tosh_set_piomode, + .set_dmamode = tosh_set_dmamode +}; + +/** + * ata_tosh_init - attach generic IDE + * @dev: PCI device found + * @id: match entry + * + * Called each time a matching IDE interface is found. We check if the + * interface is one we wish to claim and if so we perform any chip + * specific hacks then let the ATA layer do the heavy lifting. + */ + +static int ata_tosh_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + static const struct ata_port_info info = { + .flags = ATA_FLAG_SLAVE_POSS, + .pio_mask = ATA_PIO5, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA2, + .port_ops = &tosh_port_ops + }; + const struct ata_port_info *ppi[] = { &info, &ata_dummy_port_info }; + /* Just one port for the moment */ + return ata_pci_sff_init_one(dev, ppi, &tosh_sht, NULL); +} + +static struct pci_device_id ata_tosh[] = { + { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1), }, + { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2), }, + { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_3), }, + { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_5), }, + { 0, }, +}; + +static struct pci_driver ata_tosh_pci_driver = { + .name = DRV_NAME, + .id_table = ata_tosh, + .probe = ata_tosh_init_one, + .remove = ata_pci_remove_one, +#ifdef CONFIG_PM + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, +#endif +}; + +static int __init ata_tosh_init(void) +{ + return pci_register_driver(&ata_tosh_pci_driver); +} + + +static void __exit ata_tosh_exit(void) +{ + pci_unregister_driver(&ata_tosh_pci_driver); +} + + +MODULE_AUTHOR("Alan Cox"); +MODULE_DESCRIPTION("Low level driver for Toshiba Piccolo ATA"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, ata_tosh); +MODULE_VERSION(DRV_VERSION); + +module_init(ata_tosh_init); +module_exit(ata_tosh_exit); + diff --git a/drivers/ide/ide-pci-generic.c b/drivers/ide/ide-pci-generic.c index 39d4e01f5c9c..a743e68a8903 100644 --- a/drivers/ide/ide-pci-generic.c +++ b/drivers/ide/ide-pci-generic.c @@ -162,9 +162,10 @@ static const struct pci_device_id generic_pci_tbl[] = { #ifdef CONFIG_BLK_DEV_IDE_SATA { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_8237_SATA), 5 }, #endif - { PCI_VDEVICE(TOSHIBA, PCI_DEVICE_ID_TOSHIBA_PICCOLO), 4 }, { PCI_VDEVICE(TOSHIBA, PCI_DEVICE_ID_TOSHIBA_PICCOLO_1), 4 }, { PCI_VDEVICE(TOSHIBA, PCI_DEVICE_ID_TOSHIBA_PICCOLO_2), 4 }, + { PCI_VDEVICE(TOSHIBA, PCI_DEVICE_ID_TOSHIBA_PICCOLO_3), 4 }, + { PCI_VDEVICE(TOSHIBA, PCI_DEVICE_ID_TOSHIBA_PICCOLO_5), 4 }, { PCI_VDEVICE(NETCELL, PCI_DEVICE_ID_REVOLUTION), 6 }, /* * Must come last. If you add entries adjust diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 84cf1f3b7838..9ca483be68d5 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1496,9 +1496,10 @@ #define PCI_DEVICE_ID_SBE_WANXL400 0x0104 #define PCI_VENDOR_ID_TOSHIBA 0x1179 -#define PCI_DEVICE_ID_TOSHIBA_PICCOLO 0x0102 -#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_1 0x0103 -#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_2 0x0105 +#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_1 0x0101 +#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_2 0x0102 +#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_3 0x0103 +#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_5 0x0105 #define PCI_DEVICE_ID_TOSHIBA_TOPIC95 0x060a #define PCI_DEVICE_ID_TOSHIBA_TOPIC97 0x060f #define PCI_DEVICE_ID_TOSHIBA_TOPIC100 0x0617 -- cgit v1.2.3 From 95514fd8ff0f30de7815950edfd84ef1e19fb1c8 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 25 Nov 2009 18:12:48 +0100 Subject: libata: add private driver field to struct ata_device This brings struct ata_device in-line with struct ata_{port,host}. Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Jeff Garzik --- include/linux/libata.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/libata.h b/include/linux/libata.h index ba07e84c9840..a5b3dc71e819 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -595,6 +595,7 @@ struct ata_device { unsigned int horkage; /* List of broken features */ unsigned long flags; /* ATA_DFLAG_xxx */ struct scsi_device *sdev; /* attached SCSI device */ + void *private_data; #ifdef CONFIG_ATA_ACPI acpi_handle acpi_handle; union acpi_object *gtf_cache; -- cgit v1.2.3 From e78db4dfb1355a895f7ea50133b702b55b8ed184 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Thu, 26 Nov 2009 22:46:03 -0500 Subject: libata: Report zeroed read after TRIM and max discard size Our current TRIM payload is a single sector that can accommodate 64 * 65535 blocks being unmapped. Report this value in the Block Limits Maximum Unmap LBA count field. If a storage device supports TRIM and the DRAT and RZAT bits are set, report TPRZ=1 in Read Capacity(16). Signed-off-by: Martin K. Petersen Signed-off-by: Jeff Garzik --- drivers/ata/libata-scsi.c | 12 +++++++++--- include/linux/ata.h | 11 +++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 340a616d226b..e1e186b9dfcc 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2115,8 +2115,10 @@ static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf) * that we support some form of unmap - in thise case via WRITE SAME * with the unmap bit set. */ - if (ata_id_has_trim(args->id)) + if (ata_id_has_trim(args->id)) { + put_unaligned_be32(65535 * 512 / 8, &rbuf[20]); put_unaligned_be32(1, &rbuf[28]); + } return 0; } @@ -2411,8 +2413,12 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf) rbuf[14] = (lowest_aligned >> 8) & 0x3f; rbuf[15] = lowest_aligned; - if (ata_id_has_trim(args->id)) - rbuf[14] |= 0x80; + if (ata_id_has_trim(args->id)) { + rbuf[14] |= 0x80; /* TPE */ + + if (ata_id_has_zero_after_trim(args->id)) + rbuf[14] |= 0x40; /* TPRZ */ + } } return 0; diff --git a/include/linux/ata.h b/include/linux/ata.h index e2595e877e44..dfa2298bf488 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -75,6 +75,7 @@ enum { ATA_ID_EIDE_DMA_TIME = 66, ATA_ID_EIDE_PIO = 67, ATA_ID_EIDE_PIO_IORDY = 68, + ATA_ID_ADDITIONAL_SUPP = 69, ATA_ID_QUEUE_DEPTH = 75, ATA_ID_MAJOR_VER = 80, ATA_ID_COMMAND_SET_1 = 82, @@ -816,6 +817,16 @@ static inline int ata_id_has_trim(const u16 *id) return 0; } +static inline int ata_id_has_zero_after_trim(const u16 *id) +{ + /* DSM supported, deterministic read, and read zero after trim set */ + if (ata_id_has_trim(id) && + (id[ATA_ID_ADDITIONAL_SUPP] & 0x4020) == 0x4020) + return 1; + + return 0; +} + static inline int ata_id_current_chs_valid(const u16 *id) { /* For ATA-1 devices, if the INITIALIZE DEVICE PARAMETERS command -- cgit v1.2.3 From d0634c4aea0b80447cbdc4c0db285004b860c455 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Thu, 26 Nov 2009 12:00:43 -0500 Subject: libata: Clarify ata_set_lba_range_entries function ata_set_lba_range_entries used the variable max for two different things which was confusing. Make the function take a buffer size in bytes as argument and return the used buffer size upon completion. Signed-off-by: Martin K. Petersen Signed-off-by: Jeff Garzik --- drivers/ata/libata-scsi.c | 2 +- include/linux/ata.h | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index e1e186b9dfcc..62e6b9ea96af 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2972,7 +2972,7 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) goto invalid_fld; buf = page_address(sg_page(scsi_sglist(scmd))); - size = ata_set_lba_range_entries(buf, 512 / 8, block, n_block); + size = ata_set_lba_range_entries(buf, 512, block, n_block); tf->protocol = ATA_PROT_DMA; tf->hob_feature = 0; diff --git a/include/linux/ata.h b/include/linux/ata.h index dfa2298bf488..38a6948ce0c2 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -982,17 +982,17 @@ static inline void ata_id_to_hd_driveid(u16 *id) } /* - * Write up to 'max' LBA Range Entries to the buffer that will cover the - * extent from sector to sector + count. This is used for TRIM and for - * ADD LBA(S) TO NV CACHE PINNED SET. + * Write LBA Range Entries to the buffer that will cover the extent from + * sector to sector + count. This is used for TRIM and for ADD LBA(S) + * TO NV CACHE PINNED SET. */ -static inline unsigned ata_set_lba_range_entries(void *_buffer, unsigned max, - u64 sector, unsigned long count) +static inline unsigned ata_set_lba_range_entries(void *_buffer, + unsigned buf_size, u64 sector, unsigned long count) { __le64 *buffer = _buffer; - unsigned i = 0; + unsigned i = 0, used_bytes; - while (i < max) { + while (i < buf_size / 8 ) { /* 6-byte LBA + 2-byte range per entry */ u64 entry = sector | ((u64)(count > 0xffff ? 0xffff : count) << 48); buffer[i++] = __cpu_to_le64(entry); @@ -1002,9 +1002,9 @@ static inline unsigned ata_set_lba_range_entries(void *_buffer, unsigned max, sector += 0xffff; } - max = ALIGN(i * 8, 512); - memset(buffer + i, 0, max - i * 8); - return max; + used_bytes = ALIGN(i * 8, 512); + memset(buffer + i, 0, used_bytes - i * 8); + return used_bytes; } static inline int is_multi_taskfile(struct ata_taskfile *tf) -- cgit v1.2.3