The ATA trim command is used by the file system to notify devices which logical addresses are no longer occupied and can be recycled as free space by devices. In the ATA command set, the trim command is only the datamanagement set (DMS) the DMs command is specially used for device optimization (the data set management command provides information for deviceoptimization (e.g ., file System Information), 1 shows that when the feature attribute of DMS is at the lowest position 1, trim command is sent.
During trim command transmission, the LBA address of the device needs to be notified through the portal. For example, the device must be notified that 11th to 18 blocks can be recycled, in the DMA buffer, 8 bytes are required. The 16-bit high value is the Len value 8, and the 48-bit low value is the starting address 11 of LBA. The length of each entry is represented by two 16 bits bytes, and then the value is all 0. Therefore, each entry can represent a maximum of 65535 blocks. To notify devices of more addresses at a time, an entry will be added accordingly.
Figure 1. DMS command ata format
The code for sending the ata_trim command is as follows. You need to put it into a module compiled with the kernel and call it through the value input of/proc/variable. If you are interested, you can discuss it together.
int ata_trim(uint block, uint n_block){struct ata_queued_cmd *qc=NULL;struct ata_taskfile *tf =NULL; struct sg_table *table=kmalloc(sizeof(struct sg_table),GFP_ATOMIC);int rc=0, nents=1; //entry(sg list) number of scatter/gathering list in sg_tablestruct page *pg_pt;u32 size;void *buf;//transfer buffer to send lba addresses...if(ata_dev_lookup())goto error_exit;/*allocate an ata cmd structure from the ata port*/qc = ata_qc_new_init(dev);if(unlikely(!qc))goto error_exit;/*allocate sg_table and sg list*/allocate_mempool();rc = __sg_alloc_table(table, nents, SCSI_MAX_SG_SEGMENTS,GFP_ATOMIC, scsi_sg_alloc);if (unlikely(rc)){__sg_free_table(table, SCSI_MAX_SG_SEGMENTS,scsi_sg_free);goto error_exit;}pg_pt=alloc_pages(GFP_ATOMIC,0); //allocate 1page: 4k dataspace...if(!pg_pt)goto error_exit;printk("\nStarting block is : %lu , blocks count is : %d \n\n", block, n_block);sg_set_page(table->sgl, pg_pt, 8, 0);// 8 bytes for 1 trim entrytable->nents=1;table->orig_nents=1;ata_sg_init(qc,table->sgl,1); qc->scsidone=my_scsidone; qc->complete_fn=my_ata_scsi_qc_complete;//orignally for write_same of multiple areas... now to transfer only one LBA...buf = page_address(sg_page(table->sgl));if(!buf)goto error_exit;//size is the used bytes and it is the size for DMA to transfersize = ata_set_lba_range_entries(buf, 4096, block, n_block);qc->dma_dir=DMA_TO_DEVICE;qc->nbytes=size;//data size in bytes to be transferedtf=&qc->tf;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;if(!qc->sg || !qc->n_elem || !qc->nbytes)goto error_exit;ata_qc_issue(qc);mdelay(800);qc_error_disp(qc->err_mask);return 0;error_exit:printk("\n\nTO client--------------Getting Resourcesfailed----------------- \n\n");return 1;}