diff options
Diffstat (limited to 'include/linux/lightnvm.h')
-rw-r--r-- | include/linux/lightnvm.h | 522 |
1 files changed, 522 insertions, 0 deletions
diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h new file mode 100644 index 000000000000..69c9057e1ab8 --- /dev/null +++ b/include/linux/lightnvm.h | |||
@@ -0,0 +1,522 @@ | |||
1 | #ifndef NVM_H | ||
2 | #define NVM_H | ||
3 | |||
4 | enum { | ||
5 | NVM_IO_OK = 0, | ||
6 | NVM_IO_REQUEUE = 1, | ||
7 | NVM_IO_DONE = 2, | ||
8 | NVM_IO_ERR = 3, | ||
9 | |||
10 | NVM_IOTYPE_NONE = 0, | ||
11 | NVM_IOTYPE_GC = 1, | ||
12 | }; | ||
13 | |||
14 | #ifdef CONFIG_NVM | ||
15 | |||
16 | #include <linux/blkdev.h> | ||
17 | #include <linux/types.h> | ||
18 | #include <linux/file.h> | ||
19 | #include <linux/dmapool.h> | ||
20 | |||
21 | enum { | ||
22 | /* HW Responsibilities */ | ||
23 | NVM_RSP_L2P = 1 << 0, | ||
24 | NVM_RSP_ECC = 1 << 1, | ||
25 | |||
26 | /* Physical Adressing Mode */ | ||
27 | NVM_ADDRMODE_LINEAR = 0, | ||
28 | NVM_ADDRMODE_CHANNEL = 1, | ||
29 | |||
30 | /* Plane programming mode for LUN */ | ||
31 | NVM_PLANE_SINGLE = 0, | ||
32 | NVM_PLANE_DOUBLE = 1, | ||
33 | NVM_PLANE_QUAD = 2, | ||
34 | |||
35 | /* Status codes */ | ||
36 | NVM_RSP_SUCCESS = 0x0, | ||
37 | NVM_RSP_NOT_CHANGEABLE = 0x1, | ||
38 | NVM_RSP_ERR_FAILWRITE = 0x40ff, | ||
39 | NVM_RSP_ERR_EMPTYPAGE = 0x42ff, | ||
40 | |||
41 | /* Device opcodes */ | ||
42 | NVM_OP_HBREAD = 0x02, | ||
43 | NVM_OP_HBWRITE = 0x81, | ||
44 | NVM_OP_PWRITE = 0x91, | ||
45 | NVM_OP_PREAD = 0x92, | ||
46 | NVM_OP_ERASE = 0x90, | ||
47 | |||
48 | /* PPA Command Flags */ | ||
49 | NVM_IO_SNGL_ACCESS = 0x0, | ||
50 | NVM_IO_DUAL_ACCESS = 0x1, | ||
51 | NVM_IO_QUAD_ACCESS = 0x2, | ||
52 | |||
53 | NVM_IO_SUSPEND = 0x80, | ||
54 | NVM_IO_SLC_MODE = 0x100, | ||
55 | NVM_IO_SCRAMBLE_DISABLE = 0x200, | ||
56 | }; | ||
57 | |||
58 | struct nvm_id_group { | ||
59 | u8 mtype; | ||
60 | u8 fmtype; | ||
61 | u16 res16; | ||
62 | u8 num_ch; | ||
63 | u8 num_lun; | ||
64 | u8 num_pln; | ||
65 | u16 num_blk; | ||
66 | u16 num_pg; | ||
67 | u16 fpg_sz; | ||
68 | u16 csecs; | ||
69 | u16 sos; | ||
70 | u32 trdt; | ||
71 | u32 trdm; | ||
72 | u32 tprt; | ||
73 | u32 tprm; | ||
74 | u32 tbet; | ||
75 | u32 tbem; | ||
76 | u32 mpos; | ||
77 | u16 cpar; | ||
78 | u8 res[913]; | ||
79 | } __packed; | ||
80 | |||
81 | struct nvm_addr_format { | ||
82 | u8 ch_offset; | ||
83 | u8 ch_len; | ||
84 | u8 lun_offset; | ||
85 | u8 lun_len; | ||
86 | u8 pln_offset; | ||
87 | u8 pln_len; | ||
88 | u8 blk_offset; | ||
89 | u8 blk_len; | ||
90 | u8 pg_offset; | ||
91 | u8 pg_len; | ||
92 | u8 sect_offset; | ||
93 | u8 sect_len; | ||
94 | u8 res[4]; | ||
95 | }; | ||
96 | |||
97 | struct nvm_id { | ||
98 | u8 ver_id; | ||
99 | u8 vmnt; | ||
100 | u8 cgrps; | ||
101 | u8 res[5]; | ||
102 | u32 cap; | ||
103 | u32 dom; | ||
104 | struct nvm_addr_format ppaf; | ||
105 | u8 ppat; | ||
106 | u8 resv[224]; | ||
107 | struct nvm_id_group groups[4]; | ||
108 | } __packed; | ||
109 | |||
110 | struct nvm_target { | ||
111 | struct list_head list; | ||
112 | struct nvm_tgt_type *type; | ||
113 | struct gendisk *disk; | ||
114 | }; | ||
115 | |||
116 | struct nvm_tgt_instance { | ||
117 | struct nvm_tgt_type *tt; | ||
118 | }; | ||
119 | |||
120 | #define ADDR_EMPTY (~0ULL) | ||
121 | |||
122 | #define NVM_VERSION_MAJOR 1 | ||
123 | #define NVM_VERSION_MINOR 0 | ||
124 | #define NVM_VERSION_PATCH 0 | ||
125 | |||
126 | #define NVM_SEC_BITS (8) | ||
127 | #define NVM_PL_BITS (6) | ||
128 | #define NVM_PG_BITS (16) | ||
129 | #define NVM_BLK_BITS (16) | ||
130 | #define NVM_LUN_BITS (10) | ||
131 | #define NVM_CH_BITS (8) | ||
132 | |||
133 | struct ppa_addr { | ||
134 | union { | ||
135 | /* Channel-based PPA format in nand 4x2x2x2x8x10 */ | ||
136 | struct { | ||
137 | u64 ch : 4; | ||
138 | u64 sec : 2; /* 4 sectors per page */ | ||
139 | u64 pl : 2; /* 4 planes per LUN */ | ||
140 | u64 lun : 2; /* 4 LUNs per channel */ | ||
141 | u64 pg : 8; /* 256 pages per block */ | ||
142 | u64 blk : 10;/* 1024 blocks per plane */ | ||
143 | u64 resved : 36; | ||
144 | } chnl; | ||
145 | |||
146 | /* Generic structure for all addresses */ | ||
147 | struct { | ||
148 | u64 sec : NVM_SEC_BITS; | ||
149 | u64 pl : NVM_PL_BITS; | ||
150 | u64 pg : NVM_PG_BITS; | ||
151 | u64 blk : NVM_BLK_BITS; | ||
152 | u64 lun : NVM_LUN_BITS; | ||
153 | u64 ch : NVM_CH_BITS; | ||
154 | } g; | ||
155 | |||
156 | u64 ppa; | ||
157 | }; | ||
158 | } __packed; | ||
159 | |||
160 | struct nvm_rq { | ||
161 | struct nvm_tgt_instance *ins; | ||
162 | struct nvm_dev *dev; | ||
163 | |||
164 | struct bio *bio; | ||
165 | |||
166 | union { | ||
167 | struct ppa_addr ppa_addr; | ||
168 | dma_addr_t dma_ppa_list; | ||
169 | }; | ||
170 | |||
171 | struct ppa_addr *ppa_list; | ||
172 | |||
173 | void *metadata; | ||
174 | dma_addr_t dma_metadata; | ||
175 | |||
176 | uint8_t opcode; | ||
177 | uint16_t nr_pages; | ||
178 | uint16_t flags; | ||
179 | }; | ||
180 | |||
181 | static inline struct nvm_rq *nvm_rq_from_pdu(void *pdu) | ||
182 | { | ||
183 | return pdu - sizeof(struct nvm_rq); | ||
184 | } | ||
185 | |||
186 | static inline void *nvm_rq_to_pdu(struct nvm_rq *rqdata) | ||
187 | { | ||
188 | return rqdata + 1; | ||
189 | } | ||
190 | |||
191 | struct nvm_block; | ||
192 | |||
193 | typedef int (nvm_l2p_update_fn)(u64, u32, __le64 *, void *); | ||
194 | typedef int (nvm_bb_update_fn)(u32, void *, unsigned int, void *); | ||
195 | typedef int (nvm_id_fn)(struct request_queue *, struct nvm_id *); | ||
196 | typedef int (nvm_get_l2p_tbl_fn)(struct request_queue *, u64, u32, | ||
197 | nvm_l2p_update_fn *, void *); | ||
198 | typedef int (nvm_op_bb_tbl_fn)(struct request_queue *, int, unsigned int, | ||
199 | nvm_bb_update_fn *, void *); | ||
200 | typedef int (nvm_op_set_bb_fn)(struct request_queue *, struct nvm_rq *, int); | ||
201 | typedef int (nvm_submit_io_fn)(struct request_queue *, struct nvm_rq *); | ||
202 | typedef int (nvm_erase_blk_fn)(struct request_queue *, struct nvm_rq *); | ||
203 | typedef void *(nvm_create_dma_pool_fn)(struct request_queue *, char *); | ||
204 | typedef void (nvm_destroy_dma_pool_fn)(void *); | ||
205 | typedef void *(nvm_dev_dma_alloc_fn)(struct request_queue *, void *, gfp_t, | ||
206 | dma_addr_t *); | ||
207 | typedef void (nvm_dev_dma_free_fn)(void *, void*, dma_addr_t); | ||
208 | |||
209 | struct nvm_dev_ops { | ||
210 | nvm_id_fn *identity; | ||
211 | nvm_get_l2p_tbl_fn *get_l2p_tbl; | ||
212 | nvm_op_bb_tbl_fn *get_bb_tbl; | ||
213 | nvm_op_set_bb_fn *set_bb; | ||
214 | |||
215 | nvm_submit_io_fn *submit_io; | ||
216 | nvm_erase_blk_fn *erase_block; | ||
217 | |||
218 | nvm_create_dma_pool_fn *create_dma_pool; | ||
219 | nvm_destroy_dma_pool_fn *destroy_dma_pool; | ||
220 | nvm_dev_dma_alloc_fn *dev_dma_alloc; | ||
221 | nvm_dev_dma_free_fn *dev_dma_free; | ||
222 | |||
223 | uint8_t max_phys_sect; | ||
224 | }; | ||
225 | |||
226 | struct nvm_lun { | ||
227 | int id; | ||
228 | |||
229 | int lun_id; | ||
230 | int chnl_id; | ||
231 | |||
232 | unsigned int nr_free_blocks; /* Number of unused blocks */ | ||
233 | struct nvm_block *blocks; | ||
234 | |||
235 | spinlock_t lock; | ||
236 | }; | ||
237 | |||
238 | struct nvm_block { | ||
239 | struct list_head list; | ||
240 | struct nvm_lun *lun; | ||
241 | unsigned long id; | ||
242 | |||
243 | void *priv; | ||
244 | int type; | ||
245 | }; | ||
246 | |||
247 | struct nvm_dev { | ||
248 | struct nvm_dev_ops *ops; | ||
249 | |||
250 | struct list_head devices; | ||
251 | struct list_head online_targets; | ||
252 | |||
253 | /* Media manager */ | ||
254 | struct nvmm_type *mt; | ||
255 | void *mp; | ||
256 | |||
257 | /* Device information */ | ||
258 | int nr_chnls; | ||
259 | int nr_planes; | ||
260 | int luns_per_chnl; | ||
261 | int sec_per_pg; /* only sectors for a single page */ | ||
262 | int pgs_per_blk; | ||
263 | int blks_per_lun; | ||
264 | int sec_size; | ||
265 | int oob_size; | ||
266 | int addr_mode; | ||
267 | struct nvm_addr_format addr_format; | ||
268 | |||
269 | /* Calculated/Cached values. These do not reflect the actual usable | ||
270 | * blocks at run-time. | ||
271 | */ | ||
272 | int max_rq_size; | ||
273 | int plane_mode; /* drive device in single, double or quad mode */ | ||
274 | |||
275 | int sec_per_pl; /* all sectors across planes */ | ||
276 | int sec_per_blk; | ||
277 | int sec_per_lun; | ||
278 | |||
279 | unsigned long total_pages; | ||
280 | unsigned long total_blocks; | ||
281 | int nr_luns; | ||
282 | unsigned max_pages_per_blk; | ||
283 | |||
284 | void *ppalist_pool; | ||
285 | |||
286 | struct nvm_id identity; | ||
287 | |||
288 | /* Backend device */ | ||
289 | struct request_queue *q; | ||
290 | char name[DISK_NAME_LEN]; | ||
291 | }; | ||
292 | |||
293 | /* fallback conversion */ | ||
294 | static struct ppa_addr __generic_to_linear_addr(struct nvm_dev *dev, | ||
295 | struct ppa_addr r) | ||
296 | { | ||
297 | struct ppa_addr l; | ||
298 | |||
299 | l.ppa = r.g.sec + | ||
300 | r.g.pg * dev->sec_per_pg + | ||
301 | r.g.blk * (dev->pgs_per_blk * | ||
302 | dev->sec_per_pg) + | ||
303 | r.g.lun * (dev->blks_per_lun * | ||
304 | dev->pgs_per_blk * | ||
305 | dev->sec_per_pg) + | ||
306 | r.g.ch * (dev->blks_per_lun * | ||
307 | dev->pgs_per_blk * | ||
308 | dev->luns_per_chnl * | ||
309 | dev->sec_per_pg); | ||
310 | |||
311 | return l; | ||
312 | } | ||
313 | |||
314 | /* fallback conversion */ | ||
315 | static struct ppa_addr __linear_to_generic_addr(struct nvm_dev *dev, | ||
316 | struct ppa_addr r) | ||
317 | { | ||
318 | struct ppa_addr l; | ||
319 | int secs, pgs, blks, luns; | ||
320 | sector_t ppa = r.ppa; | ||
321 | |||
322 | l.ppa = 0; | ||
323 | |||
324 | div_u64_rem(ppa, dev->sec_per_pg, &secs); | ||
325 | l.g.sec = secs; | ||
326 | |||
327 | sector_div(ppa, dev->sec_per_pg); | ||
328 | div_u64_rem(ppa, dev->sec_per_blk, &pgs); | ||
329 | l.g.pg = pgs; | ||
330 | |||
331 | sector_div(ppa, dev->pgs_per_blk); | ||
332 | div_u64_rem(ppa, dev->blks_per_lun, &blks); | ||
333 | l.g.blk = blks; | ||
334 | |||
335 | sector_div(ppa, dev->blks_per_lun); | ||
336 | div_u64_rem(ppa, dev->luns_per_chnl, &luns); | ||
337 | l.g.lun = luns; | ||
338 | |||
339 | sector_div(ppa, dev->luns_per_chnl); | ||
340 | l.g.ch = ppa; | ||
341 | |||
342 | return l; | ||
343 | } | ||
344 | |||
345 | static struct ppa_addr __generic_to_chnl_addr(struct ppa_addr r) | ||
346 | { | ||
347 | struct ppa_addr l; | ||
348 | |||
349 | l.ppa = 0; | ||
350 | |||
351 | l.chnl.sec = r.g.sec; | ||
352 | l.chnl.pl = r.g.pl; | ||
353 | l.chnl.pg = r.g.pg; | ||
354 | l.chnl.blk = r.g.blk; | ||
355 | l.chnl.lun = r.g.lun; | ||
356 | l.chnl.ch = r.g.ch; | ||
357 | |||
358 | return l; | ||
359 | } | ||
360 | |||
361 | static struct ppa_addr __chnl_to_generic_addr(struct ppa_addr r) | ||
362 | { | ||
363 | struct ppa_addr l; | ||
364 | |||
365 | l.ppa = 0; | ||
366 | |||
367 | l.g.sec = r.chnl.sec; | ||
368 | l.g.pl = r.chnl.pl; | ||
369 | l.g.pg = r.chnl.pg; | ||
370 | l.g.blk = r.chnl.blk; | ||
371 | l.g.lun = r.chnl.lun; | ||
372 | l.g.ch = r.chnl.ch; | ||
373 | |||
374 | return l; | ||
375 | } | ||
376 | |||
377 | static inline struct ppa_addr addr_to_generic_mode(struct nvm_dev *dev, | ||
378 | struct ppa_addr gppa) | ||
379 | { | ||
380 | switch (dev->addr_mode) { | ||
381 | case NVM_ADDRMODE_LINEAR: | ||
382 | return __linear_to_generic_addr(dev, gppa); | ||
383 | case NVM_ADDRMODE_CHANNEL: | ||
384 | return __chnl_to_generic_addr(gppa); | ||
385 | default: | ||
386 | BUG(); | ||
387 | } | ||
388 | return gppa; | ||
389 | } | ||
390 | |||
391 | static inline struct ppa_addr generic_to_addr_mode(struct nvm_dev *dev, | ||
392 | struct ppa_addr gppa) | ||
393 | { | ||
394 | switch (dev->addr_mode) { | ||
395 | case NVM_ADDRMODE_LINEAR: | ||
396 | return __generic_to_linear_addr(dev, gppa); | ||
397 | case NVM_ADDRMODE_CHANNEL: | ||
398 | return __generic_to_chnl_addr(gppa); | ||
399 | default: | ||
400 | BUG(); | ||
401 | } | ||
402 | return gppa; | ||
403 | } | ||
404 | |||
405 | static inline int ppa_empty(struct ppa_addr ppa_addr) | ||
406 | { | ||
407 | return (ppa_addr.ppa == ADDR_EMPTY); | ||
408 | } | ||
409 | |||
410 | static inline void ppa_set_empty(struct ppa_addr *ppa_addr) | ||
411 | { | ||
412 | ppa_addr->ppa = ADDR_EMPTY; | ||
413 | } | ||
414 | |||
415 | static inline struct ppa_addr block_to_ppa(struct nvm_dev *dev, | ||
416 | struct nvm_block *blk) | ||
417 | { | ||
418 | struct ppa_addr ppa; | ||
419 | struct nvm_lun *lun = blk->lun; | ||
420 | |||
421 | ppa.ppa = 0; | ||
422 | ppa.g.blk = blk->id % dev->blks_per_lun; | ||
423 | ppa.g.lun = lun->lun_id; | ||
424 | ppa.g.ch = lun->chnl_id; | ||
425 | |||
426 | return ppa; | ||
427 | } | ||
428 | |||
429 | typedef blk_qc_t (nvm_tgt_make_rq_fn)(struct request_queue *, struct bio *); | ||
430 | typedef sector_t (nvm_tgt_capacity_fn)(void *); | ||
431 | typedef int (nvm_tgt_end_io_fn)(struct nvm_rq *, int); | ||
432 | typedef void *(nvm_tgt_init_fn)(struct nvm_dev *, struct gendisk *, int, int); | ||
433 | typedef void (nvm_tgt_exit_fn)(void *); | ||
434 | |||
435 | struct nvm_tgt_type { | ||
436 | const char *name; | ||
437 | unsigned int version[3]; | ||
438 | |||
439 | /* target entry points */ | ||
440 | nvm_tgt_make_rq_fn *make_rq; | ||
441 | nvm_tgt_capacity_fn *capacity; | ||
442 | nvm_tgt_end_io_fn *end_io; | ||
443 | |||
444 | /* module-specific init/teardown */ | ||
445 | nvm_tgt_init_fn *init; | ||
446 | nvm_tgt_exit_fn *exit; | ||
447 | |||
448 | /* For internal use */ | ||
449 | struct list_head list; | ||
450 | }; | ||
451 | |||
452 | extern int nvm_register_target(struct nvm_tgt_type *); | ||
453 | extern void nvm_unregister_target(struct nvm_tgt_type *); | ||
454 | |||
455 | extern void *nvm_dev_dma_alloc(struct nvm_dev *, gfp_t, dma_addr_t *); | ||
456 | extern void nvm_dev_dma_free(struct nvm_dev *, void *, dma_addr_t); | ||
457 | |||
458 | typedef int (nvmm_register_fn)(struct nvm_dev *); | ||
459 | typedef void (nvmm_unregister_fn)(struct nvm_dev *); | ||
460 | typedef struct nvm_block *(nvmm_get_blk_fn)(struct nvm_dev *, | ||
461 | struct nvm_lun *, unsigned long); | ||
462 | typedef void (nvmm_put_blk_fn)(struct nvm_dev *, struct nvm_block *); | ||
463 | typedef int (nvmm_open_blk_fn)(struct nvm_dev *, struct nvm_block *); | ||
464 | typedef int (nvmm_close_blk_fn)(struct nvm_dev *, struct nvm_block *); | ||
465 | typedef void (nvmm_flush_blk_fn)(struct nvm_dev *, struct nvm_block *); | ||
466 | typedef int (nvmm_submit_io_fn)(struct nvm_dev *, struct nvm_rq *); | ||
467 | typedef int (nvmm_end_io_fn)(struct nvm_rq *, int); | ||
468 | typedef int (nvmm_erase_blk_fn)(struct nvm_dev *, struct nvm_block *, | ||
469 | unsigned long); | ||
470 | typedef struct nvm_lun *(nvmm_get_lun_fn)(struct nvm_dev *, int); | ||
471 | typedef void (nvmm_free_blocks_print_fn)(struct nvm_dev *); | ||
472 | |||
473 | struct nvmm_type { | ||
474 | const char *name; | ||
475 | unsigned int version[3]; | ||
476 | |||
477 | nvmm_register_fn *register_mgr; | ||
478 | nvmm_unregister_fn *unregister_mgr; | ||
479 | |||
480 | /* Block administration callbacks */ | ||
481 | nvmm_get_blk_fn *get_blk; | ||
482 | nvmm_put_blk_fn *put_blk; | ||
483 | nvmm_open_blk_fn *open_blk; | ||
484 | nvmm_close_blk_fn *close_blk; | ||
485 | nvmm_flush_blk_fn *flush_blk; | ||
486 | |||
487 | nvmm_submit_io_fn *submit_io; | ||
488 | nvmm_end_io_fn *end_io; | ||
489 | nvmm_erase_blk_fn *erase_blk; | ||
490 | |||
491 | /* Configuration management */ | ||
492 | nvmm_get_lun_fn *get_lun; | ||
493 | |||
494 | /* Statistics */ | ||
495 | nvmm_free_blocks_print_fn *free_blocks_print; | ||
496 | struct list_head list; | ||
497 | }; | ||
498 | |||
499 | extern int nvm_register_mgr(struct nvmm_type *); | ||
500 | extern void nvm_unregister_mgr(struct nvmm_type *); | ||
501 | |||
502 | extern struct nvm_block *nvm_get_blk(struct nvm_dev *, struct nvm_lun *, | ||
503 | unsigned long); | ||
504 | extern void nvm_put_blk(struct nvm_dev *, struct nvm_block *); | ||
505 | |||
506 | extern int nvm_register(struct request_queue *, char *, | ||
507 | struct nvm_dev_ops *); | ||
508 | extern void nvm_unregister(char *); | ||
509 | |||
510 | extern int nvm_submit_io(struct nvm_dev *, struct nvm_rq *); | ||
511 | extern int nvm_erase_blk(struct nvm_dev *, struct nvm_block *); | ||
512 | #else /* CONFIG_NVM */ | ||
513 | struct nvm_dev_ops; | ||
514 | |||
515 | static inline int nvm_register(struct request_queue *q, char *disk_name, | ||
516 | struct nvm_dev_ops *ops) | ||
517 | { | ||
518 | return -EINVAL; | ||
519 | } | ||
520 | static inline void nvm_unregister(char *disk_name) {} | ||
521 | #endif /* CONFIG_NVM */ | ||
522 | #endif /* LIGHTNVM.H */ | ||