diff options
author | Asai Thambi S P <asamymuthupa@micron.com> | 2013-01-11 08:41:34 -0500 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2013-01-11 08:41:34 -0500 |
commit | 152834694dcb90d3088bc77fa436755c66553929 (patch) | |
tree | 0235dc7a7b0d1be0dabeb28b9fe720aa4acf9d20 /drivers/block/mtip32xx/mtip32xx.c | |
parent | 16c906e51c6f08a15763a85b5686e1ded35e77ab (diff) |
mtip32xx: add trim support
TRIM support added through vendor unique command.
Signed-off-by: Sam Bradshaw < sbradshaw@micron.com>
Signed-off-by: Asai Thambi S P <asamymuthupa@micron.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'drivers/block/mtip32xx/mtip32xx.c')
-rw-r--r-- | drivers/block/mtip32xx/mtip32xx.c | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index 99c2cf461be3..b7579b76b4a1 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c | |||
@@ -1519,6 +1519,12 @@ static int mtip_get_identify(struct mtip_port *port, void __user *user_buffer) | |||
1519 | } | 1519 | } |
1520 | #endif | 1520 | #endif |
1521 | 1521 | ||
1522 | /* Demux ID.DRAT & ID.RZAT to determine trim support */ | ||
1523 | if (port->identify[69] & (1 << 14) && port->identify[69] & (1 << 5)) | ||
1524 | port->dd->trim_supp = true; | ||
1525 | else | ||
1526 | port->dd->trim_supp = false; | ||
1527 | |||
1522 | /* Set the identify buffer as valid. */ | 1528 | /* Set the identify buffer as valid. */ |
1523 | port->identify_valid = 1; | 1529 | port->identify_valid = 1; |
1524 | 1530 | ||
@@ -1706,6 +1712,81 @@ static int mtip_get_smart_attr(struct mtip_port *port, unsigned int id, | |||
1706 | } | 1712 | } |
1707 | 1713 | ||
1708 | /* | 1714 | /* |
1715 | * Trim unused sectors | ||
1716 | * | ||
1717 | * @dd pointer to driver_data structure | ||
1718 | * @lba starting lba | ||
1719 | * @len # of 512b sectors to trim | ||
1720 | * | ||
1721 | * return value | ||
1722 | * -ENOMEM Out of dma memory | ||
1723 | * -EINVAL Invalid parameters passed in, trim not supported | ||
1724 | * -EIO Error submitting trim request to hw | ||
1725 | */ | ||
1726 | int mtip_send_trim(struct driver_data *dd, unsigned int lba, unsigned int len) | ||
1727 | { | ||
1728 | int i, rv = 0; | ||
1729 | u64 tlba, tlen, sect_left; | ||
1730 | struct mtip_trim_entry *buf; | ||
1731 | dma_addr_t dma_addr; | ||
1732 | struct host_to_dev_fis fis; | ||
1733 | |||
1734 | if (!len || dd->trim_supp == false) | ||
1735 | return -EINVAL; | ||
1736 | |||
1737 | /* Trim request too big */ | ||
1738 | WARN_ON(len > (MTIP_MAX_TRIM_ENTRY_LEN * MTIP_MAX_TRIM_ENTRIES)); | ||
1739 | |||
1740 | /* Trim request not aligned on 4k boundary */ | ||
1741 | WARN_ON(len % 8 != 0); | ||
1742 | |||
1743 | /* Warn if vu_trim structure is too big */ | ||
1744 | WARN_ON(sizeof(struct mtip_trim) > ATA_SECT_SIZE); | ||
1745 | |||
1746 | /* Allocate a DMA buffer for the trim structure */ | ||
1747 | buf = dmam_alloc_coherent(&dd->pdev->dev, ATA_SECT_SIZE, &dma_addr, | ||
1748 | GFP_KERNEL); | ||
1749 | if (!buf) | ||
1750 | return -ENOMEM; | ||
1751 | memset(buf, 0, ATA_SECT_SIZE); | ||
1752 | |||
1753 | for (i = 0, sect_left = len, tlba = lba; | ||
1754 | i < MTIP_MAX_TRIM_ENTRIES && sect_left; | ||
1755 | i++) { | ||
1756 | tlen = (sect_left >= MTIP_MAX_TRIM_ENTRY_LEN ? | ||
1757 | MTIP_MAX_TRIM_ENTRY_LEN : | ||
1758 | sect_left); | ||
1759 | buf[i].lba = __force_bit2int cpu_to_le32(tlba); | ||
1760 | buf[i].range = __force_bit2int cpu_to_le16(tlen); | ||
1761 | tlba += tlen; | ||
1762 | sect_left -= tlen; | ||
1763 | } | ||
1764 | WARN_ON(sect_left != 0); | ||
1765 | |||
1766 | /* Build the fis */ | ||
1767 | memset(&fis, 0, sizeof(struct host_to_dev_fis)); | ||
1768 | fis.type = 0x27; | ||
1769 | fis.opts = 1 << 7; | ||
1770 | fis.command = 0xfb; | ||
1771 | fis.features = 0x60; | ||
1772 | fis.sect_count = 1; | ||
1773 | fis.device = ATA_DEVICE_OBS; | ||
1774 | |||
1775 | if (mtip_exec_internal_command(dd->port, | ||
1776 | &fis, | ||
1777 | 5, | ||
1778 | dma_addr, | ||
1779 | ATA_SECT_SIZE, | ||
1780 | 0, | ||
1781 | GFP_KERNEL, | ||
1782 | MTIP_TRIM_TIMEOUT_MS) < 0) | ||
1783 | rv = -EIO; | ||
1784 | |||
1785 | dmam_free_coherent(&dd->pdev->dev, ATA_SECT_SIZE, buf, dma_addr); | ||
1786 | return rv; | ||
1787 | } | ||
1788 | |||
1789 | /* | ||
1709 | * Get the drive capacity. | 1790 | * Get the drive capacity. |
1710 | * | 1791 | * |
1711 | * @dd Pointer to the device data structure. | 1792 | * @dd Pointer to the device data structure. |
@@ -3675,6 +3756,12 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio) | |||
3675 | } | 3756 | } |
3676 | } | 3757 | } |
3677 | 3758 | ||
3759 | if (unlikely(bio->bi_rw & REQ_DISCARD)) { | ||
3760 | bio_endio(bio, mtip_send_trim(dd, bio->bi_sector, | ||
3761 | bio_sectors(bio))); | ||
3762 | return; | ||
3763 | } | ||
3764 | |||
3678 | if (unlikely(!bio_has_data(bio))) { | 3765 | if (unlikely(!bio_has_data(bio))) { |
3679 | blk_queue_flush(queue, 0); | 3766 | blk_queue_flush(queue, 0); |
3680 | bio_endio(bio, 0); | 3767 | bio_endio(bio, 0); |
@@ -3817,6 +3904,15 @@ skip_create_disk: | |||
3817 | */ | 3904 | */ |
3818 | blk_queue_flush(dd->queue, 0); | 3905 | blk_queue_flush(dd->queue, 0); |
3819 | 3906 | ||
3907 | /* Signal trim support */ | ||
3908 | if (dd->trim_supp == true) { | ||
3909 | set_bit(QUEUE_FLAG_DISCARD, &dd->queue->queue_flags); | ||
3910 | dd->queue->limits.discard_granularity = 4096; | ||
3911 | blk_queue_max_discard_sectors(dd->queue, | ||
3912 | MTIP_MAX_TRIM_ENTRY_LEN * MTIP_MAX_TRIM_ENTRIES); | ||
3913 | dd->queue->limits.discard_zeroes_data = 0; | ||
3914 | } | ||
3915 | |||
3820 | /* Set the capacity of the device in 512 byte sectors. */ | 3916 | /* Set the capacity of the device in 512 byte sectors. */ |
3821 | if (!(mtip_hw_get_capacity(dd, &capacity))) { | 3917 | if (!(mtip_hw_get_capacity(dd, &capacity))) { |
3822 | dev_warn(&dd->pdev->dev, | 3918 | dev_warn(&dd->pdev->dev, |