diff options
Diffstat (limited to 'kernel/drivers/s390/block/scm_blk.h')
-rw-r--r-- | kernel/drivers/s390/block/scm_blk.h | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/kernel/drivers/s390/block/scm_blk.h b/kernel/drivers/s390/block/scm_blk.h new file mode 100644 index 000000000..09218cdc5 --- /dev/null +++ b/kernel/drivers/s390/block/scm_blk.h @@ -0,0 +1,136 @@ +#ifndef SCM_BLK_H +#define SCM_BLK_H + +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/blkdev.h> +#include <linux/genhd.h> +#include <linux/list.h> + +#include <asm/debug.h> +#include <asm/eadm.h> + +#define SCM_NR_PARTS 8 +#define SCM_QUEUE_DELAY 5 + +struct scm_blk_dev { + struct tasklet_struct tasklet; + struct request_queue *rq; + struct gendisk *gendisk; + struct scm_device *scmdev; + spinlock_t rq_lock; /* guard the request queue */ + spinlock_t lock; /* guard the rest of the blockdev */ + atomic_t queued_reqs; + enum {SCM_OPER, SCM_WR_PROHIBIT} state; + struct list_head finished_requests; +#ifdef CONFIG_SCM_BLOCK_CLUSTER_WRITE + struct list_head cluster_list; +#endif +}; + +struct scm_request { + struct scm_blk_dev *bdev; + struct aidaw *next_aidaw; + struct request **request; + struct aob *aob; + struct list_head list; + u8 retries; + int error; +#ifdef CONFIG_SCM_BLOCK_CLUSTER_WRITE + struct { + enum {CLUSTER_NONE, CLUSTER_READ, CLUSTER_WRITE} state; + struct list_head list; + void **buf; + } cluster; +#endif +}; + +#define to_aobrq(rq) container_of((void *) rq, struct aob_rq_header, data) + +int scm_blk_dev_setup(struct scm_blk_dev *, struct scm_device *); +void scm_blk_dev_cleanup(struct scm_blk_dev *); +void scm_blk_set_available(struct scm_blk_dev *); +void scm_blk_irq(struct scm_device *, void *, int); + +void scm_request_finish(struct scm_request *); +void scm_request_requeue(struct scm_request *); + +struct aidaw *scm_aidaw_fetch(struct scm_request *scmrq, unsigned int bytes); + +int scm_drv_init(void); +void scm_drv_cleanup(void); + +#ifdef CONFIG_SCM_BLOCK_CLUSTER_WRITE +void __scm_free_rq_cluster(struct scm_request *); +int __scm_alloc_rq_cluster(struct scm_request *); +void scm_request_cluster_init(struct scm_request *); +bool scm_reserve_cluster(struct scm_request *); +void scm_release_cluster(struct scm_request *); +void scm_blk_dev_cluster_setup(struct scm_blk_dev *); +bool scm_need_cluster_request(struct scm_request *); +void scm_initiate_cluster_request(struct scm_request *); +void scm_cluster_request_irq(struct scm_request *); +bool scm_test_cluster_request(struct scm_request *); +bool scm_cluster_size_valid(void); +#else /* CONFIG_SCM_BLOCK_CLUSTER_WRITE */ +static inline void __scm_free_rq_cluster(struct scm_request *scmrq) {} +static inline int __scm_alloc_rq_cluster(struct scm_request *scmrq) +{ + return 0; +} +static inline void scm_request_cluster_init(struct scm_request *scmrq) {} +static inline bool scm_reserve_cluster(struct scm_request *scmrq) +{ + return true; +} +static inline void scm_release_cluster(struct scm_request *scmrq) {} +static inline void scm_blk_dev_cluster_setup(struct scm_blk_dev *bdev) {} +static inline bool scm_need_cluster_request(struct scm_request *scmrq) +{ + return false; +} +static inline void scm_initiate_cluster_request(struct scm_request *scmrq) {} +static inline void scm_cluster_request_irq(struct scm_request *scmrq) {} +static inline bool scm_test_cluster_request(struct scm_request *scmrq) +{ + return false; +} +static inline bool scm_cluster_size_valid(void) +{ + return true; +} +#endif /* CONFIG_SCM_BLOCK_CLUSTER_WRITE */ + +extern debug_info_t *scm_debug; + +#define SCM_LOG(imp, txt) do { \ + debug_text_event(scm_debug, imp, txt); \ + } while (0) + +static inline void SCM_LOG_HEX(int level, void *data, int length) +{ + if (!debug_level_enabled(scm_debug, level)) + return; + while (length > 0) { + debug_event(scm_debug, level, data, length); + length -= scm_debug->buf_size; + data += scm_debug->buf_size; + } +} + +static inline void SCM_LOG_STATE(int level, struct scm_device *scmdev) +{ + struct { + u64 address; + u8 oper_state; + u8 rank; + } __packed data = { + .address = scmdev->address, + .oper_state = scmdev->attrs.oper_state, + .rank = scmdev->attrs.rank, + }; + + SCM_LOG_HEX(level, &data, sizeof(data)); +} + +#endif /* SCM_BLK_H */ |