|  | /* Copyright (c) 2010 The Regents of the University of California | 
|  | * Barret Rhoden <brho@cs.berkeley.edu> | 
|  | * See LICENSE for details. | 
|  | * | 
|  | * Block device interfaces and structures */ | 
|  |  | 
|  | #pragma once | 
|  |  | 
|  | #include <ros/common.h> | 
|  | #include <kref.h> | 
|  | #include <slab.h> | 
|  | #include <pagemap.h> | 
|  | #include <kthread.h> | 
|  |  | 
|  | /* All block IO is done assuming a certain size sector, which is the smallest | 
|  | * possible unit of transfer between the kernel and the block layer.  This can | 
|  | * be bigger than what the underlying hardware can handle, but it shouldn't be | 
|  | * smaller than any higher-level block (like an FS block, which are often 1 KB). | 
|  | */ | 
|  | #define SECTOR_SZ_LOG 9 | 
|  | #define SECTOR_SZ (1 << SECTOR_SZ_LOG) | 
|  |  | 
|  | /* Every block device is represented by one of these, with custom methods, as | 
|  | * applicable for the type of device.  Subject to massive changes. */ | 
|  | #define BDEV_INLINE_NAME 10 | 
|  | struct block_device { | 
|  | int							b_id; | 
|  | unsigned int				b_sector_sz;		/* HW sector size */ | 
|  | unsigned long				b_nr_sector;		/* Total sectors on dev */ | 
|  | struct kref					b_kref; | 
|  | struct page_map				b_pm; | 
|  | void						*b_data;			/* dev-specific use */ | 
|  | char						b_name[BDEV_INLINE_NAME]; | 
|  | // TODO: list or something of buffer heads (?) | 
|  | // list of outstanding requests | 
|  | // io scheduler | 
|  | // callbacks for completion | 
|  | }; | 
|  |  | 
|  | /* So far, only NEEDS_ZEROED is used */ | 
|  | #define BH_LOCKED		0x001	/* involved in an IO op */ | 
|  | #define BH_UPTODATE		0x002	/* buffer is filled with file data */ | 
|  | #define BH_DIRTY		0x004	/* buffer is dirty */ | 
|  | #define BH_NEEDS_ZEROED	0x008	/* buffer should be 0'd, not read in */ | 
|  |  | 
|  | /* This maps to and from a buffer within a page to a block(s) on a bdev.  Some | 
|  | * of it might not be needed later, etc (page, numblock). */ | 
|  | struct buffer_head { | 
|  | struct page					*bh_page;			/* redundant with buffer */ | 
|  | void						*bh_buffer; | 
|  | unsigned int				bh_flags; | 
|  | struct buffer_head			*bh_next;			/* circular LL of BHs */ | 
|  | struct block_device			*bh_bdev; | 
|  | unsigned long				bh_sector; | 
|  | unsigned int				bh_nr_sector;		/* length (in sectors) */ | 
|  | }; | 
|  | struct kmem_cache *bh_kcache; | 
|  |  | 
|  | /* Buffer Head Requests.  For now, just use these for dealing with non-file IO | 
|  | * on a block device.  Tell it what size you think blocks are. */ | 
|  | struct buffer_head *bdev_get_buffer(struct block_device *bdev, | 
|  | unsigned long blk_num, unsigned int blk_sz); | 
|  | void bdev_dirty_buffer(struct buffer_head *bh); | 
|  | void bdev_put_buffer(struct buffer_head *bh); | 
|  |  | 
|  | /* This encapsulates the work of a request (instead of having a variety of | 
|  | * slightly-different functions for things like read/write and scatter-gather | 
|  | * ops).  Reads and writes are essentially the same, so all we need is a flag to | 
|  | * differentiate.  This struct also serves as a tool to track the progress of a | 
|  | * block request throughout its servicing.  This is analagous to Linux's struct | 
|  | * bio. | 
|  | * | 
|  | * bhs normally points to the inline version (enough for a page).  kmalloc | 
|  | * another array of BH pointers if you want more.  The BHs do not need to be | 
|  | * linked or otherwise associated with a page mapping. */ | 
|  | #define NR_INLINE_BH (PGSIZE >> SECTOR_SZ_LOG) | 
|  | struct block_request; | 
|  | struct block_request { | 
|  | unsigned int				flags; | 
|  | void						(*callback)(struct block_request *breq); | 
|  | void						*data; | 
|  | struct semaphore			sem; | 
|  | struct buffer_head			**bhs;				/* BHs describing the IOs */ | 
|  | unsigned int				nr_bhs; | 
|  | struct buffer_head			*local_bhs[NR_INLINE_BH]; | 
|  | }; | 
|  | struct kmem_cache *breq_kcache;	/* for the block requests */ | 
|  |  | 
|  | /* Block request flags */ | 
|  | #define BREQ_READ 			0x001 | 
|  | #define BREQ_WRITE 			0x002 | 
|  |  | 
|  | void block_init(void); | 
|  | struct block_device *get_bdev(char *path); | 
|  | void free_bhs(struct page *page); | 
|  | int bdev_submit_request(struct block_device *bdev, struct block_request *breq); | 
|  | void generic_breq_done(struct block_request *breq); | 
|  | void sleep_on_breq(struct block_request *breq); |