| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | 
|---|
| 2 | #ifndef _LINUX_BADBLOCKS_H | 
|---|
| 3 | #define _LINUX_BADBLOCKS_H | 
|---|
| 4 |  | 
|---|
| 5 | #include <linux/seqlock.h> | 
|---|
| 6 | #include <linux/device.h> | 
|---|
| 7 | #include <linux/kernel.h> | 
|---|
| 8 | #include <linux/stddef.h> | 
|---|
| 9 | #include <linux/types.h> | 
|---|
| 10 |  | 
|---|
| 11 | #define BB_LEN_MASK	(0x00000000000001FFULL) | 
|---|
| 12 | #define BB_OFFSET_MASK	(0x7FFFFFFFFFFFFE00ULL) | 
|---|
| 13 | #define BB_ACK_MASK	(0x8000000000000000ULL) | 
|---|
| 14 | #define BB_MAX_LEN	512 | 
|---|
| 15 | #define BB_OFFSET(x)	(((x) & BB_OFFSET_MASK) >> 9) | 
|---|
| 16 | #define BB_LEN(x)	(((x) & BB_LEN_MASK) + 1) | 
|---|
| 17 | #define BB_ACK(x)	(!!((x) & BB_ACK_MASK)) | 
|---|
| 18 | #define BB_END(x)	(BB_OFFSET(x) + BB_LEN(x)) | 
|---|
| 19 | #define BB_MAKE(a, l, ack) (((a)<<9) | ((l)-1) | ((u64)(!!(ack)) << 63)) | 
|---|
| 20 |  | 
|---|
| 21 | /* Bad block numbers are stored sorted in a single page. | 
|---|
| 22 | * 64bits is used for each block or extent. | 
|---|
| 23 | * 54 bits are sector number, 9 bits are extent size, | 
|---|
| 24 | * 1 bit is an 'acknowledged' flag. | 
|---|
| 25 | */ | 
|---|
| 26 | #define MAX_BADBLOCKS	(PAGE_SIZE/8) | 
|---|
| 27 |  | 
|---|
| 28 | struct badblocks { | 
|---|
| 29 | struct device *dev;	/* set by devm_init_badblocks */ | 
|---|
| 30 | int count;		/* count of bad blocks */ | 
|---|
| 31 | int unacked_exist;	/* there probably are unacknowledged | 
|---|
| 32 | * bad blocks.  This is only cleared | 
|---|
| 33 | * when a read discovers none | 
|---|
| 34 | */ | 
|---|
| 35 | int shift;		/* shift from sectors to block size | 
|---|
| 36 | * a -ve shift means badblocks are | 
|---|
| 37 | * disabled.*/ | 
|---|
| 38 | u64 *page;		/* badblock list */ | 
|---|
| 39 | int changed; | 
|---|
| 40 | seqlock_t lock; | 
|---|
| 41 | sector_t sector; | 
|---|
| 42 | sector_t size;		/* in sectors */ | 
|---|
| 43 | }; | 
|---|
| 44 |  | 
|---|
| 45 | struct badblocks_context { | 
|---|
| 46 | sector_t	start; | 
|---|
| 47 | sector_t	len; | 
|---|
| 48 | int		ack; | 
|---|
| 49 | }; | 
|---|
| 50 |  | 
|---|
| 51 | int badblocks_check(struct badblocks *bb, sector_t s, sector_t sectors, | 
|---|
| 52 | sector_t *first_bad, sector_t *bad_sectors); | 
|---|
| 53 | bool badblocks_set(struct badblocks *bb, sector_t s, sector_t sectors, | 
|---|
| 54 | int acknowledged); | 
|---|
| 55 | bool badblocks_clear(struct badblocks *bb, sector_t s, sector_t sectors); | 
|---|
| 56 | void ack_all_badblocks(struct badblocks *bb); | 
|---|
| 57 | ssize_t badblocks_show(struct badblocks *bb, char *page, int unack); | 
|---|
| 58 | ssize_t badblocks_store(struct badblocks *bb, const char *page, size_t len, | 
|---|
| 59 | int unack); | 
|---|
| 60 | int badblocks_init(struct badblocks *bb, int enable); | 
|---|
| 61 | void badblocks_exit(struct badblocks *bb); | 
|---|
| 62 | struct device; | 
|---|
| 63 | int devm_init_badblocks(struct device *dev, struct badblocks *bb); | 
|---|
| 64 | static inline void devm_exit_badblocks(struct device *dev, struct badblocks *bb) | 
|---|
| 65 | { | 
|---|
| 66 | if (bb->dev != dev) { | 
|---|
| 67 | dev_WARN_ONCE(dev, 1, "%s: badblocks instance not associated\n", | 
|---|
| 68 | __func__); | 
|---|
| 69 | return; | 
|---|
| 70 | } | 
|---|
| 71 | badblocks_exit(bb); | 
|---|
| 72 | } | 
|---|
| 73 |  | 
|---|
| 74 | static inline int badblocks_full(struct badblocks *bb) | 
|---|
| 75 | { | 
|---|
| 76 | return (bb->count >= MAX_BADBLOCKS); | 
|---|
| 77 | } | 
|---|
| 78 |  | 
|---|
| 79 | static inline int badblocks_empty(struct badblocks *bb) | 
|---|
| 80 | { | 
|---|
| 81 | return (bb->count == 0); | 
|---|
| 82 | } | 
|---|
| 83 |  | 
|---|
| 84 | static inline void set_changed(struct badblocks *bb) | 
|---|
| 85 | { | 
|---|
| 86 | if (bb->changed != 1) | 
|---|
| 87 | bb->changed = 1; | 
|---|
| 88 | } | 
|---|
| 89 |  | 
|---|
| 90 | static inline void clear_changed(struct badblocks *bb) | 
|---|
| 91 | { | 
|---|
| 92 | if (bb->changed != 0) | 
|---|
| 93 | bb->changed = 0; | 
|---|
| 94 | } | 
|---|
| 95 |  | 
|---|
| 96 | #endif | 
|---|
| 97 |  | 
|---|