debuggers.hg

view freebsd-5.3-xen-sparse/i386-xen/xen/blkfront/xb_blkfront.c @ 4628:35357e323f14

bitkeeper revision 1.1338 (4266317ezHysqYzH_WRvfueqwU4i4Q)

Grant tables for FreeBSD.
Signed-off-by: Kip Macy <kmacy@fsmware.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Wed Apr 20 10:39:58 2005 +0000 (2005-04-20)
parents 445b12a7221a
children 23682e5da945 79b7835ac75d
line source
1 /*-
2 * All rights reserved.
3 *
4 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
5 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
6 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
8 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
9 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
10 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
11 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
14 * SUCH DAMAGE.
15 *
16 */
18 /*
19 * XenoBSD block device driver
20 */
22 #include <sys/param.h>
23 #include <sys/systm.h>
24 #include <sys/malloc.h>
25 #include <sys/kernel.h>
26 #include <vm/vm.h>
27 #include <vm/pmap.h>
29 #include <sys/bio.h>
30 #include <sys/bus.h>
31 #include <sys/conf.h>
33 #include <machine/bus.h>
34 #include <sys/rman.h>
35 #include <machine/resource.h>
36 #include <machine/intr_machdep.h>
37 #include <machine/vmparam.h>
39 #include <machine/hypervisor.h>
40 #include <machine/hypervisor-ifs.h>
41 #include <machine/xen-os.h>
42 #include <machine/xen_intr.h>
43 #include <machine/evtchn.h>
45 #include <geom/geom_disk.h>
46 #include <machine/ctrl_if.h>
47 #include <machine/xenfunc.h>
51 #ifdef CONFIG_XEN_BLKDEV_GRANT
52 #include <machine/gnttab.h>
53 #endif
55 /* prototypes */
56 struct xb_softc;
57 static void xb_startio(struct xb_softc *sc);
58 static void xb_vbdinit(void);
59 static void blkif_control_send(blkif_request_t *req, blkif_response_t *rsp);
60 static void blkif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id);
61 static void blkif_control_probe_send(blkif_request_t *req, blkif_response_t *rsp, unsigned long address);
63 struct xb_softc {
64 device_t xb_dev;
65 struct disk xb_disk; /* disk params */
66 struct bio_queue_head xb_bioq; /* sort queue */
67 struct resource *xb_irq;
68 void *xb_resp_handler;
69 int xb_unit;
70 int xb_flags;
71 #define XB_OPEN (1<<0) /* drive is open (can't shut down) */
72 };
74 /* Control whether runtime update of vbds is enabled. */
75 #define ENABLE_VBD_UPDATE 1
77 #if ENABLE_VBD_UPDATE
78 static void vbd_update(void);
79 #else
80 static void vbd_update(void){};
81 #endif
83 #define BLKIF_STATE_CLOSED 0
84 #define BLKIF_STATE_DISCONNECTED 1
85 #define BLKIF_STATE_CONNECTED 2
87 static char *blkif_state_name[] = {
88 [BLKIF_STATE_CLOSED] = "closed",
89 [BLKIF_STATE_DISCONNECTED] = "disconnected",
90 [BLKIF_STATE_CONNECTED] = "connected",
91 };
93 static char * blkif_status_name[] = {
94 [BLKIF_INTERFACE_STATUS_CLOSED] = "closed",
95 [BLKIF_INTERFACE_STATUS_DISCONNECTED] = "disconnected",
96 [BLKIF_INTERFACE_STATUS_CONNECTED] = "connected",
97 [BLKIF_INTERFACE_STATUS_CHANGED] = "changed",
98 };
100 #define WPRINTK(fmt, args...) printk("[XEN] " fmt, ##args)
102 static int blkif_handle;
103 static unsigned int blkif_state = BLKIF_STATE_CLOSED;
104 static unsigned int blkif_evtchn;
105 static unsigned int blkif_irq;
107 static int blkif_control_rsp_valid;
108 static blkif_response_t blkif_control_rsp;
110 static blkif_front_ring_t blk_ring;
112 #define BLK_RING_SIZE __RING_SIZE((blkif_sring_t *)0, PAGE_SIZE)
114 #ifdef CONFIG_XEN_BLKDEV_GRANT
115 static domid_t rdomid = 0;
116 static grant_ref_t gref_head, gref_terminal;
117 #define MAXIMUM_OUTSTANDING_BLOCK_REQS \
118 (BLKIF_MAX_SEGMENTS_PER_REQUEST * BLKIF_RING_SIZE)
119 #endif
122 static unsigned long rec_ring_free;
123 blkif_request_t rec_ring[BLK_RING_SIZE];
125 /* XXX move to xb_vbd.c when VBD update support is added */
126 #define MAX_VBDS 64
127 static vdisk_t xb_diskinfo[MAX_VBDS];
128 static int xb_ndisks;
130 #define XBD_SECTOR_SIZE 512 /* XXX: assume for now */
131 #define XBD_SECTOR_SHFT 9
133 static unsigned int xb_kick_pending;
135 static struct mtx blkif_io_lock;
138 static int xb_recovery = 0; /* "Recovery in progress" flag. Protected
139 * by the blkif_io_lock */
142 void blkif_completion(blkif_request_t *req);
143 void xb_response_intr(void *);
145 /* XXX: This isn't supported in FreeBSD, so ignore it for now. */
146 #define TASK_UNINTERRUPTIBLE 0
148 static inline int
149 GET_ID_FROM_FREELIST( void )
150 {
151 unsigned long free = rec_ring_free;
153 KASSERT(free <= BLK_RING_SIZE, ("free %lu > RING_SIZE", free));
155 rec_ring_free = rec_ring[free].id;
157 rec_ring[free].id = 0x0fffffee; /* debug */
159 return free;
160 }
162 static inline void
163 ADD_ID_TO_FREELIST( unsigned long id )
164 {
165 rec_ring[id].id = rec_ring_free;
166 rec_ring_free = id;
167 }
169 static inline void
170 translate_req_to_pfn(blkif_request_t *xreq,
171 blkif_request_t *req)
172 {
173 int i;
175 xreq->operation = req->operation;
176 xreq->nr_segments = req->nr_segments;
177 xreq->device = req->device;
178 /* preserve id */
179 xreq->sector_number = req->sector_number;
181 for ( i = 0; i < req->nr_segments; i++ ){
182 #ifdef CONFIG_XEN_BLKDEV_GRANT
183 xreq->frame_and_sects[i] = req->frame_and_sects[i];
184 #else
185 xreq->frame_and_sects[i] = xpmap_mtop(req->frame_and_sects[i]);
186 #endif
187 }
188 }
190 static inline void translate_req_to_mfn(blkif_request_t *xreq,
191 blkif_request_t *req)
192 {
193 int i;
195 xreq->operation = req->operation;
196 xreq->nr_segments = req->nr_segments;
197 xreq->device = req->device;
198 xreq->id = req->id; /* copy id (unlike above) */
199 xreq->sector_number = req->sector_number;
201 for ( i = 0; i < req->nr_segments; i++ ){
202 #ifdef CONFIG_XEN_BLKDEV_GRANT
203 xreq->frame_and_sects[i] = req->frame_and_sects[i];
204 #else
205 xreq->frame_and_sects[i] = xpmap_ptom(req->frame_and_sects[i]);
206 #endif
207 }
208 }
211 static inline void flush_requests(void)
212 {
213 RING_PUSH_REQUESTS(&blk_ring);
214 notify_via_evtchn(blkif_evtchn);
215 }
218 #if ENABLE_VBD_UPDATE
219 static void vbd_update()
220 {
221 XENPRINTF(">\n");
222 XENPRINTF("<\n");
223 }
224 #endif /* ENABLE_VBD_UPDATE */
226 void
227 xb_response_intr(void *xsc)
228 {
229 struct xb_softc *sc = NULL;
230 struct bio *bp;
231 blkif_response_t *bret;
232 RING_IDX i, rp;
233 unsigned long flags;
235 mtx_lock_irqsave(&blkif_io_lock, flags);
237 if ( unlikely(blkif_state == BLKIF_STATE_CLOSED) ||
238 unlikely(xb_recovery) ) {
239 mtx_unlock_irqrestore(&blkif_io_lock, flags);
240 return;
241 }
243 rp = blk_ring.sring->rsp_prod;
244 rmb(); /* Ensure we see queued responses up to 'rp'. */
246 /* sometimes we seem to lose i/o. stay in the interrupt handler while
247 * there is stuff to process: continually recheck the response producer.
248 */
249 for ( i = blk_ring.rsp_cons; i != (rp = blk_ring.sring->rsp_prod); i++ ) {
250 unsigned long id;
251 bret = RING_GET_RESPONSE(&blk_ring, i);
253 id = bret->id;
254 bp = (struct bio *)rec_ring[id].id;
256 blkif_completion(&rec_ring[id]);
258 ADD_ID_TO_FREELIST(id); /* overwrites req */
260 switch ( bret->operation ) {
261 case BLKIF_OP_READ:
262 /* had an unaligned buffer that needs to be copied */
263 if (bp->bio_driver1)
264 bcopy(bp->bio_data, bp->bio_driver1, bp->bio_bcount);
265 case BLKIF_OP_WRITE:
267 /* free the copy buffer */
268 if (bp->bio_driver1) {
269 free(bp->bio_data, M_DEVBUF);
270 bp->bio_data = bp->bio_driver1;
271 bp->bio_driver1 = NULL;
272 }
274 if ( unlikely(bret->status != BLKIF_RSP_OKAY) ) {
275 XENPRINTF("Bad return from blkdev data request: %x\n",
276 bret->status);
277 bp->bio_flags |= BIO_ERROR;
278 }
280 sc = (struct xb_softc *)bp->bio_disk->d_drv1;
282 if (bp->bio_flags & BIO_ERROR)
283 bp->bio_error = EIO;
284 else
285 bp->bio_resid = 0;
287 biodone(bp);
288 break;
289 case BLKIF_OP_PROBE:
290 memcpy(&blkif_control_rsp, bret, sizeof(*bret));
291 blkif_control_rsp_valid = 1;
292 break;
293 default:
294 panic("received invalid operation");
295 break;
296 }
297 }
299 blk_ring.rsp_cons = i;
301 if (sc && xb_kick_pending) {
302 xb_kick_pending = FALSE;
303 xb_startio(sc);
304 }
306 mtx_unlock_irqrestore(&blkif_io_lock, flags);
307 }
309 static int
310 xb_open(struct disk *dp)
311 {
312 struct xb_softc *sc = (struct xb_softc *)dp->d_drv1;
314 if (sc == NULL) {
315 printk("xb%d: not found", sc->xb_unit);
316 return (ENXIO);
317 }
319 /* block dev not active */
320 if (blkif_state != BLKIF_STATE_CONNECTED) {
321 printk("xb%d: bad state: %dn", sc->xb_unit, blkif_state);
322 return(ENXIO);
323 }
325 sc->xb_flags |= XB_OPEN;
326 return (0);
327 }
329 static int
330 xb_close(struct disk *dp)
331 {
332 struct xb_softc *sc = (struct xb_softc *)dp->d_drv1;
334 if (sc == NULL)
335 return (ENXIO);
336 sc->xb_flags &= ~XB_OPEN;
337 return (0);
338 }
340 static int
341 xb_ioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
342 {
343 struct xb_softc *sc = (struct xb_softc *)dp->d_drv1;
345 if (sc == NULL)
346 return (ENXIO);
348 return (ENOTTY);
349 }
351 /*
352 * Dequeue buffers and place them in the shared communication ring.
353 * Return when no more requests can be accepted or all buffers have
354 * been queued.
355 *
356 * Signal XEN once the ring has been filled out.
357 */
358 static void
359 xb_startio(struct xb_softc *sc)
360 {
361 struct bio *bp;
362 unsigned long buffer_ma;
363 blkif_request_t *req;
364 int s, queued = 0;
365 unsigned long id;
366 unsigned int fsect, lsect;
367 #ifdef CONFIG_XEN_BLKDEV_GRANT
368 int ref;
369 #endif
372 if (unlikely(blkif_state != BLKIF_STATE_CONNECTED))
373 return;
375 s = splbio();
377 for (bp = bioq_first(&sc->xb_bioq);
378 bp && !RING_FULL(&blk_ring);
379 blk_ring.req_prod_pvt++, queued++, bp = bioq_first(&sc->xb_bioq)) {
381 /* Check if the buffer is properly aligned */
382 if ((vm_offset_t)bp->bio_data & PAGE_MASK) {
383 int align = (bp->bio_bcount < PAGE_SIZE/2) ? XBD_SECTOR_SIZE :
384 PAGE_SIZE;
385 caddr_t newbuf = malloc(bp->bio_bcount + align, M_DEVBUF,
386 M_WAITOK);
387 caddr_t alignbuf = (char *)roundup2((u_long)newbuf, align);
389 /* save a copy of the current buffer */
390 bp->bio_driver1 = bp->bio_data;
392 /* Copy the data for a write */
393 if (bp->bio_cmd == BIO_WRITE)
394 bcopy(bp->bio_data, alignbuf, bp->bio_bcount);
395 bp->bio_data = alignbuf;
396 }
398 bioq_remove(&sc->xb_bioq, bp);
399 buffer_ma = vtomach(bp->bio_data);
400 fsect = (buffer_ma & PAGE_MASK) >> XBD_SECTOR_SHFT;
401 lsect = fsect + (bp->bio_bcount >> XBD_SECTOR_SHFT) - 1;
403 KASSERT((buffer_ma & (XBD_SECTOR_SIZE-1)) == 0,
404 ("XEN buffer must be sector aligned"));
405 KASSERT(lsect <= 7,
406 ("XEN disk driver data cannot cross a page boundary"));
408 buffer_ma &= ~PAGE_MASK;
410 /* Fill out a communications ring structure. */
411 req = RING_GET_REQUEST(&blk_ring,
412 blk_ring.req_prod_pvt);
413 id = GET_ID_FROM_FREELIST();
414 rec_ring[id].id= (unsigned long)bp;
416 req->id = id;
417 req->operation = (bp->bio_cmd == BIO_READ) ? BLKIF_OP_READ :
418 BLKIF_OP_WRITE;
420 req->sector_number= (blkif_sector_t)bp->bio_pblkno;
421 req->device = xb_diskinfo[sc->xb_unit].device;
423 req->nr_segments = 1; /* not doing scatter/gather since buffer
424 * chaining is not supported.
425 */
426 #ifdef CONFIG_XEN_BLKDEV_GRANT
427 /* install a grant reference. */
428 ref = gnttab_claim_grant_reference(&gref_head, gref_terminal);
429 KASSERT( ref != -ENOSPC, ("grant_reference failed") );
431 gnttab_grant_foreign_access_ref(
432 ref,
433 rdomid,
434 buffer_ma >> PAGE_SHIFT,
435 req->operation & 1 ); /* ??? */
437 req->frame_and_sects[0] =
438 (((uint32_t) ref) << 16) | (fsect << 3) | lsect;
439 #else
440 /*
441 * upper bits represent the machine address of the buffer and the
442 * lower bits is the number of sectors to be read/written.
443 */
444 req->frame_and_sects[0] = buffer_ma | (fsect << 3) | lsect;
445 #endif
446 /* Keep a private copy so we can reissue requests when recovering. */
447 translate_req_to_pfn( &rec_ring[id], req);
449 }
451 if (RING_FULL(&blk_ring))
452 xb_kick_pending = TRUE;
454 if (queued != 0)
455 flush_requests();
456 splx(s);
457 }
459 /*
460 * Read/write routine for a buffer. Finds the proper unit, place it on
461 * the sortq and kick the controller.
462 */
463 static void
464 xb_strategy(struct bio *bp)
465 {
466 struct xb_softc *sc = (struct xb_softc *)bp->bio_disk->d_drv1;
467 int s;
469 /* bogus disk? */
470 if (sc == NULL) {
471 bp->bio_error = EINVAL;
472 bp->bio_flags |= BIO_ERROR;
473 goto bad;
474 }
476 s = splbio();
477 /*
478 * Place it in the queue of disk activities for this disk
479 */
480 bioq_disksort(&sc->xb_bioq, bp);
481 splx(s);
483 xb_startio(sc);
484 return;
486 bad:
487 /*
488 * Correctly set the bio to indicate a failed tranfer.
489 */
490 bp->bio_resid = bp->bio_bcount;
491 biodone(bp);
492 return;
493 }
496 static int
497 xb_create(int unit)
498 {
499 struct xb_softc *sc;
500 int error = 0;
502 sc = (struct xb_softc *)malloc(sizeof(*sc), M_DEVBUF, M_WAITOK);
503 sc->xb_unit = unit;
505 memset(&sc->xb_disk, 0, sizeof(sc->xb_disk));
506 sc->xb_disk.d_unit = unit;
507 sc->xb_disk.d_open = xb_open;
508 sc->xb_disk.d_close = xb_close;
509 sc->xb_disk.d_ioctl = xb_ioctl;
510 sc->xb_disk.d_strategy = xb_strategy;
511 sc->xb_disk.d_name = "xbd";
512 sc->xb_disk.d_drv1 = sc;
513 sc->xb_disk.d_sectorsize = XBD_SECTOR_SIZE;
514 sc->xb_disk.d_mediasize = xb_diskinfo[sc->xb_unit].capacity
515 << XBD_SECTOR_SHFT;
516 #if 0
517 sc->xb_disk.d_maxsize = DFLTPHYS;
518 #else /* XXX: xen can't handle large single i/o requests */
519 sc->xb_disk.d_maxsize = 4096;
520 #endif
522 XENPRINTF("attaching device 0x%x unit %d capacity %llu\n",
523 xb_diskinfo[sc->xb_unit].device, sc->xb_unit,
524 sc->xb_disk.d_mediasize);
526 disk_create(&sc->xb_disk, DISK_VERSION_00);
527 bioq_init(&sc->xb_bioq);
529 return error;
530 }
532 /* XXX move to xb_vbd.c when vbd update support is added */
533 static void
534 xb_vbdinit(void)
535 {
536 int i;
537 blkif_request_t req;
538 blkif_response_t rsp;
539 vdisk_t *buf;
541 buf = (vdisk_t *)malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK);
543 /* Probe for disk information. */
544 memset(&req, 0, sizeof(req));
545 req.operation = BLKIF_OP_PROBE;
546 req.nr_segments = 1;
547 #ifdef CONFIG_XEN_BLKDEV_GRANT
548 blkif_control_probe_send(&req, &rsp,
549 (unsigned long)(vtomach(buf)));
551 #else
552 req.frame_and_sects[0] = vtomach(buf) | 7;
553 blkif_control_send(&req, &rsp);
554 #endif
555 if ( rsp.status <= 0 ) {
556 printk("xb_identify: Could not identify disks (%d)\n", rsp.status);
557 free(buf, M_DEVBUF);
558 return;
559 }
561 if ((xb_ndisks = rsp.status) > MAX_VBDS)
562 xb_ndisks = MAX_VBDS;
564 memcpy(xb_diskinfo, buf, xb_ndisks * sizeof(vdisk_t));
566 for (i = 0; i < xb_ndisks; i++)
567 xb_create(i);
569 free(buf, M_DEVBUF);
570 }
573 /***************************** COMMON CODE *******************************/
575 #ifdef CONFIG_XEN_BLKDEV_GRANT
576 static void
577 blkif_control_probe_send(blkif_request_t *req, blkif_response_t *rsp,
578 unsigned long address)
579 {
580 int ref = gnttab_claim_grant_reference(&gref_head, gref_terminal);
581 KASSERT( ref != -ENOSPC, ("couldn't get grant reference") );
583 gnttab_grant_foreign_access_ref( ref, rdomid, address >> PAGE_SHIFT, 0 );
585 req->frame_and_sects[0] = (((uint32_t) ref) << 16) | 7;
587 blkif_control_send(req, rsp);
588 }
589 #endif
591 void
592 blkif_control_send(blkif_request_t *req, blkif_response_t *rsp)
593 {
594 unsigned long flags, id;
595 blkif_request_t *req_d;
597 retry:
598 while ( RING_FULL(&blk_ring) )
599 {
600 tsleep( req, PWAIT | PCATCH, "blkif", hz);
601 }
603 mtx_lock_irqsave(&blkif_io_lock, flags);
604 if ( RING_FULL(&blk_ring) )
605 {
606 mtx_unlock_irqrestore(&blkif_io_lock, flags);
607 goto retry;
608 }
610 req_d = RING_GET_REQUEST(&blk_ring, blk_ring.req_prod_pvt);
611 *req_d = *req;
613 id = GET_ID_FROM_FREELIST();
614 req_d->id = id;
615 rec_ring[id].id = (unsigned long) req;
617 translate_req_to_pfn( &rec_ring[id], req );
619 blk_ring.req_prod_pvt++;
620 flush_requests();
622 mtx_unlock_irqrestore(&blkif_io_lock, flags);
624 while ( !blkif_control_rsp_valid )
625 {
626 tsleep( &blkif_control_rsp_valid, PWAIT | PCATCH, "blkif", hz);
627 }
629 memcpy(rsp, &blkif_control_rsp, sizeof(*rsp));
630 blkif_control_rsp_valid = 0;
631 }
634 /* Send a driver status notification to the domain controller. */
635 static void
636 send_driver_status(int ok)
637 {
638 ctrl_msg_t cmsg = {
639 .type = CMSG_BLKIF_FE,
640 .subtype = CMSG_BLKIF_FE_DRIVER_STATUS,
641 .length = sizeof(blkif_fe_driver_status_t),
642 };
643 blkif_fe_driver_status_t *msg = (void*)cmsg.msg;
645 msg->status = (ok ? BLKIF_DRIVER_STATUS_UP : BLKIF_DRIVER_STATUS_DOWN);
647 ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
648 }
650 /* Tell the controller to bring up the interface. */
651 static void
652 blkif_send_interface_connect(void)
653 {
654 ctrl_msg_t cmsg = {
655 .type = CMSG_BLKIF_FE,
656 .subtype = CMSG_BLKIF_FE_INTERFACE_CONNECT,
657 .length = sizeof(blkif_fe_interface_connect_t),
658 };
659 blkif_fe_interface_connect_t *msg = (void*)cmsg.msg;
661 msg->handle = 0;
662 msg->shmem_frame = (vtomach(blk_ring.sring) >> PAGE_SHIFT);
664 ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
665 }
667 static void
668 blkif_free(void)
669 {
671 unsigned long flags;
673 printk("[XEN] Recovering virtual block device driver\n");
675 /* Prevent new requests being issued until we fix things up. */
676 mtx_lock_irqsave(&blkif_io_lock, flags);
677 xb_recovery = 1;
678 blkif_state = BLKIF_STATE_DISCONNECTED;
679 mtx_unlock_irqrestore(&blkif_io_lock, flags);
681 /* Free resources associated with old device channel. */
682 if (blk_ring.sring != NULL) {
683 free(blk_ring.sring, M_DEVBUF);
684 blk_ring.sring = NULL;
685 }
686 /* free_irq(blkif_irq, NULL);*/
687 blkif_irq = 0;
689 unbind_evtchn_from_irq(blkif_evtchn);
690 blkif_evtchn = 0;
691 }
693 static void
694 blkif_close(void)
695 {
696 }
698 /* Move from CLOSED to DISCONNECTED state. */
699 static void
700 blkif_disconnect(void)
701 {
702 if (blk_ring.sring) free(blk_ring.sring, M_DEVBUF);
703 blk_ring.sring = (blkif_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK);
704 SHARED_RING_INIT(blk_ring.sring);
705 FRONT_RING_INIT(&blk_ring, blk_ring.sring, PAGE_SIZE);
706 blkif_state = BLKIF_STATE_DISCONNECTED;
707 blkif_send_interface_connect();
708 }
710 static void
711 blkif_reset(void)
712 {
713 printk("[XEN] Recovering virtual block device driver\n");
714 blkif_free();
715 blkif_disconnect();
716 }
718 static void
719 blkif_recover(void)
720 {
722 int i;
723 blkif_request_t *req;
725 /* Hmm, requests might be re-ordered when we re-issue them.
726 * This will need to be fixed once we have barriers */
728 /* Stage 1 : Find active and move to safety. */
729 for ( i = 0; i < BLK_RING_SIZE; i++ ) {
730 if ( rec_ring[i].id >= KERNBASE ) {
731 req = RING_GET_REQUEST(&blk_ring,
732 blk_ring.req_prod_pvt);
733 translate_req_to_mfn(req, &rec_ring[i]);
734 blk_ring.req_prod_pvt++;
735 }
736 }
738 printk("blkfront: recovered %d descriptors\n",blk_ring.req_prod_pvt);
740 /* Stage 2 : Set up shadow list. */
741 for ( i = 0; i < blk_ring.req_prod_pvt; i++ ) {
742 req = RING_GET_REQUEST(&blk_ring, i);
743 rec_ring[i].id = req->id;
744 req->id = i;
745 translate_req_to_pfn(&rec_ring[i], req);
746 }
748 /* Stage 3 : Set up free list. */
749 for ( ; i < BLK_RING_SIZE; i++ ){
750 rec_ring[i].id = i+1;
751 }
752 rec_ring_free = blk_ring.req_prod_pvt;
753 rec_ring[BLK_RING_SIZE-1].id = 0x0fffffff;
755 /* blk_ring.req_prod will be set when we flush_requests().*/
756 wmb();
758 /* Switch off recovery mode, using a memory barrier to ensure that
759 * it's seen before we flush requests - we don't want to miss any
760 * interrupts. */
761 xb_recovery = 0;
762 wmb();
764 /* Kicks things back into life. */
765 flush_requests();
767 /* Now safe to left other peope use interface. */
768 blkif_state = BLKIF_STATE_CONNECTED;
769 }
771 static void
772 blkif_connect(blkif_fe_interface_status_t *status)
773 {
774 int err = 0;
776 blkif_evtchn = status->evtchn;
777 blkif_irq = bind_evtchn_to_irq(blkif_evtchn);
778 #ifdef CONFIG_XEN_BLKDEV_GRANT
779 rdomid = status->domid;
780 #endif
783 err = intr_add_handler("xbd", blkif_irq,
784 (driver_intr_t *)xb_response_intr, NULL,
785 INTR_TYPE_BIO | INTR_MPSAFE, NULL);
786 if(err){
787 printk("[XEN] blkfront request_irq failed (err=%d)\n", err);
788 return;
789 }
791 if ( xb_recovery ) {
792 blkif_recover();
793 } else {
794 /* Probe for discs attached to the interface. */
795 xb_vbdinit();
797 /* XXX: transition state after probe */
798 blkif_state = BLKIF_STATE_CONNECTED;
799 }
801 /* Kick pending requests. */
802 #if 0 /* XXX: figure out sortq logic */
803 mtx_lock_irq(&blkif_io_lock);
804 kick_pending_request_queues();
805 mtx_unlock_irq(&blkif_io_lock);
806 #endif
807 }
809 static void
810 unexpected(blkif_fe_interface_status_t *status)
811 {
812 WPRINTK(" Unexpected blkif status %s in state %s\n",
813 blkif_status_name[status->status],
814 blkif_state_name[blkif_state]);
815 }
817 static void
818 blkif_status(blkif_fe_interface_status_t *status)
819 {
820 if (status->handle != blkif_handle) {
821 WPRINTK(" Invalid blkif: handle=%u", status->handle);
822 return;
823 }
825 switch (status->status) {
827 case BLKIF_INTERFACE_STATUS_CLOSED:
828 switch(blkif_state){
829 case BLKIF_STATE_CLOSED:
830 unexpected(status);
831 break;
832 case BLKIF_STATE_DISCONNECTED:
833 case BLKIF_STATE_CONNECTED:
834 unexpected(status);
835 blkif_close();
836 break;
837 }
838 break;
840 case BLKIF_INTERFACE_STATUS_DISCONNECTED:
841 switch(blkif_state){
842 case BLKIF_STATE_CLOSED:
843 blkif_disconnect();
844 break;
845 case BLKIF_STATE_DISCONNECTED:
846 case BLKIF_STATE_CONNECTED:
847 unexpected(status);
848 blkif_reset();
849 break;
850 }
851 break;
853 case BLKIF_INTERFACE_STATUS_CONNECTED:
854 switch(blkif_state){
855 case BLKIF_STATE_CLOSED:
856 unexpected(status);
857 blkif_disconnect();
858 blkif_connect(status);
859 break;
860 case BLKIF_STATE_DISCONNECTED:
861 blkif_connect(status);
862 break;
863 case BLKIF_STATE_CONNECTED:
864 unexpected(status);
865 blkif_connect(status);
866 break;
867 }
868 break;
870 case BLKIF_INTERFACE_STATUS_CHANGED:
871 switch(blkif_state){
872 case BLKIF_STATE_CLOSED:
873 case BLKIF_STATE_DISCONNECTED:
874 unexpected(status);
875 break;
876 case BLKIF_STATE_CONNECTED:
877 vbd_update();
878 break;
879 }
880 break;
882 default:
883 WPRINTK("Invalid blkif status: %d\n", status->status);
884 break;
885 }
886 }
889 static void
890 blkif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
891 {
892 switch ( msg->subtype )
893 {
894 case CMSG_BLKIF_FE_INTERFACE_STATUS:
895 if ( msg->length != sizeof(blkif_fe_interface_status_t) )
896 goto parse_error;
897 blkif_status((blkif_fe_interface_status_t *)
898 &msg->msg[0]);
899 break;
900 default:
901 goto parse_error;
902 }
904 ctrl_if_send_response(msg);
905 return;
907 parse_error:
908 msg->length = 0;
909 ctrl_if_send_response(msg);
910 }
912 static int
913 wait_for_blkif(void)
914 {
915 int err = 0;
916 int i;
917 send_driver_status(1);
919 /*
920 * We should read 'nr_interfaces' from response message and wait
921 * for notifications before proceeding. For now we assume that we
922 * will be notified of exactly one interface.
923 */
924 for ( i=0; (blkif_state != BLKIF_STATE_CONNECTED) && (i < 10*hz); i++ )
925 {
926 tsleep(&blkif_state, PWAIT | PCATCH, "blkif", hz);
927 }
929 if (blkif_state != BLKIF_STATE_CONNECTED){
930 printk("[XEN] Timeout connecting block device driver!\n");
931 err = -ENOSYS;
932 }
933 return err;
934 }
937 static void
938 xb_init(void *unused)
939 {
940 int i;
942 printk("[XEN] Initialising virtual block device driver\n");
944 #ifdef CONFIG_XEN_BLKDEV_GRANT
945 if ( 0 > gnttab_alloc_grant_references( MAXIMUM_OUTSTANDING_BLOCK_REQS,
946 &gref_head, &gref_terminal ))
947 return;
948 printk("Blkif frontend is using grant tables.\n");
949 #endif
952 rec_ring_free = 0;
953 for (i = 0; i < BLK_RING_SIZE; i++) {
954 rec_ring[i].id = i+1;
955 }
956 rec_ring[BLK_RING_SIZE-1].id = 0x0fffffff;
958 (void)ctrl_if_register_receiver(CMSG_BLKIF_FE, blkif_ctrlif_rx, 0);
960 wait_for_blkif();
961 }
963 #if 0 /* XXX not yet */
964 void
965 blkdev_suspend(void)
966 {
967 }
969 void
970 blkdev_resume(void)
971 {
972 send_driver_status(1);
973 }
974 #endif
976 void
977 blkif_completion(blkif_request_t *req)
978 {
979 int i;
981 #ifdef CONFIG_XEN_BLKDEV_GRANT
982 grant_ref_t gref;
984 for ( i = 0; i < req->nr_segments; i++ )
985 {
986 gref = blkif_gref_from_fas(req->frame_and_sects[i]);
987 gnttab_release_grant_reference(&gref_head, gref);
988 }
989 #else
990 /* This is a hack to get the dirty logging bits set */
991 switch ( req->operation )
992 {
993 case BLKIF_OP_READ:
994 for ( i = 0; i < req->nr_segments; i++ )
995 {
996 unsigned long pfn = req->frame_and_sects[i] >> PAGE_SHIFT;
997 unsigned long mfn = xen_phys_machine[pfn];
998 xen_machphys_update(mfn, pfn);
999 }
1000 break;
1002 #endif
1004 MTX_SYSINIT(ioreq, &blkif_io_lock, "BIO LOCK", MTX_SPIN | MTX_NOWITNESS); /* XXX how does one enroll a lock? */
1005 SYSINIT(xbdev, SI_SUB_PSEUDO, SI_ORDER_ANY, xb_init, NULL)