aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/mtip32xx/mtip32xx.c
diff options
context:
space:
mode:
authorAsai Thambi S P <asamymuthupa@micron.com>2013-01-11 08:41:34 -0500
committerJens Axboe <axboe@kernel.dk>2013-01-11 08:41:34 -0500
commit152834694dcb90d3088bc77fa436755c66553929 (patch)
tree0235dc7a7b0d1be0dabeb28b9fe720aa4acf9d20 /drivers/block/mtip32xx/mtip32xx.c
parent16c906e51c6f08a15763a85b5686e1ded35e77ab (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.c96
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 */
1726int 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,