These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / roms / ipxe / src / core / blocktrans.c
1 /*
2  * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26 /**
27  * @file
28  *
29  * Block device translator
30  *
31  */
32
33 #include <stdlib.h>
34 #include <errno.h>
35 #include <assert.h>
36 #include <ipxe/iobuf.h>
37 #include <ipxe/xfer.h>
38 #include <ipxe/blockdev.h>
39 #include <ipxe/blocktrans.h>
40
41 /**
42  * Reallocate block device translator data buffer
43  *
44  * @v xferbuf           Data transfer buffer
45  * @v len               New length (or zero to free buffer)
46  * @ret rc              Return status code
47  */
48 static int blktrans_xferbuf_realloc ( struct xfer_buffer *xferbuf,
49                                       size_t len ) {
50         struct block_translator *blktrans =
51                 container_of ( xferbuf, struct block_translator, xferbuf );
52
53         /* Record length, if applicable */
54         if ( blktrans->buffer ) {
55
56                 /* We have a (non-reallocatable) data buffer */
57                 return -ENOTSUP;
58
59         } else {
60
61                 /* Record length (for block device capacity) */
62                 xferbuf->len = len;
63                 return 0;
64         }
65 }
66
67 /**
68  * Write data to block device translator data buffer
69  *
70  * @v xferbuf           Data transfer buffer
71  * @v offset            Starting offset
72  * @v data              Data to copy
73  * @v len               Length of data
74  */
75 static void blktrans_xferbuf_write ( struct xfer_buffer *xferbuf, size_t offset,
76                                      const void *data, size_t len ) {
77         struct block_translator *blktrans =
78                 container_of ( xferbuf, struct block_translator, xferbuf );
79
80         /* Write data to buffer, if applicable */
81         if ( blktrans->buffer ) {
82
83                 /* Write data to buffer */
84                 copy_to_user ( blktrans->buffer, offset, data, len );
85
86         } else {
87
88                 /* Sanity check */
89                 assert ( len == 0 );
90         }
91 }
92
93 /**
94  * Read data from block device translator data buffer
95  *
96  * @v xferbuf           Data transfer buffer
97  * @v offset            Starting offset
98  * @v data              Data to read
99  * @v len               Length of data
100  */
101 static void blktrans_xferbuf_read ( struct xfer_buffer *xferbuf, size_t offset,
102                                     void *data, size_t len ) {
103         struct block_translator *blktrans =
104                 container_of ( xferbuf, struct block_translator, xferbuf );
105
106         /* Read data from buffer, if applicable */
107         if ( blktrans->buffer ) {
108
109                 /* Read data from buffer */
110                 copy_from_user ( data, blktrans->buffer, offset, len );
111
112         } else {
113
114                 /* Sanity check */
115                 assert ( len == 0 );
116         }
117 }
118
119 /** Block device translator data transfer buffer operations */
120 static struct xfer_buffer_operations blktrans_xferbuf_operations = {
121         .realloc = blktrans_xferbuf_realloc,
122         .write = blktrans_xferbuf_write,
123         .read = blktrans_xferbuf_read,
124 };
125
126 /**
127  * Close block device translator
128  *
129  * @v blktrans          Block device translator
130  * @v rc                Reason for close
131  */
132 static void blktrans_close ( struct block_translator *blktrans, int rc ) {
133         struct block_device_capacity capacity;
134
135         /* Report block device capacity, if applicable */
136         if ( ( rc == 0 ) && ( blktrans->blksize ) ) {
137
138                 /* Construct block device capacity */
139                 capacity.blocks =
140                         ( blktrans->xferbuf.len / blktrans->blksize );
141                 capacity.blksize = blktrans->blksize;
142                 capacity.max_count = -1U;
143
144                 /* Report block device capacity */
145                 block_capacity ( &blktrans->block, &capacity );
146         }
147
148         /* Shut down interfaces */
149         intf_shutdown ( &blktrans->xfer, rc );
150         intf_shutdown ( &blktrans->block, rc );
151 }
152
153 /**
154  * Deliver data
155  *
156  * @v blktrans          Block device translator
157  * @v iobuf             I/O buffer
158  * @v meta              Data transfer metadata
159  * @ret rc              Return status code
160  */
161 static int blktrans_deliver ( struct block_translator *blktrans,
162                               struct io_buffer *iobuf,
163                               struct xfer_metadata *meta ) {
164         int rc;
165
166         /* Deliver to buffer */
167         if ( ( rc = xferbuf_deliver ( &blktrans->xferbuf, iob_disown ( iobuf ),
168                                       meta ) ) != 0 ) {
169                 DBGC ( blktrans, "BLKTRANS %p could not deliver: %s\n",
170                        blktrans, strerror ( rc ) );
171                 goto err;
172         }
173
174         return 0;
175
176  err:
177         blktrans_close ( blktrans, rc );
178         return rc;
179 }
180
181 /**
182  * Get underlying data transfer buffer
183  *
184  * @v blktrans          Block device translator
185  * @ret xferbuf         Data transfer buffer
186  */
187 static struct xfer_buffer *
188 blktrans_buffer ( struct block_translator *blktrans ) {
189
190         return &blktrans->xferbuf;
191 }
192
193 /** Block device translator block device interface operations */
194 static struct interface_operation blktrans_block_operations[] = {
195         INTF_OP ( intf_close, struct block_translator *, blktrans_close ),
196 };
197
198 /** Block device translator block device interface descriptor */
199 static struct interface_descriptor blktrans_block_desc =
200         INTF_DESC_PASSTHRU ( struct block_translator, block,
201                              blktrans_block_operations, xfer );
202
203 /** Block device translator data transfer interface operations */
204 static struct interface_operation blktrans_xfer_operations[] = {
205         INTF_OP ( xfer_deliver, struct block_translator *, blktrans_deliver ),
206         INTF_OP ( xfer_buffer, struct block_translator *, blktrans_buffer ),
207         INTF_OP ( intf_close, struct block_translator *, blktrans_close ),
208 };
209
210 /** Block device translator data transfer interface descriptor */
211 static struct interface_descriptor blktrans_xfer_desc =
212         INTF_DESC_PASSTHRU ( struct block_translator, xfer,
213                              blktrans_xfer_operations, block );
214
215 /**
216  * Insert block device translator
217  *
218  * @v block             Block device interface
219  * @v buffer            Data buffer (or UNULL)
220  * @v size              Length of data buffer, or block size
221  * @ret rc              Return status code
222  */
223 int block_translate ( struct interface *block, userptr_t buffer, size_t size ) {
224         struct block_translator *blktrans;
225         int rc;
226
227         /* Allocate and initialise structure */
228         blktrans = zalloc ( sizeof ( *blktrans ) );
229         if ( ! blktrans ) {
230                 rc = -ENOMEM;
231                 goto err_alloc;
232         }
233         ref_init ( &blktrans->refcnt, NULL );
234         intf_init ( &blktrans->block, &blktrans_block_desc, &blktrans->refcnt );
235         intf_init ( &blktrans->xfer, &blktrans_xfer_desc, &blktrans->refcnt );
236         blktrans->xferbuf.op = &blktrans_xferbuf_operations;
237         blktrans->buffer = buffer;
238         if ( buffer ) {
239                 blktrans->xferbuf.len = size;
240         } else {
241                 blktrans->blksize = size;
242         }
243
244         /* Attach to interfaces, mortalise self, and return */
245         assert ( block->dest != &null_intf );
246         intf_plug_plug ( &blktrans->xfer, block->dest );
247         intf_plug_plug ( &blktrans->block, block );
248         ref_put ( &blktrans->refcnt );
249
250         DBGC2 ( blktrans, "BLKTRANS %p created", blktrans );
251         if ( buffer ) {
252                 DBGC2 ( blktrans, " for %#lx+%#zx",
253                         user_to_phys ( buffer, 0 ), size );
254         }
255         DBGC2 ( blktrans, "\n" );
256         return 0;
257
258         ref_put ( &blktrans->refcnt );
259  err_alloc:
260         return rc;
261 }