/*
* Copyright (C) 2015 IT University of Copenhagen (rrpc.h)
* Copyright (C) 2016 CNEX Labs
* Initial release: Matias Bjorling <matias@cnexlabs.com>
* Write buffering: Javier Gonzalez <javier@cnexlabs.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* Implementation of a Physical Block-device target for Open-channel SSDs.
*
*/
#ifndef PBLK_H_
#define PBLK_H_
#include <linux/blkdev.h>
#include <linux/blk-mq.h>
#include <linux/bio.h>
#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/vmalloc.h>
#include <linux/crc32.h>
#include <linux/uuid.h>
#include <linux/lightnvm.h>
/* Run only GC if less than 1/X blocks are free */
#define GC_LIMIT_INVERSE 5
#define GC_TIME_MSECS 1000
#define PBLK_SECTOR (512)
#define PBLK_EXPOSED_PAGE_SIZE (4096)
#define PBLK_MAX_REQ_ADDRS (64)
#define PBLK_MAX_REQ_ADDRS_PW (6)
#define PBLK_META_POOL_SIZE (128)
#define PBLK_READ_REQ_POOL_SIZE (1024)
#define PBLK_NR_CLOSE_JOBS (4)
#define PBLK_CACHE_NAME_LEN (DISK_NAME_LEN + 16)
#define PBLK_COMMAND_TIMEOUT_MS 30000
/* Max 512 LUNs per device */
#define PBLK_MAX_LUNS_BITMAP (4)
#define NR_PHY_IN_LOG (PBLK_EXPOSED_PAGE_SIZE / PBLK_SECTOR)
#define pblk_for_each_lun(pblk, rlun, i) \
for ((i) = 0, rlun = &(pblk)->luns[0]; \
(i) < (pblk)->nr_luns; (i)++, rlun = &(pblk)->luns[(i)])
#define ERASE 2 /* READ = 0, WRITE = 1 */
#define PBLK_GEN_WS_POOL_SIZE (2)
enum {
/* IO Types */
PBLK_IOTYPE_USER = 1 << 0,
PBLK_IOTYPE_GC = 1 << 1,
/* Write buffer flags */
PBLK_FLUSH_ENTRY = 1 << 2,
PBLK_WRITTEN_DATA = 1 << 3,
PBLK_SUBMITTED_ENTRY = 1 << 4,
PBLK_WRITABLE_ENTRY = 1 << 5,
};
enum {
PBLK_BLK_ST_OPEN = 0x1,
PBLK_BLK_ST_CLOSED = 0x2,
};
struct pblk_sec_meta {
u64 reserved;
__le64 lba;
};
/* The number of GC lists and the rate-limiter states go together. This way the
* rate-limiter can dictate how much GC is needed based on resource utilization.
*/
#define PBLK_GC_NR_LISTS 3
enum {
PBLK_RL_HIGH = 1,
PBLK_RL_MID = 2,
PBLK_RL_LOW = 3,
};
#define pblk_dma_meta_size (sizeof(struct pblk_sec_meta) * PBLK_MAX_REQ_ADDRS)
/* write buffer completion context */
struct pblk_c_ctx {
struct list_head list; /* Head for out-of-order completion */
unsigned long *lun_bitmap; /* Luns used on current request */
unsigned int sentry;
unsigned int nr_valid;
unsigned int nr_padded;
};
/* generic context */
struct pblk_g_ctx {
void *private;
};
/* Pad context */
struct pblk_pad_rq {
struct pblk *pblk;
struct completion wait;
struct kref ref;
};
/* Recovery context */
struct pblk_rec_ctx {
struct pblk *pblk;
struct nvm_rq *rqd;
struct list_head failed;
struct work_struct ws_rec;
};
/* Write context */
struct pblk_w_ctx {
struct bio_list bios; /* Original bios - used for completion
* in REQ_FUA, REQ_FLUSH case
*/
u64 lba; /* Logic addr. associated with entry */
struct ppa_addr ppa; /* Physic addr. associated with entry */
int flags; /* Write context flags */
};
struct pblk_rb_entry {
struct ppa_addr cacheline; /* Cacheline for this entry */
void *data; /* Pointer to data on this entry */
struct pblk_w_ctx w_ctx; /* Context for this entry */
struct list_head index; /* List head to enable indexes */
};
#define EMPTY_ENTRY (~0U)
struct pblk_rb_pages {
struct page *pages;
int order;
struct list_head list;
};
struct pblk_rb {
struct pblk_rb_entry *entries; /* Ring buffer entries */
unsigned int mem; /* Write offset - points to next
* writable entry in memory
*/
unsigned int subm; /* Read offset - points to last entry
* that has been submitted to the media
* to be persisted
*/
unsigned int sync; /* Synced - backpointer that signals
* the last submitted entry that has
* been successfully persisted to media
*/
unsigned int sync_point; /* Sync point - last entry that must be
* flushed to the media. Used with
* REQ_FLUSH and REQ_FUA
*/
unsigned int l2p_update; /* l2p update point - next entry for
* which l2p mapping will be updated to
* conta