1185ace93SMatthew Dillon /* 2185ace93SMatthew Dillon * Copyright (c) 2012 The DragonFly Project. All rights reserved. 3185ace93SMatthew Dillon * 4185ace93SMatthew Dillon * This code is derived from software contributed to The DragonFly Project 5185ace93SMatthew Dillon * by Matthew Dillon <dillon@backplane.com> 6185ace93SMatthew Dillon * 7185ace93SMatthew Dillon * Redistribution and use in source and binary forms, with or without 8185ace93SMatthew Dillon * modification, are permitted provided that the following conditions 9185ace93SMatthew Dillon * are met: 10185ace93SMatthew Dillon * 11185ace93SMatthew Dillon * 1. Redistributions of source code must retain the above copyright 12185ace93SMatthew Dillon * notice, this list of conditions and the following disclaimer. 13185ace93SMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright 14185ace93SMatthew Dillon * notice, this list of conditions and the following disclaimer in 15185ace93SMatthew Dillon * the documentation and/or other materials provided with the 16185ace93SMatthew Dillon * distribution. 17185ace93SMatthew Dillon * 3. Neither the name of The DragonFly Project nor the names of its 18185ace93SMatthew Dillon * contributors may be used to endorse or promote products derived 19185ace93SMatthew Dillon * from this software without specific, prior written permission. 20185ace93SMatthew Dillon * 21185ace93SMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22185ace93SMatthew Dillon * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23185ace93SMatthew Dillon * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24185ace93SMatthew Dillon * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25185ace93SMatthew Dillon * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26185ace93SMatthew Dillon * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27185ace93SMatthew Dillon * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28185ace93SMatthew Dillon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29185ace93SMatthew Dillon * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30185ace93SMatthew Dillon * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31185ace93SMatthew Dillon * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32185ace93SMatthew Dillon * SUCH DAMAGE. 33185ace93SMatthew Dillon */ 34185ace93SMatthew Dillon #include <sys/param.h> 35185ace93SMatthew Dillon #include <sys/systm.h> 36185ace93SMatthew Dillon #include <sys/kernel.h> 37185ace93SMatthew Dillon #include <sys/proc.h> 38185ace93SMatthew Dillon #include <sys/sysctl.h> 39185ace93SMatthew Dillon #include <sys/buf.h> 40185ace93SMatthew Dillon #include <sys/conf.h> 41185ace93SMatthew Dillon #include <sys/disklabel.h> 42185ace93SMatthew Dillon #include <sys/disklabel32.h> 43185ace93SMatthew Dillon #include <sys/disklabel64.h> 44185ace93SMatthew Dillon #include <sys/diskslice.h> 45185ace93SMatthew Dillon #include <sys/diskmbr.h> 46185ace93SMatthew Dillon #include <sys/disk.h> 47185ace93SMatthew Dillon #include <sys/malloc.h> 48185ace93SMatthew Dillon #include <sys/device.h> 49185ace93SMatthew Dillon #include <sys/devfs.h> 50185ace93SMatthew Dillon #include <sys/thread.h> 51185ace93SMatthew Dillon #include <sys/queue.h> 52185ace93SMatthew Dillon #include <sys/lock.h> 538d6d37b8SMatthew Dillon #include <sys/stat.h> 54185ace93SMatthew Dillon #include <sys/uuid.h> 55185ace93SMatthew Dillon #include <sys/dmsg.h> 56185ace93SMatthew Dillon 57185ace93SMatthew Dillon #include <sys/buf2.h> 58185ace93SMatthew Dillon #include <sys/mplock2.h> 59185ace93SMatthew Dillon #include <sys/msgport2.h> 60185ace93SMatthew Dillon #include <sys/thread2.h> 61185ace93SMatthew Dillon 628d6d37b8SMatthew Dillon struct dios_open { 638d6d37b8SMatthew Dillon int openrd; 648d6d37b8SMatthew Dillon int openwr; 658d6d37b8SMatthew Dillon }; 668d6d37b8SMatthew Dillon 678d6d37b8SMatthew Dillon struct dios_io { 688d6d37b8SMatthew Dillon int count; 698d6d37b8SMatthew Dillon int eof; 70*1a2a529dSMatthew Dillon kdmsg_data_t data; 718d6d37b8SMatthew Dillon }; 728d6d37b8SMatthew Dillon 73185ace93SMatthew Dillon static MALLOC_DEFINE(M_DMSG_DISK, "dmsg_disk", "disk dmsg"); 74185ace93SMatthew Dillon 75185ace93SMatthew Dillon static int disk_iocom_reconnect(struct disk *dp, struct file *fp); 7603d99ea4SMatthew Dillon static int disk_rcvdmsg(kdmsg_msg_t *msg); 77185ace93SMatthew Dillon 788d6d37b8SMatthew Dillon static void disk_blk_open(struct disk *dp, kdmsg_msg_t *msg); 798d6d37b8SMatthew Dillon static void disk_blk_read(struct disk *dp, kdmsg_msg_t *msg); 808d6d37b8SMatthew Dillon static void disk_blk_write(struct disk *dp, kdmsg_msg_t *msg); 818d6d37b8SMatthew Dillon static void disk_blk_flush(struct disk *dp, kdmsg_msg_t *msg); 828d6d37b8SMatthew Dillon static void disk_blk_freeblks(struct disk *dp, kdmsg_msg_t *msg); 838d6d37b8SMatthew Dillon static void diskiodone(struct bio *bio); 848d6d37b8SMatthew Dillon 85185ace93SMatthew Dillon void 86185ace93SMatthew Dillon disk_iocom_init(struct disk *dp) 87185ace93SMatthew Dillon { 8803d99ea4SMatthew Dillon kdmsg_iocom_init(&dp->d_iocom, dp, 8903d99ea4SMatthew Dillon KDMSG_IOCOMF_AUTOCONN | 908e226bc8SMatthew Dillon KDMSG_IOCOMF_AUTORXSPAN | 911b8eded1SMatthew Dillon KDMSG_IOCOMF_AUTOTXSPAN, 9203d99ea4SMatthew Dillon M_DMSG_DISK, disk_rcvdmsg); 93185ace93SMatthew Dillon } 94185ace93SMatthew Dillon 95185ace93SMatthew Dillon void 96185ace93SMatthew Dillon disk_iocom_update(struct disk *dp) 97185ace93SMatthew Dillon { 98185ace93SMatthew Dillon } 99185ace93SMatthew Dillon 100185ace93SMatthew Dillon void 101185ace93SMatthew Dillon disk_iocom_uninit(struct disk *dp) 102185ace93SMatthew Dillon { 103185ace93SMatthew Dillon kdmsg_iocom_uninit(&dp->d_iocom); 104185ace93SMatthew Dillon } 105185ace93SMatthew Dillon 106185ace93SMatthew Dillon int 107185ace93SMatthew Dillon disk_iocom_ioctl(struct disk *dp, int cmd, void *data) 108185ace93SMatthew Dillon { 109185ace93SMatthew Dillon struct file *fp; 110185ace93SMatthew Dillon struct disk_ioc_recluster *recl; 111185ace93SMatthew Dillon int error; 112185ace93SMatthew Dillon 113185ace93SMatthew Dillon switch(cmd) { 114185ace93SMatthew Dillon case DIOCRECLUSTER: 115185ace93SMatthew Dillon recl = data; 116185ace93SMatthew Dillon fp = holdfp(curproc->p_fd, recl->fd, -1); 117185ace93SMatthew Dillon if (fp) { 118185ace93SMatthew Dillon error = disk_iocom_reconnect(dp, fp); 119185ace93SMatthew Dillon } else { 120185ace93SMatthew Dillon error = EINVAL; 121185ace93SMatthew Dillon } 122185ace93SMatthew Dillon break; 123185ace93SMatthew Dillon default: 124185ace93SMatthew Dillon error = EOPNOTSUPP; 125185ace93SMatthew Dillon break; 126185ace93SMatthew Dillon } 127185ace93SMatthew Dillon return error; 128185ace93SMatthew Dillon } 129185ace93SMatthew Dillon 130185ace93SMatthew Dillon static 131185ace93SMatthew Dillon int 132185ace93SMatthew Dillon disk_iocom_reconnect(struct disk *dp, struct file *fp) 133185ace93SMatthew Dillon { 134185ace93SMatthew Dillon char devname[64]; 135185ace93SMatthew Dillon 136185ace93SMatthew Dillon ksnprintf(devname, sizeof(devname), "%s%d", 137185ace93SMatthew Dillon dev_dname(dp->d_rawdev), dkunit(dp->d_rawdev)); 138185ace93SMatthew Dillon 139185ace93SMatthew Dillon kdmsg_iocom_reconnect(&dp->d_iocom, fp, devname); 140185ace93SMatthew Dillon 14103d99ea4SMatthew Dillon dp->d_iocom.auto_lnk_conn.pfs_type = DMSG_PFSTYPE_SERVER; 14203d99ea4SMatthew Dillon dp->d_iocom.auto_lnk_conn.proto_version = DMSG_SPAN_PROTO_1; 14303d99ea4SMatthew Dillon dp->d_iocom.auto_lnk_conn.peer_type = DMSG_PEER_BLOCK; 14403d99ea4SMatthew Dillon dp->d_iocom.auto_lnk_conn.peer_mask = 1LLU << DMSG_PEER_BLOCK; 14503d99ea4SMatthew Dillon dp->d_iocom.auto_lnk_conn.pfs_mask = (uint64_t)-1; 14603d99ea4SMatthew Dillon ksnprintf(dp->d_iocom.auto_lnk_conn.cl_label, 14703d99ea4SMatthew Dillon sizeof(dp->d_iocom.auto_lnk_conn.cl_label), 148185ace93SMatthew Dillon "%s/%s", hostname, devname); 14903d99ea4SMatthew Dillon if (dp->d_info.d_serialno) { 15003d99ea4SMatthew Dillon ksnprintf(dp->d_iocom.auto_lnk_conn.fs_label, 15103d99ea4SMatthew Dillon sizeof(dp->d_iocom.auto_lnk_conn.fs_label), 15203d99ea4SMatthew Dillon "%s", dp->d_info.d_serialno); 15303d99ea4SMatthew Dillon } 15403d99ea4SMatthew Dillon 15503d99ea4SMatthew Dillon dp->d_iocom.auto_lnk_span.pfs_type = DMSG_PFSTYPE_SERVER; 15603d99ea4SMatthew Dillon dp->d_iocom.auto_lnk_span.proto_version = DMSG_SPAN_PROTO_1; 15703d99ea4SMatthew Dillon dp->d_iocom.auto_lnk_span.peer_type = DMSG_PEER_BLOCK; 15803d99ea4SMatthew Dillon dp->d_iocom.auto_lnk_span.media.block.bytes = 15903d99ea4SMatthew Dillon dp->d_info.d_media_size; 16003d99ea4SMatthew Dillon dp->d_iocom.auto_lnk_span.media.block.blksize = 16103d99ea4SMatthew Dillon dp->d_info.d_media_blksize; 16203d99ea4SMatthew Dillon ksnprintf(dp->d_iocom.auto_lnk_span.cl_label, 16303d99ea4SMatthew Dillon sizeof(dp->d_iocom.auto_lnk_span.cl_label), 16403d99ea4SMatthew Dillon "%s/%s", hostname, devname); 16503d99ea4SMatthew Dillon if (dp->d_info.d_serialno) { 16603d99ea4SMatthew Dillon ksnprintf(dp->d_iocom.auto_lnk_span.fs_label, 16703d99ea4SMatthew Dillon sizeof(dp->d_iocom.auto_lnk_span.fs_label), 16803d99ea4SMatthew Dillon "%s", dp->d_info.d_serialno); 16903d99ea4SMatthew Dillon } 17003d99ea4SMatthew Dillon 17103d99ea4SMatthew Dillon kdmsg_iocom_autoinitiate(&dp->d_iocom, NULL); 172185ace93SMatthew Dillon 173185ace93SMatthew Dillon return (0); 174185ace93SMatthew Dillon } 175185ace93SMatthew Dillon 17659b728a7SSascha Wildner static int 17703d99ea4SMatthew Dillon disk_rcvdmsg(kdmsg_msg_t *msg) 178185ace93SMatthew Dillon { 1791b8eded1SMatthew Dillon struct disk *dp = msg->state->iocom->handle; 180185ace93SMatthew Dillon 1818d6d37b8SMatthew Dillon /* 1828d6d37b8SMatthew Dillon * Handle debug messages (these might not be in transactions) 1838d6d37b8SMatthew Dillon */ 1848d6d37b8SMatthew Dillon switch(msg->any.head.cmd & DMSGF_CMDSWMASK) { 185185ace93SMatthew Dillon case DMSG_DBG_SHELL: 186185ace93SMatthew Dillon /* 187185ace93SMatthew Dillon * Execute shell command (not supported atm) 188185ace93SMatthew Dillon */ 189185ace93SMatthew Dillon kdmsg_msg_reply(msg, DMSG_ERR_NOSUPP); 1908d6d37b8SMatthew Dillon return(0); 191185ace93SMatthew Dillon case DMSG_DBG_SHELL | DMSGF_REPLY: 192185ace93SMatthew Dillon if (msg->aux_data) { 193185ace93SMatthew Dillon msg->aux_data[msg->aux_size - 1] = 0; 19403d99ea4SMatthew Dillon kprintf("diskiocom: DEBUGMSG: %s\n", msg->aux_data); 195185ace93SMatthew Dillon } 1968d6d37b8SMatthew Dillon return(0); 1978d6d37b8SMatthew Dillon } 1988d6d37b8SMatthew Dillon 1998d6d37b8SMatthew Dillon /* 200d34b92afSMatthew Dillon * All remaining messages must be in a transaction. 201d34b92afSMatthew Dillon * 202d34b92afSMatthew Dillon * NOTE! We currently don't care if the transaction is just 203d34b92afSMatthew Dillon * the span transaction (for disk probes) or if it is the 204d34b92afSMatthew Dillon * BLK_OPEN transaction. 2058d6d37b8SMatthew Dillon * 2068d6d37b8SMatthew Dillon * NOTE! We are switching on the first message's command. The 2078d6d37b8SMatthew Dillon * actual message command within the transaction may be 2088d6d37b8SMatthew Dillon * different (if streaming within a transaction). 2098d6d37b8SMatthew Dillon */ 2101b8eded1SMatthew Dillon if (msg->state == &msg->state->iocom->state0) { 211185ace93SMatthew Dillon kdmsg_msg_reply(msg, DMSG_ERR_NOSUPP); 2128d6d37b8SMatthew Dillon return(0); 2138d6d37b8SMatthew Dillon } 2148d6d37b8SMatthew Dillon 2158d6d37b8SMatthew Dillon switch(msg->state->rxcmd & DMSGF_CMDSWMASK) { 2168d6d37b8SMatthew Dillon case DMSG_BLK_OPEN: 2178d6d37b8SMatthew Dillon disk_blk_open(dp, msg); 2188d6d37b8SMatthew Dillon break; 2198d6d37b8SMatthew Dillon case DMSG_BLK_READ: 220d34b92afSMatthew Dillon /* 221d34b92afSMatthew Dillon * not reached normally but leave in for completeness 222d34b92afSMatthew Dillon */ 2238d6d37b8SMatthew Dillon disk_blk_read(dp, msg); 2248d6d37b8SMatthew Dillon break; 2258d6d37b8SMatthew Dillon case DMSG_BLK_WRITE: 2268d6d37b8SMatthew Dillon disk_blk_write(dp, msg); 2278d6d37b8SMatthew Dillon break; 2288d6d37b8SMatthew Dillon case DMSG_BLK_FLUSH: 2298d6d37b8SMatthew Dillon disk_blk_flush(dp, msg); 2308d6d37b8SMatthew Dillon break; 2318d6d37b8SMatthew Dillon case DMSG_BLK_FREEBLKS: 2328d6d37b8SMatthew Dillon disk_blk_freeblks(dp, msg); 2338d6d37b8SMatthew Dillon break; 2348d6d37b8SMatthew Dillon default: 2358d6d37b8SMatthew Dillon if ((msg->any.head.cmd & DMSGF_REPLY) == 0) { 2368d6d37b8SMatthew Dillon if (msg->any.head.cmd & DMSGF_DELETE) 2378d6d37b8SMatthew Dillon kdmsg_msg_reply(msg, DMSG_ERR_NOSUPP); 2388d6d37b8SMatthew Dillon else 2398d6d37b8SMatthew Dillon kdmsg_msg_result(msg, DMSG_ERR_NOSUPP); 2408d6d37b8SMatthew Dillon } 241185ace93SMatthew Dillon break; 242185ace93SMatthew Dillon } 243185ace93SMatthew Dillon return (0); 244185ace93SMatthew Dillon } 2458d6d37b8SMatthew Dillon 2468d6d37b8SMatthew Dillon static 2478d6d37b8SMatthew Dillon void 2488d6d37b8SMatthew Dillon disk_blk_open(struct disk *dp, kdmsg_msg_t *msg) 2498d6d37b8SMatthew Dillon { 2508d6d37b8SMatthew Dillon struct dios_open *openst; 2518d6d37b8SMatthew Dillon int error = DMSG_ERR_NOSUPP; 2528d6d37b8SMatthew Dillon int fflags; 2538d6d37b8SMatthew Dillon 2548d6d37b8SMatthew Dillon openst = msg->state->any.any; 2558d6d37b8SMatthew Dillon if ((msg->any.head.cmd & DMSGF_CMDSWMASK) == DMSG_BLK_OPEN) { 2568d6d37b8SMatthew Dillon if (openst == NULL) { 2578d6d37b8SMatthew Dillon openst = kmalloc(sizeof(*openst), M_DEVBUF, 2588d6d37b8SMatthew Dillon M_WAITOK | M_ZERO); 2598d6d37b8SMatthew Dillon msg->state->any.any = openst; 2608d6d37b8SMatthew Dillon } 2618d6d37b8SMatthew Dillon fflags = 0; 2628d6d37b8SMatthew Dillon if (msg->any.blk_open.modes & DMSG_BLKOPEN_RD) 2638d6d37b8SMatthew Dillon fflags = FREAD; 2648d6d37b8SMatthew Dillon if (msg->any.blk_open.modes & DMSG_BLKOPEN_WR) 2658d6d37b8SMatthew Dillon fflags |= FWRITE; 2668c530b23SJohannes Hofmann error = dev_dopen(dp->d_rawdev, fflags, S_IFCHR, proc0.p_ucred, NULL); 2678d6d37b8SMatthew Dillon if (error) { 2688d6d37b8SMatthew Dillon error = DMSG_ERR_IO; 2698d6d37b8SMatthew Dillon } else { 2708d6d37b8SMatthew Dillon if (msg->any.blk_open.modes & DMSG_BLKOPEN_RD) 2718d6d37b8SMatthew Dillon ++openst->openrd; 2728d6d37b8SMatthew Dillon if (msg->any.blk_open.modes & DMSG_BLKOPEN_WR) 2738d6d37b8SMatthew Dillon ++openst->openwr; 2748d6d37b8SMatthew Dillon } 2758d6d37b8SMatthew Dillon } 276d30cab67SMatthew Dillon #if 0 2778d6d37b8SMatthew Dillon if ((msg->any.head.cmd & DMSGF_CMDSWMASK) == DMSG_BLK_CLOSE && 2788d6d37b8SMatthew Dillon openst) { 2798d6d37b8SMatthew Dillon fflags = 0; 2808d6d37b8SMatthew Dillon if ((msg->any.blk_open.modes & DMSG_BLKOPEN_RD) && 2818d6d37b8SMatthew Dillon openst->openrd) { 2828d6d37b8SMatthew Dillon fflags = FREAD; 2838d6d37b8SMatthew Dillon } 2848d6d37b8SMatthew Dillon if ((msg->any.blk_open.modes & DMSG_BLKOPEN_WR) && 2858d6d37b8SMatthew Dillon openst->openwr) { 2868d6d37b8SMatthew Dillon fflags |= FWRITE; 2878d6d37b8SMatthew Dillon } 288ce486e08SMarkus Pfeiffer error = dev_dclose(dp->d_rawdev, fflags, S_IFCHR, NULL); 2898d6d37b8SMatthew Dillon if (error) { 2908d6d37b8SMatthew Dillon error = DMSG_ERR_IO; 2918d6d37b8SMatthew Dillon } else { 2928d6d37b8SMatthew Dillon if (msg->any.blk_open.modes & DMSG_BLKOPEN_RD) 2938d6d37b8SMatthew Dillon --openst->openrd; 2948d6d37b8SMatthew Dillon if (msg->any.blk_open.modes & DMSG_BLKOPEN_WR) 2958d6d37b8SMatthew Dillon --openst->openwr; 2968d6d37b8SMatthew Dillon } 2978d6d37b8SMatthew Dillon } 298d30cab67SMatthew Dillon #endif 2998d6d37b8SMatthew Dillon if (msg->any.head.cmd & DMSGF_DELETE) { 3008d6d37b8SMatthew Dillon if (openst) { 3018d6d37b8SMatthew Dillon while (openst->openrd && openst->openwr) { 3028d6d37b8SMatthew Dillon --openst->openrd; 3038d6d37b8SMatthew Dillon --openst->openwr; 304ce486e08SMarkus Pfeiffer dev_dclose(dp->d_rawdev, FREAD|FWRITE, S_IFCHR, NULL); 3058d6d37b8SMatthew Dillon } 3068d6d37b8SMatthew Dillon while (openst->openrd) { 3078d6d37b8SMatthew Dillon --openst->openrd; 308ce486e08SMarkus Pfeiffer dev_dclose(dp->d_rawdev, FREAD, S_IFCHR, NULL); 3098d6d37b8SMatthew Dillon } 3108d6d37b8SMatthew Dillon while (openst->openwr) { 3118d6d37b8SMatthew Dillon --openst->openwr; 312ce486e08SMarkus Pfeiffer dev_dclose(dp->d_rawdev, FWRITE, S_IFCHR, NULL); 3138d6d37b8SMatthew Dillon } 3148d6d37b8SMatthew Dillon kfree(openst, M_DEVBUF); 3158d6d37b8SMatthew Dillon msg->state->any.any = NULL; 3168d6d37b8SMatthew Dillon } 3178d6d37b8SMatthew Dillon kdmsg_msg_reply(msg, error); 3188d6d37b8SMatthew Dillon } else { 3198d6d37b8SMatthew Dillon kdmsg_msg_result(msg, error); 3208d6d37b8SMatthew Dillon } 3218d6d37b8SMatthew Dillon } 3228d6d37b8SMatthew Dillon 3238d6d37b8SMatthew Dillon static 3248d6d37b8SMatthew Dillon void 3258d6d37b8SMatthew Dillon disk_blk_read(struct disk *dp, kdmsg_msg_t *msg) 3268d6d37b8SMatthew Dillon { 3278d6d37b8SMatthew Dillon struct dios_io *iost; 3288d6d37b8SMatthew Dillon struct buf *bp; 3298d6d37b8SMatthew Dillon struct bio *bio; 3308d6d37b8SMatthew Dillon int error = DMSG_ERR_NOSUPP; 3318d6d37b8SMatthew Dillon int reterr = 1; 3328d6d37b8SMatthew Dillon 3338d6d37b8SMatthew Dillon /* 3348d6d37b8SMatthew Dillon * Only DMSG_BLK_READ commands imply read ops. 3358d6d37b8SMatthew Dillon */ 3368d6d37b8SMatthew Dillon iost = msg->state->any.any; 3378d6d37b8SMatthew Dillon if ((msg->any.head.cmd & DMSGF_CMDSWMASK) == DMSG_BLK_READ) { 3388d6d37b8SMatthew Dillon if (msg->any.blk_read.bytes < DEV_BSIZE || 3398d6d37b8SMatthew Dillon msg->any.blk_read.bytes > MAXPHYS) { 3408d6d37b8SMatthew Dillon error = DMSG_ERR_PARAM; 3418d6d37b8SMatthew Dillon goto done; 3428d6d37b8SMatthew Dillon } 3438d6d37b8SMatthew Dillon if (iost == NULL) { 3448d6d37b8SMatthew Dillon iost = kmalloc(sizeof(*iost), M_DEVBUF, 3458d6d37b8SMatthew Dillon M_WAITOK | M_ZERO); 3468d6d37b8SMatthew Dillon msg->state->any.any = iost; 3478d6d37b8SMatthew Dillon } 3488d6d37b8SMatthew Dillon reterr = 0; 3498d6d37b8SMatthew Dillon bp = geteblk(msg->any.blk_read.bytes); 3508d6d37b8SMatthew Dillon bio = &bp->b_bio1; 3518d6d37b8SMatthew Dillon bp->b_cmd = BUF_CMD_READ; 3528d6d37b8SMatthew Dillon bp->b_bcount = msg->any.blk_read.bytes; 3538d6d37b8SMatthew Dillon bp->b_resid = bp->b_bcount; 3548d6d37b8SMatthew Dillon bio->bio_offset = msg->any.blk_read.offset; 3558d6d37b8SMatthew Dillon bio->bio_caller_info1.ptr = msg->state; 3568d6d37b8SMatthew Dillon bio->bio_done = diskiodone; 3578d6d37b8SMatthew Dillon /* kdmsg_state_hold(msg->state); */ 3588d6d37b8SMatthew Dillon 3598d6d37b8SMatthew Dillon atomic_add_int(&iost->count, 1); 3608d6d37b8SMatthew Dillon if (msg->any.head.cmd & DMSGF_DELETE) 3618d6d37b8SMatthew Dillon iost->eof = 1; 3628d6d37b8SMatthew Dillon BUF_KERNPROC(bp); 3638d6d37b8SMatthew Dillon dev_dstrategy(dp->d_rawdev, bio); 3648d6d37b8SMatthew Dillon } 3658d6d37b8SMatthew Dillon done: 3668d6d37b8SMatthew Dillon if (reterr) { 3678d6d37b8SMatthew Dillon if (msg->any.head.cmd & DMSGF_DELETE) { 3688d6d37b8SMatthew Dillon if (iost && iost->count == 0) { 3698d6d37b8SMatthew Dillon kfree(iost, M_DEVBUF); 3708d6d37b8SMatthew Dillon msg->state->any.any = NULL; 3718d6d37b8SMatthew Dillon } 3728d6d37b8SMatthew Dillon kdmsg_msg_reply(msg, error); 3738d6d37b8SMatthew Dillon } else { 3748d6d37b8SMatthew Dillon kdmsg_msg_result(msg, error); 3758d6d37b8SMatthew Dillon } 3768d6d37b8SMatthew Dillon } 3778d6d37b8SMatthew Dillon } 3788d6d37b8SMatthew Dillon 3798d6d37b8SMatthew Dillon static 3808d6d37b8SMatthew Dillon void 3818d6d37b8SMatthew Dillon disk_blk_write(struct disk *dp, kdmsg_msg_t *msg) 3828d6d37b8SMatthew Dillon { 3838d6d37b8SMatthew Dillon struct dios_io *iost; 3848d6d37b8SMatthew Dillon struct buf *bp; 3858d6d37b8SMatthew Dillon struct bio *bio; 3868d6d37b8SMatthew Dillon int error = DMSG_ERR_NOSUPP; 3878d6d37b8SMatthew Dillon int reterr = 1; 3888d6d37b8SMatthew Dillon 3898d6d37b8SMatthew Dillon /* 3908d6d37b8SMatthew Dillon * Only DMSG_BLK_WRITE commands imply read ops. 3918d6d37b8SMatthew Dillon */ 3928d6d37b8SMatthew Dillon iost = msg->state->any.any; 3938d6d37b8SMatthew Dillon if ((msg->any.head.cmd & DMSGF_CMDSWMASK) == DMSG_BLK_WRITE) { 3948d6d37b8SMatthew Dillon if (msg->any.blk_write.bytes < DEV_BSIZE || 3958d6d37b8SMatthew Dillon msg->any.blk_write.bytes > MAXPHYS) { 3968d6d37b8SMatthew Dillon error = DMSG_ERR_PARAM; 3978d6d37b8SMatthew Dillon goto done; 3988d6d37b8SMatthew Dillon } 3998d6d37b8SMatthew Dillon if (iost == NULL) { 4008d6d37b8SMatthew Dillon iost = kmalloc(sizeof(*iost), M_DEVBUF, 4018d6d37b8SMatthew Dillon M_WAITOK | M_ZERO); 4028d6d37b8SMatthew Dillon msg->state->any.any = iost; 4038d6d37b8SMatthew Dillon } 4048d6d37b8SMatthew Dillon 4058d6d37b8SMatthew Dillon /* 4068d6d37b8SMatthew Dillon * Issue WRITE. Short data implies zeros. Try to optimize 4078d6d37b8SMatthew Dillon * the buffer cache buffer for the case where we can just 4088d6d37b8SMatthew Dillon * use the message's data pointer. 4098d6d37b8SMatthew Dillon */ 4108d6d37b8SMatthew Dillon reterr = 0; 4118d6d37b8SMatthew Dillon if (msg->aux_size >= msg->any.blk_write.bytes) 4128d6d37b8SMatthew Dillon bp = getpbuf(NULL); 4138d6d37b8SMatthew Dillon else 4148d6d37b8SMatthew Dillon bp = geteblk(msg->any.blk_write.bytes); 4158d6d37b8SMatthew Dillon bio = &bp->b_bio1; 4168d6d37b8SMatthew Dillon bp->b_cmd = BUF_CMD_WRITE; 4178d6d37b8SMatthew Dillon bp->b_bcount = msg->any.blk_write.bytes; 4188d6d37b8SMatthew Dillon bp->b_resid = bp->b_bcount; 4198d6d37b8SMatthew Dillon if (msg->aux_size >= msg->any.blk_write.bytes) { 4208d6d37b8SMatthew Dillon bp->b_data = msg->aux_data; 421*1a2a529dSMatthew Dillon kdmsg_detach_aux_data(msg, &iost->data); 4228d6d37b8SMatthew Dillon } else { 4238d6d37b8SMatthew Dillon bcopy(msg->aux_data, bp->b_data, msg->aux_size); 4248d6d37b8SMatthew Dillon bzero(bp->b_data + msg->aux_size, 4258d6d37b8SMatthew Dillon msg->any.blk_write.bytes - msg->aux_size); 426*1a2a529dSMatthew Dillon bzero(&iost->data, sizeof(iost->data)); 4278d6d37b8SMatthew Dillon } 4288d6d37b8SMatthew Dillon bio->bio_offset = msg->any.blk_write.offset; 4298d6d37b8SMatthew Dillon bio->bio_caller_info1.ptr = msg->state; 4308d6d37b8SMatthew Dillon bio->bio_done = diskiodone; 4318d6d37b8SMatthew Dillon /* kdmsg_state_hold(msg->state); */ 4328d6d37b8SMatthew Dillon 4338d6d37b8SMatthew Dillon atomic_add_int(&iost->count, 1); 4348d6d37b8SMatthew Dillon if (msg->any.head.cmd & DMSGF_DELETE) 4358d6d37b8SMatthew Dillon iost->eof = 1; 4368d6d37b8SMatthew Dillon BUF_KERNPROC(bp); 4378d6d37b8SMatthew Dillon dev_dstrategy(dp->d_rawdev, bio); 4388d6d37b8SMatthew Dillon } 4398d6d37b8SMatthew Dillon done: 4408d6d37b8SMatthew Dillon if (reterr) { 4418d6d37b8SMatthew Dillon if (msg->any.head.cmd & DMSGF_DELETE) { 4428d6d37b8SMatthew Dillon if (iost && iost->count == 0) { 4438d6d37b8SMatthew Dillon kfree(iost, M_DEVBUF); 4448d6d37b8SMatthew Dillon msg->state->any.any = NULL; 4458d6d37b8SMatthew Dillon } 4468d6d37b8SMatthew Dillon kdmsg_msg_reply(msg, error); 4478d6d37b8SMatthew Dillon } else { 4488d6d37b8SMatthew Dillon kdmsg_msg_result(msg, error); 4498d6d37b8SMatthew Dillon } 4508d6d37b8SMatthew Dillon } 4518d6d37b8SMatthew Dillon } 4528d6d37b8SMatthew Dillon 4538d6d37b8SMatthew Dillon static 4548d6d37b8SMatthew Dillon void 4558d6d37b8SMatthew Dillon disk_blk_flush(struct disk *dp, kdmsg_msg_t *msg) 4568d6d37b8SMatthew Dillon { 4578d6d37b8SMatthew Dillon struct dios_io *iost; 4588d6d37b8SMatthew Dillon struct buf *bp; 4598d6d37b8SMatthew Dillon struct bio *bio; 4608d6d37b8SMatthew Dillon int error = DMSG_ERR_NOSUPP; 4618d6d37b8SMatthew Dillon int reterr = 1; 4628d6d37b8SMatthew Dillon 4638d6d37b8SMatthew Dillon /* 4648d6d37b8SMatthew Dillon * Only DMSG_BLK_FLUSH commands imply read ops. 4658d6d37b8SMatthew Dillon */ 4668d6d37b8SMatthew Dillon iost = msg->state->any.any; 4678d6d37b8SMatthew Dillon if ((msg->any.head.cmd & DMSGF_CMDSWMASK) == DMSG_BLK_FLUSH) { 4688d6d37b8SMatthew Dillon if (iost == NULL) { 4698d6d37b8SMatthew Dillon iost = kmalloc(sizeof(*iost), M_DEVBUF, 4708d6d37b8SMatthew Dillon M_WAITOK | M_ZERO); 4718d6d37b8SMatthew Dillon msg->state->any.any = iost; 4728d6d37b8SMatthew Dillon } 4738d6d37b8SMatthew Dillon reterr = 0; 4748d6d37b8SMatthew Dillon bp = getpbuf(NULL); 4758d6d37b8SMatthew Dillon bio = &bp->b_bio1; 4768d6d37b8SMatthew Dillon bp->b_cmd = BUF_CMD_FLUSH; 4778d6d37b8SMatthew Dillon bp->b_bcount = msg->any.blk_flush.bytes; 4788d6d37b8SMatthew Dillon bp->b_resid = 0; 4798d6d37b8SMatthew Dillon bio->bio_offset = msg->any.blk_flush.offset; 4808d6d37b8SMatthew Dillon bio->bio_caller_info1.ptr = msg->state; 4818d6d37b8SMatthew Dillon bio->bio_done = diskiodone; 4828d6d37b8SMatthew Dillon /* kdmsg_state_hold(msg->state); */ 4838d6d37b8SMatthew Dillon 4848d6d37b8SMatthew Dillon atomic_add_int(&iost->count, 1); 4858d6d37b8SMatthew Dillon if (msg->any.head.cmd & DMSGF_DELETE) 4868d6d37b8SMatthew Dillon iost->eof = 1; 4878d6d37b8SMatthew Dillon BUF_KERNPROC(bp); 4888d6d37b8SMatthew Dillon dev_dstrategy(dp->d_rawdev, bio); 4898d6d37b8SMatthew Dillon } 4908d6d37b8SMatthew Dillon if (reterr) { 4918d6d37b8SMatthew Dillon if (msg->any.head.cmd & DMSGF_DELETE) { 4928d6d37b8SMatthew Dillon if (iost && iost->count == 0) { 4938d6d37b8SMatthew Dillon kfree(iost, M_DEVBUF); 4948d6d37b8SMatthew Dillon msg->state->any.any = NULL; 4958d6d37b8SMatthew Dillon } 4968d6d37b8SMatthew Dillon kdmsg_msg_reply(msg, error); 4978d6d37b8SMatthew Dillon } else { 4988d6d37b8SMatthew Dillon kdmsg_msg_result(msg, error); 4998d6d37b8SMatthew Dillon } 5008d6d37b8SMatthew Dillon } 5018d6d37b8SMatthew Dillon } 5028d6d37b8SMatthew Dillon 5038d6d37b8SMatthew Dillon static 5048d6d37b8SMatthew Dillon void 5058d6d37b8SMatthew Dillon disk_blk_freeblks(struct disk *dp, kdmsg_msg_t *msg) 5068d6d37b8SMatthew Dillon { 5078d6d37b8SMatthew Dillon struct dios_io *iost; 5088d6d37b8SMatthew Dillon struct buf *bp; 5098d6d37b8SMatthew Dillon struct bio *bio; 5108d6d37b8SMatthew Dillon int error = DMSG_ERR_NOSUPP; 5118d6d37b8SMatthew Dillon int reterr = 1; 5128d6d37b8SMatthew Dillon 5138d6d37b8SMatthew Dillon /* 5148d6d37b8SMatthew Dillon * Only DMSG_BLK_FREEBLKS commands imply read ops. 5158d6d37b8SMatthew Dillon */ 5168d6d37b8SMatthew Dillon iost = msg->state->any.any; 5178d6d37b8SMatthew Dillon if ((msg->any.head.cmd & DMSGF_CMDSWMASK) == DMSG_BLK_FREEBLKS) { 5188d6d37b8SMatthew Dillon if (iost == NULL) { 5198d6d37b8SMatthew Dillon iost = kmalloc(sizeof(*iost), M_DEVBUF, 5208d6d37b8SMatthew Dillon M_WAITOK | M_ZERO); 5218d6d37b8SMatthew Dillon msg->state->any.any = iost; 5228d6d37b8SMatthew Dillon } 5238d6d37b8SMatthew Dillon reterr = 0; 5248d6d37b8SMatthew Dillon bp = getpbuf(NULL); 5258d6d37b8SMatthew Dillon bio = &bp->b_bio1; 5268d6d37b8SMatthew Dillon bp->b_cmd = BUF_CMD_FREEBLKS; 5278d6d37b8SMatthew Dillon bp->b_bcount = msg->any.blk_freeblks.bytes; 5288d6d37b8SMatthew Dillon bp->b_resid = 0; 5298d6d37b8SMatthew Dillon bio->bio_offset = msg->any.blk_freeblks.offset; 5308d6d37b8SMatthew Dillon bio->bio_caller_info1.ptr = msg->state; 5318d6d37b8SMatthew Dillon bio->bio_done = diskiodone; 5328d6d37b8SMatthew Dillon /* kdmsg_state_hold(msg->state); */ 5338d6d37b8SMatthew Dillon 5348d6d37b8SMatthew Dillon atomic_add_int(&iost->count, 1); 5358d6d37b8SMatthew Dillon if (msg->any.head.cmd & DMSGF_DELETE) 5368d6d37b8SMatthew Dillon iost->eof = 1; 5378d6d37b8SMatthew Dillon BUF_KERNPROC(bp); 5388d6d37b8SMatthew Dillon dev_dstrategy(dp->d_rawdev, bio); 5398d6d37b8SMatthew Dillon } 5408d6d37b8SMatthew Dillon if (reterr) { 5418d6d37b8SMatthew Dillon if (msg->any.head.cmd & DMSGF_DELETE) { 5428d6d37b8SMatthew Dillon if (iost && iost->count == 0) { 5438d6d37b8SMatthew Dillon kfree(iost, M_DEVBUF); 5448d6d37b8SMatthew Dillon msg->state->any.any = NULL; 5458d6d37b8SMatthew Dillon } 5468d6d37b8SMatthew Dillon kdmsg_msg_reply(msg, error); 5478d6d37b8SMatthew Dillon } else { 5488d6d37b8SMatthew Dillon kdmsg_msg_result(msg, error); 5498d6d37b8SMatthew Dillon } 5508d6d37b8SMatthew Dillon } 5518d6d37b8SMatthew Dillon } 5528d6d37b8SMatthew Dillon 5538d6d37b8SMatthew Dillon static 5548d6d37b8SMatthew Dillon void 5558d6d37b8SMatthew Dillon diskiodone(struct bio *bio) 5568d6d37b8SMatthew Dillon { 5578d6d37b8SMatthew Dillon struct buf *bp = bio->bio_buf; 5588d6d37b8SMatthew Dillon kdmsg_state_t *state = bio->bio_caller_info1.ptr; 5598d6d37b8SMatthew Dillon kdmsg_msg_t *rmsg; 5608d6d37b8SMatthew Dillon struct dios_io *iost = state->any.any; 5618d6d37b8SMatthew Dillon int error; 5628d6d37b8SMatthew Dillon int resid = 0; 5638d6d37b8SMatthew Dillon int bytes; 5648d6d37b8SMatthew Dillon uint32_t cmd; 5658d6d37b8SMatthew Dillon void *data; 5668d6d37b8SMatthew Dillon 5678d6d37b8SMatthew Dillon cmd = DMSG_LNK_ERROR; 5688d6d37b8SMatthew Dillon data = NULL; 5698d6d37b8SMatthew Dillon bytes = 0; 5708d6d37b8SMatthew Dillon 5718d6d37b8SMatthew Dillon switch(bp->b_cmd) { 5728d6d37b8SMatthew Dillon case BUF_CMD_READ: 5738d6d37b8SMatthew Dillon cmd = DMSG_LNK_ERROR; 5748d6d37b8SMatthew Dillon data = bp->b_data; 5758d6d37b8SMatthew Dillon bytes = bp->b_bcount; 5768d6d37b8SMatthew Dillon /* fall through */ 5778d6d37b8SMatthew Dillon case BUF_CMD_WRITE: 5788d6d37b8SMatthew Dillon if (bp->b_flags & B_ERROR) { 5798d6d37b8SMatthew Dillon error = bp->b_error; 5808d6d37b8SMatthew Dillon } else { 5818d6d37b8SMatthew Dillon error = 0; 5828d6d37b8SMatthew Dillon resid = bp->b_resid; 5838d6d37b8SMatthew Dillon } 584*1a2a529dSMatthew Dillon kdmsg_free_aux_data(&iost->data); 5858d6d37b8SMatthew Dillon break; 5868d6d37b8SMatthew Dillon case BUF_CMD_FLUSH: 5878d6d37b8SMatthew Dillon case BUF_CMD_FREEBLKS: 5888d6d37b8SMatthew Dillon if (bp->b_flags & B_ERROR) 5898d6d37b8SMatthew Dillon error = bp->b_error; 5908d6d37b8SMatthew Dillon else 5918d6d37b8SMatthew Dillon error = 0; 5928d6d37b8SMatthew Dillon break; 5938d6d37b8SMatthew Dillon default: 5948d6d37b8SMatthew Dillon panic("diskiodone: Unknown bio cmd = %d\n", 5958d6d37b8SMatthew Dillon bio->bio_buf->b_cmd); 5965a78b06aSMatthew Dillon error = 0; /* avoid compiler warning */ 5978d6d37b8SMatthew Dillon break; /* NOT REACHED */ 5988d6d37b8SMatthew Dillon } 5998d6d37b8SMatthew Dillon 6008d6d37b8SMatthew Dillon /* 6015a78b06aSMatthew Dillon * Convert error to DMSG_ERR_* code. 6025a78b06aSMatthew Dillon */ 6035a78b06aSMatthew Dillon if (error) 6045a78b06aSMatthew Dillon error = DMSG_ERR_IO; 6055a78b06aSMatthew Dillon 6065a78b06aSMatthew Dillon /* 6078d6d37b8SMatthew Dillon * Convert LNK_ERROR or BLK_ERROR if non-zero resid. READS will 6088d6d37b8SMatthew Dillon * have already converted cmd to BLK_ERROR and set up data to return. 6098d6d37b8SMatthew Dillon */ 6108d6d37b8SMatthew Dillon if (resid && cmd == DMSG_LNK_ERROR) 6118d6d37b8SMatthew Dillon cmd = DMSG_BLK_ERROR; 6128d6d37b8SMatthew Dillon /* XXX txcmd is delayed so this won't work for streaming */ 6138d6d37b8SMatthew Dillon if ((state->txcmd & DMSGF_CREATE) == 0) /* assume serialized */ 6148d6d37b8SMatthew Dillon cmd |= DMSGF_CREATE; 6158d6d37b8SMatthew Dillon if (iost->eof) { 6168d6d37b8SMatthew Dillon if (atomic_fetchadd_int(&iost->count, -1) == 1) 6178d6d37b8SMatthew Dillon cmd |= DMSGF_DELETE; 6188d6d37b8SMatthew Dillon } else { 6198d6d37b8SMatthew Dillon atomic_add_int(&iost->count, -1); 6208d6d37b8SMatthew Dillon } 6218d6d37b8SMatthew Dillon cmd |= DMSGF_REPLY; 6228d6d37b8SMatthew Dillon 6238d6d37b8SMatthew Dillon /* 6248d6d37b8SMatthew Dillon * Allocate a basic or extended reply. Be careful not to populate 6258d6d37b8SMatthew Dillon * extended header fields unless we allocated an extended reply. 6268d6d37b8SMatthew Dillon */ 6271b8eded1SMatthew Dillon rmsg = kdmsg_msg_alloc(state, cmd, NULL, 0); 6288d6d37b8SMatthew Dillon if (data) { 6298d6d37b8SMatthew Dillon rmsg->aux_data = kmalloc(bytes, state->iocom->mmsg, M_INTWAIT); 6308d6d37b8SMatthew Dillon rmsg->aux_size = bytes; 6318d6d37b8SMatthew Dillon rmsg->flags |= KDMSG_FLAG_AUXALLOC; 6328d6d37b8SMatthew Dillon bcopy(data, rmsg->aux_data, bytes); 6338d6d37b8SMatthew Dillon } 6348d6d37b8SMatthew Dillon rmsg->any.blk_error.head.error = error; 6358d6d37b8SMatthew Dillon if ((cmd & DMSGF_BASECMDMASK) == DMSG_BLK_ERROR) 6368d6d37b8SMatthew Dillon rmsg->any.blk_error.resid = resid; 6378d6d37b8SMatthew Dillon bio->bio_caller_info1.ptr = NULL; 6388d6d37b8SMatthew Dillon /* kdmsg_state_drop(state); */ 6398d6d37b8SMatthew Dillon kdmsg_msg_write(rmsg); 6408d6d37b8SMatthew Dillon if (bp->b_flags & B_PAGING) { 6418d6d37b8SMatthew Dillon relpbuf(bio->bio_buf, NULL); 6428d6d37b8SMatthew Dillon } else { 6438d6d37b8SMatthew Dillon bp->b_flags |= B_INVAL | B_AGE; 6448d6d37b8SMatthew Dillon brelse(bp); 6458d6d37b8SMatthew Dillon } 6468d6d37b8SMatthew Dillon } 647