debuggers.hg

view netbsd-2.0-xen-sparse/sys/arch/xen/xen/xbd.c @ 2632:a4fbb98f00cb

bitkeeper revision 1.1159.1.202 (41616cc2-ciBh_VkJKwmQaCL6BEU6Q)

Merge labyrinth.cl.cam.ac.uk:/auto/groups/xeno/BK/xeno.bk
into labyrinth.cl.cam.ac.uk:/auto/anfs/scratch/labyrinth/iap10/xeno-clone/xeno.bk
author iap10@labyrinth.cl.cam.ac.uk
date Mon Oct 04 15:31:14 2004 +0000 (2004-10-04)
parents 3f0a9708178b aa75f00efa54
children 322541dd9041 fb095fda8aa2
line source
1 /* $NetBSD: xbd.c,v 1.9.2.1 2004/05/22 15:59:11 he Exp $ */
3 /*
4 *
5 * Copyright (c) 2004 Christian Limpach.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Christian Limpach.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: xbd.c,v 1.9.2.1 2004/05/22 15:59:11 he Exp $");
38 #include "xbd.h"
40 #include <sys/types.h>
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/proc.h>
44 #include <sys/errno.h>
45 #include <sys/buf.h>
46 #include <sys/malloc.h>
47 #include <sys/pool.h>
48 #include <sys/ioctl.h>
49 #include <sys/device.h>
50 #include <sys/disk.h>
51 #include <sys/disklabel.h>
52 #include <sys/fcntl.h>
53 #include <sys/vnode.h>
54 #include <sys/lock.h>
55 #include <sys/conf.h>
56 #include <sys/queue.h>
57 #include <sys/stat.h>
58 #include <sys/sysctl.h>
59 #include <sys/kernel.h>
60 #include <sys/kthread.h>
62 #include <uvm/uvm.h>
64 #include <dev/dkvar.h>
65 #include <machine/xbdvar.h>
67 #include <machine/xen.h>
68 #include <machine/hypervisor.h>
69 #include <machine/evtchn.h>
70 #include <machine/ctrl_if.h>
73 static void control_send(blkif_request_t *, blkif_response_t *);
74 static void send_interface_connect(void);
76 static void xbd_attach(struct device *, struct device *, void *);
77 static int xbd_detach(struct device *, int);
79 #if NXBD > 0
80 int xbd_match(struct device *, struct cfdata *, void *);
81 CFATTACH_DECL(xbd, sizeof(struct xbd_softc),
82 xbd_match, xbd_attach, xbd_detach, NULL);
84 extern struct cfdriver xbd_cd;
85 #endif
87 #if NWD > 0
88 int xbd_wd_match(struct device *, struct cfdata *, void *);
89 CFATTACH_DECL(wd, sizeof(struct xbd_softc),
90 xbd_wd_match, xbd_attach, xbd_detach, NULL);
92 extern struct cfdriver wd_cd;
93 #endif
95 #if NSD > 0
96 int xbd_sd_match(struct device *, struct cfdata *, void *);
97 CFATTACH_DECL(sd, sizeof(struct xbd_softc),
98 xbd_sd_match, xbd_attach, xbd_detach, NULL);
100 extern struct cfdriver sd_cd;
101 #endif
103 #if NCD > 0
104 int xbd_cd_match(struct device *, struct cfdata *, void *);
105 CFATTACH_DECL(cd, sizeof(struct xbd_softc),
106 xbd_cd_match, xbd_attach, xbd_detach, NULL);
108 extern struct cfdriver cd_cd;
109 #endif
112 dev_type_open(xbdopen);
113 dev_type_close(xbdclose);
114 dev_type_read(xbdread);
115 dev_type_write(xbdwrite);
116 dev_type_ioctl(xbdioctl);
117 dev_type_ioctl(xbdioctl_cdev);
118 dev_type_strategy(xbdstrategy);
119 dev_type_dump(xbddump);
120 dev_type_size(xbdsize);
122 #if NXBD > 0
123 const struct bdevsw xbd_bdevsw = {
124 xbdopen, xbdclose, xbdstrategy, xbdioctl,
125 xbddump, xbdsize, D_DISK
126 };
128 const struct cdevsw xbd_cdevsw = {
129 xbdopen, xbdclose, xbdread, xbdwrite, xbdioctl_cdev,
130 nostop, notty, nopoll, nommap, nokqfilter, D_DISK
131 };
133 static dev_t xbd_major;
134 #endif
136 #if NWD > 0
137 const struct bdevsw wd_bdevsw = {
138 xbdopen, xbdclose, xbdstrategy, xbdioctl,
139 xbddump, xbdsize, D_DISK
140 };
142 const struct cdevsw wd_cdevsw = {
143 xbdopen, xbdclose, xbdread, xbdwrite, xbdioctl_cdev,
144 nostop, notty, nopoll, nommap, nokqfilter, D_DISK
145 };
147 static dev_t xbd_wd_major;
148 static dev_t xbd_wd_cdev_major;
149 #endif
151 #if NSD > 0
152 const struct bdevsw sd_bdevsw = {
153 xbdopen, xbdclose, xbdstrategy, xbdioctl,
154 xbddump, xbdsize, D_DISK
155 };
157 const struct cdevsw sd_cdevsw = {
158 xbdopen, xbdclose, xbdread, xbdwrite, xbdioctl_cdev,
159 nostop, notty, nopoll, nommap, nokqfilter, D_DISK
160 };
162 static dev_t xbd_sd_major;
163 static dev_t xbd_sd_cdev_major;
164 #endif
166 #if NCD > 0
167 const struct bdevsw cd_bdevsw = {
168 xbdopen, xbdclose, xbdstrategy, xbdioctl,
169 xbddump, xbdsize, D_DISK
170 };
172 const struct cdevsw cd_cdevsw = {
173 xbdopen, xbdclose, xbdread, xbdwrite, xbdioctl_cdev,
174 nostop, notty, nopoll, nommap, nokqfilter, D_DISK
175 };
177 static dev_t xbd_cd_major;
178 static dev_t xbd_cd_cdev_major;
179 #endif
182 static int xbdstart(struct dk_softc *, struct buf *);
183 static int xbd_response_handler(void *);
184 #if 0
185 static void xbd_update_create_kthread(void *);
186 static void xbd_update_kthread(void *);
187 static int xbd_update_handler(void *);
188 #endif
190 static int xbdinit(struct xbd_softc *, vdisk_t *, struct dk_intf *);
192 /* Pseudo-disk Interface */
193 static struct dk_intf dkintf_esdi = {
194 DTYPE_ESDI,
195 "Xen Virtual ESDI",
196 xbdopen,
197 xbdclose,
198 xbdstrategy,
199 xbdstart,
200 };
201 #if NSD > 0
202 static struct dk_intf dkintf_scsi = {
203 DTYPE_SCSI,
204 "Xen Virtual SCSI",
205 xbdopen,
206 xbdclose,
207 xbdstrategy,
208 xbdstart,
209 };
210 #endif
212 #if NXBD > 0
213 static struct xbd_attach_args xbd_ata = {
214 .xa_device = "xbd",
215 .xa_dkintf = &dkintf_esdi,
216 };
217 #endif
219 #if NWD > 0
220 static struct xbd_attach_args wd_ata = {
221 .xa_device = "wd",
222 .xa_dkintf = &dkintf_esdi,
223 };
224 #endif
226 #if NSD > 0
227 static struct xbd_attach_args sd_ata = {
228 .xa_device = "sd",
229 .xa_dkintf = &dkintf_scsi,
230 };
231 #endif
233 #if NCD > 0
234 static struct xbd_attach_args cd_ata = {
235 .xa_device = "cd",
236 .xa_dkintf = &dkintf_esdi,
237 };
238 #endif
240 static struct sysctlnode *diskcookies;
243 #if defined(XBDDEBUG) && !defined(DEBUG)
244 #define DEBUG
245 #endif
247 #ifdef DEBUG
248 int xbddebug = 0;
250 #define XBDB_FOLLOW 0x1
251 #define XBDB_IO 0x2
252 #define XBDB_SETUP 0x4
253 #define XBDB_HOTPLUG 0x8
255 #define IFDEBUG(x,y) if (xbddebug & (x)) y
256 #define DPRINTF(x,y) IFDEBUG(x, printf y)
257 #define DPRINTF_FOLLOW(y) DPRINTF(XBDB_FOLLOW, y)
258 #define DEBUG_MARK_UNUSED(_xr) (_xr)->xr_sc = (void *)0xdeadbeef
260 struct xbdreq *xbd_allxr;
261 #else
262 #define IFDEBUG(x,y)
263 #define DPRINTF(x,y)
264 #define DPRINTF_FOLLOW(y)
265 #define DEBUG_MARK_UNUSED(_xr)
266 #endif
268 #ifdef DIAGNOSTIC
269 #define DIAGPANIC(x) panic x
270 #define DIAGCONDPANIC(x,y) if (x) panic y
271 #else
272 #define DIAGPANIC(x)
273 #define DIAGCONDPANIC(x,y)
274 #endif
277 struct xbdreq {
278 union {
279 SLIST_ENTRY(xbdreq) _unused; /* ptr. to next free xbdreq */
280 SIMPLEQ_ENTRY(xbdreq) _suspended;
281 /* link when on suspended queue. */
282 } _link;
283 struct xbdreq *xr_parent; /* ptr. to parent xbdreq */
284 struct buf *xr_bp; /* ptr. to original I/O buf */
285 daddr_t xr_bn; /* block no. to process */
286 long xr_bqueue; /* bytes left to queue */
287 long xr_bdone; /* bytes left */
288 vaddr_t xr_data; /* ptr. to data to be proc. */
289 vaddr_t xr_aligned; /* ptr. to aligned data */
290 long xr_breq; /* bytes in this req. */
291 struct xbd_softc *xr_sc; /* ptr. to xbd softc */
292 };
293 #define xr_unused _link._unused
294 #define xr_suspended _link._suspended
296 SLIST_HEAD(,xbdreq) xbdreqs =
297 SLIST_HEAD_INITIALIZER(xbdreqs);
298 static SIMPLEQ_HEAD(, xbdreq) xbdr_suspended =
299 SIMPLEQ_HEAD_INITIALIZER(xbdr_suspended);
301 #define CANGET_XBDREQ() (!SLIST_EMPTY(&xbdreqs))
303 #define GET_XBDREQ(_xr) do { \
304 (_xr) = SLIST_FIRST(&xbdreqs); \
305 if (__predict_true(_xr)) \
306 SLIST_REMOVE_HEAD(&xbdreqs, xr_unused); \
307 } while (/*CONSTCOND*/0)
309 #define PUT_XBDREQ(_xr) do { \
310 DEBUG_MARK_UNUSED(_xr); \
311 SLIST_INSERT_HEAD(&xbdreqs, _xr, xr_unused); \
312 } while (/*CONSTCOND*/0)
314 static struct bufq_state bufq;
315 static int bufq_users = 0;
317 #define XEN_MAJOR(_dev) ((_dev) >> 8)
318 #define XEN_MINOR(_dev) ((_dev) & 0xff)
320 #define XEN_SCSI_DISK0_MAJOR 8
321 #define XEN_SCSI_DISK1_MAJOR 65
322 #define XEN_SCSI_DISK2_MAJOR 66
323 #define XEN_SCSI_DISK3_MAJOR 67
324 #define XEN_SCSI_DISK4_MAJOR 68
325 #define XEN_SCSI_DISK5_MAJOR 69
326 #define XEN_SCSI_DISK6_MAJOR 70
327 #define XEN_SCSI_DISK7_MAJOR 71
328 #define XEN_SCSI_DISK8_MAJOR 128
329 #define XEN_SCSI_DISK9_MAJOR 129
330 #define XEN_SCSI_DISK10_MAJOR 130
331 #define XEN_SCSI_DISK11_MAJOR 131
332 #define XEN_SCSI_DISK12_MAJOR 132
333 #define XEN_SCSI_DISK13_MAJOR 133
334 #define XEN_SCSI_DISK14_MAJOR 134
335 #define XEN_SCSI_DISK15_MAJOR 135
336 #define XEN_SCSI_CDROM_MAJOR 11
338 #define XEN_IDE0_MAJOR 3
339 #define XEN_IDE1_MAJOR 22
340 #define XEN_IDE2_MAJOR 33
341 #define XEN_IDE3_MAJOR 34
342 #define XEN_IDE4_MAJOR 56
343 #define XEN_IDE5_MAJOR 57
344 #define XEN_IDE6_MAJOR 88
345 #define XEN_IDE7_MAJOR 89
346 #define XEN_IDE8_MAJOR 90
347 #define XEN_IDE9_MAJOR 91
349 #define XEN_BSHIFT 9 /* log2(XEN_BSIZE) */
350 #define XEN_BSIZE (1 << XEN_BSHIFT)
352 #define MAX_VBDS 64
353 static int nr_vbds;
354 static vdisk_t *vbd_info;
356 static blkif_ring_t *blk_ring = NULL;
357 static BLKIF_RING_IDX resp_cons; /* Response consumer for comms ring. */
358 static BLKIF_RING_IDX req_prod; /* Private request producer. */
359 static BLKIF_RING_IDX last_req_prod; /* Request producer at last trap. */
361 #define STATE_CLOSED 0
362 #define STATE_DISCONNECTED 1
363 #define STATE_CONNECTED 2
364 static unsigned int state = STATE_CLOSED;
365 static unsigned int blkif_evtchn = 0;
366 static unsigned int blkif_irq = 0;
367 static unsigned int blkif_handle = 0;
369 static int blkif_control_rsp_valid = 0;
370 static blkif_response_t blkif_control_rsp;
372 /** Network interface info. */
373 struct xbd_ctrl {
375 cfprint_t xc_cfprint;
376 struct device *xc_parent;
377 };
379 static struct xbd_ctrl blkctrl;
381 #define XBDUNIT(x) DISKUNIT(x)
382 #define GETXBD_SOFTC(_xs, x) if (!((_xs) = getxbd_softc(x))) return ENXIO
383 #define GETXBD_SOFTC_CDEV(_xs, x) do { \
384 dev_t bx = devsw_chr2blk((x)); \
385 if (bx == NODEV) \
386 return ENXIO; \
387 if (!((_xs) = getxbd_softc(bx))) \
388 return ENXIO; \
389 } while (/*CONSTCOND*/0)
391 static struct xbd_softc *
392 getxbd_softc(dev_t dev)
393 {
394 int unit = XBDUNIT(dev);
396 DPRINTF_FOLLOW(("getxbd_softc(0x%x): major = %d unit = %d\n", dev,
397 major(dev), unit));
398 #if NXBD > 0
399 if (major(dev) == xbd_major)
400 return device_lookup(&xbd_cd, unit);
401 #endif
402 #if NWD > 0
403 if (major(dev) == xbd_wd_major || major(dev) == xbd_wd_cdev_major)
404 return device_lookup(&wd_cd, unit);
405 #endif
406 #if NSD > 0
407 if (major(dev) == xbd_sd_major || major(dev) == xbd_sd_cdev_major)
408 return device_lookup(&sd_cd, unit);
409 #endif
410 #if NCD > 0
411 if (major(dev) == xbd_cd_major || major(dev) == xbd_cd_cdev_major)
412 return device_lookup(&cd_cd, unit);
413 #endif
414 return NULL;
415 }
417 static int
418 get_vbd_info(vdisk_t *disk_info)
419 {
420 vdisk_t *buf;
421 int nr;
422 blkif_request_t req;
423 blkif_response_t rsp;
424 paddr_t pa;
426 buf = (vdisk_t *)uvm_km_kmemalloc1(kmem_map, NULL,
427 PAGE_SIZE, PAGE_SIZE, UVM_UNKNOWN_OFFSET, 0);
428 pmap_extract(pmap_kernel(), (vaddr_t)buf, &pa);
429 /* Probe for disk information. */
430 memset(&req, 0, sizeof(req));
431 req.operation = BLKIF_OP_PROBE;
432 req.nr_segments = 1;
433 req.frame_and_sects[0] = xpmap_ptom_masked(pa) | 7;
435 control_send(&req, &rsp);
436 nr = rsp.status > MAX_VBDS ? MAX_VBDS : rsp.status;
438 if (rsp.status < 0)
439 printf("WARNING: Could not probe disks (%d)\n", rsp.status);
441 memcpy(disk_info, buf, nr * sizeof(vdisk_t));
443 uvm_km_free(kmem_map, (vaddr_t)buf, PAGE_SIZE);
445 return nr;
446 }
448 static struct xbd_attach_args *
449 get_xbda(vdisk_t *xd)
450 {
452 switch (XEN_MAJOR(xd->device)) {
453 #if NSD > 0
454 case XEN_SCSI_DISK0_MAJOR:
455 case XEN_SCSI_DISK1_MAJOR ... XEN_SCSI_DISK7_MAJOR:
456 case XEN_SCSI_DISK8_MAJOR ... XEN_SCSI_DISK15_MAJOR:
457 if (xd->capacity == 0)
458 return NULL;
459 return &sd_ata;
460 case XEN_SCSI_CDROM_MAJOR:
461 return &cd_ata;
462 #endif
463 #if NWD > 0
464 case XEN_IDE0_MAJOR:
465 case XEN_IDE1_MAJOR:
466 case XEN_IDE2_MAJOR:
467 case XEN_IDE3_MAJOR:
468 case XEN_IDE4_MAJOR:
469 case XEN_IDE5_MAJOR:
470 case XEN_IDE6_MAJOR:
471 case XEN_IDE7_MAJOR:
472 case XEN_IDE8_MAJOR:
473 case XEN_IDE9_MAJOR:
474 switch (VDISK_TYPE(xd->info)) {
475 case VDISK_TYPE_CDROM:
476 return &cd_ata;
477 case VDISK_TYPE_DISK:
478 if (xd->capacity == 0)
479 return NULL;
480 return &wd_ata;
481 default:
482 return NULL;
483 }
484 break;
485 #endif
486 default:
487 if (xd->capacity == 0)
488 return NULL;
489 return &xbd_ata;
490 }
491 return NULL;
492 }
494 static void
495 free_interface(void)
496 {
498 /* Prevent new requests being issued until we fix things up. */
499 // simple_lock(&blkif_io_lock);
500 // recovery = 1;
501 state = STATE_DISCONNECTED;
502 // simple_unlock(&blkif_io_lock);
504 /* Free resources associated with old device channel. */
505 if (blk_ring) {
506 uvm_km_free(kmem_map, (vaddr_t)blk_ring, PAGE_SIZE);
507 blk_ring = NULL;
508 }
510 if (blkif_irq) {
511 #if 0
512 free_irq(blkif_irq, NULL);
513 #endif
514 blkif_irq = 0;
515 }
517 if (blkif_evtchn) {
518 #if 0
519 unbind_evtchn_from_irq(blkif_evtchn);
520 #endif
521 blkif_evtchn = 0;
522 }
523 }
525 static void
526 close_interface(void){
527 }
529 static void
530 disconnect_interface(void)
531 {
533 if (blk_ring == NULL)
534 blk_ring = (blkif_ring_t *)uvm_km_kmemalloc1(kmem_map, NULL,
535 PAGE_SIZE, PAGE_SIZE, UVM_UNKNOWN_OFFSET, 0);
536 memset(blk_ring, 0, PAGE_SIZE);
537 blk_ring->req_prod = blk_ring->resp_prod = resp_cons = req_prod =
538 last_req_prod = 0;
539 state = STATE_DISCONNECTED;
540 send_interface_connect();
541 }
543 static void
544 reset_interface(void)
545 {
547 printf("Recovering virtual block device driver\n");
548 free_interface();
549 disconnect_interface();
550 }
552 static void
553 connect_interface(blkif_fe_interface_status_t *status)
554 {
555 // unsigned long flags;
556 struct xbd_attach_args *xbda;
557 vdisk_t *xd;
558 int i;
560 blkif_evtchn = status->evtchn;
561 blkif_irq = bind_evtchn_to_irq(blkif_evtchn);
563 event_set_handler(blkif_irq, &xbd_response_handler, NULL, IPL_BIO);
564 hypervisor_enable_irq(blkif_irq);
566 /* Transition to connected in case we need to do
567 * a partition probe on a whole disk. */
568 state = STATE_CONNECTED;
570 /* Probe for discs attached to the interface. */
571 // xlvbd_init();
572 MALLOC(vbd_info, vdisk_t *, MAX_VBDS * sizeof(vdisk_t),
573 M_DEVBUF, M_WAITOK);
574 memset(vbd_info, 0, MAX_VBDS * sizeof(vdisk_t));
575 nr_vbds = get_vbd_info(vbd_info);
576 if (nr_vbds <= 0)
577 goto out;
579 for (i = 0; i < nr_vbds; i++) {
580 xd = &vbd_info[i];
581 xbda = get_xbda(xd);
582 if (xbda) {
583 xbda->xa_xd = xd;
584 config_found(blkctrl.xc_parent, xbda,
585 blkctrl.xc_cfprint);
586 }
587 }
589 #if 0
590 /* Kick pending requests. */
591 save_and_cli(flags);
592 // simple_lock(&blkif_io_lock);
593 kick_pending_request_queues();
594 // simple_unlock(&blkif_io_lock);
595 restore_flags(flags);
596 #endif
597 return;
599 out:
600 FREE(vbd_info, M_DEVBUF);
601 vbd_info = NULL;
602 return;
603 }
605 static void
606 unexpected(blkif_fe_interface_status_t *status)
607 {
609 printf("Unexpected blkif status %d in state %d\n",
610 status->status, state);
611 }
613 #if 0
614 static struct device *
615 find_device(vdisk_t *xd)
616 {
617 struct device *dv;
618 struct xbd_softc *xs = NULL;
620 for (dv = alldevs.tqh_first; dv != NULL; dv = dv->dv_list.tqe_next) {
621 if (dv->dv_cfattach == NULL ||
622 dv->dv_cfattach->ca_attach != xbd_attach)
623 continue;
624 xs = (struct xbd_softc *)dv;
625 if (xd == NULL || xs->sc_xd_device == xd->device)
626 break;
627 }
628 return dv;
629 }
630 #endif
632 static void
633 blkif_status(blkif_fe_interface_status_t *status)
634 {
636 if (status->handle != blkif_handle) {
637 printf("Invalid blkif: handle=%u", status->handle);
638 return;
639 }
641 switch (status->status) {
642 case BLKIF_INTERFACE_STATUS_CLOSED:
643 switch (state) {
644 case STATE_CLOSED:
645 unexpected(status);
646 break;
647 case STATE_DISCONNECTED:
648 case STATE_CONNECTED:
649 unexpected(status);
650 close_interface();
651 break;
652 }
653 break;
655 case BLKIF_INTERFACE_STATUS_DISCONNECTED:
656 switch (state) {
657 case STATE_CLOSED:
658 disconnect_interface();
659 break;
660 case STATE_DISCONNECTED:
661 case STATE_CONNECTED:
662 unexpected(status);
663 reset_interface();
664 break;
665 }
666 break;
668 case BLKIF_INTERFACE_STATUS_CONNECTED:
669 switch (state) {
670 case STATE_CLOSED:
671 unexpected(status);
672 disconnect_interface();
673 connect_interface(status);
674 break;
675 case STATE_DISCONNECTED:
676 connect_interface(status);
677 break;
678 case STATE_CONNECTED:
679 unexpected(status);
680 connect_interface(status);
681 break;
682 }
683 break;
685 case BLKIF_INTERFACE_STATUS_CHANGED:
686 switch (state) {
687 case STATE_CLOSED:
688 case STATE_DISCONNECTED:
689 unexpected(status);
690 break;
691 case STATE_CONNECTED:
692 #if 0
693 vbd_update();
694 #endif
695 break;
696 }
697 break;
699 default:
700 printf(" Invalid blkif status: %d\n", status->status);
701 break;
702 }
703 }
706 static void
707 xbd_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
708 {
709 switch (msg->subtype) {
710 case CMSG_BLKIF_FE_INTERFACE_STATUS:
711 if (msg->length != sizeof(blkif_fe_interface_status_t))
712 goto parse_error;
713 blkif_status((blkif_fe_interface_status_t *)
714 &msg->msg[0]);
715 break;
716 default:
717 goto parse_error;
718 }
720 ctrl_if_send_response(msg);
721 return;
723 parse_error:
724 msg->length = 0;
725 ctrl_if_send_response(msg);
726 }
728 #if 0
729 static void
730 enable_update_events(struct device *self)
731 {
733 kthread_create(xbd_update_create_kthread, self);
734 event_set_handler(_EVENT_VBD_UPD, &xbd_update_handler, self, IPL_BIO);
735 hypervisor_enable_event(_EVENT_VBD_UPD);
736 }
737 #endif
739 static void
740 signal_requests_to_xen(void)
741 {
743 DPRINTF(XBDB_IO, ("signal_requests_to_xen: %x -> %x\n",
744 blk_ring->req_prod, req_prod));
745 blk_ring->req_prod = req_prod;
746 last_req_prod = req_prod;
748 hypervisor_notify_via_evtchn(blkif_evtchn);
749 return;
750 }
752 static void
753 control_send(blkif_request_t *req, blkif_response_t *rsp)
754 {
755 unsigned long flags;
756 struct xbdreq *xr;
758 retry:
759 while ((req_prod - resp_cons) == BLKIF_RING_SIZE) {
760 tsleep((caddr_t) &req_prod, PUSER | PCATCH,
761 "blkfront", 0);
762 }
764 save_and_cli(flags);
765 // simple_lock(&blkif_io_lock);
766 if ((req_prod - resp_cons) == BLKIF_RING_SIZE) {
767 // simple_unlock(&blkif_io_lock);
768 restore_flags(flags);
769 goto retry;
770 }
772 blk_ring->ring[MASK_BLKIF_IDX(req_prod)].req = *req;
774 GET_XBDREQ(xr);
775 blk_ring->ring[MASK_BLKIF_IDX(req_prod)].req.id = (unsigned long)xr;
776 // rec_ring[id].id = (unsigned long) req;
778 // translate_req_to_pfn( &rec_ring[id], req );
780 req_prod++;
781 signal_requests_to_xen();
783 // simple_unlock(&blkif_io_lock);
784 restore_flags(flags);
786 while (!blkif_control_rsp_valid) {
787 /* XXXcl: sleep/wakeup not ready yet - busy wait for now.
788 * interrupts are still of, so we pick up the control
789 * channel response on return from HYPERVISOR_yield().
790 */
791 #if 0
792 tsleep((caddr_t)&blkif_control_rsp_valid, PUSER | PCATCH,
793 "blkfront", 0);
794 #else
795 HYPERVISOR_yield();
796 #endif
797 }
799 memcpy(rsp, &blkif_control_rsp, sizeof(*rsp));
800 blkif_control_rsp_valid = 0;
801 }
803 /* Send a driver status notification to the domain controller. */
804 static void
805 send_driver_status(int ok)
806 {
807 ctrl_msg_t cmsg = {
808 .type = CMSG_BLKIF_FE,
809 .subtype = CMSG_BLKIF_FE_DRIVER_STATUS,
810 .length = sizeof(blkif_fe_driver_status_t),
811 };
812 blkif_fe_driver_status_t *msg = (blkif_fe_driver_status_t *)cmsg.msg;
814 msg->status = ok ? BLKIF_DRIVER_STATUS_UP : BLKIF_DRIVER_STATUS_DOWN;
816 ctrl_if_send_message_block(&cmsg, NULL, 0, 0);
817 }
819 /* Tell the controller to bring up the interface. */
820 static void
821 send_interface_connect(void)
822 {
823 ctrl_msg_t cmsg = {
824 .type = CMSG_BLKIF_FE,
825 .subtype = CMSG_BLKIF_FE_INTERFACE_CONNECT,
826 .length = sizeof(blkif_fe_interface_connect_t),
827 };
828 blkif_fe_interface_connect_t *msg =
829 (blkif_fe_interface_connect_t *)cmsg.msg;
830 paddr_t pa;
832 pmap_extract(pmap_kernel(), (vaddr_t)blk_ring, &pa);
834 msg->handle = 0;
835 msg->shmem_frame = xpmap_ptom_masked(pa) >> PAGE_SHIFT;
837 ctrl_if_send_message_block(&cmsg, NULL, 0, 0);
838 }
840 static void
841 setup_sysctl(void)
842 {
843 struct sysctlnode *pnode;
845 sysctl_createv(NULL, 0, NULL, NULL,
846 0,
847 CTLTYPE_NODE, "machdep", NULL,
848 NULL, 0, NULL, 0,
849 CTL_MACHDEP, CTL_EOL);
851 sysctl_createv(NULL, 0, NULL, &pnode,
852 0,
853 CTLTYPE_NODE, "domain0", NULL,
854 NULL, 0, NULL, 0,
855 CTL_MACHDEP, CTL_CREATE, CTL_EOL);
857 if (pnode == NULL)
858 return;
860 sysctl_createv(NULL, 0, &pnode, &pnode,
861 0,
862 CTLTYPE_NODE, "diskcookie", NULL,
863 NULL, 0, NULL, 0,
864 CTL_CREATE, CTL_EOL);
866 if (pnode)
867 diskcookies = pnode;
868 }
870 static int
871 xbd_wait_for_interfaces(void)
872 {
874 while (state != STATE_CONNECTED)
875 HYPERVISOR_yield();
876 return 0;
877 }
879 int
880 xbd_scan(struct device *self, struct xbd_attach_args *mainbus_xbda,
881 cfprint_t print)
882 {
883 struct xbdreq *xr;
884 int i;
886 blkctrl.xc_parent = self;
887 blkctrl.xc_cfprint = print;
889 if (xen_start_info.flags & SIF_PRIVILEGED)
890 setup_sysctl();
892 #if NXBD > 0
893 xbd_major = devsw_name2blk("xbd", NULL, 0);
894 #endif
895 #if NWD > 0
896 xbd_wd_major = devsw_name2blk("wd", NULL, 0);
897 /* XXX Also handle the cdev majors since stuff like
898 * read_sector calls strategy on the cdev. This only works if
899 * all the majors we care about are different.
900 */
901 xbd_wd_cdev_major = major(devsw_blk2chr(makedev(xbd_wd_major, 0)));
902 #endif
903 #if NSD > 0
904 xbd_sd_major = devsw_name2blk("sd", NULL, 0);
905 xbd_sd_cdev_major = major(devsw_blk2chr(makedev(xbd_sd_major, 0)));
906 #endif
907 #if NCD > 0
908 xbd_cd_major = devsw_name2blk("cd", NULL, 0);
909 xbd_cd_cdev_major = major(devsw_blk2chr(makedev(xbd_cd_major, 0)));
910 #endif
912 MALLOC(xr, struct xbdreq *, BLKIF_RING_SIZE * sizeof(struct xbdreq),
913 M_DEVBUF, M_WAITOK | M_ZERO);
914 #ifdef DEBUG
915 xbd_allxr = xr;
916 #endif
917 for (i = 0; i < BLKIF_RING_SIZE - 1; i++)
918 PUT_XBDREQ(&xr[i]);
920 (void)ctrl_if_register_receiver(CMSG_BLKIF_FE, xbd_ctrlif_rx,
921 CALLBACK_IN_BLOCKING_CONTEXT);
923 send_driver_status(1);
925 return 0;
926 }
928 void
929 xbd_scan_finish(struct device *parent)
930 {
931 int err;
933 err = xbd_wait_for_interfaces();
934 if (err)
935 ctrl_if_unregister_receiver(CMSG_NETIF_FE, xbd_ctrlif_rx);
936 }
938 #if NXBD > 0
939 int
940 xbd_match(struct device *parent, struct cfdata *match, void *aux)
941 {
942 struct xbd_attach_args *xa = (struct xbd_attach_args *)aux;
944 if (strcmp(xa->xa_device, "xbd") == 0)
945 return 1;
946 return 0;
947 }
948 #endif
950 #if NWD > 0
951 int
952 xbd_wd_match(struct device *parent, struct cfdata *match, void *aux)
953 {
954 struct xbd_attach_args *xa = (struct xbd_attach_args *)aux;
956 if (strcmp(xa->xa_device, "wd") == 0)
957 return 1;
958 return 0;
959 }
960 #endif
962 #if NSD > 0
963 int
964 xbd_sd_match(struct device *parent, struct cfdata *match, void *aux)
965 {
966 struct xbd_attach_args *xa = (struct xbd_attach_args *)aux;
968 if (strcmp(xa->xa_device, "sd") == 0)
969 return 1;
970 return 0;
971 }
972 #endif
974 #if NCD > 0
975 int
976 xbd_cd_match(struct device *parent, struct cfdata *match, void *aux)
977 {
978 struct xbd_attach_args *xa = (struct xbd_attach_args *)aux;
980 if (strcmp(xa->xa_device, "cd") == 0)
981 return 1;
982 return 0;
983 }
984 #endif
986 static void
987 xbd_attach(struct device *parent, struct device *self, void *aux)
988 {
989 struct xbd_attach_args *xbda = (struct xbd_attach_args *)aux;
990 struct xbd_softc *xs = (struct xbd_softc *)self;
992 aprint_normal(": Xen Virtual Block Device");
994 simple_lock_init(&xs->sc_slock);
995 dk_sc_init(&xs->sc_dksc, xs, xs->sc_dev.dv_xname);
996 xbdinit(xs, xbda->xa_xd, xbda->xa_dkintf);
997 if (diskcookies) {
998 /* XXX beware that xs->sc_xd_device is a long */
999 sysctl_createv(NULL, 0, &diskcookies, NULL,
1000 0,
1001 CTLTYPE_INT, xs->sc_dev.dv_xname, NULL,
1002 NULL, 0, &xs->sc_xd_device, 0,
1003 CTL_CREATE, CTL_EOL);
1007 static int
1008 xbd_detach(struct device *dv, int flags)
1010 struct xbd_softc *xs = (struct xbd_softc *)dv;
1012 /*
1013 * Mark disk about to be removed (between now and when the xs
1014 * will be freed).
1015 */
1016 xs->sc_shutdown = 1;
1018 /* And give it some time to settle if it's busy. */
1019 if (xs->sc_dksc.sc_dkdev.dk_busy > 0)
1020 tsleep(&xs, PWAIT, "xbdetach", hz);
1022 /* Detach the disk. */
1023 disk_detach(&xs->sc_dksc.sc_dkdev);
1025 /* XXX decrement bufq_users and free? */
1027 /* XXX no need to remove sysctl nodes since they only exist
1028 * in domain0 and domain0's devices are never removed.
1029 */
1031 return 0;
1034 int
1035 xbdopen(dev_t dev, int flags, int fmt, struct proc *p)
1037 struct xbd_softc *xs;
1039 DPRINTF_FOLLOW(("xbdopen(0x%04x, %d)\n", dev, flags));
1040 switch (fmt) {
1041 case S_IFCHR:
1042 GETXBD_SOFTC_CDEV(xs, dev);
1043 break;
1044 case S_IFBLK:
1045 GETXBD_SOFTC(xs, dev);
1046 break;
1047 default:
1048 return ENXIO;
1050 return dk_open(xs->sc_di, &xs->sc_dksc, dev, flags, fmt, p);
1053 int
1054 xbdclose(dev_t dev, int flags, int fmt, struct proc *p)
1056 struct xbd_softc *xs;
1058 DPRINTF_FOLLOW(("xbdclose(%d, %d)\n", dev, flags));
1059 switch (fmt) {
1060 case S_IFCHR:
1061 GETXBD_SOFTC_CDEV(xs, dev);
1062 break;
1063 case S_IFBLK:
1064 GETXBD_SOFTC(xs, dev);
1065 break;
1066 default:
1067 return ENXIO;
1069 return dk_close(xs->sc_di, &xs->sc_dksc, dev, flags, fmt, p);
1072 void
1073 xbdstrategy(struct buf *bp)
1075 struct xbd_softc *xs = getxbd_softc(bp->b_dev);
1077 DPRINTF_FOLLOW(("xbdstrategy(%p): b_bcount = %ld\n", bp,
1078 (long)bp->b_bcount));
1080 if (xs == NULL || xs->sc_shutdown) {
1081 bp->b_flags |= B_ERROR;
1082 bp->b_error = EIO;
1083 biodone(bp);
1084 return;
1087 dk_strategy(xs->sc_di, &xs->sc_dksc, bp);
1088 return;
1091 int
1092 xbdsize(dev_t dev)
1094 struct xbd_softc *xs = getxbd_softc(dev);
1096 DPRINTF_FOLLOW(("xbdsize(%d)\n", dev));
1097 if (xs == NULL || xs->sc_shutdown)
1098 return -1;
1099 return dk_size(xs->sc_di, &xs->sc_dksc, dev);
1102 static void
1103 map_align(struct xbdreq *xr)
1105 int s;
1107 s = splvm();
1108 xr->xr_aligned = uvm_km_kmemalloc1(kmem_map, NULL,
1109 xr->xr_bqueue, XEN_BSIZE, UVM_UNKNOWN_OFFSET,
1110 0/* UVM_KMF_NOWAIT */);
1111 splx(s);
1112 DPRINTF(XBDB_IO, ("map_align(%p): bp %p addr %p align 0x%08lx "
1113 "size 0x%04lx\n", xr, xr->xr_bp, xr->xr_bp->b_data,
1114 xr->xr_aligned, xr->xr_bqueue));
1115 xr->xr_data = xr->xr_aligned;
1116 if ((xr->xr_bp->b_flags & B_READ) == 0)
1117 memcpy((void *)xr->xr_aligned, xr->xr_bp->b_data,
1118 xr->xr_bqueue);
1121 static void
1122 unmap_align(struct xbdreq *xr)
1124 int s;
1126 if (xr->xr_bp->b_flags & B_READ)
1127 memcpy(xr->xr_bp->b_data, (void *)xr->xr_aligned,
1128 xr->xr_bp->b_bcount);
1129 DPRINTF(XBDB_IO, ("unmap_align(%p): bp %p addr %p align 0x%08lx "
1130 "size 0x%04lx\n", xr, xr->xr_bp, xr->xr_bp->b_data,
1131 xr->xr_aligned, xr->xr_bp->b_bcount));
1132 s = splvm();
1133 uvm_km_free(kmem_map, xr->xr_aligned, xr->xr_bp->b_bcount);
1134 splx(s);
1135 xr->xr_aligned = (vaddr_t)0;
1138 static void
1139 fill_ring(struct xbdreq *xr)
1141 struct xbdreq *pxr = xr->xr_parent;
1142 paddr_t pa;
1143 unsigned long ma;
1144 vaddr_t addr, off;
1145 blkif_request_t *ring_req;
1146 int breq, nr_sectors, fsect, lsect;
1148 /* Fill out a communications ring structure. */
1149 ring_req = &blk_ring->ring[MASK_BLKIF_IDX(req_prod)].req;
1150 ring_req->id = (unsigned long)xr;
1151 ring_req->operation = pxr->xr_bp->b_flags & B_READ ? BLKIF_OP_READ :
1152 BLKIF_OP_WRITE;
1153 ring_req->sector_number = pxr->xr_bn;
1154 ring_req->device = pxr->xr_sc->sc_xd_device;
1156 DPRINTF(XBDB_IO, ("fill_ring(%d): bp %p sector %llu pxr %p xr %p\n",
1157 MASK_BLKIF_IDX(req_prod), pxr->xr_bp,
1158 (unsigned long long)pxr->xr_bn,
1159 pxr, xr));
1161 xr->xr_breq = 0;
1162 ring_req->nr_segments = 0;
1163 addr = trunc_page(pxr->xr_data);
1164 off = pxr->xr_data - addr;
1165 while (pxr->xr_bqueue > 0) {
1166 #if 0
1167 pmap_extract(vm_map_pmap(&bp->b_proc->p_vmspace->vm_map),
1168 addr, &pa);
1169 #else
1170 pmap_extract(pmap_kernel(), addr, &pa);
1171 #endif
1172 ma = xpmap_ptom_masked(pa);
1173 DIAGCONDPANIC((ma & (XEN_BSIZE - 1)) != 0,
1174 ("xbd request ma not sector aligned"));
1176 if (pxr->xr_bqueue > PAGE_SIZE - off)
1177 breq = PAGE_SIZE - off;
1178 else
1179 breq = pxr->xr_bqueue;
1181 nr_sectors = breq >> XEN_BSHIFT;
1182 DIAGCONDPANIC(nr_sectors >= XEN_BSIZE,
1183 ("xbd request nr_sectors >= XEN_BSIZE"));
1185 fsect = off >> XEN_BSHIFT;
1186 lsect = fsect + nr_sectors - 1;
1187 DIAGCONDPANIC(fsect > 7, ("xbd request fsect > 7"));
1188 DIAGCONDPANIC(lsect > 7, ("xbd request lsect > 7"));
1190 DPRINTF(XBDB_IO, ("fill_ring(%d): va 0x%08lx pa 0x%08lx "
1191 "ma 0x%08lx, sectors %d, left %ld/%ld\n",
1192 MASK_BLKIF_IDX(req_prod), addr, pa, ma, nr_sectors,
1193 pxr->xr_bqueue >> XEN_BSHIFT, pxr->xr_bqueue));
1195 ring_req->frame_and_sects[ring_req->nr_segments++] =
1196 ma | (fsect<<3) | lsect;
1197 addr += PAGE_SIZE;
1198 pxr->xr_bqueue -= breq;
1199 pxr->xr_bn += nr_sectors;
1200 xr->xr_breq += breq;
1201 off = 0;
1202 if (ring_req->nr_segments == BLKIF_MAX_SEGMENTS_PER_REQUEST)
1203 break;
1205 pxr->xr_data = addr;
1207 req_prod++;
1210 static void
1211 xbdresume(void)
1213 struct xbdreq *pxr, *xr;
1214 struct xbd_softc *xs;
1215 struct buf *bp;
1217 while ((pxr = SIMPLEQ_FIRST(&xbdr_suspended)) != NULL) {
1218 DPRINTF(XBDB_IO, ("xbdstart: resuming xbdreq %p for bp %p\n",
1219 pxr, pxr->xr_bp));
1220 bp = pxr->xr_bp;
1221 xs = getxbd_softc(bp->b_dev);
1222 if (xs == NULL || xs->sc_shutdown) {
1223 bp->b_flags |= B_ERROR;
1224 bp->b_error = EIO;
1226 if (bp->b_flags & B_ERROR) {
1227 pxr->xr_bdone -= pxr->xr_bqueue;
1228 pxr->xr_bqueue = 0;
1229 if (pxr->xr_bdone == 0) {
1230 bp->b_resid = bp->b_bcount;
1231 if (pxr->xr_aligned)
1232 unmap_align(pxr);
1233 PUT_XBDREQ(pxr);
1234 if (xs)
1235 disk_unbusy(&xs->sc_dksc.sc_dkdev,
1236 (bp->b_bcount - bp->b_resid),
1237 (bp->b_flags & B_READ));
1238 biodone(bp);
1240 continue;
1242 while (__predict_true(pxr->xr_bqueue > 0)) {
1243 GET_XBDREQ(xr);
1244 if (__predict_false(xr == NULL))
1245 goto out;
1246 xr->xr_parent = pxr;
1247 fill_ring(xr);
1249 DPRINTF(XBDB_IO, ("xbdstart: resumed xbdreq %p for bp %p\n",
1250 pxr, bp));
1251 SIMPLEQ_REMOVE_HEAD(&xbdr_suspended, xr_suspended);
1254 out:
1255 return;
1258 static int
1259 xbdstart(struct dk_softc *dksc, struct buf *bp)
1261 struct xbd_softc *xs;
1262 struct xbdreq *pxr, *xr;
1263 struct partition *pp;
1264 daddr_t bn;
1265 int ret, runqueue;
1267 DPRINTF_FOLLOW(("xbdstart(%p, %p)\n", dksc, bp));
1269 runqueue = 1;
1270 ret = -1;
1272 xs = getxbd_softc(bp->b_dev);
1273 if (xs == NULL || xs->sc_shutdown) {
1274 bp->b_flags |= B_ERROR;
1275 bp->b_error = EIO;
1276 biodone(bp);
1277 return 0;
1279 dksc = &xs->sc_dksc;
1281 /* XXXrcd:
1282 * Translate partition relative blocks to absolute blocks,
1283 * this probably belongs (somehow) in dksubr.c, since it
1284 * is independant of the underlying code... This will require
1285 * that the interface be expanded slightly, though.
1286 */
1287 bn = bp->b_blkno;
1288 if (DISKPART(bp->b_dev) != RAW_PART) {
1289 pp = &xs->sc_dksc.sc_dkdev.dk_label->
1290 d_partitions[DISKPART(bp->b_dev)];
1291 bn += pp->p_offset;
1294 DPRINTF(XBDB_IO, ("xbdstart: addr %p, sector %llu, "
1295 "count %ld [%s]\n", bp->b_data, (unsigned long long)bn,
1296 bp->b_bcount, bp->b_flags & B_READ ? "read" : "write"));
1298 GET_XBDREQ(pxr);
1299 if (__predict_false(pxr == NULL))
1300 goto out;
1302 disk_busy(&dksc->sc_dkdev); /* XXX: put in dksubr.c */
1303 /*
1304 * We have a request slot, return 0 to make dk_start remove
1305 * the bp from the work queue.
1306 */
1307 ret = 0;
1309 pxr->xr_bp = bp;
1310 pxr->xr_parent = pxr;
1311 pxr->xr_bn = bn;
1312 pxr->xr_bqueue = bp->b_bcount;
1313 pxr->xr_bdone = bp->b_bcount;
1314 pxr->xr_data = (vaddr_t)bp->b_data;
1315 pxr->xr_sc = xs;
1317 if (pxr->xr_data & (XEN_BSIZE - 1))
1318 map_align(pxr);
1320 fill_ring(pxr);
1322 while (__predict_false(pxr->xr_bqueue > 0)) {
1323 GET_XBDREQ(xr);
1324 if (__predict_false(xr == NULL))
1325 break;
1326 xr->xr_parent = pxr;
1327 fill_ring(xr);
1330 if (__predict_false(pxr->xr_bqueue > 0)) {
1331 SIMPLEQ_INSERT_TAIL(&xbdr_suspended, pxr,
1332 xr_suspended);
1333 DPRINTF(XBDB_IO, ("xbdstart: suspended xbdreq %p "
1334 "for bp %p\n", pxr, bp));
1335 } else if (CANGET_XBDREQ() && BUFQ_PEEK(&bufq) != NULL) {
1336 /*
1337 * We have enough resources to start another bp and
1338 * there are additional bps on the queue, dk_start
1339 * will call us again and we'll run the queue then.
1340 */
1341 runqueue = 0;
1344 out:
1345 if (runqueue && last_req_prod != req_prod)
1346 signal_requests_to_xen();
1348 return ret;
1351 static int
1352 xbd_response_handler(void *arg)
1354 struct buf *bp;
1355 struct xbd_softc *xs;
1356 blkif_response_t *ring_resp;
1357 struct xbdreq *pxr, *xr;
1358 BLKIF_RING_IDX i, rp;
1360 rp = blk_ring->resp_prod;
1361 __insn_barrier(); /* Ensure we see queued responses up to 'rp'. */
1363 for (i = resp_cons; i != rp; i++) {
1364 ring_resp = &blk_ring->ring[MASK_BLKIF_IDX(i)].resp;
1365 xr = (struct xbdreq *)ring_resp->id;
1367 switch (ring_resp->operation) {
1368 case BLKIF_OP_READ:
1369 case BLKIF_OP_WRITE:
1370 pxr = xr->xr_parent;
1372 DPRINTF(XBDB_IO, ("xbd_response_handler(%d): pxr %p "
1373 "xr %p bdone %04lx breq %04lx\n", i, pxr,
1374 xr, pxr->xr_bdone, xr->xr_breq));
1375 pxr->xr_bdone -= xr->xr_breq;
1376 DIAGCONDPANIC(pxr->xr_bdone < 0,
1377 ("xbd_response_handler: pxr->xr_bdone < 0"));
1379 if (__predict_false(ring_resp->status)) {
1380 pxr->xr_bp->b_flags |= B_ERROR;
1381 pxr->xr_bp->b_error = EIO;
1384 if (xr != pxr) {
1385 PUT_XBDREQ(xr);
1386 if (!SIMPLEQ_EMPTY(&xbdr_suspended))
1387 xbdresume();
1390 if (pxr->xr_bdone == 0) {
1391 bp = pxr->xr_bp;
1392 xs = getxbd_softc(bp->b_dev);
1393 if (xs == NULL) { /* don't fail bp if we're shutdown */
1394 bp->b_flags |= B_ERROR;
1395 bp->b_error = EIO;
1397 DPRINTF(XBDB_IO, ("xbd_response_handler(%d): "
1398 "completed bp %p\n", i, bp));
1399 if (bp->b_flags & B_ERROR)
1400 bp->b_resid = bp->b_bcount;
1401 else
1402 bp->b_resid = 0;
1404 if (pxr->xr_aligned)
1405 unmap_align(pxr);
1407 PUT_XBDREQ(pxr);
1408 if (xs)
1409 disk_unbusy(&xs->sc_dksc.sc_dkdev,
1410 (bp->b_bcount - bp->b_resid),
1411 (bp->b_flags & B_READ));
1412 biodone(bp);
1413 if (!SIMPLEQ_EMPTY(&xbdr_suspended))
1414 xbdresume();
1415 /* XXX possible lockup if this was the only
1416 * active device and requests were held back in
1417 * the queue.
1418 */
1419 if (xs)
1420 dk_iodone(xs->sc_di, &xs->sc_dksc);
1422 break;
1423 case BLKIF_OP_PROBE:
1424 memcpy(&blkif_control_rsp, ring_resp,
1425 sizeof(*ring_resp));
1426 blkif_control_rsp_valid = 1;
1427 wakeup((caddr_t)&blkif_control_rsp_valid);
1428 break;
1429 default:
1430 panic("unknown response");
1433 resp_cons = i;
1434 /* check if xbdresume queued any requests */
1435 if (last_req_prod != req_prod)
1436 signal_requests_to_xen();
1437 return 0;
1440 #if 0
1441 static void
1442 xbd_update_create_kthread(void *arg)
1445 kthread_create1(xbd_update_kthread, arg, NULL, "xbdupdate");
1448 static void
1449 xbd_update_kthread(void *arg)
1451 struct device *parent = arg;
1452 struct xbd_attach_args *xbda;
1453 struct device *dev;
1454 vdisk_t *xd;
1455 vdisk_t *vbd_info_update, *vbd_info_old;
1456 int i, j, new_nr_vbds;
1457 extern int hypervisor_print(void *, const char *);
1459 MALLOC(vbd_info_update, vdisk_t *, MAX_VBDS *
1460 sizeof(vdisk_t), M_DEVBUF, M_WAITOK);
1462 for (;;) {
1463 memset(vbd_info_update, 0, MAX_VBDS * sizeof(vdisk_t));
1464 new_nr_vbds = get_vbd_info(vbd_info_update);
1466 if (memcmp(vbd_info, vbd_info_update, MAX_VBDS *
1467 sizeof(vdisk_t)) == 0) {
1468 FREE(vbd_info_update, M_DEVBUF);
1469 tsleep(parent, PWAIT, "xbdupd", 0);
1470 MALLOC(vbd_info_update, vdisk_t *, MAX_VBDS *
1471 sizeof(vdisk_t), M_DEVBUF, M_WAITOK);
1472 continue;
1475 j = 0;
1476 for (i = 0; i < new_nr_vbds; i++) {
1477 while (j < nr_vbds &&
1478 vbd_info[j].device < vbd_info_update[i].device) {
1479 DPRINTF(XBDB_HOTPLUG,
1480 ("delete device %x size %lx\n",
1481 vbd_info[j].device,
1482 vbd_info[j].capacity));
1483 xd = &vbd_info[j];
1484 dev = find_device(xd);
1485 if (dev)
1486 config_detach(dev, DETACH_FORCE);
1487 j++;
1489 if (j < nr_vbds &&
1490 vbd_info[j].device == vbd_info_update[i].device) {
1491 DPRINTF(XBDB_HOTPLUG,
1492 ("update device %x size %lx size %lx\n",
1493 vbd_info_update[i].device,
1494 vbd_info[j].capacity,
1495 vbd_info_update[i].capacity));
1496 j++;
1497 } else {
1498 DPRINTF(XBDB_HOTPLUG,
1499 ("add device %x size %lx\n",
1500 vbd_info_update[i].device,
1501 vbd_info_update[i].capacity));
1502 xd = &vbd_info_update[i];
1503 xbda = get_xbda(xd);
1504 if (xbda) {
1505 xbda->xa_xd = xd;
1506 config_found(parent, xbda, hypervisor_print);
1511 while (j < nr_vbds) {
1512 DPRINTF(XBDB_HOTPLUG, ("delete device %x\n",
1513 vbd_info[j].device));
1514 xd = &vbd_info[j];
1515 dev = find_device(xd);
1516 if (dev)
1517 config_detach(dev, DETACH_FORCE);
1518 j++;
1521 nr_vbds = new_nr_vbds;
1523 vbd_info_old = vbd_info;
1524 vbd_info = vbd_info_update;
1525 vbd_info_update = vbd_info_old;
1529 static int
1530 xbd_update_handler(void *arg)
1533 wakeup(arg);
1535 return 0;
1537 #endif
1539 /* XXX: we should probably put these into dksubr.c, mostly */
1540 int
1541 xbdread(dev_t dev, struct uio *uio, int flags)
1543 struct xbd_softc *xs;
1544 struct dk_softc *dksc;
1546 DPRINTF_FOLLOW(("xbdread(%d, %p, %d)\n", dev, uio, flags));
1547 GETXBD_SOFTC_CDEV(xs, dev);
1548 dksc = &xs->sc_dksc;
1549 if ((dksc->sc_flags & DKF_INITED) == 0)
1550 return ENXIO;
1551 /* XXX see the comments about minphys in ccd.c */
1552 return physio(xbdstrategy, NULL, dev, B_READ, minphys, uio);
1555 /* XXX: we should probably put these into dksubr.c, mostly */
1556 int
1557 xbdwrite(dev_t dev, struct uio *uio, int flags)
1559 struct xbd_softc *xs;
1560 struct dk_softc *dksc;
1562 DPRINTF_FOLLOW(("xbdwrite(%d, %p, %d)\n", dev, uio, flags));
1563 GETXBD_SOFTC_CDEV(xs, dev);
1564 dksc = &xs->sc_dksc;
1565 if ((dksc->sc_flags & DKF_INITED) == 0)
1566 return ENXIO;
1567 /* XXX see the comments about minphys in ccd.c */
1568 return physio(xbdstrategy, NULL, dev, B_WRITE, minphys, uio);
1571 int
1572 xbdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
1574 struct xbd_softc *xs;
1575 struct dk_softc *dksc;
1576 int ret;
1578 DPRINTF_FOLLOW(("xbdioctl(%d, %08lx, %p, %d, %p)\n",
1579 dev, cmd, data, flag, p));
1580 GETXBD_SOFTC(xs, dev);
1581 dksc = &xs->sc_dksc;
1583 if ((ret = lockmgr(&dksc->sc_lock, LK_EXCLUSIVE, NULL)) != 0)
1584 return ret;
1586 switch (cmd) {
1587 default:
1588 ret = dk_ioctl(xs->sc_di, dksc, dev, cmd, data, flag, p);
1589 break;
1592 lockmgr(&dksc->sc_lock, LK_RELEASE, NULL);
1593 return ret;
1596 int
1597 xbdioctl_cdev(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
1599 dev_t bdev;
1601 bdev = devsw_chr2blk(dev);
1602 if (bdev == NODEV)
1603 return ENXIO;
1604 return xbdioctl(bdev, cmd, data, flag, p);
1607 int
1608 xbddump(dev_t dev, daddr_t blkno, caddr_t va, size_t size)
1610 struct xbd_softc *xs;
1612 DPRINTF_FOLLOW(("xbddump(%d, %" PRId64 ", %p, %lu)\n", dev, blkno, va,
1613 (unsigned long)size));
1614 GETXBD_SOFTC(xs, dev);
1615 return dk_dump(xs->sc_di, &xs->sc_dksc, dev, blkno, va, size);
1618 static int
1619 xbdinit(struct xbd_softc *xs, vdisk_t *xd, struct dk_intf *dkintf)
1621 struct dk_geom *pdg;
1622 char buf[9];
1623 int ret;
1625 ret = 0;
1627 xs->sc_dksc.sc_size = xd->capacity;
1628 xs->sc_xd_device = xd->device;
1629 xs->sc_di = dkintf;
1630 xs->sc_shutdown = 0;
1632 /*
1633 * XXX here we should probe the underlying device. If we
1634 * are accessing a partition of type RAW_PART, then
1635 * we should populate our initial geometry with the
1636 * geometry that we discover from the device.
1637 */
1638 pdg = &xs->sc_dksc.sc_geom;
1639 pdg->pdg_secsize = DEV_BSIZE;
1640 pdg->pdg_ntracks = 1;
1641 pdg->pdg_nsectors = 1024 * (1024 / pdg->pdg_secsize);
1642 pdg->pdg_ncylinders = xs->sc_dksc.sc_size / pdg->pdg_nsectors;
1644 /*
1645 * We have one shared bufq for all devices because otherwise
1646 * requests can stall if there were no free request slots
1647 * available in xbdstart and this device had no requests
1648 * in-flight which would trigger a dk_start from the interrupt
1649 * handler.
1650 * XXX this assumes that we can just memcpy struct bufq_state
1651 * to share it between devices.
1652 * XXX we reference count the usage in case so we can de-alloc
1653 * the bufq if all devices are deconfigured.
1654 */
1655 if (bufq_users == 0) {
1656 bufq_alloc(&bufq, BUFQ_FCFS);
1657 bufq_users = 1;
1659 memcpy(&xs->sc_dksc.sc_bufq, &bufq, sizeof(struct bufq_state));
1661 xs->sc_dksc.sc_flags |= DKF_INITED;
1663 /* Attach the disk. */
1664 disk_attach(&xs->sc_dksc.sc_dkdev);
1666 /* Try and read the disklabel. */
1667 dk_getdisklabel(xs->sc_di, &xs->sc_dksc, 0 /* XXX ? */);
1669 format_bytes(buf, sizeof(buf), (uint64_t)xs->sc_dksc.sc_size *
1670 pdg->pdg_secsize);
1671 printf(" %s\n", buf);
1673 /* out: */
1674 return ret;