xref: /freebsd/sys/cam/ctl/ctl_backend_block.c (revision 1f83483d73924de5fa2d5915676f6b2cd350d986)
1130f4520SKenneth D. Merry /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3bec9534dSPedro F. Giffuni  *
4130f4520SKenneth D. Merry  * Copyright (c) 2003 Silicon Graphics International Corp.
5130f4520SKenneth D. Merry  * Copyright (c) 2009-2011 Spectra Logic Corporation
649050613SKa Ho Ng  * Copyright (c) 2012,2021 The FreeBSD Foundation
7b06771aaSAlexander Motin  * Copyright (c) 2014-2021 Alexander Motin <mav@FreeBSD.org>
8130f4520SKenneth D. Merry  * All rights reserved.
9130f4520SKenneth D. Merry  *
1081177295SEdward Tomasz Napierala  * Portions of this software were developed by Edward Tomasz Napierala
1181177295SEdward Tomasz Napierala  * under sponsorship from the FreeBSD Foundation.
1281177295SEdward Tomasz Napierala  *
1349050613SKa Ho Ng  * Portions of this software were developed by Ka Ho Ng <khng@FreeBSD.org>
1449050613SKa Ho Ng  * under sponsorship from the FreeBSD Foundation.
1549050613SKa Ho Ng  *
16130f4520SKenneth D. Merry  * Redistribution and use in source and binary forms, with or without
17130f4520SKenneth D. Merry  * modification, are permitted provided that the following conditions
18130f4520SKenneth D. Merry  * are met:
19130f4520SKenneth D. Merry  * 1. Redistributions of source code must retain the above copyright
20130f4520SKenneth D. Merry  *    notice, this list of conditions, and the following disclaimer,
21130f4520SKenneth D. Merry  *    without modification.
22130f4520SKenneth D. Merry  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
23130f4520SKenneth D. Merry  *    substantially similar to the "NO WARRANTY" disclaimer below
24130f4520SKenneth D. Merry  *    ("Disclaimer") and any redistribution must be conditioned upon
25130f4520SKenneth D. Merry  *    including a substantially similar Disclaimer requirement for further
26130f4520SKenneth D. Merry  *    binary redistribution.
27130f4520SKenneth D. Merry  *
28130f4520SKenneth D. Merry  * NO WARRANTY
29130f4520SKenneth D. Merry  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30130f4520SKenneth D. Merry  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31130f4520SKenneth D. Merry  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
32130f4520SKenneth D. Merry  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33130f4520SKenneth D. Merry  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34130f4520SKenneth D. Merry  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35130f4520SKenneth D. Merry  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36130f4520SKenneth D. Merry  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37130f4520SKenneth D. Merry  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
38130f4520SKenneth D. Merry  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39130f4520SKenneth D. Merry  * POSSIBILITY OF SUCH DAMAGES.
40130f4520SKenneth D. Merry  *
41130f4520SKenneth D. Merry  * $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/ctl_backend_block.c#5 $
42130f4520SKenneth D. Merry  */
43130f4520SKenneth D. Merry /*
44130f4520SKenneth D. Merry  * CAM Target Layer driver backend for block devices.
45130f4520SKenneth D. Merry  *
46130f4520SKenneth D. Merry  * Author: Ken Merry <ken@FreeBSD.org>
47130f4520SKenneth D. Merry  */
48130f4520SKenneth D. Merry #include <sys/param.h>
49130f4520SKenneth D. Merry #include <sys/systm.h>
50130f4520SKenneth D. Merry #include <sys/kernel.h>
51130f4520SKenneth D. Merry #include <sys/types.h>
52130f4520SKenneth D. Merry #include <sys/kthread.h>
53130f4520SKenneth D. Merry #include <sys/bio.h>
54130f4520SKenneth D. Merry #include <sys/fcntl.h>
55ee7f31c0SAlexander Motin #include <sys/limits.h>
56130f4520SKenneth D. Merry #include <sys/lock.h>
57130f4520SKenneth D. Merry #include <sys/mutex.h>
58130f4520SKenneth D. Merry #include <sys/condvar.h>
59130f4520SKenneth D. Merry #include <sys/malloc.h>
60130f4520SKenneth D. Merry #include <sys/conf.h>
61130f4520SKenneth D. Merry #include <sys/ioccom.h>
62130f4520SKenneth D. Merry #include <sys/queue.h>
63130f4520SKenneth D. Merry #include <sys/sbuf.h>
64130f4520SKenneth D. Merry #include <sys/endian.h>
65130f4520SKenneth D. Merry #include <sys/uio.h>
66130f4520SKenneth D. Merry #include <sys/buf.h>
67130f4520SKenneth D. Merry #include <sys/taskqueue.h>
68130f4520SKenneth D. Merry #include <sys/vnode.h>
69130f4520SKenneth D. Merry #include <sys/namei.h>
70130f4520SKenneth D. Merry #include <sys/mount.h>
71130f4520SKenneth D. Merry #include <sys/disk.h>
72130f4520SKenneth D. Merry #include <sys/fcntl.h>
73130f4520SKenneth D. Merry #include <sys/filedesc.h>
74ef8daf3fSAlexander Motin #include <sys/filio.h>
75130f4520SKenneth D. Merry #include <sys/proc.h>
76130f4520SKenneth D. Merry #include <sys/pcpu.h>
77130f4520SKenneth D. Merry #include <sys/module.h>
78130f4520SKenneth D. Merry #include <sys/sdt.h>
79130f4520SKenneth D. Merry #include <sys/devicestat.h>
80130f4520SKenneth D. Merry #include <sys/sysctl.h>
818951f055SMarcelo Araujo #include <sys/nv.h>
828951f055SMarcelo Araujo #include <sys/dnv.h>
8334144c2cSAlexander Motin #include <sys/sx.h>
8449050613SKa Ho Ng #include <sys/unistd.h>
85130f4520SKenneth D. Merry 
86130f4520SKenneth D. Merry #include <geom/geom.h>
87130f4520SKenneth D. Merry 
88130f4520SKenneth D. Merry #include <cam/cam.h>
89130f4520SKenneth D. Merry #include <cam/scsi/scsi_all.h>
90130f4520SKenneth D. Merry #include <cam/scsi/scsi_da.h>
91130f4520SKenneth D. Merry #include <cam/ctl/ctl_io.h>
92130f4520SKenneth D. Merry #include <cam/ctl/ctl.h>
93130f4520SKenneth D. Merry #include <cam/ctl/ctl_backend.h>
94130f4520SKenneth D. Merry #include <cam/ctl/ctl_ioctl.h>
957ac58230SAlexander Motin #include <cam/ctl/ctl_ha.h>
96130f4520SKenneth D. Merry #include <cam/ctl/ctl_scsi_all.h>
977ac58230SAlexander Motin #include <cam/ctl/ctl_private.h>
98130f4520SKenneth D. Merry #include <cam/ctl/ctl_error.h>
99130f4520SKenneth D. Merry 
100130f4520SKenneth D. Merry /*
101b06771aaSAlexander Motin  * The idea here is to allocate enough S/G space to handle at least 1MB I/Os.
102b06771aaSAlexander Motin  * On systems with small maxphys it can be 8 128KB segments.  On large systems
103b06771aaSAlexander Motin  * it can be up to 8 1MB segments.  I/Os larger than that we'll split.
104130f4520SKenneth D. Merry  */
105b06771aaSAlexander Motin #define	CTLBLK_MAX_SEGS		8
106b06771aaSAlexander Motin #define	CTLBLK_HALF_SEGS	(CTLBLK_MAX_SEGS / 2)
107cd853791SKonstantin Belousov #define	CTLBLK_MIN_SEG		(128 * 1024)
108b06771aaSAlexander Motin #define	CTLBLK_MAX_SEG		MIN(1024 * 1024, MAX(CTLBLK_MIN_SEG, maxphys))
109b06771aaSAlexander Motin #define	CTLBLK_MAX_IO_SIZE	(CTLBLK_MAX_SEG * CTLBLK_MAX_SEGS)
110130f4520SKenneth D. Merry 
111130f4520SKenneth D. Merry #ifdef CTLBLK_DEBUG
112130f4520SKenneth D. Merry #define DPRINTF(fmt, args...) \
113130f4520SKenneth D. Merry     printf("cbb(%s:%d): " fmt, __FUNCTION__, __LINE__, ##args)
114130f4520SKenneth D. Merry #else
115130f4520SKenneth D. Merry #define DPRINTF(fmt, args...) do {} while(0)
116130f4520SKenneth D. Merry #endif
117130f4520SKenneth D. Merry 
118e86a4142SAlexander Motin #define PRIV(io)	\
119e86a4142SAlexander Motin     ((struct ctl_ptr_len_flags *)&(io)->io_hdr.ctl_private[CTL_PRIV_BACKEND])
12011b569f7SAlexander Motin #define ARGS(io)	\
12111b569f7SAlexander Motin     ((struct ctl_lba_len_flags *)&(io)->io_hdr.ctl_private[CTL_PRIV_LBA_LEN])
122374f12c5SJohn Baldwin #define	DSM_RANGE(io)	((io)->io_hdr.ctl_private[CTL_PRIV_LBA_LEN].integer)
123e86a4142SAlexander Motin 
124130f4520SKenneth D. Merry SDT_PROVIDER_DEFINE(cbb);
125130f4520SKenneth D. Merry 
126130f4520SKenneth D. Merry typedef enum {
127130f4520SKenneth D. Merry 	CTL_BE_BLOCK_LUN_UNCONFIGURED	= 0x01,
128130f4520SKenneth D. Merry 	CTL_BE_BLOCK_LUN_WAITING	= 0x04,
129130f4520SKenneth D. Merry } ctl_be_block_lun_flags;
130130f4520SKenneth D. Merry 
131130f4520SKenneth D. Merry typedef enum {
132130f4520SKenneth D. Merry 	CTL_BE_BLOCK_NONE,
133130f4520SKenneth D. Merry 	CTL_BE_BLOCK_DEV,
134130f4520SKenneth D. Merry 	CTL_BE_BLOCK_FILE
135130f4520SKenneth D. Merry } ctl_be_block_type;
136130f4520SKenneth D. Merry 
137130f4520SKenneth D. Merry struct ctl_be_block_filedata {
138130f4520SKenneth D. Merry 	struct ucred *cred;
139130f4520SKenneth D. Merry };
140130f4520SKenneth D. Merry 
141130f4520SKenneth D. Merry union ctl_be_block_bedata {
142130f4520SKenneth D. Merry 	struct ctl_be_block_filedata file;
143130f4520SKenneth D. Merry };
144130f4520SKenneth D. Merry 
145130f4520SKenneth D. Merry struct ctl_be_block_io;
146130f4520SKenneth D. Merry struct ctl_be_block_lun;
147130f4520SKenneth D. Merry 
148130f4520SKenneth D. Merry typedef void (*cbb_dispatch_t)(struct ctl_be_block_lun *be_lun,
149130f4520SKenneth D. Merry 			       struct ctl_be_block_io *beio);
150c3e7ba3eSAlexander Motin typedef uint64_t (*cbb_getattr_t)(struct ctl_be_block_lun *be_lun,
151c3e7ba3eSAlexander Motin 				  const char *attrname);
152130f4520SKenneth D. Merry 
153130f4520SKenneth D. Merry /*
154130f4520SKenneth D. Merry  * Backend LUN structure.  There is a 1:1 mapping between a block device
155130f4520SKenneth D. Merry  * and a backend block LUN, and between a backend block LUN and a CTL LUN.
156130f4520SKenneth D. Merry  */
157130f4520SKenneth D. Merry struct ctl_be_block_lun {
158767300e8SAlexander Motin 	struct ctl_be_lun cbe_lun;		/* Must be first element. */
15919720f41SAlexander Motin 	struct ctl_lun_create_params params;
160130f4520SKenneth D. Merry 	char *dev_path;
161130f4520SKenneth D. Merry 	ctl_be_block_type dev_type;
162130f4520SKenneth D. Merry 	struct vnode *vn;
163130f4520SKenneth D. Merry 	union ctl_be_block_bedata backend;
164130f4520SKenneth D. Merry 	cbb_dispatch_t dispatch;
165130f4520SKenneth D. Merry 	cbb_dispatch_t lun_flush;
166ee7f31c0SAlexander Motin 	cbb_dispatch_t unmap;
167ef8daf3fSAlexander Motin 	cbb_dispatch_t get_lba_status;
168c3e7ba3eSAlexander Motin 	cbb_getattr_t getattr;
169130f4520SKenneth D. Merry 	uint64_t size_blocks;
170130f4520SKenneth D. Merry 	uint64_t size_bytes;
171130f4520SKenneth D. Merry 	struct ctl_be_block_softc *softc;
172130f4520SKenneth D. Merry 	struct devstat *disk_stats;
173130f4520SKenneth D. Merry 	ctl_be_block_lun_flags flags;
17434144c2cSAlexander Motin 	SLIST_ENTRY(ctl_be_block_lun) links;
175130f4520SKenneth D. Merry 	struct taskqueue *io_taskqueue;
176130f4520SKenneth D. Merry 	struct task io_task;
177130f4520SKenneth D. Merry 	int num_threads;
178130f4520SKenneth D. Merry 	STAILQ_HEAD(, ctl_io_hdr) input_queue;
179ef8daf3fSAlexander Motin 	STAILQ_HEAD(, ctl_io_hdr) config_read_queue;
180130f4520SKenneth D. Merry 	STAILQ_HEAD(, ctl_io_hdr) config_write_queue;
181130f4520SKenneth D. Merry 	STAILQ_HEAD(, ctl_io_hdr) datamove_queue;
18275c7a1d3SAlexander Motin 	struct mtx_padalign io_lock;
18375c7a1d3SAlexander Motin 	struct mtx_padalign queue_lock;
184130f4520SKenneth D. Merry };
185130f4520SKenneth D. Merry 
186130f4520SKenneth D. Merry /*
187130f4520SKenneth D. Merry  * Overall softc structure for the block backend module.
188130f4520SKenneth D. Merry  */
189130f4520SKenneth D. Merry struct ctl_be_block_softc {
19034144c2cSAlexander Motin 	struct sx			 modify_lock;
191130f4520SKenneth D. Merry 	struct mtx			 lock;
192130f4520SKenneth D. Merry 	int				 num_luns;
19334144c2cSAlexander Motin 	SLIST_HEAD(, ctl_be_block_lun)	 lun_list;
1940d7fed74SAlexander Motin 	uma_zone_t			 beio_zone;
195cd853791SKonstantin Belousov 	uma_zone_t			 bufmin_zone;
196cd853791SKonstantin Belousov 	uma_zone_t			 bufmax_zone;
197130f4520SKenneth D. Merry };
198130f4520SKenneth D. Merry 
199130f4520SKenneth D. Merry static struct ctl_be_block_softc backend_block_softc;
200130f4520SKenneth D. Merry 
201130f4520SKenneth D. Merry /*
202130f4520SKenneth D. Merry  * Per-I/O information.
203130f4520SKenneth D. Merry  */
204130f4520SKenneth D. Merry struct ctl_be_block_io {
205130f4520SKenneth D. Merry 	union ctl_io			*io;
206130f4520SKenneth D. Merry 	struct ctl_sg_entry		sg_segs[CTLBLK_MAX_SEGS];
207130f4520SKenneth D. Merry 	struct iovec			xiovecs[CTLBLK_MAX_SEGS];
2089a4510acSAlexander Motin 	int				refcnt;
209130f4520SKenneth D. Merry 	int				bio_cmd;
2100d7fed74SAlexander Motin 	int				two_sglists;
211130f4520SKenneth D. Merry 	int				num_segs;
212130f4520SKenneth D. Merry 	int				num_bios_sent;
213130f4520SKenneth D. Merry 	int				num_bios_done;
214130f4520SKenneth D. Merry 	int				send_complete;
2151f0694a6SAlexander Motin 	int				first_error;
2161f0694a6SAlexander Motin 	uint64_t			first_error_offset;
217130f4520SKenneth D. Merry 	struct bintime			ds_t0;
218130f4520SKenneth D. Merry 	devstat_tag_type		ds_tag_type;
219130f4520SKenneth D. Merry 	devstat_trans_flags		ds_trans_type;
220130f4520SKenneth D. Merry 	uint64_t			io_len;
221130f4520SKenneth D. Merry 	uint64_t			io_offset;
2227d0d4342SAlexander Motin 	int				io_arg;
223130f4520SKenneth D. Merry 	struct ctl_be_block_softc	*softc;
224130f4520SKenneth D. Merry 	struct ctl_be_block_lun		*lun;
225ee7f31c0SAlexander Motin 	void (*beio_cont)(struct ctl_be_block_io *beio); /* to continue processing */
226130f4520SKenneth D. Merry };
227130f4520SKenneth D. Merry 
2287ac58230SAlexander Motin extern struct ctl_softc *control_softc;
2297ac58230SAlexander Motin 
2307d4c4443SAlexander Motin static int cbb_num_threads = 32;
2317029da5cSPawel Biernacki SYSCTL_NODE(_kern_cam_ctl, OID_AUTO, block, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
232130f4520SKenneth D. Merry 	    "CAM Target Layer Block Backend");
233af3b2549SHans Petter Selasky SYSCTL_INT(_kern_cam_ctl_block, OID_AUTO, num_threads, CTLFLAG_RWTUN,
234130f4520SKenneth D. Merry            &cbb_num_threads, 0, "Number of threads per backing file");
235130f4520SKenneth D. Merry 
236130f4520SKenneth D. Merry static struct ctl_be_block_io *ctl_alloc_beio(struct ctl_be_block_softc *softc);
237130f4520SKenneth D. Merry static void ctl_free_beio(struct ctl_be_block_io *beio);
238130f4520SKenneth D. Merry static void ctl_complete_beio(struct ctl_be_block_io *beio);
2392c7dc6baSAlexander Motin static int ctl_be_block_move_done(union ctl_io *io, bool samethr);
240130f4520SKenneth D. Merry static void ctl_be_block_biodone(struct bio *bio);
241130f4520SKenneth D. Merry static void ctl_be_block_flush_file(struct ctl_be_block_lun *be_lun,
242130f4520SKenneth D. Merry 				    struct ctl_be_block_io *beio);
243130f4520SKenneth D. Merry static void ctl_be_block_dispatch_file(struct ctl_be_block_lun *be_lun,
244130f4520SKenneth D. Merry 				       struct ctl_be_block_io *beio);
245ef8daf3fSAlexander Motin static void ctl_be_block_gls_file(struct ctl_be_block_lun *be_lun,
246ef8daf3fSAlexander Motin 				  struct ctl_be_block_io *beio);
24753c146deSAlexander Motin static uint64_t ctl_be_block_getattr_file(struct ctl_be_block_lun *be_lun,
24853c146deSAlexander Motin 					 const char *attrname);
24949050613SKa Ho Ng static void ctl_be_block_unmap_file(struct ctl_be_block_lun *be_lun,
25049050613SKa Ho Ng 				    struct ctl_be_block_io *beio);
251130f4520SKenneth D. Merry static void ctl_be_block_flush_dev(struct ctl_be_block_lun *be_lun,
252130f4520SKenneth D. Merry 				   struct ctl_be_block_io *beio);
253ee7f31c0SAlexander Motin static void ctl_be_block_unmap_dev(struct ctl_be_block_lun *be_lun,
254ee7f31c0SAlexander Motin 				   struct ctl_be_block_io *beio);
255130f4520SKenneth D. Merry static void ctl_be_block_dispatch_dev(struct ctl_be_block_lun *be_lun,
256130f4520SKenneth D. Merry 				      struct ctl_be_block_io *beio);
257c3e7ba3eSAlexander Motin static uint64_t ctl_be_block_getattr_dev(struct ctl_be_block_lun *be_lun,
258c3e7ba3eSAlexander Motin 					 const char *attrname);
259ef8daf3fSAlexander Motin static void ctl_be_block_cr_dispatch(struct ctl_be_block_lun *be_lun,
260ef8daf3fSAlexander Motin 				    union ctl_io *io);
261130f4520SKenneth D. Merry static void ctl_be_block_cw_dispatch(struct ctl_be_block_lun *be_lun,
262130f4520SKenneth D. Merry 				    union ctl_io *io);
263130f4520SKenneth D. Merry static void ctl_be_block_dispatch(struct ctl_be_block_lun *be_lun,
264130f4520SKenneth D. Merry 				  union ctl_io *io);
265130f4520SKenneth D. Merry static void ctl_be_block_worker(void *context, int pending);
266130f4520SKenneth D. Merry static int ctl_be_block_submit(union ctl_io *io);
267130f4520SKenneth D. Merry static int ctl_be_block_ioctl(struct cdev *dev, u_long cmd, caddr_t addr,
268130f4520SKenneth D. Merry 				   int flag, struct thread *td);
269130f4520SKenneth D. Merry static int ctl_be_block_open_file(struct ctl_be_block_lun *be_lun,
270130f4520SKenneth D. Merry 				  struct ctl_lun_req *req);
271130f4520SKenneth D. Merry static int ctl_be_block_open_dev(struct ctl_be_block_lun *be_lun,
272130f4520SKenneth D. Merry 				 struct ctl_lun_req *req);
273130f4520SKenneth D. Merry static int ctl_be_block_close(struct ctl_be_block_lun *be_lun);
274648dfc1aSAlexander Motin static int ctl_be_block_open(struct ctl_be_block_lun *be_lun,
275130f4520SKenneth D. Merry 			     struct ctl_lun_req *req);
276130f4520SKenneth D. Merry static int ctl_be_block_create(struct ctl_be_block_softc *softc,
277130f4520SKenneth D. Merry 			       struct ctl_lun_req *req);
278130f4520SKenneth D. Merry static int ctl_be_block_rm(struct ctl_be_block_softc *softc,
279130f4520SKenneth D. Merry 			   struct ctl_lun_req *req);
28081177295SEdward Tomasz Napierala static int ctl_be_block_modify(struct ctl_be_block_softc *softc,
28181177295SEdward Tomasz Napierala 			   struct ctl_lun_req *req);
282767300e8SAlexander Motin static void ctl_be_block_lun_shutdown(struct ctl_be_lun *cbe_lun);
283130f4520SKenneth D. Merry static int ctl_be_block_config_write(union ctl_io *io);
284130f4520SKenneth D. Merry static int ctl_be_block_config_read(union ctl_io *io);
285767300e8SAlexander Motin static int ctl_be_block_lun_info(struct ctl_be_lun *cbe_lun, struct sbuf *sb);
286767300e8SAlexander Motin static uint64_t ctl_be_block_lun_attr(struct ctl_be_lun *cbe_lun, const char *attrname);
2870c629e28SAlexander Motin static int ctl_be_block_init(void);
2880c629e28SAlexander Motin static int ctl_be_block_shutdown(void);
289130f4520SKenneth D. Merry 
290130f4520SKenneth D. Merry static struct ctl_backend_driver ctl_be_block_driver =
291130f4520SKenneth D. Merry {
2922a2443d8SKenneth D. Merry 	.name = "block",
2932a2443d8SKenneth D. Merry 	.flags = CTL_BE_FLAG_HAS_CONFIG,
2942a2443d8SKenneth D. Merry 	.init = ctl_be_block_init,
2950c629e28SAlexander Motin 	.shutdown = ctl_be_block_shutdown,
2962a2443d8SKenneth D. Merry 	.data_submit = ctl_be_block_submit,
2972a2443d8SKenneth D. Merry 	.config_read = ctl_be_block_config_read,
2982a2443d8SKenneth D. Merry 	.config_write = ctl_be_block_config_write,
2992a2443d8SKenneth D. Merry 	.ioctl = ctl_be_block_ioctl,
300c3e7ba3eSAlexander Motin 	.lun_info = ctl_be_block_lun_info,
301c3e7ba3eSAlexander Motin 	.lun_attr = ctl_be_block_lun_attr
302130f4520SKenneth D. Merry };
303130f4520SKenneth D. Merry 
30434144c2cSAlexander Motin MALLOC_DEFINE(M_CTLBLK, "ctlblock", "Memory used for CTL block backend");
305130f4520SKenneth D. Merry CTL_BACKEND_DECLARE(cbb, ctl_be_block_driver);
306130f4520SKenneth D. Merry 
3078054320eSAlexander Motin static void
3088054320eSAlexander Motin ctl_alloc_seg(struct ctl_be_block_softc *softc, struct ctl_sg_entry *sg,
3098054320eSAlexander Motin     size_t len)
3108054320eSAlexander Motin {
3118054320eSAlexander Motin 
312cd853791SKonstantin Belousov 	if (len <= CTLBLK_MIN_SEG) {
313cd853791SKonstantin Belousov 		sg->addr = uma_zalloc(softc->bufmin_zone, M_WAITOK);
314cd853791SKonstantin Belousov 	} else {
315cd853791SKonstantin Belousov 		KASSERT(len <= CTLBLK_MAX_SEG,
316cd853791SKonstantin Belousov 		    ("Too large alloc %zu > %lu", len, CTLBLK_MAX_SEG));
317cd853791SKonstantin Belousov 		sg->addr = uma_zalloc(softc->bufmax_zone, M_WAITOK);
318cd853791SKonstantin Belousov 	}
3198054320eSAlexander Motin 	sg->len = len;
3208054320eSAlexander Motin }
3218054320eSAlexander Motin 
3228054320eSAlexander Motin static void
3238054320eSAlexander Motin ctl_free_seg(struct ctl_be_block_softc *softc, struct ctl_sg_entry *sg)
3248054320eSAlexander Motin {
3258054320eSAlexander Motin 
326cd853791SKonstantin Belousov 	if (sg->len <= CTLBLK_MIN_SEG) {
327cd853791SKonstantin Belousov 		uma_zfree(softc->bufmin_zone, sg->addr);
328cd853791SKonstantin Belousov 	} else {
329cd853791SKonstantin Belousov 		KASSERT(sg->len <= CTLBLK_MAX_SEG,
330cd853791SKonstantin Belousov 		    ("Too large free %zu > %lu", sg->len, CTLBLK_MAX_SEG));
331cd853791SKonstantin Belousov 		uma_zfree(softc->bufmax_zone, sg->addr);
332cd853791SKonstantin Belousov 	}
3338054320eSAlexander Motin }
3348054320eSAlexander Motin 
335130f4520SKenneth D. Merry static struct ctl_be_block_io *
336130f4520SKenneth D. Merry ctl_alloc_beio(struct ctl_be_block_softc *softc)
337130f4520SKenneth D. Merry {
338130f4520SKenneth D. Merry 	struct ctl_be_block_io *beio;
339130f4520SKenneth D. Merry 
3400c629e28SAlexander Motin 	beio = uma_zalloc(softc->beio_zone, M_WAITOK | M_ZERO);
341130f4520SKenneth D. Merry 	beio->softc = softc;
3429a4510acSAlexander Motin 	beio->refcnt = 1;
343130f4520SKenneth D. Merry 	return (beio);
344130f4520SKenneth D. Merry }
345130f4520SKenneth D. Merry 
346130f4520SKenneth D. Merry static void
3479a4510acSAlexander Motin ctl_real_free_beio(struct ctl_be_block_io *beio)
348130f4520SKenneth D. Merry {
3490d7fed74SAlexander Motin 	struct ctl_be_block_softc *softc = beio->softc;
350130f4520SKenneth D. Merry 	int i;
351130f4520SKenneth D. Merry 
352130f4520SKenneth D. Merry 	for (i = 0; i < beio->num_segs; i++) {
3538054320eSAlexander Motin 		ctl_free_seg(softc, &beio->sg_segs[i]);
35411b569f7SAlexander Motin 
35511b569f7SAlexander Motin 		/* For compare we had two equal S/G lists. */
3560d7fed74SAlexander Motin 		if (beio->two_sglists) {
3578054320eSAlexander Motin 			ctl_free_seg(softc,
3588054320eSAlexander Motin 			    &beio->sg_segs[i + CTLBLK_HALF_SEGS]);
35911b569f7SAlexander Motin 		}
360130f4520SKenneth D. Merry 	}
361130f4520SKenneth D. Merry 
3620d7fed74SAlexander Motin 	uma_zfree(softc->beio_zone, beio);
363130f4520SKenneth D. Merry }
364130f4520SKenneth D. Merry 
365130f4520SKenneth D. Merry static void
3669a4510acSAlexander Motin ctl_refcnt_beio(void *arg, int diff)
3679a4510acSAlexander Motin {
3689a4510acSAlexander Motin 	struct ctl_be_block_io *beio = arg;
3699a4510acSAlexander Motin 
3709a4510acSAlexander Motin 	if (atomic_fetchadd_int(&beio->refcnt, diff) + diff == 0)
3719a4510acSAlexander Motin 		ctl_real_free_beio(beio);
3729a4510acSAlexander Motin }
3739a4510acSAlexander Motin 
3749a4510acSAlexander Motin static void
3759a4510acSAlexander Motin ctl_free_beio(struct ctl_be_block_io *beio)
3769a4510acSAlexander Motin {
3779a4510acSAlexander Motin 
3789a4510acSAlexander Motin 	ctl_refcnt_beio(beio, -1);
3799a4510acSAlexander Motin }
3809a4510acSAlexander Motin 
3819a4510acSAlexander Motin static void
382130f4520SKenneth D. Merry ctl_complete_beio(struct ctl_be_block_io *beio)
383130f4520SKenneth D. Merry {
38475c7a1d3SAlexander Motin 	union ctl_io *io = beio->io;
385130f4520SKenneth D. Merry 
386ee7f31c0SAlexander Motin 	if (beio->beio_cont != NULL) {
387ee7f31c0SAlexander Motin 		beio->beio_cont(beio);
388ee7f31c0SAlexander Motin 	} else {
389130f4520SKenneth D. Merry 		ctl_free_beio(beio);
39011b569f7SAlexander Motin 		ctl_data_submit_done(io);
391130f4520SKenneth D. Merry 	}
392ee7f31c0SAlexander Motin }
393130f4520SKenneth D. Merry 
39440a43590SJohn Baldwin static void
39540a43590SJohn Baldwin ctl_be_block_io_error(union ctl_io *io, int bio_cmd, uint16_t retry_count)
39640a43590SJohn Baldwin {
39740a43590SJohn Baldwin 	switch (io->io_hdr.io_type) {
39840a43590SJohn Baldwin 	case CTL_IO_SCSI:
39940a43590SJohn Baldwin 		if (bio_cmd == BIO_FLUSH) {
40040a43590SJohn Baldwin 			/* XXX KDM is there is a better error here? */
40140a43590SJohn Baldwin 			ctl_set_internal_failure(&io->scsiio,
40240a43590SJohn Baldwin 						 /*sks_valid*/ 1,
40340a43590SJohn Baldwin 						 retry_count);
40440a43590SJohn Baldwin 		} else {
40540a43590SJohn Baldwin 			ctl_set_medium_error(&io->scsiio, bio_cmd == BIO_READ);
40640a43590SJohn Baldwin 		}
40740a43590SJohn Baldwin 		break;
40840a43590SJohn Baldwin 	case CTL_IO_NVME:
40940a43590SJohn Baldwin 		switch (bio_cmd) {
41040a43590SJohn Baldwin 		case BIO_FLUSH:
41140a43590SJohn Baldwin 		case BIO_WRITE:
41240a43590SJohn Baldwin 			ctl_nvme_set_write_fault(&io->nvmeio);
41340a43590SJohn Baldwin 			break;
41440a43590SJohn Baldwin 		case BIO_READ:
41540a43590SJohn Baldwin 			ctl_nvme_set_unrecoverable_read_error(&io->nvmeio);
41640a43590SJohn Baldwin 			break;
41740a43590SJohn Baldwin 		default:
41840a43590SJohn Baldwin 			ctl_nvme_set_internal_error(&io->nvmeio);
41940a43590SJohn Baldwin 			break;
42040a43590SJohn Baldwin 		}
42140a43590SJohn Baldwin 		break;
42240a43590SJohn Baldwin 	default:
42340a43590SJohn Baldwin 		__assert_unreachable();
42440a43590SJohn Baldwin 	}
42540a43590SJohn Baldwin }
42640a43590SJohn Baldwin 
427d6043e46SAlexander Motin static size_t
428d6043e46SAlexander Motin cmp(uint8_t *a, uint8_t *b, size_t size)
429d6043e46SAlexander Motin {
430d6043e46SAlexander Motin 	size_t i;
431d6043e46SAlexander Motin 
432d6043e46SAlexander Motin 	for (i = 0; i < size; i++) {
433d6043e46SAlexander Motin 		if (a[i] != b[i])
434d6043e46SAlexander Motin 			break;
435d6043e46SAlexander Motin 	}
436d6043e46SAlexander Motin 	return (i);
437d6043e46SAlexander Motin }
438d6043e46SAlexander Motin 
439d6043e46SAlexander Motin static void
440d6043e46SAlexander Motin ctl_be_block_compare(union ctl_io *io)
441d6043e46SAlexander Motin {
442d6043e46SAlexander Motin 	struct ctl_be_block_io *beio;
443d6043e46SAlexander Motin 	uint64_t off, res;
444d6043e46SAlexander Motin 	int i;
445d6043e46SAlexander Motin 
446d6043e46SAlexander Motin 	beio = (struct ctl_be_block_io *)PRIV(io)->ptr;
447d6043e46SAlexander Motin 	off = 0;
448d6043e46SAlexander Motin 	for (i = 0; i < beio->num_segs; i++) {
449d6043e46SAlexander Motin 		res = cmp(beio->sg_segs[i].addr,
450d6043e46SAlexander Motin 		    beio->sg_segs[i + CTLBLK_HALF_SEGS].addr,
451d6043e46SAlexander Motin 		    beio->sg_segs[i].len);
452d6043e46SAlexander Motin 		off += res;
453d6043e46SAlexander Motin 		if (res < beio->sg_segs[i].len)
454d6043e46SAlexander Motin 			break;
455d6043e46SAlexander Motin 	}
456d6043e46SAlexander Motin 	if (i < beio->num_segs) {
45740a43590SJohn Baldwin 		ctl_io_set_compare_failure(io, off);
458d6043e46SAlexander Motin 	} else
45940a43590SJohn Baldwin 		ctl_io_set_success(io);
460d6043e46SAlexander Motin }
461d6043e46SAlexander Motin 
462130f4520SKenneth D. Merry static int
4632c7dc6baSAlexander Motin ctl_be_block_move_done(union ctl_io *io, bool samethr)
464130f4520SKenneth D. Merry {
465130f4520SKenneth D. Merry 	struct ctl_be_block_io *beio;
466130f4520SKenneth D. Merry 	struct ctl_be_block_lun *be_lun;
46711b569f7SAlexander Motin 	struct ctl_lba_len_flags *lbalen;
468130f4520SKenneth D. Merry 
469e86a4142SAlexander Motin 	beio = (struct ctl_be_block_io *)PRIV(io)->ptr;
470130f4520SKenneth D. Merry 
471130f4520SKenneth D. Merry 	DPRINTF("entered\n");
47240a43590SJohn Baldwin 	ctl_add_kern_rel_offset(io, ctl_kern_data_len(io));
473130f4520SKenneth D. Merry 
474130f4520SKenneth D. Merry 	/*
4752c7dc6baSAlexander Motin 	 * We set status at this point for read and compare commands.
476130f4520SKenneth D. Merry 	 */
4772c7dc6baSAlexander Motin 	if ((io->io_hdr.flags & CTL_FLAG_ABORT) == 0 &&
4782c7dc6baSAlexander Motin 	    (io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE) {
479a59e2982SAlexander Motin 		lbalen = ARGS(io);
48011b569f7SAlexander Motin 		if (lbalen->flags & CTL_LLF_READ) {
48140a43590SJohn Baldwin 			ctl_io_set_success(io);
48211b569f7SAlexander Motin 		} else if (lbalen->flags & CTL_LLF_COMPARE) {
48311b569f7SAlexander Motin 			/* We have two data blocks ready for comparison. */
484d6043e46SAlexander Motin 			ctl_be_block_compare(io);
48511b569f7SAlexander Motin 		}
486130f4520SKenneth D. Merry 	}
487130f4520SKenneth D. Merry 
488130f4520SKenneth D. Merry 	/*
489130f4520SKenneth D. Merry 	 * If this is a read, or a write with errors, it is done.
490130f4520SKenneth D. Merry 	 */
491130f4520SKenneth D. Merry 	if ((beio->bio_cmd == BIO_READ)
492130f4520SKenneth D. Merry 	 || ((io->io_hdr.flags & CTL_FLAG_ABORT) != 0)
493130f4520SKenneth D. Merry 	 || ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE)) {
494130f4520SKenneth D. Merry 		ctl_complete_beio(beio);
495130f4520SKenneth D. Merry 		return (0);
496130f4520SKenneth D. Merry 	}
497130f4520SKenneth D. Merry 
498130f4520SKenneth D. Merry 	/*
4992c7dc6baSAlexander Motin 	 * At this point, we have a write and the DMA completed successfully.
5002c7dc6baSAlexander Motin 	 * If we were called synchronously in the original thread then just
5012c7dc6baSAlexander Motin 	 * dispatch, otherwise we now have to queue it to the task queue to
502130f4520SKenneth D. Merry 	 * execute the backend I/O.  That is because we do blocking
503130f4520SKenneth D. Merry 	 * memory allocations, and in the file backing case, blocking I/O.
504130f4520SKenneth D. Merry 	 * This move done routine is generally called in the SIM's
505130f4520SKenneth D. Merry 	 * interrupt context, and therefore we cannot block.
506130f4520SKenneth D. Merry 	 */
507a59e2982SAlexander Motin 	be_lun = (struct ctl_be_block_lun *)CTL_BACKEND_LUN(io);
5082c7dc6baSAlexander Motin 	if (samethr) {
5092c7dc6baSAlexander Motin 		be_lun->dispatch(be_lun, beio);
5102c7dc6baSAlexander Motin 	} else {
51175c7a1d3SAlexander Motin 		mtx_lock(&be_lun->queue_lock);
512130f4520SKenneth D. Merry 		STAILQ_INSERT_TAIL(&be_lun->datamove_queue, &io->io_hdr, links);
51375c7a1d3SAlexander Motin 		mtx_unlock(&be_lun->queue_lock);
514130f4520SKenneth D. Merry 		taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task);
5152c7dc6baSAlexander Motin 	}
516130f4520SKenneth D. Merry 	return (0);
517130f4520SKenneth D. Merry }
518130f4520SKenneth D. Merry 
519130f4520SKenneth D. Merry static void
520130f4520SKenneth D. Merry ctl_be_block_biodone(struct bio *bio)
521130f4520SKenneth D. Merry {
522ac503c19SAlexander Motin 	struct ctl_be_block_io *beio = bio->bio_caller1;
523ac503c19SAlexander Motin 	struct ctl_be_block_lun *be_lun = beio->lun;
524ac503c19SAlexander Motin 	struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun;
525130f4520SKenneth D. Merry 	union ctl_io *io;
526e0c2f975SAlexander Motin 	int error;
527130f4520SKenneth D. Merry 
528130f4520SKenneth D. Merry 	io = beio->io;
529130f4520SKenneth D. Merry 
530130f4520SKenneth D. Merry 	DPRINTF("entered\n");
531130f4520SKenneth D. Merry 
532e0c2f975SAlexander Motin 	error = bio->bio_error;
53375c7a1d3SAlexander Motin 	mtx_lock(&be_lun->io_lock);
5341f0694a6SAlexander Motin 	if (error != 0 &&
5351f0694a6SAlexander Motin 	    (beio->first_error == 0 ||
5361f0694a6SAlexander Motin 	     bio->bio_offset < beio->first_error_offset)) {
5371f0694a6SAlexander Motin 		beio->first_error = error;
5381f0694a6SAlexander Motin 		beio->first_error_offset = bio->bio_offset;
5391f0694a6SAlexander Motin 	}
540130f4520SKenneth D. Merry 
541130f4520SKenneth D. Merry 	beio->num_bios_done++;
542130f4520SKenneth D. Merry 
543130f4520SKenneth D. Merry 	/*
544130f4520SKenneth D. Merry 	 * XXX KDM will this cause WITNESS to complain?  Holding a lock
545130f4520SKenneth D. Merry 	 * during the free might cause it to complain.
546130f4520SKenneth D. Merry 	 */
547130f4520SKenneth D. Merry 	g_destroy_bio(bio);
548130f4520SKenneth D. Merry 
549130f4520SKenneth D. Merry 	/*
550130f4520SKenneth D. Merry 	 * If the send complete bit isn't set, or we aren't the last I/O to
551130f4520SKenneth D. Merry 	 * complete, then we're done.
552130f4520SKenneth D. Merry 	 */
553130f4520SKenneth D. Merry 	if ((beio->send_complete == 0)
554130f4520SKenneth D. Merry 	 || (beio->num_bios_done < beio->num_bios_sent)) {
55575c7a1d3SAlexander Motin 		mtx_unlock(&be_lun->io_lock);
556130f4520SKenneth D. Merry 		return;
557130f4520SKenneth D. Merry 	}
558130f4520SKenneth D. Merry 
559130f4520SKenneth D. Merry 	/*
560130f4520SKenneth D. Merry 	 * At this point, we've verified that we are the last I/O to
561130f4520SKenneth D. Merry 	 * complete, so it's safe to drop the lock.
562130f4520SKenneth D. Merry 	 */
56375c7a1d3SAlexander Motin 	devstat_end_transaction(beio->lun->disk_stats, beio->io_len,
56475c7a1d3SAlexander Motin 	    beio->ds_tag_type, beio->ds_trans_type,
56575c7a1d3SAlexander Motin 	    /*now*/ NULL, /*then*/&beio->ds_t0);
56675c7a1d3SAlexander Motin 	mtx_unlock(&be_lun->io_lock);
567130f4520SKenneth D. Merry 
568130f4520SKenneth D. Merry 	/*
569130f4520SKenneth D. Merry 	 * If there are any errors from the backing device, we fail the
570130f4520SKenneth D. Merry 	 * entire I/O with a medium error.
571130f4520SKenneth D. Merry 	 */
5721f0694a6SAlexander Motin 	error = beio->first_error;
5731f0694a6SAlexander Motin 	if (error != 0) {
574e0c2f975SAlexander Motin 		if (error == EOPNOTSUPP) {
57540a43590SJohn Baldwin 			ctl_io_set_invalid_opcode(io);
5760631de4aSAlexander Motin 		} else if (error == ENOSPC || error == EDQUOT) {
57740a43590SJohn Baldwin 			ctl_io_set_space_alloc_fail(io);
5786187d472SAlexander Motin 		} else if (error == EROFS || error == EACCES) {
57940a43590SJohn Baldwin 			ctl_io_set_hw_write_protected(io);
5807f7bb97aSAlexander Motin 		} else {
58140a43590SJohn Baldwin 			ctl_be_block_io_error(io, beio->bio_cmd,
58240a43590SJohn Baldwin 			    /*retry_count*/ 0xbad2);
5837f7bb97aSAlexander Motin 		}
584130f4520SKenneth D. Merry 		ctl_complete_beio(beio);
585130f4520SKenneth D. Merry 		return;
586130f4520SKenneth D. Merry 	}
587130f4520SKenneth D. Merry 
588130f4520SKenneth D. Merry 	/*
58911b569f7SAlexander Motin 	 * If this is a write, a flush, a delete or verify, we're all done.
590130f4520SKenneth D. Merry 	 * If this is a read, we can now send the data to the user.
591130f4520SKenneth D. Merry 	 */
592130f4520SKenneth D. Merry 	if ((beio->bio_cmd == BIO_WRITE)
593ee7f31c0SAlexander Motin 	 || (beio->bio_cmd == BIO_FLUSH)
59411b569f7SAlexander Motin 	 || (beio->bio_cmd == BIO_DELETE)
59511b569f7SAlexander Motin 	 || (ARGS(io)->flags & CTL_LLF_VERIFY)) {
59640a43590SJohn Baldwin 		ctl_io_set_success(io);
597130f4520SKenneth D. Merry 		ctl_complete_beio(beio);
598130f4520SKenneth D. Merry 	} else {
599f7241cceSAlexander Motin 		if ((ARGS(io)->flags & CTL_LLF_READ) &&
60075a3108eSAlexander Motin 		    beio->beio_cont == NULL) {
60140a43590SJohn Baldwin 			ctl_io_set_success(io);
602ac503c19SAlexander Motin 			if (cbe_lun->serseq >= CTL_LUN_SERSEQ_SOFT)
60375a3108eSAlexander Motin 				ctl_serseq_done(io);
60475a3108eSAlexander Motin 		}
605130f4520SKenneth D. Merry 		ctl_datamove(io);
606130f4520SKenneth D. Merry 	}
607130f4520SKenneth D. Merry }
608130f4520SKenneth D. Merry 
609130f4520SKenneth D. Merry static void
610130f4520SKenneth D. Merry ctl_be_block_flush_file(struct ctl_be_block_lun *be_lun,
611130f4520SKenneth D. Merry 			struct ctl_be_block_io *beio)
612130f4520SKenneth D. Merry {
61375c7a1d3SAlexander Motin 	union ctl_io *io = beio->io;
614130f4520SKenneth D. Merry 	struct mount *mountpoint;
6150ef5eee9SKonstantin Belousov 	int error;
616130f4520SKenneth D. Merry 
617130f4520SKenneth D. Merry 	DPRINTF("entered\n");
618130f4520SKenneth D. Merry 
61975c7a1d3SAlexander Motin 	binuptime(&beio->ds_t0);
62075c7a1d3SAlexander Motin 	devstat_start_transaction(beio->lun->disk_stats, &beio->ds_t0);
621130f4520SKenneth D. Merry 
622130f4520SKenneth D. Merry 	(void) vn_start_write(be_lun->vn, &mountpoint, V_WAIT);
623130f4520SKenneth D. Merry 
6240ef5eee9SKonstantin Belousov 	vn_lock(be_lun->vn, vn_lktype_write(mountpoint, be_lun->vn) |
6250ef5eee9SKonstantin Belousov 	    LK_RETRY);
6267d0d4342SAlexander Motin 	error = VOP_FSYNC(be_lun->vn, beio->io_arg ? MNT_NOWAIT : MNT_WAIT,
6277d0d4342SAlexander Motin 	    curthread);
628b249ce48SMateusz Guzik 	VOP_UNLOCK(be_lun->vn);
629130f4520SKenneth D. Merry 
630130f4520SKenneth D. Merry 	vn_finished_write(mountpoint);
631130f4520SKenneth D. Merry 
63275c7a1d3SAlexander Motin 	mtx_lock(&be_lun->io_lock);
63375c7a1d3SAlexander Motin 	devstat_end_transaction(beio->lun->disk_stats, beio->io_len,
63475c7a1d3SAlexander Motin 	    beio->ds_tag_type, beio->ds_trans_type,
63575c7a1d3SAlexander Motin 	    /*now*/ NULL, /*then*/&beio->ds_t0);
63675c7a1d3SAlexander Motin 	mtx_unlock(&be_lun->io_lock);
63775c7a1d3SAlexander Motin 
638130f4520SKenneth D. Merry 	if (error == 0)
63940a43590SJohn Baldwin 		ctl_io_set_success(io);
640130f4520SKenneth D. Merry 	else {
64140a43590SJohn Baldwin 		ctl_be_block_io_error(io, BIO_FLUSH,
642130f4520SKenneth D. Merry 		    /*retry_count*/ 0xbad1);
643130f4520SKenneth D. Merry 	}
644130f4520SKenneth D. Merry 
645130f4520SKenneth D. Merry 	ctl_complete_beio(beio);
646130f4520SKenneth D. Merry }
647130f4520SKenneth D. Merry 
64836160958SMark Johnston SDT_PROBE_DEFINE1(cbb, , read, file_start, "uint64_t");
64936160958SMark Johnston SDT_PROBE_DEFINE1(cbb, , write, file_start, "uint64_t");
65036160958SMark Johnston SDT_PROBE_DEFINE1(cbb, , read, file_done,"uint64_t");
65136160958SMark Johnston SDT_PROBE_DEFINE1(cbb, , write, file_done, "uint64_t");
652130f4520SKenneth D. Merry 
653130f4520SKenneth D. Merry static void
654130f4520SKenneth D. Merry ctl_be_block_dispatch_file(struct ctl_be_block_lun *be_lun,
655130f4520SKenneth D. Merry 			   struct ctl_be_block_io *beio)
656130f4520SKenneth D. Merry {
657ac503c19SAlexander Motin 	struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun;
658130f4520SKenneth D. Merry 	struct ctl_be_block_filedata *file_data;
659130f4520SKenneth D. Merry 	union ctl_io *io;
660130f4520SKenneth D. Merry 	struct uio xuio;
661130f4520SKenneth D. Merry 	struct iovec *xiovec;
66283981e31SAlexander Motin 	size_t s;
66383981e31SAlexander Motin 	int error, flags, i;
664130f4520SKenneth D. Merry 
665130f4520SKenneth D. Merry 	DPRINTF("entered\n");
666130f4520SKenneth D. Merry 
667130f4520SKenneth D. Merry 	file_data = &be_lun->backend.file;
668130f4520SKenneth D. Merry 	io = beio->io;
66955551d05SAlexander Motin 	flags = 0;
67055551d05SAlexander Motin 	if (ARGS(io)->flags & CTL_LLF_DPO)
67155551d05SAlexander Motin 		flags |= IO_DIRECT;
67255551d05SAlexander Motin 	if (beio->bio_cmd == BIO_WRITE && ARGS(io)->flags & CTL_LLF_FUA)
67355551d05SAlexander Motin 		flags |= IO_SYNC;
674130f4520SKenneth D. Merry 
67511b569f7SAlexander Motin 	bzero(&xuio, sizeof(xuio));
676130f4520SKenneth D. Merry 	if (beio->bio_cmd == BIO_READ) {
67736160958SMark Johnston 		SDT_PROBE0(cbb, , read, file_start);
67811b569f7SAlexander Motin 		xuio.uio_rw = UIO_READ;
679130f4520SKenneth D. Merry 	} else {
68036160958SMark Johnston 		SDT_PROBE0(cbb, , write, file_start);
681130f4520SKenneth D. Merry 		xuio.uio_rw = UIO_WRITE;
68211b569f7SAlexander Motin 	}
683130f4520SKenneth D. Merry 	xuio.uio_offset = beio->io_offset;
684130f4520SKenneth D. Merry 	xuio.uio_resid = beio->io_len;
685130f4520SKenneth D. Merry 	xuio.uio_segflg = UIO_SYSSPACE;
686130f4520SKenneth D. Merry 	xuio.uio_iov = beio->xiovecs;
687130f4520SKenneth D. Merry 	xuio.uio_iovcnt = beio->num_segs;
688130f4520SKenneth D. Merry 	xuio.uio_td = curthread;
689130f4520SKenneth D. Merry 
690130f4520SKenneth D. Merry 	for (i = 0, xiovec = xuio.uio_iov; i < xuio.uio_iovcnt; i++, xiovec++) {
691130f4520SKenneth D. Merry 		xiovec->iov_base = beio->sg_segs[i].addr;
692130f4520SKenneth D. Merry 		xiovec->iov_len = beio->sg_segs[i].len;
693130f4520SKenneth D. Merry 	}
694130f4520SKenneth D. Merry 
69575c7a1d3SAlexander Motin 	binuptime(&beio->ds_t0);
69675c7a1d3SAlexander Motin 	devstat_start_transaction(beio->lun->disk_stats, &beio->ds_t0);
69775c7a1d3SAlexander Motin 
698130f4520SKenneth D. Merry 	if (beio->bio_cmd == BIO_READ) {
699130f4520SKenneth D. Merry 		vn_lock(be_lun->vn, LK_SHARED | LK_RETRY);
700130f4520SKenneth D. Merry 
701ac503c19SAlexander Motin 		if (beio->beio_cont == NULL &&
702ac503c19SAlexander Motin 		    cbe_lun->serseq == CTL_LUN_SERSEQ_SOFT)
703ac503c19SAlexander Motin 			ctl_serseq_done(io);
704130f4520SKenneth D. Merry 		/*
705130f4520SKenneth D. Merry 		 * UFS pays attention to IO_DIRECT for reads.  If the
706130f4520SKenneth D. Merry 		 * DIRECTIO option is configured into the kernel, it calls
707130f4520SKenneth D. Merry 		 * ffs_rawread().  But that only works for single-segment
708130f4520SKenneth D. Merry 		 * uios with user space addresses.  In our case, with a
709130f4520SKenneth D. Merry 		 * kernel uio, it still reads into the buffer cache, but it
710130f4520SKenneth D. Merry 		 * will just try to release the buffer from the cache later
711130f4520SKenneth D. Merry 		 * on in ffs_read().
712130f4520SKenneth D. Merry 		 *
713130f4520SKenneth D. Merry 		 * ZFS does not pay attention to IO_DIRECT for reads.
714130f4520SKenneth D. Merry 		 *
715130f4520SKenneth D. Merry 		 * UFS does not pay attention to IO_SYNC for reads.
716130f4520SKenneth D. Merry 		 *
717130f4520SKenneth D. Merry 		 * ZFS pays attention to IO_SYNC (which translates into the
718130f4520SKenneth D. Merry 		 * Solaris define FRSYNC for zfs_read()) for reads.  It
719130f4520SKenneth D. Merry 		 * attempts to sync the file before reading.
720130f4520SKenneth D. Merry 		 */
72155551d05SAlexander Motin 		error = VOP_READ(be_lun->vn, &xuio, flags, file_data->cred);
722130f4520SKenneth D. Merry 
723b249ce48SMateusz Guzik 		VOP_UNLOCK(be_lun->vn);
72436160958SMark Johnston 		SDT_PROBE0(cbb, , read, file_done);
72583981e31SAlexander Motin 		if (error == 0 && xuio.uio_resid > 0) {
72683981e31SAlexander Motin 			/*
72740a43590SJohn Baldwin 			 * If we read less then requested (EOF), then
72883981e31SAlexander Motin 			 * we should clean the rest of the buffer.
72983981e31SAlexander Motin 			 */
73083981e31SAlexander Motin 			s = beio->io_len - xuio.uio_resid;
73183981e31SAlexander Motin 			for (i = 0; i < beio->num_segs; i++) {
73283981e31SAlexander Motin 				if (s >= beio->sg_segs[i].len) {
73383981e31SAlexander Motin 					s -= beio->sg_segs[i].len;
73483981e31SAlexander Motin 					continue;
73583981e31SAlexander Motin 				}
73683981e31SAlexander Motin 				bzero((uint8_t *)beio->sg_segs[i].addr + s,
73783981e31SAlexander Motin 				    beio->sg_segs[i].len - s);
73883981e31SAlexander Motin 				s = 0;
73983981e31SAlexander Motin 			}
74083981e31SAlexander Motin 		}
741130f4520SKenneth D. Merry 	} else {
742130f4520SKenneth D. Merry 		struct mount *mountpoint;
743130f4520SKenneth D. Merry 
744130f4520SKenneth D. Merry 		(void)vn_start_write(be_lun->vn, &mountpoint, V_WAIT);
7450ef5eee9SKonstantin Belousov 		vn_lock(be_lun->vn, vn_lktype_write(mountpoint,
7460ef5eee9SKonstantin Belousov 		    be_lun->vn) | LK_RETRY);
747130f4520SKenneth D. Merry 
748130f4520SKenneth D. Merry 		/*
749130f4520SKenneth D. Merry 		 * UFS pays attention to IO_DIRECT for writes.  The write
750130f4520SKenneth D. Merry 		 * is done asynchronously.  (Normally the write would just
751130f4520SKenneth D. Merry 		 * get put into cache.
752130f4520SKenneth D. Merry 		 *
753130f4520SKenneth D. Merry 		 * UFS pays attention to IO_SYNC for writes.  It will
754130f4520SKenneth D. Merry 		 * attempt to write the buffer out synchronously if that
755130f4520SKenneth D. Merry 		 * flag is set.
756130f4520SKenneth D. Merry 		 *
757130f4520SKenneth D. Merry 		 * ZFS does not pay attention to IO_DIRECT for writes.
758130f4520SKenneth D. Merry 		 *
759130f4520SKenneth D. Merry 		 * ZFS pays attention to IO_SYNC (a.k.a. FSYNC or FRSYNC)
760130f4520SKenneth D. Merry 		 * for writes.  It will flush the transaction from the
761130f4520SKenneth D. Merry 		 * cache before returning.
762130f4520SKenneth D. Merry 		 */
76355551d05SAlexander Motin 		error = VOP_WRITE(be_lun->vn, &xuio, flags, file_data->cred);
764b249ce48SMateusz Guzik 		VOP_UNLOCK(be_lun->vn);
765130f4520SKenneth D. Merry 
766130f4520SKenneth D. Merry 		vn_finished_write(mountpoint);
76736160958SMark Johnston 		SDT_PROBE0(cbb, , write, file_done);
768130f4520SKenneth D. Merry         }
769130f4520SKenneth D. Merry 
77075c7a1d3SAlexander Motin 	mtx_lock(&be_lun->io_lock);
77175c7a1d3SAlexander Motin 	devstat_end_transaction(beio->lun->disk_stats, beio->io_len,
77275c7a1d3SAlexander Motin 	    beio->ds_tag_type, beio->ds_trans_type,
77375c7a1d3SAlexander Motin 	    /*now*/ NULL, /*then*/&beio->ds_t0);
77475c7a1d3SAlexander Motin 	mtx_unlock(&be_lun->io_lock);
77575c7a1d3SAlexander Motin 
776130f4520SKenneth D. Merry 	/*
777130f4520SKenneth D. Merry 	 * If we got an error, set the sense data to "MEDIUM ERROR" and
778130f4520SKenneth D. Merry 	 * return the I/O to the user.
779130f4520SKenneth D. Merry 	 */
780130f4520SKenneth D. Merry 	if (error != 0) {
7810631de4aSAlexander Motin 		if (error == ENOSPC || error == EDQUOT) {
78240a43590SJohn Baldwin 			ctl_io_set_space_alloc_fail(io);
7836187d472SAlexander Motin 		} else if (error == EROFS || error == EACCES) {
78440a43590SJohn Baldwin 			ctl_io_set_hw_write_protected(io);
7857f7bb97aSAlexander Motin 		} else {
78640a43590SJohn Baldwin 			ctl_be_block_io_error(io, beio->bio_cmd, 0);
7877f7bb97aSAlexander Motin 		}
788130f4520SKenneth D. Merry 		ctl_complete_beio(beio);
789130f4520SKenneth D. Merry 		return;
790130f4520SKenneth D. Merry 	}
791130f4520SKenneth D. Merry 
792130f4520SKenneth D. Merry 	/*
793696297adSAlexander Motin 	 * If this is a write or a verify, we're all done.
794130f4520SKenneth D. Merry 	 * If this is a read, we can now send the data to the user.
795130f4520SKenneth D. Merry 	 */
796696297adSAlexander Motin 	if ((beio->bio_cmd == BIO_WRITE) ||
797696297adSAlexander Motin 	    (ARGS(io)->flags & CTL_LLF_VERIFY)) {
79840a43590SJohn Baldwin 		ctl_io_set_success(io);
799130f4520SKenneth D. Merry 		ctl_complete_beio(beio);
800130f4520SKenneth D. Merry 	} else {
801f7241cceSAlexander Motin 		if ((ARGS(io)->flags & CTL_LLF_READ) &&
80275a3108eSAlexander Motin 		    beio->beio_cont == NULL) {
80340a43590SJohn Baldwin 			ctl_io_set_success(io);
804ac503c19SAlexander Motin 			if (cbe_lun->serseq > CTL_LUN_SERSEQ_SOFT)
80575a3108eSAlexander Motin 				ctl_serseq_done(io);
80675a3108eSAlexander Motin 		}
807130f4520SKenneth D. Merry 		ctl_datamove(io);
808130f4520SKenneth D. Merry 	}
809130f4520SKenneth D. Merry }
810130f4520SKenneth D. Merry 
811130f4520SKenneth D. Merry static void
812ef8daf3fSAlexander Motin ctl_be_block_gls_file(struct ctl_be_block_lun *be_lun,
813ef8daf3fSAlexander Motin 			struct ctl_be_block_io *beio)
814ef8daf3fSAlexander Motin {
815ef8daf3fSAlexander Motin 	union ctl_io *io = beio->io;
816ef8daf3fSAlexander Motin 	struct ctl_lba_len_flags *lbalen = ARGS(io);
817ef8daf3fSAlexander Motin 	struct scsi_get_lba_status_data *data;
818ef8daf3fSAlexander Motin 	off_t roff, off;
819ef8daf3fSAlexander Motin 	int error, status;
820ef8daf3fSAlexander Motin 
821ef8daf3fSAlexander Motin 	DPRINTF("entered\n");
822ef8daf3fSAlexander Motin 
823374f12c5SJohn Baldwin 	CTL_IO_ASSERT(io, SCSI);
824374f12c5SJohn Baldwin 
8250bcd4ab6SAlexander Motin 	off = roff = ((off_t)lbalen->lba) * be_lun->cbe_lun.blocksize;
826ef8daf3fSAlexander Motin 	vn_lock(be_lun->vn, LK_SHARED | LK_RETRY);
827ef8daf3fSAlexander Motin 	error = VOP_IOCTL(be_lun->vn, FIOSEEKHOLE, &off,
828ef8daf3fSAlexander Motin 	    0, curthread->td_ucred, curthread);
829ef8daf3fSAlexander Motin 	if (error == 0 && off > roff)
830ef8daf3fSAlexander Motin 		status = 0;	/* mapped up to off */
831ef8daf3fSAlexander Motin 	else {
832ef8daf3fSAlexander Motin 		error = VOP_IOCTL(be_lun->vn, FIOSEEKDATA, &off,
833ef8daf3fSAlexander Motin 		    0, curthread->td_ucred, curthread);
834ef8daf3fSAlexander Motin 		if (error == 0 && off > roff)
835ef8daf3fSAlexander Motin 			status = 1;	/* deallocated up to off */
836ef8daf3fSAlexander Motin 		else {
837ef8daf3fSAlexander Motin 			status = 0;	/* unknown up to the end */
838ef8daf3fSAlexander Motin 			off = be_lun->size_bytes;
839ef8daf3fSAlexander Motin 		}
840ef8daf3fSAlexander Motin 	}
841b249ce48SMateusz Guzik 	VOP_UNLOCK(be_lun->vn);
842ef8daf3fSAlexander Motin 
843ef8daf3fSAlexander Motin 	data = (struct scsi_get_lba_status_data *)io->scsiio.kern_data_ptr;
844ef8daf3fSAlexander Motin 	scsi_u64to8b(lbalen->lba, data->descr[0].addr);
8450bcd4ab6SAlexander Motin 	scsi_ulto4b(MIN(UINT32_MAX, off / be_lun->cbe_lun.blocksize -
8460bcd4ab6SAlexander Motin 	    lbalen->lba), data->descr[0].length);
847ef8daf3fSAlexander Motin 	data->descr[0].status = status;
848ef8daf3fSAlexander Motin 
849ef8daf3fSAlexander Motin 	ctl_complete_beio(beio);
850ef8daf3fSAlexander Motin }
851ef8daf3fSAlexander Motin 
85253c146deSAlexander Motin static uint64_t
85353c146deSAlexander Motin ctl_be_block_getattr_file(struct ctl_be_block_lun *be_lun, const char *attrname)
85453c146deSAlexander Motin {
85553c146deSAlexander Motin 	struct vattr		vattr;
85653c146deSAlexander Motin 	struct statfs		statfs;
857b9b4269cSAlexander Motin 	uint64_t		val;
85853c146deSAlexander Motin 	int			error;
85953c146deSAlexander Motin 
860b9b4269cSAlexander Motin 	val = UINT64_MAX;
86153c146deSAlexander Motin 	if (be_lun->vn == NULL)
862b9b4269cSAlexander Motin 		return (val);
863b9b4269cSAlexander Motin 	vn_lock(be_lun->vn, LK_SHARED | LK_RETRY);
86453c146deSAlexander Motin 	if (strcmp(attrname, "blocksused") == 0) {
86553c146deSAlexander Motin 		error = VOP_GETATTR(be_lun->vn, &vattr, curthread->td_ucred);
866b9b4269cSAlexander Motin 		if (error == 0)
8670bcd4ab6SAlexander Motin 			val = vattr.va_bytes / be_lun->cbe_lun.blocksize;
86853c146deSAlexander Motin 	}
869b9b4269cSAlexander Motin 	if (strcmp(attrname, "blocksavail") == 0 &&
870abd80ddbSMateusz Guzik 	    !VN_IS_DOOMED(be_lun->vn)) {
87153c146deSAlexander Motin 		error = VFS_STATFS(be_lun->vn->v_mount, &statfs);
872b9b4269cSAlexander Motin 		if (error == 0)
873a15bbf15SAlexander Motin 			val = statfs.f_bavail * statfs.f_bsize /
8740bcd4ab6SAlexander Motin 			    be_lun->cbe_lun.blocksize;
87553c146deSAlexander Motin 	}
876b249ce48SMateusz Guzik 	VOP_UNLOCK(be_lun->vn);
877b9b4269cSAlexander Motin 	return (val);
87853c146deSAlexander Motin }
87953c146deSAlexander Motin 
880ef8daf3fSAlexander Motin static void
88149050613SKa Ho Ng ctl_be_block_unmap_file(struct ctl_be_block_lun *be_lun,
88249050613SKa Ho Ng 		        struct ctl_be_block_io *beio)
88349050613SKa Ho Ng {
88449050613SKa Ho Ng 	struct ctl_be_block_filedata *file_data;
88549050613SKa Ho Ng 	union ctl_io *io;
88649050613SKa Ho Ng 	struct ctl_ptr_len_flags *ptrlen;
88749050613SKa Ho Ng 	struct scsi_unmap_desc *buf, *end;
88849050613SKa Ho Ng 	struct mount *mp;
88949050613SKa Ho Ng 	off_t off, len;
89049050613SKa Ho Ng 	int error;
89149050613SKa Ho Ng 
89249050613SKa Ho Ng 	io = beio->io;
89349050613SKa Ho Ng 	file_data = &be_lun->backend.file;
89449050613SKa Ho Ng 	mp = NULL;
89549050613SKa Ho Ng 	error = 0;
89649050613SKa Ho Ng 
89749050613SKa Ho Ng 	binuptime(&beio->ds_t0);
89849050613SKa Ho Ng 	devstat_start_transaction(be_lun->disk_stats, &beio->ds_t0);
89949050613SKa Ho Ng 
90049050613SKa Ho Ng 	(void)vn_start_write(be_lun->vn, &mp, V_WAIT);
90149050613SKa Ho Ng 	vn_lock(be_lun->vn, vn_lktype_write(mp, be_lun->vn) | LK_RETRY);
90249050613SKa Ho Ng 	if (beio->io_offset == -1) {
90349050613SKa Ho Ng 		beio->io_len = 0;
90449050613SKa Ho Ng 		ptrlen = (struct ctl_ptr_len_flags *)
90549050613SKa Ho Ng 		    &io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN];
90649050613SKa Ho Ng 		buf = (struct scsi_unmap_desc *)ptrlen->ptr;
90749050613SKa Ho Ng 		end = buf + ptrlen->len / sizeof(*buf);
90849050613SKa Ho Ng 		for (; buf < end; buf++) {
90949050613SKa Ho Ng 			off = (off_t)scsi_8btou64(buf->lba) *
91049050613SKa Ho Ng 			    be_lun->cbe_lun.blocksize;
91149050613SKa Ho Ng 			len = (off_t)scsi_4btoul(buf->length) *
91249050613SKa Ho Ng 			    be_lun->cbe_lun.blocksize;
91349050613SKa Ho Ng 			beio->io_len += len;
91449050613SKa Ho Ng 			error = vn_deallocate(be_lun->vn, &off, &len,
91549050613SKa Ho Ng 			    0, IO_NOMACCHECK | IO_NODELOCKED, file_data->cred,
91649050613SKa Ho Ng 			    NOCRED);
91749050613SKa Ho Ng 			if (error != 0)
91849050613SKa Ho Ng 				break;
91949050613SKa Ho Ng 		}
92049050613SKa Ho Ng 	} else {
92149050613SKa Ho Ng 		/* WRITE_SAME */
92249050613SKa Ho Ng 		off = beio->io_offset;
92349050613SKa Ho Ng 		len = beio->io_len;
92449050613SKa Ho Ng 		error = vn_deallocate(be_lun->vn, &off, &len, 0,
92549050613SKa Ho Ng 		    IO_NOMACCHECK | IO_NODELOCKED, file_data->cred, NOCRED);
92649050613SKa Ho Ng 	}
92749050613SKa Ho Ng 	VOP_UNLOCK(be_lun->vn);
92849050613SKa Ho Ng 	vn_finished_write(mp);
92949050613SKa Ho Ng 
93049050613SKa Ho Ng 	mtx_lock(&be_lun->io_lock);
93149050613SKa Ho Ng 	devstat_end_transaction(beio->lun->disk_stats, beio->io_len,
93249050613SKa Ho Ng 	    beio->ds_tag_type, beio->ds_trans_type,
93349050613SKa Ho Ng 	    /*now*/ NULL, /*then*/&beio->ds_t0);
93449050613SKa Ho Ng 	mtx_unlock(&be_lun->io_lock);
93549050613SKa Ho Ng 
93649050613SKa Ho Ng 	/*
93749050613SKa Ho Ng 	 * If we got an error, set the sense data to "MEDIUM ERROR" and
93849050613SKa Ho Ng 	 * return the I/O to the user.
93949050613SKa Ho Ng 	 */
94049050613SKa Ho Ng 	switch (error) {
94149050613SKa Ho Ng 	case 0:
94240a43590SJohn Baldwin 		ctl_io_set_success(io);
94349050613SKa Ho Ng 		break;
94449050613SKa Ho Ng 	case ENOSPC:
94549050613SKa Ho Ng 	case EDQUOT:
94640a43590SJohn Baldwin 		ctl_io_set_space_alloc_fail(io);
94749050613SKa Ho Ng 		break;
94849050613SKa Ho Ng 	case EROFS:
94949050613SKa Ho Ng 	case EACCES:
95040a43590SJohn Baldwin 		ctl_io_set_hw_write_protected(io);
95149050613SKa Ho Ng 		break;
95249050613SKa Ho Ng 	default:
95340a43590SJohn Baldwin 		ctl_be_block_io_error(io, BIO_DELETE, 0);
95449050613SKa Ho Ng 	}
95549050613SKa Ho Ng 	ctl_complete_beio(beio);
95649050613SKa Ho Ng }
95749050613SKa Ho Ng 
95849050613SKa Ho Ng static void
95967f586a8SAlexander Motin ctl_be_block_dispatch_zvol(struct ctl_be_block_lun *be_lun,
96067f586a8SAlexander Motin 			   struct ctl_be_block_io *beio)
96167f586a8SAlexander Motin {
962ac503c19SAlexander Motin 	struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun;
96367f586a8SAlexander Motin 	union ctl_io *io;
9643236151eSAlexander Motin 	struct cdevsw *csw;
9653236151eSAlexander Motin 	struct cdev *dev;
96667f586a8SAlexander Motin 	struct uio xuio;
96767f586a8SAlexander Motin 	struct iovec *xiovec;
9683236151eSAlexander Motin 	int error, flags, i, ref;
96967f586a8SAlexander Motin 
97067f586a8SAlexander Motin 	DPRINTF("entered\n");
97167f586a8SAlexander Motin 
97267f586a8SAlexander Motin 	io = beio->io;
97355551d05SAlexander Motin 	flags = 0;
97455551d05SAlexander Motin 	if (ARGS(io)->flags & CTL_LLF_DPO)
97555551d05SAlexander Motin 		flags |= IO_DIRECT;
97655551d05SAlexander Motin 	if (beio->bio_cmd == BIO_WRITE && ARGS(io)->flags & CTL_LLF_FUA)
97755551d05SAlexander Motin 		flags |= IO_SYNC;
97867f586a8SAlexander Motin 
97967f586a8SAlexander Motin 	bzero(&xuio, sizeof(xuio));
98067f586a8SAlexander Motin 	if (beio->bio_cmd == BIO_READ) {
98136160958SMark Johnston 		SDT_PROBE0(cbb, , read, file_start);
98267f586a8SAlexander Motin 		xuio.uio_rw = UIO_READ;
98367f586a8SAlexander Motin 	} else {
98436160958SMark Johnston 		SDT_PROBE0(cbb, , write, file_start);
98567f586a8SAlexander Motin 		xuio.uio_rw = UIO_WRITE;
98667f586a8SAlexander Motin 	}
98767f586a8SAlexander Motin 	xuio.uio_offset = beio->io_offset;
98867f586a8SAlexander Motin 	xuio.uio_resid = beio->io_len;
98967f586a8SAlexander Motin 	xuio.uio_segflg = UIO_SYSSPACE;
99067f586a8SAlexander Motin 	xuio.uio_iov = beio->xiovecs;
99167f586a8SAlexander Motin 	xuio.uio_iovcnt = beio->num_segs;
99267f586a8SAlexander Motin 	xuio.uio_td = curthread;
99367f586a8SAlexander Motin 
99467f586a8SAlexander Motin 	for (i = 0, xiovec = xuio.uio_iov; i < xuio.uio_iovcnt; i++, xiovec++) {
99567f586a8SAlexander Motin 		xiovec->iov_base = beio->sg_segs[i].addr;
99667f586a8SAlexander Motin 		xiovec->iov_len = beio->sg_segs[i].len;
99767f586a8SAlexander Motin 	}
99867f586a8SAlexander Motin 
99967f586a8SAlexander Motin 	binuptime(&beio->ds_t0);
100067f586a8SAlexander Motin 	devstat_start_transaction(beio->lun->disk_stats, &beio->ds_t0);
100167f586a8SAlexander Motin 
10023236151eSAlexander Motin 	csw = devvn_refthread(be_lun->vn, &dev, &ref);
10033236151eSAlexander Motin 	if (csw) {
1004ac503c19SAlexander Motin 		if (beio->bio_cmd == BIO_READ) {
1005ac503c19SAlexander Motin 			if (beio->beio_cont == NULL &&
1006ac503c19SAlexander Motin 			    cbe_lun->serseq == CTL_LUN_SERSEQ_SOFT)
1007ac503c19SAlexander Motin 				ctl_serseq_done(io);
10083236151eSAlexander Motin 			error = csw->d_read(dev, &xuio, flags);
1009ac503c19SAlexander Motin 		} else
10103236151eSAlexander Motin 			error = csw->d_write(dev, &xuio, flags);
10113236151eSAlexander Motin 		dev_relthread(dev, ref);
10123236151eSAlexander Motin 	} else
10133236151eSAlexander Motin 		error = ENXIO;
10143236151eSAlexander Motin 
10153236151eSAlexander Motin 	if (beio->bio_cmd == BIO_READ)
101636160958SMark Johnston 		SDT_PROBE0(cbb, , read, file_done);
10173236151eSAlexander Motin 	else
101836160958SMark Johnston 		SDT_PROBE0(cbb, , write, file_done);
101967f586a8SAlexander Motin 
102067f586a8SAlexander Motin 	mtx_lock(&be_lun->io_lock);
102167f586a8SAlexander Motin 	devstat_end_transaction(beio->lun->disk_stats, beio->io_len,
102267f586a8SAlexander Motin 	    beio->ds_tag_type, beio->ds_trans_type,
102367f586a8SAlexander Motin 	    /*now*/ NULL, /*then*/&beio->ds_t0);
102467f586a8SAlexander Motin 	mtx_unlock(&be_lun->io_lock);
102567f586a8SAlexander Motin 
102667f586a8SAlexander Motin 	/*
102767f586a8SAlexander Motin 	 * If we got an error, set the sense data to "MEDIUM ERROR" and
102867f586a8SAlexander Motin 	 * return the I/O to the user.
102967f586a8SAlexander Motin 	 */
103067f586a8SAlexander Motin 	if (error != 0) {
10310631de4aSAlexander Motin 		if (error == ENOSPC || error == EDQUOT) {
103240a43590SJohn Baldwin 			ctl_io_set_space_alloc_fail(io);
10336187d472SAlexander Motin 		} else if (error == EROFS || error == EACCES) {
103440a43590SJohn Baldwin 			ctl_io_set_hw_write_protected(io);
10357f7bb97aSAlexander Motin 		} else {
103640a43590SJohn Baldwin 			ctl_be_block_io_error(io, beio->bio_cmd, 0);
10377f7bb97aSAlexander Motin 		}
103867f586a8SAlexander Motin 		ctl_complete_beio(beio);
103967f586a8SAlexander Motin 		return;
104067f586a8SAlexander Motin 	}
104167f586a8SAlexander Motin 
104267f586a8SAlexander Motin 	/*
104367f586a8SAlexander Motin 	 * If this is a write or a verify, we're all done.
104467f586a8SAlexander Motin 	 * If this is a read, we can now send the data to the user.
104567f586a8SAlexander Motin 	 */
104667f586a8SAlexander Motin 	if ((beio->bio_cmd == BIO_WRITE) ||
104767f586a8SAlexander Motin 	    (ARGS(io)->flags & CTL_LLF_VERIFY)) {
104840a43590SJohn Baldwin 		ctl_io_set_success(io);
104967f586a8SAlexander Motin 		ctl_complete_beio(beio);
105067f586a8SAlexander Motin 	} else {
1051f7241cceSAlexander Motin 		if ((ARGS(io)->flags & CTL_LLF_READ) &&
105275a3108eSAlexander Motin 		    beio->beio_cont == NULL) {
105340a43590SJohn Baldwin 			ctl_io_set_success(io);
1054ac503c19SAlexander Motin 			if (cbe_lun->serseq > CTL_LUN_SERSEQ_SOFT)
105575a3108eSAlexander Motin 				ctl_serseq_done(io);
105675a3108eSAlexander Motin 		}
105767f586a8SAlexander Motin 		ctl_datamove(io);
105867f586a8SAlexander Motin 	}
105967f586a8SAlexander Motin }
106067f586a8SAlexander Motin 
106167f586a8SAlexander Motin static void
1062ef8daf3fSAlexander Motin ctl_be_block_gls_zvol(struct ctl_be_block_lun *be_lun,
1063ef8daf3fSAlexander Motin 			struct ctl_be_block_io *beio)
1064ef8daf3fSAlexander Motin {
1065ef8daf3fSAlexander Motin 	union ctl_io *io = beio->io;
10663236151eSAlexander Motin 	struct cdevsw *csw;
10673236151eSAlexander Motin 	struct cdev *dev;
1068ef8daf3fSAlexander Motin 	struct ctl_lba_len_flags *lbalen = ARGS(io);
1069ef8daf3fSAlexander Motin 	struct scsi_get_lba_status_data *data;
1070ef8daf3fSAlexander Motin 	off_t roff, off;
10713236151eSAlexander Motin 	int error, ref, status;
1072ef8daf3fSAlexander Motin 
1073ef8daf3fSAlexander Motin 	DPRINTF("entered\n");
1074ef8daf3fSAlexander Motin 
1075374f12c5SJohn Baldwin 	CTL_IO_ASSERT(io, SCSI);
1076374f12c5SJohn Baldwin 
10773236151eSAlexander Motin 	csw = devvn_refthread(be_lun->vn, &dev, &ref);
10783236151eSAlexander Motin 	if (csw == NULL) {
10793236151eSAlexander Motin 		status = 0;	/* unknown up to the end */
10803236151eSAlexander Motin 		off = be_lun->size_bytes;
10813236151eSAlexander Motin 		goto done;
10823236151eSAlexander Motin 	}
10830bcd4ab6SAlexander Motin 	off = roff = ((off_t)lbalen->lba) * be_lun->cbe_lun.blocksize;
10843236151eSAlexander Motin 	error = csw->d_ioctl(dev, FIOSEEKHOLE, (caddr_t)&off, FREAD,
10853236151eSAlexander Motin 	    curthread);
1086ef8daf3fSAlexander Motin 	if (error == 0 && off > roff)
1087ef8daf3fSAlexander Motin 		status = 0;	/* mapped up to off */
1088ef8daf3fSAlexander Motin 	else {
10893236151eSAlexander Motin 		error = csw->d_ioctl(dev, FIOSEEKDATA, (caddr_t)&off, FREAD,
10903236151eSAlexander Motin 		    curthread);
1091ef8daf3fSAlexander Motin 		if (error == 0 && off > roff)
1092ef8daf3fSAlexander Motin 			status = 1;	/* deallocated up to off */
1093ef8daf3fSAlexander Motin 		else {
1094ef8daf3fSAlexander Motin 			status = 0;	/* unknown up to the end */
1095ef8daf3fSAlexander Motin 			off = be_lun->size_bytes;
1096ef8daf3fSAlexander Motin 		}
1097ef8daf3fSAlexander Motin 	}
10983236151eSAlexander Motin 	dev_relthread(dev, ref);
1099ef8daf3fSAlexander Motin 
11003236151eSAlexander Motin done:
1101ef8daf3fSAlexander Motin 	data = (struct scsi_get_lba_status_data *)io->scsiio.kern_data_ptr;
1102ef8daf3fSAlexander Motin 	scsi_u64to8b(lbalen->lba, data->descr[0].addr);
11030bcd4ab6SAlexander Motin 	scsi_ulto4b(MIN(UINT32_MAX, off / be_lun->cbe_lun.blocksize -
11040bcd4ab6SAlexander Motin 	    lbalen->lba), data->descr[0].length);
1105ef8daf3fSAlexander Motin 	data->descr[0].status = status;
1106ef8daf3fSAlexander Motin 
1107ef8daf3fSAlexander Motin 	ctl_complete_beio(beio);
1108ef8daf3fSAlexander Motin }
1109ef8daf3fSAlexander Motin 
1110ef8daf3fSAlexander Motin static void
1111130f4520SKenneth D. Merry ctl_be_block_flush_dev(struct ctl_be_block_lun *be_lun,
1112130f4520SKenneth D. Merry 		       struct ctl_be_block_io *beio)
1113130f4520SKenneth D. Merry {
1114130f4520SKenneth D. Merry 	struct bio *bio;
11153236151eSAlexander Motin 	struct cdevsw *csw;
11163236151eSAlexander Motin 	struct cdev *dev;
11173236151eSAlexander Motin 	int ref;
1118130f4520SKenneth D. Merry 
1119130f4520SKenneth D. Merry 	DPRINTF("entered\n");
1120130f4520SKenneth D. Merry 
1121130f4520SKenneth D. Merry 	/* This can't fail, it's a blocking allocation. */
1122130f4520SKenneth D. Merry 	bio = g_alloc_bio();
1123130f4520SKenneth D. Merry 
1124130f4520SKenneth D. Merry 	bio->bio_cmd	    = BIO_FLUSH;
1125130f4520SKenneth D. Merry 	bio->bio_offset	    = 0;
1126130f4520SKenneth D. Merry 	bio->bio_data	    = 0;
1127130f4520SKenneth D. Merry 	bio->bio_done	    = ctl_be_block_biodone;
1128130f4520SKenneth D. Merry 	bio->bio_caller1    = beio;
1129130f4520SKenneth D. Merry 	bio->bio_pblkno	    = 0;
1130130f4520SKenneth D. Merry 
1131130f4520SKenneth D. Merry 	/*
1132130f4520SKenneth D. Merry 	 * We don't need to acquire the LUN lock here, because we are only
1133130f4520SKenneth D. Merry 	 * sending one bio, and so there is no other context to synchronize
1134130f4520SKenneth D. Merry 	 * with.
1135130f4520SKenneth D. Merry 	 */
1136130f4520SKenneth D. Merry 	beio->num_bios_sent = 1;
1137130f4520SKenneth D. Merry 	beio->send_complete = 1;
1138130f4520SKenneth D. Merry 
1139130f4520SKenneth D. Merry 	binuptime(&beio->ds_t0);
1140130f4520SKenneth D. Merry 	devstat_start_transaction(be_lun->disk_stats, &beio->ds_t0);
1141130f4520SKenneth D. Merry 
11423236151eSAlexander Motin 	csw = devvn_refthread(be_lun->vn, &dev, &ref);
11433236151eSAlexander Motin 	if (csw) {
11443236151eSAlexander Motin 		bio->bio_dev = dev;
11453236151eSAlexander Motin 		csw->d_strategy(bio);
11463236151eSAlexander Motin 		dev_relthread(dev, ref);
11473236151eSAlexander Motin 	} else {
11483236151eSAlexander Motin 		bio->bio_error = ENXIO;
11493236151eSAlexander Motin 		ctl_be_block_biodone(bio);
11503236151eSAlexander Motin 	}
1151130f4520SKenneth D. Merry }
1152130f4520SKenneth D. Merry 
1153130f4520SKenneth D. Merry static void
1154ee7f31c0SAlexander Motin ctl_be_block_unmap_dev_range(struct ctl_be_block_lun *be_lun,
1155ee7f31c0SAlexander Motin 		       struct ctl_be_block_io *beio,
1156ee7f31c0SAlexander Motin 		       uint64_t off, uint64_t len, int last)
1157ee7f31c0SAlexander Motin {
1158ee7f31c0SAlexander Motin 	struct bio *bio;
11598f5a226aSAlexander Motin 	uint64_t maxlen;
11603236151eSAlexander Motin 	struct cdevsw *csw;
11613236151eSAlexander Motin 	struct cdev *dev;
11623236151eSAlexander Motin 	int ref;
1163ee7f31c0SAlexander Motin 
11643236151eSAlexander Motin 	csw = devvn_refthread(be_lun->vn, &dev, &ref);
11650bcd4ab6SAlexander Motin 	maxlen = LONG_MAX - (LONG_MAX % be_lun->cbe_lun.blocksize);
1166ee7f31c0SAlexander Motin 	while (len > 0) {
1167ee7f31c0SAlexander Motin 		bio = g_alloc_bio();
1168ee7f31c0SAlexander Motin 		bio->bio_cmd	    = BIO_DELETE;
11693236151eSAlexander Motin 		bio->bio_dev	    = dev;
1170ee7f31c0SAlexander Motin 		bio->bio_offset	    = off;
11718f5a226aSAlexander Motin 		bio->bio_length	    = MIN(len, maxlen);
1172ee7f31c0SAlexander Motin 		bio->bio_data	    = 0;
1173ee7f31c0SAlexander Motin 		bio->bio_done	    = ctl_be_block_biodone;
1174ee7f31c0SAlexander Motin 		bio->bio_caller1    = beio;
11750bcd4ab6SAlexander Motin 		bio->bio_pblkno     = off / be_lun->cbe_lun.blocksize;
1176ee7f31c0SAlexander Motin 
1177ee7f31c0SAlexander Motin 		off += bio->bio_length;
1178ee7f31c0SAlexander Motin 		len -= bio->bio_length;
1179ee7f31c0SAlexander Motin 
118075c7a1d3SAlexander Motin 		mtx_lock(&be_lun->io_lock);
1181ee7f31c0SAlexander Motin 		beio->num_bios_sent++;
1182ee7f31c0SAlexander Motin 		if (last && len == 0)
1183ee7f31c0SAlexander Motin 			beio->send_complete = 1;
118475c7a1d3SAlexander Motin 		mtx_unlock(&be_lun->io_lock);
1185ee7f31c0SAlexander Motin 
11863236151eSAlexander Motin 		if (csw) {
11873236151eSAlexander Motin 			csw->d_strategy(bio);
11883236151eSAlexander Motin 		} else {
11893236151eSAlexander Motin 			bio->bio_error = ENXIO;
11903236151eSAlexander Motin 			ctl_be_block_biodone(bio);
1191ee7f31c0SAlexander Motin 		}
1192ee7f31c0SAlexander Motin 	}
11933236151eSAlexander Motin 	if (csw)
11943236151eSAlexander Motin 		dev_relthread(dev, ref);
11953236151eSAlexander Motin }
1196ee7f31c0SAlexander Motin 
1197ee7f31c0SAlexander Motin static void
1198ee7f31c0SAlexander Motin ctl_be_block_unmap_dev(struct ctl_be_block_lun *be_lun,
1199ee7f31c0SAlexander Motin 		       struct ctl_be_block_io *beio)
1200ee7f31c0SAlexander Motin {
1201ee7f31c0SAlexander Motin 	union ctl_io *io;
120266df9136SAlexander Motin 	struct ctl_ptr_len_flags *ptrlen;
1203ee7f31c0SAlexander Motin 	struct scsi_unmap_desc *buf, *end;
1204ee7f31c0SAlexander Motin 	uint64_t len;
1205ee7f31c0SAlexander Motin 
1206ee7f31c0SAlexander Motin 	io = beio->io;
1207ee7f31c0SAlexander Motin 
1208ee7f31c0SAlexander Motin 	DPRINTF("entered\n");
1209ee7f31c0SAlexander Motin 
1210ee7f31c0SAlexander Motin 	binuptime(&beio->ds_t0);
1211ee7f31c0SAlexander Motin 	devstat_start_transaction(be_lun->disk_stats, &beio->ds_t0);
1212ee7f31c0SAlexander Motin 
1213ee7f31c0SAlexander Motin 	if (beio->io_offset == -1) {
1214ee7f31c0SAlexander Motin 		beio->io_len = 0;
121566df9136SAlexander Motin 		ptrlen = (struct ctl_ptr_len_flags *)&io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN];
121666df9136SAlexander Motin 		buf = (struct scsi_unmap_desc *)ptrlen->ptr;
121766df9136SAlexander Motin 		end = buf + ptrlen->len / sizeof(*buf);
1218ee7f31c0SAlexander Motin 		for (; buf < end; buf++) {
1219ee7f31c0SAlexander Motin 			len = (uint64_t)scsi_4btoul(buf->length) *
12200bcd4ab6SAlexander Motin 			    be_lun->cbe_lun.blocksize;
1221ee7f31c0SAlexander Motin 			beio->io_len += len;
1222ee7f31c0SAlexander Motin 			ctl_be_block_unmap_dev_range(be_lun, beio,
12230bcd4ab6SAlexander Motin 			    scsi_8btou64(buf->lba) * be_lun->cbe_lun.blocksize,
12240bcd4ab6SAlexander Motin 			    len, (end - buf < 2) ? TRUE : FALSE);
1225ee7f31c0SAlexander Motin 		}
1226ee7f31c0SAlexander Motin 	} else
1227ee7f31c0SAlexander Motin 		ctl_be_block_unmap_dev_range(be_lun, beio,
1228ee7f31c0SAlexander Motin 		    beio->io_offset, beio->io_len, TRUE);
1229ee7f31c0SAlexander Motin }
1230ee7f31c0SAlexander Motin 
1231ee7f31c0SAlexander Motin static void
1232130f4520SKenneth D. Merry ctl_be_block_dispatch_dev(struct ctl_be_block_lun *be_lun,
1233130f4520SKenneth D. Merry 			  struct ctl_be_block_io *beio)
1234130f4520SKenneth D. Merry {
123575c7a1d3SAlexander Motin 	TAILQ_HEAD(, bio) queue = TAILQ_HEAD_INITIALIZER(queue);
1236130f4520SKenneth D. Merry 	struct bio *bio;
12373236151eSAlexander Motin 	struct cdevsw *csw;
12383236151eSAlexander Motin 	struct cdev *dev;
1239130f4520SKenneth D. Merry 	off_t cur_offset;
12403236151eSAlexander Motin 	int i, max_iosize, ref;
1241130f4520SKenneth D. Merry 
1242130f4520SKenneth D. Merry 	DPRINTF("entered\n");
12433236151eSAlexander Motin 	csw = devvn_refthread(be_lun->vn, &dev, &ref);
1244130f4520SKenneth D. Merry 
1245130f4520SKenneth D. Merry 	/*
1246130f4520SKenneth D. Merry 	 * We have to limit our I/O size to the maximum supported by the
12478054320eSAlexander Motin 	 * backend device.
1248130f4520SKenneth D. Merry 	 */
12493236151eSAlexander Motin 	if (csw) {
12503236151eSAlexander Motin 		max_iosize = dev->si_iosize_max;
1251b06771aaSAlexander Motin 		if (max_iosize <= 0)
1252130f4520SKenneth D. Merry 			max_iosize = DFLTPHYS;
12533236151eSAlexander Motin 	} else
1254b06771aaSAlexander Motin 		max_iosize = maxphys;
1255130f4520SKenneth D. Merry 
1256130f4520SKenneth D. Merry 	cur_offset = beio->io_offset;
1257130f4520SKenneth D. Merry 	for (i = 0; i < beio->num_segs; i++) {
1258130f4520SKenneth D. Merry 		size_t cur_size;
1259130f4520SKenneth D. Merry 		uint8_t *cur_ptr;
1260130f4520SKenneth D. Merry 
1261130f4520SKenneth D. Merry 		cur_size = beio->sg_segs[i].len;
1262130f4520SKenneth D. Merry 		cur_ptr = beio->sg_segs[i].addr;
1263130f4520SKenneth D. Merry 
1264130f4520SKenneth D. Merry 		while (cur_size > 0) {
1265130f4520SKenneth D. Merry 			/* This can't fail, it's a blocking allocation. */
1266130f4520SKenneth D. Merry 			bio = g_alloc_bio();
1267130f4520SKenneth D. Merry 
1268130f4520SKenneth D. Merry 			KASSERT(bio != NULL, ("g_alloc_bio() failed!\n"));
1269130f4520SKenneth D. Merry 
1270130f4520SKenneth D. Merry 			bio->bio_cmd = beio->bio_cmd;
12713236151eSAlexander Motin 			bio->bio_dev = dev;
1272130f4520SKenneth D. Merry 			bio->bio_caller1 = beio;
1273130f4520SKenneth D. Merry 			bio->bio_length = min(cur_size, max_iosize);
1274130f4520SKenneth D. Merry 			bio->bio_offset = cur_offset;
1275130f4520SKenneth D. Merry 			bio->bio_data = cur_ptr;
1276130f4520SKenneth D. Merry 			bio->bio_done = ctl_be_block_biodone;
12770bcd4ab6SAlexander Motin 			bio->bio_pblkno = cur_offset / be_lun->cbe_lun.blocksize;
1278130f4520SKenneth D. Merry 
1279130f4520SKenneth D. Merry 			cur_offset += bio->bio_length;
1280130f4520SKenneth D. Merry 			cur_ptr += bio->bio_length;
1281130f4520SKenneth D. Merry 			cur_size -= bio->bio_length;
1282130f4520SKenneth D. Merry 
128375c7a1d3SAlexander Motin 			TAILQ_INSERT_TAIL(&queue, bio, bio_queue);
1284130f4520SKenneth D. Merry 			beio->num_bios_sent++;
1285130f4520SKenneth D. Merry 		}
1286130f4520SKenneth D. Merry 	}
128775c7a1d3SAlexander Motin 	beio->send_complete = 1;
1288024932aaSAlexander Motin 	binuptime(&beio->ds_t0);
1289024932aaSAlexander Motin 	devstat_start_transaction(be_lun->disk_stats, &beio->ds_t0);
129075c7a1d3SAlexander Motin 
129175c7a1d3SAlexander Motin 	/*
129275c7a1d3SAlexander Motin 	 * Fire off all allocated requests!
129375c7a1d3SAlexander Motin 	 */
129475c7a1d3SAlexander Motin 	while ((bio = TAILQ_FIRST(&queue)) != NULL) {
129575c7a1d3SAlexander Motin 		TAILQ_REMOVE(&queue, bio, bio_queue);
12963236151eSAlexander Motin 		if (csw)
12973236151eSAlexander Motin 			csw->d_strategy(bio);
12983236151eSAlexander Motin 		else {
12993236151eSAlexander Motin 			bio->bio_error = ENXIO;
13003236151eSAlexander Motin 			ctl_be_block_biodone(bio);
130175c7a1d3SAlexander Motin 		}
1302130f4520SKenneth D. Merry 	}
13033236151eSAlexander Motin 	if (csw)
13043236151eSAlexander Motin 		dev_relthread(dev, ref);
13053236151eSAlexander Motin }
1306130f4520SKenneth D. Merry 
1307c3e7ba3eSAlexander Motin static uint64_t
1308c3e7ba3eSAlexander Motin ctl_be_block_getattr_dev(struct ctl_be_block_lun *be_lun, const char *attrname)
1309c3e7ba3eSAlexander Motin {
1310c3e7ba3eSAlexander Motin 	struct diocgattr_arg	arg;
13113236151eSAlexander Motin 	struct cdevsw *csw;
13123236151eSAlexander Motin 	struct cdev *dev;
13133236151eSAlexander Motin 	int error, ref;
1314c3e7ba3eSAlexander Motin 
13153236151eSAlexander Motin 	csw = devvn_refthread(be_lun->vn, &dev, &ref);
13163236151eSAlexander Motin 	if (csw == NULL)
1317c3e7ba3eSAlexander Motin 		return (UINT64_MAX);
1318c3e7ba3eSAlexander Motin 	strlcpy(arg.name, attrname, sizeof(arg.name));
1319c3e7ba3eSAlexander Motin 	arg.len = sizeof(arg.value.off);
13203236151eSAlexander Motin 	if (csw->d_ioctl) {
13213236151eSAlexander Motin 		error = csw->d_ioctl(dev, DIOCGATTR, (caddr_t)&arg, FREAD,
13223236151eSAlexander Motin 		    curthread);
13233236151eSAlexander Motin 	} else
13243236151eSAlexander Motin 		error = ENODEV;
13253236151eSAlexander Motin 	dev_relthread(dev, ref);
1326c3e7ba3eSAlexander Motin 	if (error != 0)
1327c3e7ba3eSAlexander Motin 		return (UINT64_MAX);
1328c3e7ba3eSAlexander Motin 	return (arg.value.off);
1329c3e7ba3eSAlexander Motin }
1330c3e7ba3eSAlexander Motin 
1331130f4520SKenneth D. Merry static void
1332374f12c5SJohn Baldwin ctl_be_block_namespace_data(struct ctl_be_block_lun *be_lun,
1333374f12c5SJohn Baldwin 			    union ctl_io *io)
1334374f12c5SJohn Baldwin {
1335374f12c5SJohn Baldwin 	struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun;
1336374f12c5SJohn Baldwin 	struct nvme_namespace_data *nsdata;
1337374f12c5SJohn Baldwin 
1338374f12c5SJohn Baldwin 	nsdata = (struct nvme_namespace_data *)io->nvmeio.kern_data_ptr;
1339374f12c5SJohn Baldwin 	memset(nsdata, 0, sizeof(*nsdata));
1340374f12c5SJohn Baldwin 	nsdata->nsze = htole64(be_lun->size_blocks);
1341374f12c5SJohn Baldwin 	nsdata->ncap = nsdata->nsze;
1342*1f83483dSJohn Baldwin 	nsdata->nuse = nsdata->nsze;
1343374f12c5SJohn Baldwin 	nsdata->nlbaf = 1 - 1;
1344374f12c5SJohn Baldwin 	nsdata->dlfeat = NVMEM(NVME_NS_DATA_DLFEAT_DWZ) |
1345374f12c5SJohn Baldwin 	    NVMEF(NVME_NS_DATA_DLFEAT_READ, NVME_NS_DATA_DLFEAT_READ_00);
1346374f12c5SJohn Baldwin 	nsdata->flbas = NVMEF(NVME_NS_DATA_FLBAS_FORMAT, 0);
1347374f12c5SJohn Baldwin 	nsdata->lbaf[0] = NVMEF(NVME_NS_DATA_LBAF_LBADS,
1348374f12c5SJohn Baldwin 	    ffs(cbe_lun->blocksize) - 1);
1349374f12c5SJohn Baldwin 
1350374f12c5SJohn Baldwin 	ctl_lun_nsdata_ids(cbe_lun, nsdata);
1351374f12c5SJohn Baldwin 	ctl_config_read_done(io);
1352374f12c5SJohn Baldwin }
1353374f12c5SJohn Baldwin 
1354374f12c5SJohn Baldwin static void
1355374f12c5SJohn Baldwin ctl_be_block_nvme_ids(struct ctl_be_block_lun *be_lun,
1356374f12c5SJohn Baldwin 		      union ctl_io *io)
1357374f12c5SJohn Baldwin {
1358374f12c5SJohn Baldwin 	struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun;
1359374f12c5SJohn Baldwin 
1360374f12c5SJohn Baldwin 	ctl_lun_nvme_ids(cbe_lun, io->nvmeio.kern_data_ptr);
1361374f12c5SJohn Baldwin 	ctl_config_read_done(io);
1362374f12c5SJohn Baldwin }
1363374f12c5SJohn Baldwin 
1364374f12c5SJohn Baldwin static void
13657d0d4342SAlexander Motin ctl_be_block_cw_dispatch_sync(struct ctl_be_block_lun *be_lun,
13667d0d4342SAlexander Motin 			    union ctl_io *io)
13677d0d4342SAlexander Motin {
13680bcd4ab6SAlexander Motin 	struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun;
13697d0d4342SAlexander Motin 	struct ctl_be_block_io *beio;
13707d0d4342SAlexander Motin 	struct ctl_lba_len_flags *lbalen;
13717d0d4342SAlexander Motin 
13727d0d4342SAlexander Motin 	DPRINTF("entered\n");
13737d0d4342SAlexander Motin 	beio = (struct ctl_be_block_io *)PRIV(io)->ptr;
13747d0d4342SAlexander Motin 	lbalen = (struct ctl_lba_len_flags *)&io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN];
13757d0d4342SAlexander Motin 
13760bcd4ab6SAlexander Motin 	beio->io_len = lbalen->len * cbe_lun->blocksize;
13770bcd4ab6SAlexander Motin 	beio->io_offset = lbalen->lba * cbe_lun->blocksize;
13787d0d4342SAlexander Motin 	beio->io_arg = (lbalen->flags & SSC_IMMED) != 0;
13797d0d4342SAlexander Motin 	beio->bio_cmd = BIO_FLUSH;
13807d0d4342SAlexander Motin 	beio->ds_trans_type = DEVSTAT_NO_DATA;
13817d0d4342SAlexander Motin 	DPRINTF("SYNC\n");
13827d0d4342SAlexander Motin 	be_lun->lun_flush(be_lun, beio);
13837d0d4342SAlexander Motin }
13847d0d4342SAlexander Motin 
13857d0d4342SAlexander Motin static void
1386ee7f31c0SAlexander Motin ctl_be_block_cw_done_ws(struct ctl_be_block_io *beio)
1387ee7f31c0SAlexander Motin {
1388ee7f31c0SAlexander Motin 	union ctl_io *io;
1389ee7f31c0SAlexander Motin 
1390ee7f31c0SAlexander Motin 	io = beio->io;
1391ee7f31c0SAlexander Motin 	ctl_free_beio(beio);
1392ead2f117SAlexander Motin 	if ((io->io_hdr.flags & CTL_FLAG_ABORT) ||
1393ead2f117SAlexander Motin 	    ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE &&
1394ead2f117SAlexander Motin 	     (io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS)) {
1395ee7f31c0SAlexander Motin 		ctl_config_write_done(io);
1396ee7f31c0SAlexander Motin 		return;
1397ee7f31c0SAlexander Motin 	}
1398ee7f31c0SAlexander Motin 
1399ee7f31c0SAlexander Motin 	ctl_be_block_config_write(io);
1400ee7f31c0SAlexander Motin }
1401ee7f31c0SAlexander Motin 
1402ee7f31c0SAlexander Motin static void
1403ee7f31c0SAlexander Motin ctl_be_block_cw_dispatch_ws(struct ctl_be_block_lun *be_lun,
1404ee7f31c0SAlexander Motin 			    union ctl_io *io)
1405ee7f31c0SAlexander Motin {
14060d7fed74SAlexander Motin 	struct ctl_be_block_softc *softc = be_lun->softc;
14070bcd4ab6SAlexander Motin 	struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun;
1408ee7f31c0SAlexander Motin 	struct ctl_be_block_io *beio;
140966df9136SAlexander Motin 	struct ctl_lba_len_flags *lbalen;
1410fee04ef7SAlexander Motin 	uint64_t len_left, lba;
1411fee04ef7SAlexander Motin 	uint32_t pb, pbo, adj;
1412ee7f31c0SAlexander Motin 	int i, seglen;
1413ee7f31c0SAlexander Motin 	uint8_t *buf, *end;
1414ee7f31c0SAlexander Motin 
1415ee7f31c0SAlexander Motin 	DPRINTF("entered\n");
1416ee7f31c0SAlexander Motin 
1417374f12c5SJohn Baldwin 	CTL_IO_ASSERT(io, SCSI);
1418374f12c5SJohn Baldwin 
1419e86a4142SAlexander Motin 	beio = (struct ctl_be_block_io *)PRIV(io)->ptr;
1420a59e2982SAlexander Motin 	lbalen = ARGS(io);
1421ee7f31c0SAlexander Motin 
142264c5167cSAlexander Motin 	if (lbalen->flags & ~(SWS_LBDATA | SWS_UNMAP | SWS_ANCHOR | SWS_NDOB) ||
14233406a2a0SAlexander Motin 	    (lbalen->flags & (SWS_UNMAP | SWS_ANCHOR) && be_lun->unmap == NULL)) {
1424ee7f31c0SAlexander Motin 		ctl_free_beio(beio);
1425ee7f31c0SAlexander Motin 		ctl_set_invalid_field(&io->scsiio,
1426ee7f31c0SAlexander Motin 				      /*sks_valid*/ 1,
1427ee7f31c0SAlexander Motin 				      /*command*/ 1,
1428ee7f31c0SAlexander Motin 				      /*field*/ 1,
1429ee7f31c0SAlexander Motin 				      /*bit_valid*/ 0,
1430ee7f31c0SAlexander Motin 				      /*bit*/ 0);
1431ee7f31c0SAlexander Motin 		ctl_config_write_done(io);
1432ee7f31c0SAlexander Motin 		return;
1433ee7f31c0SAlexander Motin 	}
1434ee7f31c0SAlexander Motin 
14353406a2a0SAlexander Motin 	if (lbalen->flags & (SWS_UNMAP | SWS_ANCHOR)) {
14360bcd4ab6SAlexander Motin 		beio->io_offset = lbalen->lba * cbe_lun->blocksize;
14370bcd4ab6SAlexander Motin 		beio->io_len = (uint64_t)lbalen->len * cbe_lun->blocksize;
1438ee7f31c0SAlexander Motin 		beio->bio_cmd = BIO_DELETE;
1439ee7f31c0SAlexander Motin 		beio->ds_trans_type = DEVSTAT_FREE;
1440ee7f31c0SAlexander Motin 
1441ee7f31c0SAlexander Motin 		be_lun->unmap(be_lun, beio);
1442ee7f31c0SAlexander Motin 		return;
1443ee7f31c0SAlexander Motin 	}
1444ee7f31c0SAlexander Motin 
1445ee7f31c0SAlexander Motin 	beio->bio_cmd = BIO_WRITE;
1446ee7f31c0SAlexander Motin 	beio->ds_trans_type = DEVSTAT_WRITE;
1447ee7f31c0SAlexander Motin 
1448ee7f31c0SAlexander Motin 	DPRINTF("WRITE SAME at LBA %jx len %u\n",
144966df9136SAlexander Motin 	       (uintmax_t)lbalen->lba, lbalen->len);
1450ee7f31c0SAlexander Motin 
14510bcd4ab6SAlexander Motin 	pb = cbe_lun->blocksize << be_lun->cbe_lun.pblockexp;
14520bcd4ab6SAlexander Motin 	if (be_lun->cbe_lun.pblockoff > 0)
14530bcd4ab6SAlexander Motin 		pbo = pb - cbe_lun->blocksize * be_lun->cbe_lun.pblockoff;
1454fee04ef7SAlexander Motin 	else
1455fee04ef7SAlexander Motin 		pbo = 0;
14560bcd4ab6SAlexander Motin 	len_left = (uint64_t)lbalen->len * cbe_lun->blocksize;
1457b06771aaSAlexander Motin 	for (i = 0, lba = 0; i < CTLBLK_MAX_SEGS && len_left > 0; i++) {
1458ee7f31c0SAlexander Motin 		/*
1459ee7f31c0SAlexander Motin 		 * Setup the S/G entry for this chunk.
1460ee7f31c0SAlexander Motin 		 */
146108a7cce5SAlexander Motin 		seglen = MIN(CTLBLK_MAX_SEG, len_left);
14620bcd4ab6SAlexander Motin 		if (pb > cbe_lun->blocksize) {
14630bcd4ab6SAlexander Motin 			adj = ((lbalen->lba + lba) * cbe_lun->blocksize +
146493b8c96cSAlexander Motin 			    seglen - pbo) % pb;
146593b8c96cSAlexander Motin 			if (seglen > adj)
146693b8c96cSAlexander Motin 				seglen -= adj;
146793b8c96cSAlexander Motin 			else
14680bcd4ab6SAlexander Motin 				seglen -= seglen % cbe_lun->blocksize;
146993b8c96cSAlexander Motin 		} else
14700bcd4ab6SAlexander Motin 			seglen -= seglen % cbe_lun->blocksize;
14718054320eSAlexander Motin 		ctl_alloc_seg(softc, &beio->sg_segs[i], seglen);
1472ee7f31c0SAlexander Motin 
1473ee7f31c0SAlexander Motin 		DPRINTF("segment %d addr %p len %zd\n", i,
1474ee7f31c0SAlexander Motin 			beio->sg_segs[i].addr, beio->sg_segs[i].len);
1475ee7f31c0SAlexander Motin 
1476ee7f31c0SAlexander Motin 		beio->num_segs++;
1477ee7f31c0SAlexander Motin 		len_left -= seglen;
1478ee7f31c0SAlexander Motin 
1479ee7f31c0SAlexander Motin 		buf = beio->sg_segs[i].addr;
1480ee7f31c0SAlexander Motin 		end = buf + seglen;
14810bcd4ab6SAlexander Motin 		for (; buf < end; buf += cbe_lun->blocksize) {
14826c2acea5SAlexander Motin 			if (lbalen->flags & SWS_NDOB) {
14836c2acea5SAlexander Motin 				memset(buf, 0, cbe_lun->blocksize);
14846c2acea5SAlexander Motin 			} else {
14856c2acea5SAlexander Motin 				memcpy(buf, io->scsiio.kern_data_ptr,
14866c2acea5SAlexander Motin 				    cbe_lun->blocksize);
14876c2acea5SAlexander Motin 			}
148866df9136SAlexander Motin 			if (lbalen->flags & SWS_LBDATA)
148966df9136SAlexander Motin 				scsi_ulto4b(lbalen->lba + lba, buf);
1490ee7f31c0SAlexander Motin 			lba++;
1491ee7f31c0SAlexander Motin 		}
1492ee7f31c0SAlexander Motin 	}
1493ee7f31c0SAlexander Motin 
14940bcd4ab6SAlexander Motin 	beio->io_offset = lbalen->lba * cbe_lun->blocksize;
14950bcd4ab6SAlexander Motin 	beio->io_len = lba * cbe_lun->blocksize;
1496ee7f31c0SAlexander Motin 
1497ee7f31c0SAlexander Motin 	/* We can not do all in one run. Correct and schedule rerun. */
1498ee7f31c0SAlexander Motin 	if (len_left > 0) {
149966df9136SAlexander Motin 		lbalen->lba += lba;
150066df9136SAlexander Motin 		lbalen->len -= lba;
1501ee7f31c0SAlexander Motin 		beio->beio_cont = ctl_be_block_cw_done_ws;
1502ee7f31c0SAlexander Motin 	}
1503ee7f31c0SAlexander Motin 
1504ee7f31c0SAlexander Motin 	be_lun->dispatch(be_lun, beio);
1505ee7f31c0SAlexander Motin }
1506ee7f31c0SAlexander Motin 
1507ee7f31c0SAlexander Motin static void
1508ee7f31c0SAlexander Motin ctl_be_block_cw_dispatch_unmap(struct ctl_be_block_lun *be_lun,
1509ee7f31c0SAlexander Motin 			       union ctl_io *io)
1510ee7f31c0SAlexander Motin {
1511ee7f31c0SAlexander Motin 	struct ctl_be_block_io *beio;
151266df9136SAlexander Motin 	struct ctl_ptr_len_flags *ptrlen;
1513ee7f31c0SAlexander Motin 
1514ee7f31c0SAlexander Motin 	DPRINTF("entered\n");
1515ee7f31c0SAlexander Motin 
1516374f12c5SJohn Baldwin 	CTL_IO_ASSERT(io, SCSI);
1517374f12c5SJohn Baldwin 
1518e86a4142SAlexander Motin 	beio = (struct ctl_be_block_io *)PRIV(io)->ptr;
151966df9136SAlexander Motin 	ptrlen = (struct ctl_ptr_len_flags *)&io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN];
1520ee7f31c0SAlexander Motin 
15213406a2a0SAlexander Motin 	if ((ptrlen->flags & ~SU_ANCHOR) != 0 || be_lun->unmap == NULL) {
1522ee7f31c0SAlexander Motin 		ctl_free_beio(beio);
1523ee7f31c0SAlexander Motin 		ctl_set_invalid_field(&io->scsiio,
1524ee7f31c0SAlexander Motin 				      /*sks_valid*/ 0,
1525ee7f31c0SAlexander Motin 				      /*command*/ 1,
1526ee7f31c0SAlexander Motin 				      /*field*/ 0,
1527ee7f31c0SAlexander Motin 				      /*bit_valid*/ 0,
1528ee7f31c0SAlexander Motin 				      /*bit*/ 0);
1529ee7f31c0SAlexander Motin 		ctl_config_write_done(io);
1530ee7f31c0SAlexander Motin 		return;
1531ee7f31c0SAlexander Motin 	}
1532ee7f31c0SAlexander Motin 
1533ee7f31c0SAlexander Motin 	beio->io_len = 0;
1534ee7f31c0SAlexander Motin 	beio->io_offset = -1;
1535ee7f31c0SAlexander Motin 	beio->bio_cmd = BIO_DELETE;
1536ee7f31c0SAlexander Motin 	beio->ds_trans_type = DEVSTAT_FREE;
153766df9136SAlexander Motin 	DPRINTF("UNMAP\n");
1538ee7f31c0SAlexander Motin 	be_lun->unmap(be_lun, beio);
1539ee7f31c0SAlexander Motin }
1540ee7f31c0SAlexander Motin 
1541ee7f31c0SAlexander Motin static void
1542374f12c5SJohn Baldwin ctl_be_block_cw_dispatch_flush(struct ctl_be_block_lun *be_lun,
1543374f12c5SJohn Baldwin 			       union ctl_io *io)
1544374f12c5SJohn Baldwin {
1545374f12c5SJohn Baldwin 	struct ctl_be_block_io *beio;
1546374f12c5SJohn Baldwin 
1547374f12c5SJohn Baldwin 	DPRINTF("entered\n");
1548374f12c5SJohn Baldwin 	beio = (struct ctl_be_block_io *)PRIV(io)->ptr;
1549374f12c5SJohn Baldwin 
1550374f12c5SJohn Baldwin 	beio->io_len = be_lun->size_bytes;
1551374f12c5SJohn Baldwin 	beio->io_offset = 0;
1552374f12c5SJohn Baldwin 	beio->io_arg = 1;
1553374f12c5SJohn Baldwin 	beio->bio_cmd = BIO_FLUSH;
1554374f12c5SJohn Baldwin 	beio->ds_trans_type = DEVSTAT_NO_DATA;
1555374f12c5SJohn Baldwin 	DPRINTF("FLUSH\n");
1556374f12c5SJohn Baldwin 	be_lun->lun_flush(be_lun, beio);
1557374f12c5SJohn Baldwin }
1558374f12c5SJohn Baldwin 
1559374f12c5SJohn Baldwin static void
1560374f12c5SJohn Baldwin ctl_be_block_cw_dispatch_wu(struct ctl_be_block_lun *be_lun,
1561374f12c5SJohn Baldwin 			    union ctl_io *io)
1562374f12c5SJohn Baldwin {
1563374f12c5SJohn Baldwin 	struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun;
1564374f12c5SJohn Baldwin 	struct ctl_be_block_io *beio;
1565374f12c5SJohn Baldwin 	struct ctl_lba_len_flags *lbalen;
1566374f12c5SJohn Baldwin 
1567374f12c5SJohn Baldwin 	CTL_IO_ASSERT(io, NVME);
1568374f12c5SJohn Baldwin 
1569374f12c5SJohn Baldwin 	beio = (struct ctl_be_block_io *)PRIV(io)->ptr;
1570374f12c5SJohn Baldwin 	lbalen = ARGS(io);
1571374f12c5SJohn Baldwin 
1572374f12c5SJohn Baldwin 	/*
1573374f12c5SJohn Baldwin 	 * XXX: Not quite right as reads will return zeroes rather
1574374f12c5SJohn Baldwin 	 * than failing.
1575374f12c5SJohn Baldwin 	 */
1576374f12c5SJohn Baldwin 	beio->io_offset = lbalen->lba * cbe_lun->blocksize;
1577374f12c5SJohn Baldwin 	beio->io_len = (uint64_t)lbalen->len * cbe_lun->blocksize;
1578374f12c5SJohn Baldwin 	beio->bio_cmd = BIO_DELETE;
1579374f12c5SJohn Baldwin 	beio->ds_trans_type = DEVSTAT_FREE;
1580374f12c5SJohn Baldwin 
1581374f12c5SJohn Baldwin 	be_lun->unmap(be_lun, beio);
1582374f12c5SJohn Baldwin }
1583374f12c5SJohn Baldwin 
1584374f12c5SJohn Baldwin static void
1585374f12c5SJohn Baldwin ctl_be_block_cw_dispatch_wz(struct ctl_be_block_lun *be_lun,
1586374f12c5SJohn Baldwin 			    union ctl_io *io)
1587374f12c5SJohn Baldwin {
1588374f12c5SJohn Baldwin 	struct ctl_be_block_softc *softc = be_lun->softc;
1589374f12c5SJohn Baldwin 	struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun;
1590374f12c5SJohn Baldwin 	struct ctl_be_block_io *beio;
1591374f12c5SJohn Baldwin 	struct ctl_lba_len_flags *lbalen;
1592374f12c5SJohn Baldwin 	uint64_t len_left, lba;
1593374f12c5SJohn Baldwin 	uint32_t pb, pbo, adj;
1594374f12c5SJohn Baldwin 	int i, seglen;
1595374f12c5SJohn Baldwin 
1596374f12c5SJohn Baldwin 	DPRINTF("entered\n");
1597374f12c5SJohn Baldwin 
1598374f12c5SJohn Baldwin 	CTL_IO_ASSERT(io, NVME);
1599374f12c5SJohn Baldwin 
1600374f12c5SJohn Baldwin 	beio = (struct ctl_be_block_io *)PRIV(io)->ptr;
1601374f12c5SJohn Baldwin 	lbalen = ARGS(io);
1602374f12c5SJohn Baldwin 
1603374f12c5SJohn Baldwin 	if ((le32toh(io->nvmeio.cmd.cdw12) & (1U << 25)) != 0 &&
1604374f12c5SJohn Baldwin 	    be_lun->unmap != NULL) {
1605374f12c5SJohn Baldwin 		beio->io_offset = lbalen->lba * cbe_lun->blocksize;
1606374f12c5SJohn Baldwin 		beio->io_len = (uint64_t)lbalen->len * cbe_lun->blocksize;
1607374f12c5SJohn Baldwin 		beio->bio_cmd = BIO_DELETE;
1608374f12c5SJohn Baldwin 		beio->ds_trans_type = DEVSTAT_FREE;
1609374f12c5SJohn Baldwin 
1610374f12c5SJohn Baldwin 		be_lun->unmap(be_lun, beio);
1611374f12c5SJohn Baldwin 		return;
1612374f12c5SJohn Baldwin 	}
1613374f12c5SJohn Baldwin 
1614374f12c5SJohn Baldwin 	beio->bio_cmd = BIO_WRITE;
1615374f12c5SJohn Baldwin 	beio->ds_trans_type = DEVSTAT_WRITE;
1616374f12c5SJohn Baldwin 
1617374f12c5SJohn Baldwin 	DPRINTF("WRITE ZEROES at LBA %jx len %u\n",
1618374f12c5SJohn Baldwin 	       (uintmax_t)lbalen->lba, lbalen->len);
1619374f12c5SJohn Baldwin 
1620374f12c5SJohn Baldwin 	pb = cbe_lun->blocksize << be_lun->cbe_lun.pblockexp;
1621374f12c5SJohn Baldwin 	if (be_lun->cbe_lun.pblockoff > 0)
1622374f12c5SJohn Baldwin 		pbo = pb - cbe_lun->blocksize * be_lun->cbe_lun.pblockoff;
1623374f12c5SJohn Baldwin 	else
1624374f12c5SJohn Baldwin 		pbo = 0;
1625374f12c5SJohn Baldwin 	len_left = (uint64_t)lbalen->len * cbe_lun->blocksize;
1626374f12c5SJohn Baldwin 	for (i = 0, lba = 0; i < CTLBLK_MAX_SEGS && len_left > 0; i++) {
1627374f12c5SJohn Baldwin 		/*
1628374f12c5SJohn Baldwin 		 * Setup the S/G entry for this chunk.
1629374f12c5SJohn Baldwin 		 */
1630374f12c5SJohn Baldwin 		seglen = MIN(CTLBLK_MAX_SEG, len_left);
1631374f12c5SJohn Baldwin 		if (pb > cbe_lun->blocksize) {
1632374f12c5SJohn Baldwin 			adj = ((lbalen->lba + lba) * cbe_lun->blocksize +
1633374f12c5SJohn Baldwin 			    seglen - pbo) % pb;
1634374f12c5SJohn Baldwin 			if (seglen > adj)
1635374f12c5SJohn Baldwin 				seglen -= adj;
1636374f12c5SJohn Baldwin 			else
1637374f12c5SJohn Baldwin 				seglen -= seglen % cbe_lun->blocksize;
1638374f12c5SJohn Baldwin 		} else
1639374f12c5SJohn Baldwin 			seglen -= seglen % cbe_lun->blocksize;
1640374f12c5SJohn Baldwin 		ctl_alloc_seg(softc, &beio->sg_segs[i], seglen);
1641374f12c5SJohn Baldwin 
1642374f12c5SJohn Baldwin 		DPRINTF("segment %d addr %p len %zd\n", i,
1643374f12c5SJohn Baldwin 			beio->sg_segs[i].addr, beio->sg_segs[i].len);
1644374f12c5SJohn Baldwin 
1645374f12c5SJohn Baldwin 		beio->num_segs++;
1646374f12c5SJohn Baldwin 		len_left -= seglen;
1647374f12c5SJohn Baldwin 
1648374f12c5SJohn Baldwin 		memset(beio->sg_segs[i].addr, 0, seglen);
1649374f12c5SJohn Baldwin 		lba += seglen / cbe_lun->blocksize;
1650374f12c5SJohn Baldwin 	}
1651374f12c5SJohn Baldwin 
1652374f12c5SJohn Baldwin 	beio->io_offset = lbalen->lba * cbe_lun->blocksize;
1653374f12c5SJohn Baldwin 	beio->io_len = lba * cbe_lun->blocksize;
1654374f12c5SJohn Baldwin 
1655374f12c5SJohn Baldwin 	/* We can not do all in one run. Correct and schedule rerun. */
1656374f12c5SJohn Baldwin 	if (len_left > 0) {
1657374f12c5SJohn Baldwin 		lbalen->lba += lba;
1658374f12c5SJohn Baldwin 		lbalen->len -= lba;
1659374f12c5SJohn Baldwin 		beio->beio_cont = ctl_be_block_cw_done_ws;
1660374f12c5SJohn Baldwin 	}
1661374f12c5SJohn Baldwin 
1662374f12c5SJohn Baldwin 	be_lun->dispatch(be_lun, beio);
1663374f12c5SJohn Baldwin }
1664374f12c5SJohn Baldwin 
1665374f12c5SJohn Baldwin static void
1666374f12c5SJohn Baldwin ctl_be_block_cw_dispatch_dsm(struct ctl_be_block_lun *be_lun,
1667374f12c5SJohn Baldwin 			     union ctl_io *io)
1668374f12c5SJohn Baldwin {
1669374f12c5SJohn Baldwin 	struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun;
1670374f12c5SJohn Baldwin 	struct ctl_be_block_io *beio;
1671374f12c5SJohn Baldwin 	struct nvme_dsm_range *r;
1672374f12c5SJohn Baldwin 	uint64_t lba;
1673374f12c5SJohn Baldwin 	uint32_t num_blocks;
1674374f12c5SJohn Baldwin 	u_int i, ranges;
1675374f12c5SJohn Baldwin 
1676374f12c5SJohn Baldwin 	CTL_IO_ASSERT(io, NVME);
1677374f12c5SJohn Baldwin 
1678374f12c5SJohn Baldwin 	beio = (struct ctl_be_block_io *)PRIV(io)->ptr;
1679374f12c5SJohn Baldwin 
1680374f12c5SJohn Baldwin 	if (be_lun->unmap == NULL) {
1681374f12c5SJohn Baldwin 		ctl_free_beio(beio);
1682374f12c5SJohn Baldwin 		ctl_nvme_set_success(&io->nvmeio);
1683374f12c5SJohn Baldwin 		ctl_config_write_done(io);
1684374f12c5SJohn Baldwin 		return;
1685374f12c5SJohn Baldwin 	}
1686374f12c5SJohn Baldwin 
1687374f12c5SJohn Baldwin 	ranges = le32toh(io->nvmeio.cmd.cdw10) & 0xff;
1688374f12c5SJohn Baldwin 	r = (struct nvme_dsm_range *)io->nvmeio.kern_data_ptr;
1689374f12c5SJohn Baldwin 
1690374f12c5SJohn Baldwin 	/* Find the next range to delete. */
1691374f12c5SJohn Baldwin 	for (i = DSM_RANGE(io); i < ranges; i++) {
1692374f12c5SJohn Baldwin 		if ((le32toh(r[i].attributes) & (1U << 2)) != 0)
1693374f12c5SJohn Baldwin 			break;
1694374f12c5SJohn Baldwin 	}
1695374f12c5SJohn Baldwin 
1696374f12c5SJohn Baldwin 	/* If no range to delete, complete the operation. */
1697374f12c5SJohn Baldwin 	if (i == ranges) {
1698374f12c5SJohn Baldwin 		ctl_free_beio(beio);
1699374f12c5SJohn Baldwin 		ctl_nvme_set_success(&io->nvmeio);
1700374f12c5SJohn Baldwin 		ctl_config_write_done(io);
1701374f12c5SJohn Baldwin 		return;
1702374f12c5SJohn Baldwin 	}
1703374f12c5SJohn Baldwin 
1704374f12c5SJohn Baldwin 	/* If this is not the last range, request a rerun after this range. */
1705374f12c5SJohn Baldwin 	if (i + 1 < ranges) {
1706374f12c5SJohn Baldwin 		DSM_RANGE(io) = i + 1;
1707374f12c5SJohn Baldwin 		beio->beio_cont = ctl_be_block_cw_done_ws;
1708374f12c5SJohn Baldwin 	}
1709374f12c5SJohn Baldwin 
1710374f12c5SJohn Baldwin 	lba = le64toh(r[i].starting_lba);
1711374f12c5SJohn Baldwin 	num_blocks = le32toh(r[i].length);
1712374f12c5SJohn Baldwin 
1713374f12c5SJohn Baldwin 	beio->io_offset = lba * cbe_lun->blocksize;
1714374f12c5SJohn Baldwin 	beio->io_len = (uint64_t)num_blocks * cbe_lun->blocksize;
1715374f12c5SJohn Baldwin 	beio->bio_cmd = BIO_DELETE;
1716374f12c5SJohn Baldwin 	beio->ds_trans_type = DEVSTAT_FREE;
1717374f12c5SJohn Baldwin 
1718374f12c5SJohn Baldwin 	be_lun->unmap(be_lun, beio);
1719374f12c5SJohn Baldwin }
1720374f12c5SJohn Baldwin 
1721374f12c5SJohn Baldwin static void
1722374f12c5SJohn Baldwin ctl_be_block_scsi_cr_done(struct ctl_be_block_io *beio)
1723ef8daf3fSAlexander Motin {
1724ef8daf3fSAlexander Motin 	union ctl_io *io;
1725ef8daf3fSAlexander Motin 
1726ef8daf3fSAlexander Motin 	io = beio->io;
1727ef8daf3fSAlexander Motin 	ctl_free_beio(beio);
1728ef8daf3fSAlexander Motin 	ctl_config_read_done(io);
1729ef8daf3fSAlexander Motin }
1730ef8daf3fSAlexander Motin 
1731ef8daf3fSAlexander Motin static void
1732374f12c5SJohn Baldwin ctl_be_block_scsi_cr_dispatch(struct ctl_be_block_lun *be_lun,
1733ef8daf3fSAlexander Motin 			      union ctl_io *io)
1734ef8daf3fSAlexander Motin {
1735ef8daf3fSAlexander Motin 	struct ctl_be_block_io *beio;
1736ef8daf3fSAlexander Motin 	struct ctl_be_block_softc *softc;
1737ef8daf3fSAlexander Motin 
1738ef8daf3fSAlexander Motin 	DPRINTF("entered\n");
1739ef8daf3fSAlexander Motin 
1740ef8daf3fSAlexander Motin 	softc = be_lun->softc;
1741ef8daf3fSAlexander Motin 	beio = ctl_alloc_beio(softc);
1742ef8daf3fSAlexander Motin 	beio->io = io;
1743ef8daf3fSAlexander Motin 	beio->lun = be_lun;
1744374f12c5SJohn Baldwin 	beio->beio_cont = ctl_be_block_scsi_cr_done;
1745ef8daf3fSAlexander Motin 	PRIV(io)->ptr = (void *)beio;
1746ef8daf3fSAlexander Motin 
1747ef8daf3fSAlexander Motin 	switch (io->scsiio.cdb[0]) {
1748ef8daf3fSAlexander Motin 	case SERVICE_ACTION_IN:		/* GET LBA STATUS */
1749ef8daf3fSAlexander Motin 		beio->bio_cmd = -1;
1750ef8daf3fSAlexander Motin 		beio->ds_trans_type = DEVSTAT_NO_DATA;
1751ef8daf3fSAlexander Motin 		beio->ds_tag_type = DEVSTAT_TAG_ORDERED;
1752ef8daf3fSAlexander Motin 		beio->io_len = 0;
1753ef8daf3fSAlexander Motin 		if (be_lun->get_lba_status)
1754ef8daf3fSAlexander Motin 			be_lun->get_lba_status(be_lun, beio);
1755ef8daf3fSAlexander Motin 		else
1756374f12c5SJohn Baldwin 			ctl_be_block_scsi_cr_done(beio);
1757ef8daf3fSAlexander Motin 		break;
1758ef8daf3fSAlexander Motin 	default:
1759ef8daf3fSAlexander Motin 		panic("Unhandled CDB type %#x", io->scsiio.cdb[0]);
1760ef8daf3fSAlexander Motin 		break;
1761ef8daf3fSAlexander Motin 	}
1762ef8daf3fSAlexander Motin }
1763ef8daf3fSAlexander Motin 
1764ef8daf3fSAlexander Motin static void
1765374f12c5SJohn Baldwin ctl_be_block_nvme_cr_dispatch(struct ctl_be_block_lun *be_lun,
1766374f12c5SJohn Baldwin 			      union ctl_io *io)
1767374f12c5SJohn Baldwin {
1768374f12c5SJohn Baldwin 	uint8_t cns;
1769374f12c5SJohn Baldwin 
1770374f12c5SJohn Baldwin 	DPRINTF("entered\n");
1771374f12c5SJohn Baldwin 
1772374f12c5SJohn Baldwin 	MPASS(io->nvmeio.cmd.opc == NVME_OPC_IDENTIFY);
1773374f12c5SJohn Baldwin 
1774374f12c5SJohn Baldwin 	cns = le32toh(io->nvmeio.cmd.cdw10) & 0xff;
1775374f12c5SJohn Baldwin 	switch (cns) {
1776374f12c5SJohn Baldwin 	case 0:
1777374f12c5SJohn Baldwin 		ctl_be_block_namespace_data(be_lun, io);
1778374f12c5SJohn Baldwin 		break;
1779374f12c5SJohn Baldwin 	case 3:
1780374f12c5SJohn Baldwin 		ctl_be_block_nvme_ids(be_lun, io);
1781374f12c5SJohn Baldwin 		break;
1782374f12c5SJohn Baldwin 	default:
1783374f12c5SJohn Baldwin 		__assert_unreachable();
1784374f12c5SJohn Baldwin 	}
1785374f12c5SJohn Baldwin }
1786374f12c5SJohn Baldwin 
1787374f12c5SJohn Baldwin static void
1788374f12c5SJohn Baldwin ctl_be_block_cr_dispatch(struct ctl_be_block_lun *be_lun,
1789374f12c5SJohn Baldwin 			 union ctl_io *io)
1790374f12c5SJohn Baldwin {
1791374f12c5SJohn Baldwin 	switch (io->io_hdr.io_type) {
1792374f12c5SJohn Baldwin 	case CTL_IO_SCSI:
1793374f12c5SJohn Baldwin 		ctl_be_block_scsi_cr_dispatch(be_lun, io);
1794374f12c5SJohn Baldwin 		break;
1795374f12c5SJohn Baldwin 	case CTL_IO_NVME_ADMIN:
1796374f12c5SJohn Baldwin 		ctl_be_block_nvme_cr_dispatch(be_lun, io);
1797374f12c5SJohn Baldwin 		break;
1798374f12c5SJohn Baldwin 	default:
1799374f12c5SJohn Baldwin 		__assert_unreachable();
1800374f12c5SJohn Baldwin 	}
1801374f12c5SJohn Baldwin }
1802374f12c5SJohn Baldwin 
1803374f12c5SJohn Baldwin static void
1804ee7f31c0SAlexander Motin ctl_be_block_cw_done(struct ctl_be_block_io *beio)
1805ee7f31c0SAlexander Motin {
1806ee7f31c0SAlexander Motin 	union ctl_io *io;
1807ee7f31c0SAlexander Motin 
1808ee7f31c0SAlexander Motin 	io = beio->io;
1809ee7f31c0SAlexander Motin 	ctl_free_beio(beio);
1810ee7f31c0SAlexander Motin 	ctl_config_write_done(io);
1811ee7f31c0SAlexander Motin }
1812ee7f31c0SAlexander Motin 
1813ee7f31c0SAlexander Motin static void
1814374f12c5SJohn Baldwin ctl_be_block_scsi_cw_dispatch(struct ctl_be_block_lun *be_lun,
1815130f4520SKenneth D. Merry 			      union ctl_io *io)
1816130f4520SKenneth D. Merry {
1817130f4520SKenneth D. Merry 	struct ctl_be_block_io *beio;
1818130f4520SKenneth D. Merry 
1819130f4520SKenneth D. Merry 	DPRINTF("entered\n");
1820130f4520SKenneth D. Merry 
1821374f12c5SJohn Baldwin 	beio = (struct ctl_be_block_io *)PRIV(io)->ptr;
1822374f12c5SJohn Baldwin 
18237d0d4342SAlexander Motin 	switch (io->scsiio.tag_type) {
18247d0d4342SAlexander Motin 	case CTL_TAG_ORDERED:
18257d0d4342SAlexander Motin 		beio->ds_tag_type = DEVSTAT_TAG_ORDERED;
18267d0d4342SAlexander Motin 		break;
18277d0d4342SAlexander Motin 	case CTL_TAG_HEAD_OF_QUEUE:
18287d0d4342SAlexander Motin 		beio->ds_tag_type = DEVSTAT_TAG_HEAD;
18297d0d4342SAlexander Motin 		break;
18307d0d4342SAlexander Motin 	case CTL_TAG_UNTAGGED:
18317d0d4342SAlexander Motin 	case CTL_TAG_SIMPLE:
18327d0d4342SAlexander Motin 	case CTL_TAG_ACA:
18337d0d4342SAlexander Motin 	default:
18347d0d4342SAlexander Motin 		beio->ds_tag_type = DEVSTAT_TAG_SIMPLE;
18357d0d4342SAlexander Motin 		break;
18367d0d4342SAlexander Motin 	}
1837130f4520SKenneth D. Merry 
1838130f4520SKenneth D. Merry 	switch (io->scsiio.cdb[0]) {
1839130f4520SKenneth D. Merry 	case SYNCHRONIZE_CACHE:
1840130f4520SKenneth D. Merry 	case SYNCHRONIZE_CACHE_16:
18417d0d4342SAlexander Motin 		ctl_be_block_cw_dispatch_sync(be_lun, io);
1842130f4520SKenneth D. Merry 		break;
1843ee7f31c0SAlexander Motin 	case WRITE_SAME_10:
1844ee7f31c0SAlexander Motin 	case WRITE_SAME_16:
1845ee7f31c0SAlexander Motin 		ctl_be_block_cw_dispatch_ws(be_lun, io);
1846ee7f31c0SAlexander Motin 		break;
1847ee7f31c0SAlexander Motin 	case UNMAP:
1848ee7f31c0SAlexander Motin 		ctl_be_block_cw_dispatch_unmap(be_lun, io);
1849ee7f31c0SAlexander Motin 		break;
1850130f4520SKenneth D. Merry 	default:
1851130f4520SKenneth D. Merry 		panic("Unhandled CDB type %#x", io->scsiio.cdb[0]);
1852130f4520SKenneth D. Merry 		break;
1853130f4520SKenneth D. Merry 	}
1854130f4520SKenneth D. Merry }
1855130f4520SKenneth D. Merry 
1856374f12c5SJohn Baldwin static void
1857374f12c5SJohn Baldwin ctl_be_block_nvme_cw_dispatch(struct ctl_be_block_lun *be_lun,
1858374f12c5SJohn Baldwin 			      union ctl_io *io)
1859374f12c5SJohn Baldwin {
1860374f12c5SJohn Baldwin 	struct ctl_be_block_io *beio;
1861374f12c5SJohn Baldwin 
1862374f12c5SJohn Baldwin 	DPRINTF("entered\n");
1863374f12c5SJohn Baldwin 
1864374f12c5SJohn Baldwin 	beio = (struct ctl_be_block_io *)PRIV(io)->ptr;
1865374f12c5SJohn Baldwin 	beio->ds_tag_type = DEVSTAT_TAG_SIMPLE;
1866374f12c5SJohn Baldwin 
1867374f12c5SJohn Baldwin 	switch (io->nvmeio.cmd.opc) {
1868374f12c5SJohn Baldwin 	case NVME_OPC_FLUSH:
1869374f12c5SJohn Baldwin 		ctl_be_block_cw_dispatch_flush(be_lun, io);
1870374f12c5SJohn Baldwin 		break;
1871374f12c5SJohn Baldwin 	case NVME_OPC_WRITE_UNCORRECTABLE:
1872374f12c5SJohn Baldwin 		ctl_be_block_cw_dispatch_wu(be_lun, io);
1873374f12c5SJohn Baldwin 		break;
1874374f12c5SJohn Baldwin 	case NVME_OPC_WRITE_ZEROES:
1875374f12c5SJohn Baldwin 		ctl_be_block_cw_dispatch_wz(be_lun, io);
1876374f12c5SJohn Baldwin 		break;
1877374f12c5SJohn Baldwin 	case NVME_OPC_DATASET_MANAGEMENT:
1878374f12c5SJohn Baldwin 		ctl_be_block_cw_dispatch_dsm(be_lun, io);
1879374f12c5SJohn Baldwin 		break;
1880374f12c5SJohn Baldwin 	default:
1881374f12c5SJohn Baldwin 		__assert_unreachable();
1882374f12c5SJohn Baldwin 	}
1883374f12c5SJohn Baldwin }
1884374f12c5SJohn Baldwin 
1885374f12c5SJohn Baldwin static void
1886374f12c5SJohn Baldwin ctl_be_block_cw_dispatch(struct ctl_be_block_lun *be_lun,
1887374f12c5SJohn Baldwin 			 union ctl_io *io)
1888374f12c5SJohn Baldwin {
1889374f12c5SJohn Baldwin 	struct ctl_be_block_io *beio;
1890374f12c5SJohn Baldwin 	struct ctl_be_block_softc *softc;
1891374f12c5SJohn Baldwin 
1892374f12c5SJohn Baldwin 	softc = be_lun->softc;
1893374f12c5SJohn Baldwin 	beio = ctl_alloc_beio(softc);
1894374f12c5SJohn Baldwin 	beio->io = io;
1895374f12c5SJohn Baldwin 	beio->lun = be_lun;
1896374f12c5SJohn Baldwin 	beio->beio_cont = ctl_be_block_cw_done;
1897374f12c5SJohn Baldwin 	PRIV(io)->ptr = (void *)beio;
1898374f12c5SJohn Baldwin 
1899374f12c5SJohn Baldwin 	switch (io->io_hdr.io_type) {
1900374f12c5SJohn Baldwin 	case CTL_IO_SCSI:
1901374f12c5SJohn Baldwin 		ctl_be_block_scsi_cw_dispatch(be_lun, io);
1902374f12c5SJohn Baldwin 		break;
1903374f12c5SJohn Baldwin 	case CTL_IO_NVME:
1904374f12c5SJohn Baldwin 		ctl_be_block_nvme_cw_dispatch(be_lun, io);
1905374f12c5SJohn Baldwin 		break;
1906374f12c5SJohn Baldwin 	default:
1907374f12c5SJohn Baldwin 		__assert_unreachable();
1908374f12c5SJohn Baldwin 	}
1909374f12c5SJohn Baldwin }
1910374f12c5SJohn Baldwin 
191136160958SMark Johnston SDT_PROBE_DEFINE1(cbb, , read, start, "uint64_t");
191236160958SMark Johnston SDT_PROBE_DEFINE1(cbb, , write, start, "uint64_t");
191336160958SMark Johnston SDT_PROBE_DEFINE1(cbb, , read, alloc_done, "uint64_t");
191436160958SMark Johnston SDT_PROBE_DEFINE1(cbb, , write, alloc_done, "uint64_t");
1915130f4520SKenneth D. Merry 
1916130f4520SKenneth D. Merry static void
191708a7cce5SAlexander Motin ctl_be_block_next(struct ctl_be_block_io *beio)
191808a7cce5SAlexander Motin {
191908a7cce5SAlexander Motin 	struct ctl_be_block_lun *be_lun;
192008a7cce5SAlexander Motin 	union ctl_io *io;
192108a7cce5SAlexander Motin 
192208a7cce5SAlexander Motin 	io = beio->io;
192308a7cce5SAlexander Motin 	be_lun = beio->lun;
192408a7cce5SAlexander Motin 	ctl_free_beio(beio);
1925ead2f117SAlexander Motin 	if ((io->io_hdr.flags & CTL_FLAG_ABORT) ||
1926ead2f117SAlexander Motin 	    ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE &&
1927ead2f117SAlexander Motin 	     (io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS)) {
192811b569f7SAlexander Motin 		ctl_data_submit_done(io);
192908a7cce5SAlexander Motin 		return;
193008a7cce5SAlexander Motin 	}
193108a7cce5SAlexander Motin 
193208a7cce5SAlexander Motin 	io->io_hdr.status &= ~CTL_STATUS_MASK;
193308a7cce5SAlexander Motin 	io->io_hdr.status |= CTL_STATUS_NONE;
193408a7cce5SAlexander Motin 
193575c7a1d3SAlexander Motin 	mtx_lock(&be_lun->queue_lock);
193608a7cce5SAlexander Motin 	STAILQ_INSERT_TAIL(&be_lun->input_queue, &io->io_hdr, links);
193775c7a1d3SAlexander Motin 	mtx_unlock(&be_lun->queue_lock);
193808a7cce5SAlexander Motin 	taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task);
193908a7cce5SAlexander Motin }
194008a7cce5SAlexander Motin 
194108a7cce5SAlexander Motin static void
1942130f4520SKenneth D. Merry ctl_be_block_dispatch(struct ctl_be_block_lun *be_lun,
1943130f4520SKenneth D. Merry 			   union ctl_io *io)
1944130f4520SKenneth D. Merry {
19450bcd4ab6SAlexander Motin 	struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun;
1946130f4520SKenneth D. Merry 	struct ctl_be_block_io *beio;
1947130f4520SKenneth D. Merry 	struct ctl_be_block_softc *softc;
194811b569f7SAlexander Motin 	struct ctl_lba_len_flags *lbalen;
1949e86a4142SAlexander Motin 	struct ctl_ptr_len_flags *bptrlen;
1950e86a4142SAlexander Motin 	uint64_t len_left, lbas;
1951130f4520SKenneth D. Merry 	int i;
1952130f4520SKenneth D. Merry 
1953130f4520SKenneth D. Merry 	softc = be_lun->softc;
1954130f4520SKenneth D. Merry 
1955130f4520SKenneth D. Merry 	DPRINTF("entered\n");
1956130f4520SKenneth D. Merry 
195711b569f7SAlexander Motin 	lbalen = ARGS(io);
195811b569f7SAlexander Motin 	if (lbalen->flags & CTL_LLF_WRITE) {
195936160958SMark Johnston 		SDT_PROBE0(cbb, , write, start);
196011b569f7SAlexander Motin 	} else {
196136160958SMark Johnston 		SDT_PROBE0(cbb, , read, start);
1962130f4520SKenneth D. Merry 	}
1963130f4520SKenneth D. Merry 
1964130f4520SKenneth D. Merry 	beio = ctl_alloc_beio(softc);
1965130f4520SKenneth D. Merry 	beio->io = io;
1966130f4520SKenneth D. Merry 	beio->lun = be_lun;
1967e86a4142SAlexander Motin 	bptrlen = PRIV(io);
1968e86a4142SAlexander Motin 	bptrlen->ptr = (void *)beio;
1969130f4520SKenneth D. Merry 
1970374f12c5SJohn Baldwin 	switch (io->io_hdr.io_type) {
1971374f12c5SJohn Baldwin 	case CTL_IO_SCSI:
1972130f4520SKenneth D. Merry 		switch (io->scsiio.tag_type) {
1973130f4520SKenneth D. Merry 		case CTL_TAG_ORDERED:
1974130f4520SKenneth D. Merry 			beio->ds_tag_type = DEVSTAT_TAG_ORDERED;
1975130f4520SKenneth D. Merry 			break;
1976130f4520SKenneth D. Merry 		case CTL_TAG_HEAD_OF_QUEUE:
1977130f4520SKenneth D. Merry 			beio->ds_tag_type = DEVSTAT_TAG_HEAD;
1978130f4520SKenneth D. Merry 			break;
1979130f4520SKenneth D. Merry 		case CTL_TAG_UNTAGGED:
1980130f4520SKenneth D. Merry 		case CTL_TAG_SIMPLE:
1981130f4520SKenneth D. Merry 		case CTL_TAG_ACA:
1982130f4520SKenneth D. Merry 		default:
1983130f4520SKenneth D. Merry 			beio->ds_tag_type = DEVSTAT_TAG_SIMPLE;
1984130f4520SKenneth D. Merry 			break;
1985130f4520SKenneth D. Merry 		}
1986374f12c5SJohn Baldwin 		break;
1987374f12c5SJohn Baldwin 	case CTL_IO_NVME:
1988374f12c5SJohn Baldwin 		beio->ds_tag_type = DEVSTAT_TAG_SIMPLE;
1989374f12c5SJohn Baldwin 		break;
1990374f12c5SJohn Baldwin 	default:
1991374f12c5SJohn Baldwin 		__assert_unreachable();
1992374f12c5SJohn Baldwin 	}
1993130f4520SKenneth D. Merry 
199411b569f7SAlexander Motin 	if (lbalen->flags & CTL_LLF_WRITE) {
1995130f4520SKenneth D. Merry 		beio->bio_cmd = BIO_WRITE;
1996130f4520SKenneth D. Merry 		beio->ds_trans_type = DEVSTAT_WRITE;
199711b569f7SAlexander Motin 	} else {
199811b569f7SAlexander Motin 		beio->bio_cmd = BIO_READ;
199911b569f7SAlexander Motin 		beio->ds_trans_type = DEVSTAT_READ;
2000130f4520SKenneth D. Merry 	}
2001130f4520SKenneth D. Merry 
200208a7cce5SAlexander Motin 	DPRINTF("%s at LBA %jx len %u @%ju\n",
2003130f4520SKenneth D. Merry 	       (beio->bio_cmd == BIO_READ) ? "READ" : "WRITE",
2004e86a4142SAlexander Motin 	       (uintmax_t)lbalen->lba, lbalen->len, bptrlen->len);
2005b06771aaSAlexander Motin 	lbas = CTLBLK_MAX_IO_SIZE;
20060d7fed74SAlexander Motin 	if (lbalen->flags & CTL_LLF_COMPARE) {
20070d7fed74SAlexander Motin 		beio->two_sglists = 1;
2008b06771aaSAlexander Motin 		lbas /= 2;
20090d7fed74SAlexander Motin 	}
20100bcd4ab6SAlexander Motin 	lbas = MIN(lbalen->len - bptrlen->len, lbas / cbe_lun->blocksize);
20110bcd4ab6SAlexander Motin 	beio->io_offset = (lbalen->lba + bptrlen->len) * cbe_lun->blocksize;
20120bcd4ab6SAlexander Motin 	beio->io_len = lbas * cbe_lun->blocksize;
2013e86a4142SAlexander Motin 	bptrlen->len += lbas;
2014130f4520SKenneth D. Merry 
201508a7cce5SAlexander Motin 	for (i = 0, len_left = beio->io_len; len_left > 0; i++) {
201608a7cce5SAlexander Motin 		KASSERT(i < CTLBLK_MAX_SEGS, ("Too many segs (%d >= %d)",
201708a7cce5SAlexander Motin 		    i, CTLBLK_MAX_SEGS));
2018130f4520SKenneth D. Merry 
2019130f4520SKenneth D. Merry 		/*
2020130f4520SKenneth D. Merry 		 * Setup the S/G entry for this chunk.
2021130f4520SKenneth D. Merry 		 */
20228054320eSAlexander Motin 		ctl_alloc_seg(softc, &beio->sg_segs[i],
2023cd853791SKonstantin Belousov 		    MIN(CTLBLK_MAX_SEG, len_left));
2024130f4520SKenneth D. Merry 
2025130f4520SKenneth D. Merry 		DPRINTF("segment %d addr %p len %zd\n", i,
2026130f4520SKenneth D. Merry 			beio->sg_segs[i].addr, beio->sg_segs[i].len);
2027130f4520SKenneth D. Merry 
202811b569f7SAlexander Motin 		/* Set up second segment for compare operation. */
20290d7fed74SAlexander Motin 		if (beio->two_sglists) {
20308054320eSAlexander Motin 			ctl_alloc_seg(softc,
20318054320eSAlexander Motin 			    &beio->sg_segs[i + CTLBLK_HALF_SEGS],
20328054320eSAlexander Motin 			    beio->sg_segs[i].len);
203311b569f7SAlexander Motin 		}
203411b569f7SAlexander Motin 
2035130f4520SKenneth D. Merry 		beio->num_segs++;
2036130f4520SKenneth D. Merry 		len_left -= beio->sg_segs[i].len;
2037130f4520SKenneth D. Merry 	}
2038e86a4142SAlexander Motin 	if (bptrlen->len < lbalen->len)
203908a7cce5SAlexander Motin 		beio->beio_cont = ctl_be_block_next;
204040a43590SJohn Baldwin 	ctl_set_be_move_done(io, ctl_be_block_move_done);
204111b569f7SAlexander Motin 	/* For compare we have separate S/G lists for read and datamove. */
20420d7fed74SAlexander Motin 	if (beio->two_sglists)
204340a43590SJohn Baldwin 		ctl_set_kern_data_ptr(io, &beio->sg_segs[CTLBLK_HALF_SEGS]);
204411b569f7SAlexander Motin 	else
204540a43590SJohn Baldwin 		ctl_set_kern_data_ptr(io, beio->sg_segs);
204640a43590SJohn Baldwin 	ctl_set_kern_data_len(io, beio->io_len);
204740a43590SJohn Baldwin 	ctl_set_kern_sg_entries(io, beio->num_segs);
204840a43590SJohn Baldwin 	ctl_set_kern_data_ref(io, ctl_refcnt_beio);
204940a43590SJohn Baldwin 	ctl_set_kern_data_arg(io, beio);
2050b2221369SAlexander Motin 	io->io_hdr.flags |= CTL_FLAG_ALLOCATED;
2051130f4520SKenneth D. Merry 
2052130f4520SKenneth D. Merry 	/*
2053130f4520SKenneth D. Merry 	 * For the read case, we need to read the data into our buffers and
2054130f4520SKenneth D. Merry 	 * then we can send it back to the user.  For the write case, we
2055130f4520SKenneth D. Merry 	 * need to get the data from the user first.
2056130f4520SKenneth D. Merry 	 */
2057130f4520SKenneth D. Merry 	if (beio->bio_cmd == BIO_READ) {
205836160958SMark Johnston 		SDT_PROBE0(cbb, , read, alloc_done);
2059130f4520SKenneth D. Merry 		be_lun->dispatch(be_lun, beio);
2060130f4520SKenneth D. Merry 	} else {
206136160958SMark Johnston 		SDT_PROBE0(cbb, , write, alloc_done);
2062130f4520SKenneth D. Merry 		ctl_datamove(io);
2063130f4520SKenneth D. Merry 	}
2064130f4520SKenneth D. Merry }
2065130f4520SKenneth D. Merry 
2066130f4520SKenneth D. Merry static void
2067130f4520SKenneth D. Merry ctl_be_block_worker(void *context, int pending)
2068130f4520SKenneth D. Merry {
2069ee4ad294SAlexander Motin 	struct ctl_be_block_lun *be_lun = (struct ctl_be_block_lun *)context;
2070ee4ad294SAlexander Motin 	struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun;
2071130f4520SKenneth D. Merry 	union ctl_io *io;
2072130f4520SKenneth D. Merry 	struct ctl_be_block_io *beio;
2073130f4520SKenneth D. Merry 
2074ee4ad294SAlexander Motin 	DPRINTF("entered\n");
2075ee4ad294SAlexander Motin 	/*
2076ee4ad294SAlexander Motin 	 * Fetch and process I/Os from all queues.  If we detect LUN
2077648dfc1aSAlexander Motin 	 * CTL_LUN_FLAG_NO_MEDIA status here -- it is result of a race,
2078ee4ad294SAlexander Motin 	 * so make response maximally opaque to not confuse initiator.
2079ee4ad294SAlexander Motin 	 */
2080ee4ad294SAlexander Motin 	for (;;) {
2081ee4ad294SAlexander Motin 		mtx_lock(&be_lun->queue_lock);
2082ee4ad294SAlexander Motin 		io = (union ctl_io *)STAILQ_FIRST(&be_lun->datamove_queue);
2083ee4ad294SAlexander Motin 		if (io != NULL) {
2084130f4520SKenneth D. Merry 			DPRINTF("datamove queue\n");
208505d882b7SAlexander Motin 			STAILQ_REMOVE_HEAD(&be_lun->datamove_queue, links);
208675c7a1d3SAlexander Motin 			mtx_unlock(&be_lun->queue_lock);
2087e86a4142SAlexander Motin 			beio = (struct ctl_be_block_io *)PRIV(io)->ptr;
2088648dfc1aSAlexander Motin 			if (cbe_lun->flags & CTL_LUN_FLAG_NO_MEDIA) {
208940a43590SJohn Baldwin 				ctl_io_set_busy(io);
2090ee4ad294SAlexander Motin 				ctl_complete_beio(beio);
20916ed39db2SAlexander Motin 				continue;
2092ee4ad294SAlexander Motin 			}
2093130f4520SKenneth D. Merry 			be_lun->dispatch(be_lun, beio);
2094130f4520SKenneth D. Merry 			continue;
2095130f4520SKenneth D. Merry 		}
2096130f4520SKenneth D. Merry 		io = (union ctl_io *)STAILQ_FIRST(&be_lun->config_write_queue);
2097130f4520SKenneth D. Merry 		if (io != NULL) {
2098130f4520SKenneth D. Merry 			DPRINTF("config write queue\n");
209905d882b7SAlexander Motin 			STAILQ_REMOVE_HEAD(&be_lun->config_write_queue, links);
210075c7a1d3SAlexander Motin 			mtx_unlock(&be_lun->queue_lock);
2101648dfc1aSAlexander Motin 			if (cbe_lun->flags & CTL_LUN_FLAG_NO_MEDIA) {
210240a43590SJohn Baldwin 				ctl_io_set_busy(io);
2103ee4ad294SAlexander Motin 				ctl_config_write_done(io);
21046ed39db2SAlexander Motin 				continue;
2105ee4ad294SAlexander Motin 			}
2106130f4520SKenneth D. Merry 			ctl_be_block_cw_dispatch(be_lun, io);
2107ef8daf3fSAlexander Motin 			continue;
2108ef8daf3fSAlexander Motin 		}
2109ef8daf3fSAlexander Motin 		io = (union ctl_io *)STAILQ_FIRST(&be_lun->config_read_queue);
2110ef8daf3fSAlexander Motin 		if (io != NULL) {
2111ef8daf3fSAlexander Motin 			DPRINTF("config read queue\n");
211205d882b7SAlexander Motin 			STAILQ_REMOVE_HEAD(&be_lun->config_read_queue, links);
2113ef8daf3fSAlexander Motin 			mtx_unlock(&be_lun->queue_lock);
2114648dfc1aSAlexander Motin 			if (cbe_lun->flags & CTL_LUN_FLAG_NO_MEDIA) {
211540a43590SJohn Baldwin 				ctl_io_set_busy(io);
2116ee4ad294SAlexander Motin 				ctl_config_read_done(io);
21176ed39db2SAlexander Motin 				continue;
2118ee4ad294SAlexander Motin 			}
2119ef8daf3fSAlexander Motin 			ctl_be_block_cr_dispatch(be_lun, io);
2120130f4520SKenneth D. Merry 			continue;
2121130f4520SKenneth D. Merry 		}
2122130f4520SKenneth D. Merry 		io = (union ctl_io *)STAILQ_FIRST(&be_lun->input_queue);
2123130f4520SKenneth D. Merry 		if (io != NULL) {
2124130f4520SKenneth D. Merry 			DPRINTF("input queue\n");
212505d882b7SAlexander Motin 			STAILQ_REMOVE_HEAD(&be_lun->input_queue, links);
212675c7a1d3SAlexander Motin 			mtx_unlock(&be_lun->queue_lock);
2127648dfc1aSAlexander Motin 			if (cbe_lun->flags & CTL_LUN_FLAG_NO_MEDIA) {
212840a43590SJohn Baldwin 				ctl_io_set_busy(io);
2129ee4ad294SAlexander Motin 				ctl_data_submit_done(io);
21306ed39db2SAlexander Motin 				continue;
2131ee4ad294SAlexander Motin 			}
2132130f4520SKenneth D. Merry 			ctl_be_block_dispatch(be_lun, io);
2133130f4520SKenneth D. Merry 			continue;
2134130f4520SKenneth D. Merry 		}
2135130f4520SKenneth D. Merry 
2136130f4520SKenneth D. Merry 		/*
2137130f4520SKenneth D. Merry 		 * If we get here, there is no work left in the queues, so
2138130f4520SKenneth D. Merry 		 * just break out and let the task queue go to sleep.
2139130f4520SKenneth D. Merry 		 */
2140ee4ad294SAlexander Motin 		mtx_unlock(&be_lun->queue_lock);
2141130f4520SKenneth D. Merry 		break;
2142130f4520SKenneth D. Merry 	}
2143130f4520SKenneth D. Merry }
2144130f4520SKenneth D. Merry 
2145130f4520SKenneth D. Merry /*
2146130f4520SKenneth D. Merry  * Entry point from CTL to the backend for I/O.  We queue everything to a
2147130f4520SKenneth D. Merry  * work thread, so this just puts the I/O on a queue and wakes up the
2148130f4520SKenneth D. Merry  * thread.
2149130f4520SKenneth D. Merry  */
2150130f4520SKenneth D. Merry static int
2151130f4520SKenneth D. Merry ctl_be_block_submit(union ctl_io *io)
2152130f4520SKenneth D. Merry {
2153130f4520SKenneth D. Merry 	struct ctl_be_block_lun *be_lun;
2154130f4520SKenneth D. Merry 
2155130f4520SKenneth D. Merry 	DPRINTF("entered\n");
2156130f4520SKenneth D. Merry 
2157767300e8SAlexander Motin 	be_lun = (struct ctl_be_block_lun *)CTL_BACKEND_LUN(io);
2158130f4520SKenneth D. Merry 
2159374f12c5SJohn Baldwin 	CTL_IO_ASSERT(io, SCSI, NVME);
2160130f4520SKenneth D. Merry 
2161e86a4142SAlexander Motin 	PRIV(io)->len = 0;
2162e86a4142SAlexander Motin 
216375c7a1d3SAlexander Motin 	mtx_lock(&be_lun->queue_lock);
2164130f4520SKenneth D. Merry 	STAILQ_INSERT_TAIL(&be_lun->input_queue, &io->io_hdr, links);
216575c7a1d3SAlexander Motin 	mtx_unlock(&be_lun->queue_lock);
2166130f4520SKenneth D. Merry 	taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task);
2167130f4520SKenneth D. Merry 
21689c71cd5aSAlexander Motin 	return (CTL_RETVAL_COMPLETE);
2169130f4520SKenneth D. Merry }
2170130f4520SKenneth D. Merry 
2171130f4520SKenneth D. Merry static int
2172130f4520SKenneth D. Merry ctl_be_block_ioctl(struct cdev *dev, u_long cmd, caddr_t addr,
2173130f4520SKenneth D. Merry 			int flag, struct thread *td)
2174130f4520SKenneth D. Merry {
217534144c2cSAlexander Motin 	struct ctl_be_block_softc *softc = &backend_block_softc;
2176130f4520SKenneth D. Merry 	int error;
2177130f4520SKenneth D. Merry 
2178130f4520SKenneth D. Merry 	error = 0;
2179130f4520SKenneth D. Merry 	switch (cmd) {
2180130f4520SKenneth D. Merry 	case CTL_LUN_REQ: {
2181130f4520SKenneth D. Merry 		struct ctl_lun_req *lun_req;
2182130f4520SKenneth D. Merry 
2183130f4520SKenneth D. Merry 		lun_req = (struct ctl_lun_req *)addr;
2184130f4520SKenneth D. Merry 
2185130f4520SKenneth D. Merry 		switch (lun_req->reqtype) {
2186130f4520SKenneth D. Merry 		case CTL_LUNREQ_CREATE:
2187130f4520SKenneth D. Merry 			error = ctl_be_block_create(softc, lun_req);
2188130f4520SKenneth D. Merry 			break;
2189130f4520SKenneth D. Merry 		case CTL_LUNREQ_RM:
2190130f4520SKenneth D. Merry 			error = ctl_be_block_rm(softc, lun_req);
2191130f4520SKenneth D. Merry 			break;
219281177295SEdward Tomasz Napierala 		case CTL_LUNREQ_MODIFY:
219381177295SEdward Tomasz Napierala 			error = ctl_be_block_modify(softc, lun_req);
219481177295SEdward Tomasz Napierala 			break;
2195130f4520SKenneth D. Merry 		default:
2196130f4520SKenneth D. Merry 			lun_req->status = CTL_LUN_ERROR;
2197130f4520SKenneth D. Merry 			snprintf(lun_req->error_str, sizeof(lun_req->error_str),
219819720f41SAlexander Motin 				 "invalid LUN request type %d",
2199130f4520SKenneth D. Merry 				 lun_req->reqtype);
2200130f4520SKenneth D. Merry 			break;
2201130f4520SKenneth D. Merry 		}
2202130f4520SKenneth D. Merry 		break;
2203130f4520SKenneth D. Merry 	}
2204130f4520SKenneth D. Merry 	default:
2205130f4520SKenneth D. Merry 		error = ENOTTY;
2206130f4520SKenneth D. Merry 		break;
2207130f4520SKenneth D. Merry 	}
2208130f4520SKenneth D. Merry 
2209130f4520SKenneth D. Merry 	return (error);
2210130f4520SKenneth D. Merry }
2211130f4520SKenneth D. Merry 
2212130f4520SKenneth D. Merry static int
2213130f4520SKenneth D. Merry ctl_be_block_open_file(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req)
2214130f4520SKenneth D. Merry {
22150bcd4ab6SAlexander Motin 	struct ctl_be_lun *cbe_lun;
2216130f4520SKenneth D. Merry 	struct ctl_be_block_filedata *file_data;
2217130f4520SKenneth D. Merry 	struct ctl_lun_create_params *params;
22188951f055SMarcelo Araujo 	const char		     *value;
2219130f4520SKenneth D. Merry 	struct vattr		      vattr;
222034961f40SAlexander Motin 	off_t			      ps, pss, po, pos, us, uss, uo, uos;
2221130f4520SKenneth D. Merry 	int			      error;
222249050613SKa Ho Ng 	long			      pconf;
2223130f4520SKenneth D. Merry 
22240bcd4ab6SAlexander Motin 	cbe_lun = &be_lun->cbe_lun;
2225130f4520SKenneth D. Merry 	file_data = &be_lun->backend.file;
222619720f41SAlexander Motin 	params = &be_lun->params;
2227130f4520SKenneth D. Merry 
2228130f4520SKenneth D. Merry 	be_lun->dev_type = CTL_BE_BLOCK_FILE;
2229130f4520SKenneth D. Merry 	be_lun->dispatch = ctl_be_block_dispatch_file;
2230130f4520SKenneth D. Merry 	be_lun->lun_flush = ctl_be_block_flush_file;
2231ef8daf3fSAlexander Motin 	be_lun->get_lba_status = ctl_be_block_gls_file;
223253c146deSAlexander Motin 	be_lun->getattr = ctl_be_block_getattr_file;
223349050613SKa Ho Ng 	be_lun->unmap = ctl_be_block_unmap_file;
22340bcd4ab6SAlexander Motin 	cbe_lun->flags &= ~CTL_LUN_FLAG_UNMAP;
2235130f4520SKenneth D. Merry 
2236130f4520SKenneth D. Merry 	error = VOP_GETATTR(be_lun->vn, &vattr, curthread->td_ucred);
2237130f4520SKenneth D. Merry 	if (error != 0) {
2238130f4520SKenneth D. Merry 		snprintf(req->error_str, sizeof(req->error_str),
2239130f4520SKenneth D. Merry 			 "error calling VOP_GETATTR() for file %s",
2240130f4520SKenneth D. Merry 			 be_lun->dev_path);
2241130f4520SKenneth D. Merry 		return (error);
2242130f4520SKenneth D. Merry 	}
2243130f4520SKenneth D. Merry 
224449050613SKa Ho Ng 	error = VOP_PATHCONF(be_lun->vn, _PC_DEALLOC_PRESENT, &pconf);
224549050613SKa Ho Ng 	if (error != 0) {
224649050613SKa Ho Ng 		snprintf(req->error_str, sizeof(req->error_str),
224749050613SKa Ho Ng 		    "error calling VOP_PATHCONF() for file %s",
224849050613SKa Ho Ng 		    be_lun->dev_path);
224949050613SKa Ho Ng 		return (error);
225049050613SKa Ho Ng 	}
225149050613SKa Ho Ng 	if (pconf == 1)
225249050613SKa Ho Ng 		cbe_lun->flags |= CTL_LUN_FLAG_UNMAP;
225349050613SKa Ho Ng 
2254130f4520SKenneth D. Merry 	file_data->cred = crhold(curthread->td_ucred);
225581177295SEdward Tomasz Napierala 	if (params->lun_size_bytes != 0)
225681177295SEdward Tomasz Napierala 		be_lun->size_bytes = params->lun_size_bytes;
225781177295SEdward Tomasz Napierala 	else
2258130f4520SKenneth D. Merry 		be_lun->size_bytes = vattr.va_size;
2259130f4520SKenneth D. Merry 
2260130f4520SKenneth D. Merry 	/*
226120a28d6cSAlexander Motin 	 * For files we can use any logical block size.  Prefer 512 bytes
226220a28d6cSAlexander Motin 	 * for compatibility reasons.  If file's vattr.va_blocksize
226320a28d6cSAlexander Motin 	 * (preferred I/O block size) is bigger and multiple to chosen
226420a28d6cSAlexander Motin 	 * logical block size -- report it as physical block size.
2265130f4520SKenneth D. Merry 	 */
2266130f4520SKenneth D. Merry 	if (params->blocksize_bytes != 0)
22670bcd4ab6SAlexander Motin 		cbe_lun->blocksize = params->blocksize_bytes;
226891be33dcSAlexander Motin 	else if (cbe_lun->lun_type == T_CDROM)
226991be33dcSAlexander Motin 		cbe_lun->blocksize = 2048;
2270130f4520SKenneth D. Merry 	else
22710bcd4ab6SAlexander Motin 		cbe_lun->blocksize = 512;
22720bcd4ab6SAlexander Motin 	be_lun->size_blocks = be_lun->size_bytes / cbe_lun->blocksize;
22730bcd4ab6SAlexander Motin 	cbe_lun->maxlba = (be_lun->size_blocks == 0) ?
22740bcd4ab6SAlexander Motin 	    0 : (be_lun->size_blocks - 1);
227534961f40SAlexander Motin 
227634961f40SAlexander Motin 	us = ps = vattr.va_blocksize;
227734961f40SAlexander Motin 	uo = po = 0;
227834961f40SAlexander Motin 
22798951f055SMarcelo Araujo 	value = dnvlist_get_string(cbe_lun->options, "pblocksize", NULL);
228034961f40SAlexander Motin 	if (value != NULL)
228134961f40SAlexander Motin 		ctl_expand_number(value, &ps);
22828951f055SMarcelo Araujo 	value = dnvlist_get_string(cbe_lun->options, "pblockoffset", NULL);
228334961f40SAlexander Motin 	if (value != NULL)
228434961f40SAlexander Motin 		ctl_expand_number(value, &po);
22850bcd4ab6SAlexander Motin 	pss = ps / cbe_lun->blocksize;
22860bcd4ab6SAlexander Motin 	pos = po / cbe_lun->blocksize;
22870bcd4ab6SAlexander Motin 	if ((pss > 0) && (pss * cbe_lun->blocksize == ps) && (pss >= pos) &&
22880bcd4ab6SAlexander Motin 	    ((pss & (pss - 1)) == 0) && (pos * cbe_lun->blocksize == po)) {
22890bcd4ab6SAlexander Motin 		cbe_lun->pblockexp = fls(pss) - 1;
22900bcd4ab6SAlexander Motin 		cbe_lun->pblockoff = (pss - pos) % pss;
229134961f40SAlexander Motin 	}
229234961f40SAlexander Motin 
22938951f055SMarcelo Araujo 	value = dnvlist_get_string(cbe_lun->options, "ublocksize", NULL);
229434961f40SAlexander Motin 	if (value != NULL)
229534961f40SAlexander Motin 		ctl_expand_number(value, &us);
22968951f055SMarcelo Araujo 	value = dnvlist_get_string(cbe_lun->options, "ublockoffset", NULL);
229734961f40SAlexander Motin 	if (value != NULL)
229834961f40SAlexander Motin 		ctl_expand_number(value, &uo);
22990bcd4ab6SAlexander Motin 	uss = us / cbe_lun->blocksize;
23000bcd4ab6SAlexander Motin 	uos = uo / cbe_lun->blocksize;
23010bcd4ab6SAlexander Motin 	if ((uss > 0) && (uss * cbe_lun->blocksize == us) && (uss >= uos) &&
23020bcd4ab6SAlexander Motin 	    ((uss & (uss - 1)) == 0) && (uos * cbe_lun->blocksize == uo)) {
23030bcd4ab6SAlexander Motin 		cbe_lun->ublockexp = fls(uss) - 1;
23040bcd4ab6SAlexander Motin 		cbe_lun->ublockoff = (uss - uos) % uss;
230520a28d6cSAlexander Motin 	}
2306130f4520SKenneth D. Merry 
2307130f4520SKenneth D. Merry 	/*
2308130f4520SKenneth D. Merry 	 * Sanity check.  The media size has to be at least one
2309130f4520SKenneth D. Merry 	 * sector long.
2310130f4520SKenneth D. Merry 	 */
23110bcd4ab6SAlexander Motin 	if (be_lun->size_bytes < cbe_lun->blocksize) {
2312130f4520SKenneth D. Merry 		error = EINVAL;
2313130f4520SKenneth D. Merry 		snprintf(req->error_str, sizeof(req->error_str),
2314130f4520SKenneth D. Merry 			 "file %s size %ju < block size %u", be_lun->dev_path,
23150bcd4ab6SAlexander Motin 			 (uintmax_t)be_lun->size_bytes, cbe_lun->blocksize);
2316130f4520SKenneth D. Merry 	}
2317cb8727e2SAlexander Motin 
23180bcd4ab6SAlexander Motin 	cbe_lun->opttxferlen = CTLBLK_MAX_IO_SIZE / cbe_lun->blocksize;
2319130f4520SKenneth D. Merry 	return (error);
2320130f4520SKenneth D. Merry }
2321130f4520SKenneth D. Merry 
2322130f4520SKenneth D. Merry static int
2323130f4520SKenneth D. Merry ctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req)
2324130f4520SKenneth D. Merry {
23250bcd4ab6SAlexander Motin 	struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun;
2326130f4520SKenneth D. Merry 	struct ctl_lun_create_params *params;
23273236151eSAlexander Motin 	struct cdevsw		     *csw;
2328130f4520SKenneth D. Merry 	struct cdev		     *dev;
23298951f055SMarcelo Araujo 	const char		     *value;
23303236151eSAlexander Motin 	int			      error, atomic, maxio, ref, unmap, tmp;
2331f6295033SAlexander Motin 	off_t			      ps, pss, po, pos, us, uss, uo, uos, otmp;
2332130f4520SKenneth D. Merry 
233319720f41SAlexander Motin 	params = &be_lun->params;
2334130f4520SKenneth D. Merry 
2335130f4520SKenneth D. Merry 	be_lun->dev_type = CTL_BE_BLOCK_DEV;
23363236151eSAlexander Motin 	csw = devvn_refthread(be_lun->vn, &dev, &ref);
23373236151eSAlexander Motin 	if (csw == NULL)
23383236151eSAlexander Motin 		return (ENXIO);
23393236151eSAlexander Motin 	if (strcmp(csw->d_name, "zvol") == 0) {
234067f586a8SAlexander Motin 		be_lun->dispatch = ctl_be_block_dispatch_zvol;
2341ef8daf3fSAlexander Motin 		be_lun->get_lba_status = ctl_be_block_gls_zvol;
2342cb8727e2SAlexander Motin 		atomic = maxio = CTLBLK_MAX_IO_SIZE;
2343cb8727e2SAlexander Motin 	} else {
234467f586a8SAlexander Motin 		be_lun->dispatch = ctl_be_block_dispatch_dev;
23450bcd4ab6SAlexander Motin 		be_lun->get_lba_status = NULL;
2346cb8727e2SAlexander Motin 		atomic = 0;
23473236151eSAlexander Motin 		maxio = dev->si_iosize_max;
2348cb8727e2SAlexander Motin 		if (maxio <= 0)
2349cb8727e2SAlexander Motin 			maxio = DFLTPHYS;
23508054320eSAlexander Motin 		if (maxio > CTLBLK_MAX_SEG)
23518054320eSAlexander Motin 			maxio = CTLBLK_MAX_SEG;
2352cb8727e2SAlexander Motin 	}
235367f586a8SAlexander Motin 	be_lun->lun_flush = ctl_be_block_flush_dev;
2354c3e7ba3eSAlexander Motin 	be_lun->getattr = ctl_be_block_getattr_dev;
23550bcd4ab6SAlexander Motin 	be_lun->unmap = ctl_be_block_unmap_dev;
2356130f4520SKenneth D. Merry 
23573236151eSAlexander Motin 	if (!csw->d_ioctl) {
23583236151eSAlexander Motin 		dev_relthread(dev, ref);
2359130f4520SKenneth D. Merry 		snprintf(req->error_str, sizeof(req->error_str),
23603236151eSAlexander Motin 			 "no d_ioctl for device %s!", be_lun->dev_path);
2361130f4520SKenneth D. Merry 		return (ENODEV);
2362130f4520SKenneth D. Merry 	}
2363130f4520SKenneth D. Merry 
23643236151eSAlexander Motin 	error = csw->d_ioctl(dev, DIOCGSECTORSIZE, (caddr_t)&tmp, FREAD,
2365130f4520SKenneth D. Merry 			       curthread);
2366130f4520SKenneth D. Merry 	if (error) {
23673236151eSAlexander Motin 		dev_relthread(dev, ref);
2368130f4520SKenneth D. Merry 		snprintf(req->error_str, sizeof(req->error_str),
236919720f41SAlexander Motin 			 "error %d returned for DIOCGSECTORSIZE ioctl "
237019720f41SAlexander Motin 			 "on %s!", error, be_lun->dev_path);
2371130f4520SKenneth D. Merry 		return (error);
2372130f4520SKenneth D. Merry 	}
2373130f4520SKenneth D. Merry 
2374130f4520SKenneth D. Merry 	/*
2375130f4520SKenneth D. Merry 	 * If the user has asked for a blocksize that is greater than the
2376130f4520SKenneth D. Merry 	 * backing device's blocksize, we can do it only if the blocksize
2377130f4520SKenneth D. Merry 	 * the user is asking for is an even multiple of the underlying
2378130f4520SKenneth D. Merry 	 * device's blocksize.
2379130f4520SKenneth D. Merry 	 */
2380a15bbf15SAlexander Motin 	if ((params->blocksize_bytes != 0) &&
2381a15bbf15SAlexander Motin 	    (params->blocksize_bytes >= tmp)) {
2382a15bbf15SAlexander Motin 		if (params->blocksize_bytes % tmp == 0) {
23830bcd4ab6SAlexander Motin 			cbe_lun->blocksize = params->blocksize_bytes;
2384130f4520SKenneth D. Merry 		} else {
23853236151eSAlexander Motin 			dev_relthread(dev, ref);
2386130f4520SKenneth D. Merry 			snprintf(req->error_str, sizeof(req->error_str),
238719720f41SAlexander Motin 				 "requested blocksize %u is not an even "
2388130f4520SKenneth D. Merry 				 "multiple of backing device blocksize %u",
2389f6295033SAlexander Motin 				 params->blocksize_bytes, tmp);
2390130f4520SKenneth D. Merry 			return (EINVAL);
2391130f4520SKenneth D. Merry 		}
2392a15bbf15SAlexander Motin 	} else if (params->blocksize_bytes != 0) {
23933236151eSAlexander Motin 		dev_relthread(dev, ref);
2394130f4520SKenneth D. Merry 		snprintf(req->error_str, sizeof(req->error_str),
239519720f41SAlexander Motin 			 "requested blocksize %u < backing device "
2396f6295033SAlexander Motin 			 "blocksize %u", params->blocksize_bytes, tmp);
2397130f4520SKenneth D. Merry 		return (EINVAL);
239891be33dcSAlexander Motin 	} else if (cbe_lun->lun_type == T_CDROM)
239991be33dcSAlexander Motin 		cbe_lun->blocksize = MAX(tmp, 2048);
240091be33dcSAlexander Motin 	else
24010bcd4ab6SAlexander Motin 		cbe_lun->blocksize = tmp;
2402130f4520SKenneth D. Merry 
24033236151eSAlexander Motin 	error = csw->d_ioctl(dev, DIOCGMEDIASIZE, (caddr_t)&otmp, FREAD,
2404130f4520SKenneth D. Merry 			     curthread);
2405130f4520SKenneth D. Merry 	if (error) {
24063236151eSAlexander Motin 		dev_relthread(dev, ref);
2407130f4520SKenneth D. Merry 		snprintf(req->error_str, sizeof(req->error_str),
240819720f41SAlexander Motin 			 "error %d returned for DIOCGMEDIASIZE "
240919720f41SAlexander Motin 			 " ioctl on %s!", error,
241081177295SEdward Tomasz Napierala 			 be_lun->dev_path);
2411130f4520SKenneth D. Merry 		return (error);
2412130f4520SKenneth D. Merry 	}
2413130f4520SKenneth D. Merry 
241481177295SEdward Tomasz Napierala 	if (params->lun_size_bytes != 0) {
2415f6295033SAlexander Motin 		if (params->lun_size_bytes > otmp) {
24163236151eSAlexander Motin 			dev_relthread(dev, ref);
241781177295SEdward Tomasz Napierala 			snprintf(req->error_str, sizeof(req->error_str),
241819720f41SAlexander Motin 				 "requested LUN size %ju > backing device "
241919720f41SAlexander Motin 				 "size %ju",
242081177295SEdward Tomasz Napierala 				 (uintmax_t)params->lun_size_bytes,
2421f6295033SAlexander Motin 				 (uintmax_t)otmp);
242281177295SEdward Tomasz Napierala 			return (EINVAL);
2423130f4520SKenneth D. Merry 		}
2424130f4520SKenneth D. Merry 
242581177295SEdward Tomasz Napierala 		be_lun->size_bytes = params->lun_size_bytes;
2426a15bbf15SAlexander Motin 	} else
2427f6295033SAlexander Motin 		be_lun->size_bytes = otmp;
24280bcd4ab6SAlexander Motin 	be_lun->size_blocks = be_lun->size_bytes / cbe_lun->blocksize;
24290bcd4ab6SAlexander Motin 	cbe_lun->maxlba = (be_lun->size_blocks == 0) ?
24300bcd4ab6SAlexander Motin 	    0 : (be_lun->size_blocks - 1);
243181177295SEdward Tomasz Napierala 
24323236151eSAlexander Motin 	error = csw->d_ioctl(dev, DIOCGSTRIPESIZE, (caddr_t)&ps, FREAD,
24333236151eSAlexander Motin 	    curthread);
2434f6012722SAlexander Motin 	if (error)
2435f6012722SAlexander Motin 		ps = po = 0;
2436f6012722SAlexander Motin 	else {
24373236151eSAlexander Motin 		error = csw->d_ioctl(dev, DIOCGSTRIPEOFFSET, (caddr_t)&po,
24383236151eSAlexander Motin 		    FREAD, curthread);
2439f6012722SAlexander Motin 		if (error)
2440f6012722SAlexander Motin 			po = 0;
2441f6012722SAlexander Motin 	}
244234961f40SAlexander Motin 	us = ps;
244334961f40SAlexander Motin 	uo = po;
244434961f40SAlexander Motin 
24458951f055SMarcelo Araujo 	value = dnvlist_get_string(cbe_lun->options, "pblocksize", NULL);
244634961f40SAlexander Motin 	if (value != NULL)
244734961f40SAlexander Motin 		ctl_expand_number(value, &ps);
24488951f055SMarcelo Araujo 	value = dnvlist_get_string(cbe_lun->options, "pblockoffset", NULL);
244934961f40SAlexander Motin 	if (value != NULL)
245034961f40SAlexander Motin 		ctl_expand_number(value, &po);
24510bcd4ab6SAlexander Motin 	pss = ps / cbe_lun->blocksize;
24520bcd4ab6SAlexander Motin 	pos = po / cbe_lun->blocksize;
24530bcd4ab6SAlexander Motin 	if ((pss > 0) && (pss * cbe_lun->blocksize == ps) && (pss >= pos) &&
24540bcd4ab6SAlexander Motin 	    ((pss & (pss - 1)) == 0) && (pos * cbe_lun->blocksize == po)) {
24550bcd4ab6SAlexander Motin 		cbe_lun->pblockexp = fls(pss) - 1;
24560bcd4ab6SAlexander Motin 		cbe_lun->pblockoff = (pss - pos) % pss;
2457f6012722SAlexander Motin 	}
2458f6012722SAlexander Motin 
24598951f055SMarcelo Araujo 	value = dnvlist_get_string(cbe_lun->options, "ublocksize", NULL);
246034961f40SAlexander Motin 	if (value != NULL)
246134961f40SAlexander Motin 		ctl_expand_number(value, &us);
24628951f055SMarcelo Araujo 	value = dnvlist_get_string(cbe_lun->options, "ublockoffset", NULL);
246334961f40SAlexander Motin 	if (value != NULL)
246434961f40SAlexander Motin 		ctl_expand_number(value, &uo);
24650bcd4ab6SAlexander Motin 	uss = us / cbe_lun->blocksize;
24660bcd4ab6SAlexander Motin 	uos = uo / cbe_lun->blocksize;
24670bcd4ab6SAlexander Motin 	if ((uss > 0) && (uss * cbe_lun->blocksize == us) && (uss >= uos) &&
24680bcd4ab6SAlexander Motin 	    ((uss & (uss - 1)) == 0) && (uos * cbe_lun->blocksize == uo)) {
24690bcd4ab6SAlexander Motin 		cbe_lun->ublockexp = fls(uss) - 1;
24700bcd4ab6SAlexander Motin 		cbe_lun->ublockoff = (uss - uos) % uss;
247134961f40SAlexander Motin 	}
247234961f40SAlexander Motin 
24730bcd4ab6SAlexander Motin 	cbe_lun->atomicblock = atomic / cbe_lun->blocksize;
24740bcd4ab6SAlexander Motin 	cbe_lun->opttxferlen = maxio / cbe_lun->blocksize;
2475fbc8d4ffSAlexander Motin 
2476fbc8d4ffSAlexander Motin 	if (be_lun->dispatch == ctl_be_block_dispatch_zvol) {
2477fbc8d4ffSAlexander Motin 		unmap = 1;
2478fbc8d4ffSAlexander Motin 	} else {
2479fbc8d4ffSAlexander Motin 		struct diocgattr_arg	arg;
2480fbc8d4ffSAlexander Motin 
2481fbc8d4ffSAlexander Motin 		strlcpy(arg.name, "GEOM::candelete", sizeof(arg.name));
2482fbc8d4ffSAlexander Motin 		arg.len = sizeof(arg.value.i);
24833236151eSAlexander Motin 		error = csw->d_ioctl(dev, DIOCGATTR, (caddr_t)&arg, FREAD,
24843236151eSAlexander Motin 		    curthread);
2485fbc8d4ffSAlexander Motin 		unmap = (error == 0) ? arg.value.i : 0;
2486fbc8d4ffSAlexander Motin 	}
24878951f055SMarcelo Araujo 	value = dnvlist_get_string(cbe_lun->options, "unmap", NULL);
2488fbc8d4ffSAlexander Motin 	if (value != NULL)
2489fbc8d4ffSAlexander Motin 		unmap = (strcmp(value, "on") == 0);
2490fbc8d4ffSAlexander Motin 	if (unmap)
24910bcd4ab6SAlexander Motin 		cbe_lun->flags |= CTL_LUN_FLAG_UNMAP;
24920bcd4ab6SAlexander Motin 	else
24930bcd4ab6SAlexander Motin 		cbe_lun->flags &= ~CTL_LUN_FLAG_UNMAP;
2494fbc8d4ffSAlexander Motin 
24953236151eSAlexander Motin 	dev_relthread(dev, ref);
249681177295SEdward Tomasz Napierala 	return (0);
249781177295SEdward Tomasz Napierala }
2498130f4520SKenneth D. Merry 
2499130f4520SKenneth D. Merry static int
2500130f4520SKenneth D. Merry ctl_be_block_close(struct ctl_be_block_lun *be_lun)
2501130f4520SKenneth D. Merry {
25020bcd4ab6SAlexander Motin 	struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun;
25030bcd4ab6SAlexander Motin 	int flags;
2504130f4520SKenneth D. Merry 
25050bcd4ab6SAlexander Motin 	if (be_lun->vn) {
25060bcd4ab6SAlexander Motin 		flags = FREAD;
25070bcd4ab6SAlexander Motin 		if ((cbe_lun->flags & CTL_LUN_FLAG_READONLY) == 0)
25080bcd4ab6SAlexander Motin 			flags |= FWRITE;
2509130f4520SKenneth D. Merry 		(void)vn_close(be_lun->vn, flags, NOCRED, curthread);
2510130f4520SKenneth D. Merry 		be_lun->vn = NULL;
2511130f4520SKenneth D. Merry 
2512130f4520SKenneth D. Merry 		switch (be_lun->dev_type) {
2513130f4520SKenneth D. Merry 		case CTL_BE_BLOCK_DEV:
2514130f4520SKenneth D. Merry 			break;
2515130f4520SKenneth D. Merry 		case CTL_BE_BLOCK_FILE:
2516130f4520SKenneth D. Merry 			if (be_lun->backend.file.cred != NULL) {
2517130f4520SKenneth D. Merry 				crfree(be_lun->backend.file.cred);
2518130f4520SKenneth D. Merry 				be_lun->backend.file.cred = NULL;
2519130f4520SKenneth D. Merry 			}
2520130f4520SKenneth D. Merry 			break;
2521130f4520SKenneth D. Merry 		case CTL_BE_BLOCK_NONE:
2522025a2301SEdward Tomasz Napierala 			break;
2523130f4520SKenneth D. Merry 		default:
25245124012aSAlexander Motin 			panic("Unexpected backend type %d", be_lun->dev_type);
2525130f4520SKenneth D. Merry 			break;
2526130f4520SKenneth D. Merry 		}
252719720f41SAlexander Motin 		be_lun->dev_type = CTL_BE_BLOCK_NONE;
2528130f4520SKenneth D. Merry 	}
2529130f4520SKenneth D. Merry 	return (0);
2530130f4520SKenneth D. Merry }
2531130f4520SKenneth D. Merry 
2532130f4520SKenneth D. Merry static int
2533648dfc1aSAlexander Motin ctl_be_block_open(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req)
2534130f4520SKenneth D. Merry {
25350bcd4ab6SAlexander Motin 	struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun;
2536130f4520SKenneth D. Merry 	struct nameidata nd;
25378951f055SMarcelo Araujo 	const char	*value;
25380bcd4ab6SAlexander Motin 	int		 error, flags;
2539130f4520SKenneth D. Merry 
2540130f4520SKenneth D. Merry 	error = 0;
2541130f4520SKenneth D. Merry 	if (rootvnode == NULL) {
2542130f4520SKenneth D. Merry 		snprintf(req->error_str, sizeof(req->error_str),
254319720f41SAlexander Motin 			 "Root filesystem is not mounted");
2544130f4520SKenneth D. Merry 		return (1);
2545130f4520SKenneth D. Merry 	}
25468a08cec1SMateusz Guzik 	pwd_ensure_dirs();
2547130f4520SKenneth D. Merry 
25488951f055SMarcelo Araujo 	value = dnvlist_get_string(cbe_lun->options, "file", NULL);
25490bcd4ab6SAlexander Motin 	if (value == NULL) {
25500bcd4ab6SAlexander Motin 		snprintf(req->error_str, sizeof(req->error_str),
25510bcd4ab6SAlexander Motin 			 "no file argument specified");
25520bcd4ab6SAlexander Motin 		return (1);
25530bcd4ab6SAlexander Motin 	}
25540bcd4ab6SAlexander Motin 	free(be_lun->dev_path, M_CTLBLK);
25550bcd4ab6SAlexander Motin 	be_lun->dev_path = strdup(value, M_CTLBLK);
25560bcd4ab6SAlexander Motin 
25570bcd4ab6SAlexander Motin 	flags = FREAD;
25588951f055SMarcelo Araujo 	value = dnvlist_get_string(cbe_lun->options, "readonly", NULL);
255991be33dcSAlexander Motin 	if (value != NULL) {
256091be33dcSAlexander Motin 		if (strcmp(value, "on") != 0)
256191be33dcSAlexander Motin 			flags |= FWRITE;
256291be33dcSAlexander Motin 	} else if (cbe_lun->lun_type == T_DIRECT)
25630bcd4ab6SAlexander Motin 		flags |= FWRITE;
25640bcd4ab6SAlexander Motin 
2565130f4520SKenneth D. Merry again:
25667e1d3eefSMateusz Guzik 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, be_lun->dev_path);
2567130f4520SKenneth D. Merry 	error = vn_open(&nd, &flags, 0, NULL);
25680bcd4ab6SAlexander Motin 	if ((error == EROFS || error == EACCES) && (flags & FWRITE)) {
25690bcd4ab6SAlexander Motin 		flags &= ~FWRITE;
25700bcd4ab6SAlexander Motin 		goto again;
25710bcd4ab6SAlexander Motin 	}
2572130f4520SKenneth D. Merry 	if (error) {
2573130f4520SKenneth D. Merry 		/*
2574130f4520SKenneth D. Merry 		 * This is the only reasonable guess we can make as far as
2575130f4520SKenneth D. Merry 		 * path if the user doesn't give us a fully qualified path.
2576130f4520SKenneth D. Merry 		 * If they want to specify a file, they need to specify the
2577130f4520SKenneth D. Merry 		 * full path.
2578130f4520SKenneth D. Merry 		 */
2579130f4520SKenneth D. Merry 		if (be_lun->dev_path[0] != '/') {
2580130f4520SKenneth D. Merry 			char *dev_name;
2581130f4520SKenneth D. Merry 
25820bcd4ab6SAlexander Motin 			asprintf(&dev_name, M_CTLBLK, "/dev/%s",
2583130f4520SKenneth D. Merry 				be_lun->dev_path);
2584130f4520SKenneth D. Merry 			free(be_lun->dev_path, M_CTLBLK);
2585130f4520SKenneth D. Merry 			be_lun->dev_path = dev_name;
2586130f4520SKenneth D. Merry 			goto again;
2587130f4520SKenneth D. Merry 		}
2588130f4520SKenneth D. Merry 		snprintf(req->error_str, sizeof(req->error_str),
258919720f41SAlexander Motin 		    "error opening %s: %d", be_lun->dev_path, error);
2590130f4520SKenneth D. Merry 		return (error);
2591130f4520SKenneth D. Merry 	}
25920bcd4ab6SAlexander Motin 	if (flags & FWRITE)
25930bcd4ab6SAlexander Motin 		cbe_lun->flags &= ~CTL_LUN_FLAG_READONLY;
25940bcd4ab6SAlexander Motin 	else
25950bcd4ab6SAlexander Motin 		cbe_lun->flags |= CTL_LUN_FLAG_READONLY;
2596130f4520SKenneth D. Merry 
2597bb92cd7bSMateusz Guzik 	NDFREE_PNBUF(&nd);
2598130f4520SKenneth D. Merry 	be_lun->vn = nd.ni_vp;
2599130f4520SKenneth D. Merry 
2600130f4520SKenneth D. Merry 	/* We only support disks and files. */
26017ad2a82dSMateusz Guzik 	if (vn_isdisk_error(be_lun->vn, &error)) {
2602130f4520SKenneth D. Merry 		error = ctl_be_block_open_dev(be_lun, req);
2603130f4520SKenneth D. Merry 	} else if (be_lun->vn->v_type == VREG) {
2604130f4520SKenneth D. Merry 		error = ctl_be_block_open_file(be_lun, req);
2605130f4520SKenneth D. Merry 	} else {
2606130f4520SKenneth D. Merry 		error = EINVAL;
2607130f4520SKenneth D. Merry 		snprintf(req->error_str, sizeof(req->error_str),
2608025a2301SEdward Tomasz Napierala 			 "%s is not a disk or plain file", be_lun->dev_path);
2609130f4520SKenneth D. Merry 	}
2610b249ce48SMateusz Guzik 	VOP_UNLOCK(be_lun->vn);
2611130f4520SKenneth D. Merry 
2612a15bbf15SAlexander Motin 	if (error != 0)
2613130f4520SKenneth D. Merry 		ctl_be_block_close(be_lun);
26140bcd4ab6SAlexander Motin 	cbe_lun->serseq = CTL_LUN_SERSEQ_OFF;
26150bcd4ab6SAlexander Motin 	if (be_lun->dispatch != ctl_be_block_dispatch_dev)
2616ac503c19SAlexander Motin 		cbe_lun->serseq = CTL_LUN_SERSEQ_SOFT;
26178951f055SMarcelo Araujo 	value = dnvlist_get_string(cbe_lun->options, "serseq", NULL);
26180bcd4ab6SAlexander Motin 	if (value != NULL && strcmp(value, "on") == 0)
26190bcd4ab6SAlexander Motin 		cbe_lun->serseq = CTL_LUN_SERSEQ_ON;
26200bcd4ab6SAlexander Motin 	else if (value != NULL && strcmp(value, "read") == 0)
26210bcd4ab6SAlexander Motin 		cbe_lun->serseq = CTL_LUN_SERSEQ_READ;
2622ac503c19SAlexander Motin 	else if (value != NULL && strcmp(value, "soft") == 0)
2623ac503c19SAlexander Motin 		cbe_lun->serseq = CTL_LUN_SERSEQ_SOFT;
26240bcd4ab6SAlexander Motin 	else if (value != NULL && strcmp(value, "off") == 0)
26250bcd4ab6SAlexander Motin 		cbe_lun->serseq = CTL_LUN_SERSEQ_OFF;
2626130f4520SKenneth D. Merry 	return (0);
2627130f4520SKenneth D. Merry }
2628130f4520SKenneth D. Merry 
2629130f4520SKenneth D. Merry static int
2630130f4520SKenneth D. Merry ctl_be_block_create(struct ctl_be_block_softc *softc, struct ctl_lun_req *req)
2631130f4520SKenneth D. Merry {
26320bcd4ab6SAlexander Motin 	struct ctl_be_lun *cbe_lun;
2633130f4520SKenneth D. Merry 	struct ctl_be_block_lun *be_lun;
2634130f4520SKenneth D. Merry 	struct ctl_lun_create_params *params;
263557a5db13SAlexander Motin 	char num_thread_str[16];
2636130f4520SKenneth D. Merry 	char tmpstr[32];
26378951f055SMarcelo Araujo 	const char *value;
2638fbc8d4ffSAlexander Motin 	int retval, num_threads;
263957a5db13SAlexander Motin 	int tmp_num_threads;
2640130f4520SKenneth D. Merry 
2641130f4520SKenneth D. Merry 	params = &req->reqdata.create;
2642130f4520SKenneth D. Merry 	retval = 0;
264319720f41SAlexander Motin 	req->status = CTL_LUN_OK;
2644130f4520SKenneth D. Merry 
2645130f4520SKenneth D. Merry 	be_lun = malloc(sizeof(*be_lun), M_CTLBLK, M_ZERO | M_WAITOK);
26460bcd4ab6SAlexander Motin 	cbe_lun = &be_lun->cbe_lun;
264719720f41SAlexander Motin 	be_lun->params = req->reqdata.create;
2648130f4520SKenneth D. Merry 	be_lun->softc = softc;
2649130f4520SKenneth D. Merry 	STAILQ_INIT(&be_lun->input_queue);
2650ef8daf3fSAlexander Motin 	STAILQ_INIT(&be_lun->config_read_queue);
2651130f4520SKenneth D. Merry 	STAILQ_INIT(&be_lun->config_write_queue);
2652130f4520SKenneth D. Merry 	STAILQ_INIT(&be_lun->datamove_queue);
265334144c2cSAlexander Motin 	mtx_init(&be_lun->io_lock, "ctlblock io", NULL, MTX_DEF);
265434144c2cSAlexander Motin 	mtx_init(&be_lun->queue_lock, "ctlblock queue", NULL, MTX_DEF);
26558951f055SMarcelo Araujo 	cbe_lun->options = nvlist_clone(req->args_nvl);
2656130f4520SKenneth D. Merry 
2657130f4520SKenneth D. Merry 	if (params->flags & CTL_LUN_FLAG_DEV_TYPE)
26580bcd4ab6SAlexander Motin 		cbe_lun->lun_type = params->device_type;
2659130f4520SKenneth D. Merry 	else
26600bcd4ab6SAlexander Motin 		cbe_lun->lun_type = T_DIRECT;
266134144c2cSAlexander Motin 	be_lun->flags = 0;
26627ac58230SAlexander Motin 	cbe_lun->flags = 0;
26638951f055SMarcelo Araujo 	value = dnvlist_get_string(cbe_lun->options, "ha_role", NULL);
26647ac58230SAlexander Motin 	if (value != NULL) {
26657ac58230SAlexander Motin 		if (strcmp(value, "primary") == 0)
26667ac58230SAlexander Motin 			cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY;
26677ac58230SAlexander Motin 	} else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF)
26687ac58230SAlexander Motin 		cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY;
2669130f4520SKenneth D. Merry 
267091be33dcSAlexander Motin 	if (cbe_lun->lun_type == T_DIRECT ||
267191be33dcSAlexander Motin 	    cbe_lun->lun_type == T_CDROM) {
2672a15bbf15SAlexander Motin 		be_lun->size_bytes = params->lun_size_bytes;
2673a15bbf15SAlexander Motin 		if (params->blocksize_bytes != 0)
26740bcd4ab6SAlexander Motin 			cbe_lun->blocksize = params->blocksize_bytes;
267591be33dcSAlexander Motin 		else if (cbe_lun->lun_type == T_CDROM)
267691be33dcSAlexander Motin 			cbe_lun->blocksize = 2048;
2677a15bbf15SAlexander Motin 		else
26780bcd4ab6SAlexander Motin 			cbe_lun->blocksize = 512;
26790bcd4ab6SAlexander Motin 		be_lun->size_blocks = be_lun->size_bytes / cbe_lun->blocksize;
26800bcd4ab6SAlexander Motin 		cbe_lun->maxlba = (be_lun->size_blocks == 0) ?
26810bcd4ab6SAlexander Motin 		    0 : (be_lun->size_blocks - 1);
2682130f4520SKenneth D. Merry 
26837ac58230SAlexander Motin 		if ((cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) ||
26847ac58230SAlexander Motin 		    control_softc->ha_mode == CTL_HA_MODE_SER_ONLY) {
2685648dfc1aSAlexander Motin 			retval = ctl_be_block_open(be_lun, req);
2686130f4520SKenneth D. Merry 			if (retval != 0) {
2687130f4520SKenneth D. Merry 				retval = 0;
268819720f41SAlexander Motin 				req->status = CTL_LUN_WARNING;
2689130f4520SKenneth D. Merry 			}
26907ac58230SAlexander Motin 		}
26910bcd4ab6SAlexander Motin 		num_threads = cbb_num_threads;
2692130f4520SKenneth D. Merry 	} else {
2693130f4520SKenneth D. Merry 		num_threads = 1;
2694130f4520SKenneth D. Merry 	}
2695130f4520SKenneth D. Merry 
26968951f055SMarcelo Araujo 	value = dnvlist_get_string(cbe_lun->options, "num_threads", NULL);
269757a5db13SAlexander Motin 	if (value != NULL) {
269857a5db13SAlexander Motin 		tmp_num_threads = strtol(value, NULL, 0);
2699130f4520SKenneth D. Merry 
2700130f4520SKenneth D. Merry 		/*
2701130f4520SKenneth D. Merry 		 * We don't let the user specify less than one
2702130f4520SKenneth D. Merry 		 * thread, but hope he's clueful enough not to
2703130f4520SKenneth D. Merry 		 * specify 1000 threads.
2704130f4520SKenneth D. Merry 		 */
2705130f4520SKenneth D. Merry 		if (tmp_num_threads < 1) {
2706130f4520SKenneth D. Merry 			snprintf(req->error_str, sizeof(req->error_str),
270719720f41SAlexander Motin 				 "invalid number of threads %s",
270819720f41SAlexander Motin 				 num_thread_str);
2709130f4520SKenneth D. Merry 			goto bailout_error;
2710130f4520SKenneth D. Merry 		}
2711130f4520SKenneth D. Merry 		num_threads = tmp_num_threads;
271257a5db13SAlexander Motin 	}
2713130f4520SKenneth D. Merry 
271419720f41SAlexander Motin 	if (be_lun->vn == NULL)
2715648dfc1aSAlexander Motin 		cbe_lun->flags |= CTL_LUN_FLAG_NO_MEDIA;
2716130f4520SKenneth D. Merry 	/* Tell the user the blocksize we ended up using */
271719720f41SAlexander Motin 	params->lun_size_bytes = be_lun->size_bytes;
27180bcd4ab6SAlexander Motin 	params->blocksize_bytes = cbe_lun->blocksize;
2719130f4520SKenneth D. Merry 	if (params->flags & CTL_LUN_FLAG_ID_REQ) {
27200bcd4ab6SAlexander Motin 		cbe_lun->req_lun_id = params->req_lun_id;
27210bcd4ab6SAlexander Motin 		cbe_lun->flags |= CTL_LUN_FLAG_ID_REQ;
2722130f4520SKenneth D. Merry 	} else
27230bcd4ab6SAlexander Motin 		cbe_lun->req_lun_id = 0;
2724130f4520SKenneth D. Merry 
27250bcd4ab6SAlexander Motin 	cbe_lun->lun_shutdown = ctl_be_block_lun_shutdown;
27260bcd4ab6SAlexander Motin 	cbe_lun->be = &ctl_be_block_driver;
2727130f4520SKenneth D. Merry 
2728130f4520SKenneth D. Merry 	if ((params->flags & CTL_LUN_FLAG_SERIAL_NUM) == 0) {
272971cd87c6SAlan Somers 		snprintf(tmpstr, sizeof(tmpstr), "MYSERIAL%04d",
2730130f4520SKenneth D. Merry 			 softc->num_luns);
27310bcd4ab6SAlexander Motin 		strncpy((char *)cbe_lun->serial_num, tmpstr,
27320bcd4ab6SAlexander Motin 			MIN(sizeof(cbe_lun->serial_num), sizeof(tmpstr)));
2733130f4520SKenneth D. Merry 
2734130f4520SKenneth D. Merry 		/* Tell the user what we used for a serial number */
2735130f4520SKenneth D. Merry 		strncpy((char *)params->serial_num, tmpstr,
2736e7038eb7SAlexander Motin 			MIN(sizeof(params->serial_num), sizeof(tmpstr)));
2737130f4520SKenneth D. Merry 	} else {
27380bcd4ab6SAlexander Motin 		strncpy((char *)cbe_lun->serial_num, params->serial_num,
27390bcd4ab6SAlexander Motin 			MIN(sizeof(cbe_lun->serial_num),
2740130f4520SKenneth D. Merry 			sizeof(params->serial_num)));
2741130f4520SKenneth D. Merry 	}
2742130f4520SKenneth D. Merry 	if ((params->flags & CTL_LUN_FLAG_DEVID) == 0) {
274371cd87c6SAlan Somers 		snprintf(tmpstr, sizeof(tmpstr), "MYDEVID%04d", softc->num_luns);
27440bcd4ab6SAlexander Motin 		strncpy((char *)cbe_lun->device_id, tmpstr,
27450bcd4ab6SAlexander Motin 			MIN(sizeof(cbe_lun->device_id), sizeof(tmpstr)));
2746130f4520SKenneth D. Merry 
2747130f4520SKenneth D. Merry 		/* Tell the user what we used for a device ID */
2748130f4520SKenneth D. Merry 		strncpy((char *)params->device_id, tmpstr,
2749e7038eb7SAlexander Motin 			MIN(sizeof(params->device_id), sizeof(tmpstr)));
2750130f4520SKenneth D. Merry 	} else {
27510bcd4ab6SAlexander Motin 		strncpy((char *)cbe_lun->device_id, params->device_id,
27520bcd4ab6SAlexander Motin 			MIN(sizeof(cbe_lun->device_id),
2753130f4520SKenneth D. Merry 			    sizeof(params->device_id)));
2754130f4520SKenneth D. Merry 	}
2755130f4520SKenneth D. Merry 
2756130f4520SKenneth D. Merry 	TASK_INIT(&be_lun->io_task, /*priority*/0, ctl_be_block_worker, be_lun);
2757130f4520SKenneth D. Merry 
275834144c2cSAlexander Motin 	be_lun->io_taskqueue = taskqueue_create("ctlblocktq", M_WAITOK,
2759130f4520SKenneth D. Merry 	    taskqueue_thread_enqueue, /*context*/&be_lun->io_taskqueue);
2760130f4520SKenneth D. Merry 
2761130f4520SKenneth D. Merry 	if (be_lun->io_taskqueue == NULL) {
2762130f4520SKenneth D. Merry 		snprintf(req->error_str, sizeof(req->error_str),
276319720f41SAlexander Motin 			 "unable to create taskqueue");
2764130f4520SKenneth D. Merry 		goto bailout_error;
2765130f4520SKenneth D. Merry 	}
2766130f4520SKenneth D. Merry 
2767130f4520SKenneth D. Merry 	/*
2768130f4520SKenneth D. Merry 	 * Note that we start the same number of threads by default for
2769130f4520SKenneth D. Merry 	 * both the file case and the block device case.  For the file
2770130f4520SKenneth D. Merry 	 * case, we need multiple threads to allow concurrency, because the
2771130f4520SKenneth D. Merry 	 * vnode interface is designed to be a blocking interface.  For the
2772130f4520SKenneth D. Merry 	 * block device case, ZFS zvols at least will block the caller's
2773130f4520SKenneth D. Merry 	 * context in many instances, and so we need multiple threads to
2774130f4520SKenneth D. Merry 	 * overcome that problem.  Other block devices don't need as many
2775130f4520SKenneth D. Merry 	 * threads, but they shouldn't cause too many problems.
2776130f4520SKenneth D. Merry 	 *
2777130f4520SKenneth D. Merry 	 * If the user wants to just have a single thread for a block
2778130f4520SKenneth D. Merry 	 * device, he can specify that when the LUN is created, or change
2779130f4520SKenneth D. Merry 	 * the tunable/sysctl to alter the default number of threads.
2780130f4520SKenneth D. Merry 	 */
278112373e95SAlexander Motin 	retval = taskqueue_start_threads_in_proc(&be_lun->io_taskqueue,
2782130f4520SKenneth D. Merry 					 /*num threads*/num_threads,
2783053db1feSAlexander Motin 					 /*priority*/PUSER,
278412373e95SAlexander Motin 					 /*proc*/control_softc->ctl_proc,
278534144c2cSAlexander Motin 					 /*thread name*/"block");
2786130f4520SKenneth D. Merry 
2787130f4520SKenneth D. Merry 	if (retval != 0)
2788130f4520SKenneth D. Merry 		goto bailout_error;
2789130f4520SKenneth D. Merry 
2790130f4520SKenneth D. Merry 	be_lun->num_threads = num_threads;
2791130f4520SKenneth D. Merry 
27920bcd4ab6SAlexander Motin 	retval = ctl_add_lun(&be_lun->cbe_lun);
2793130f4520SKenneth D. Merry 	if (retval != 0) {
2794130f4520SKenneth D. Merry 		snprintf(req->error_str, sizeof(req->error_str),
279519720f41SAlexander Motin 			 "ctl_add_lun() returned error %d, see dmesg for "
279619720f41SAlexander Motin 			 "details", retval);
2797130f4520SKenneth D. Merry 		retval = 0;
2798130f4520SKenneth D. Merry 		goto bailout_error;
2799130f4520SKenneth D. Merry 	}
2800130f4520SKenneth D. Merry 
280134144c2cSAlexander Motin 	be_lun->disk_stats = devstat_new_entry("cbb", cbe_lun->lun_id,
28020bcd4ab6SAlexander Motin 					       cbe_lun->blocksize,
2803130f4520SKenneth D. Merry 					       DEVSTAT_ALL_SUPPORTED,
28040bcd4ab6SAlexander Motin 					       cbe_lun->lun_type
2805130f4520SKenneth D. Merry 					       | DEVSTAT_TYPE_IF_OTHER,
2806130f4520SKenneth D. Merry 					       DEVSTAT_PRIORITY_OTHER);
2807130f4520SKenneth D. Merry 
280834144c2cSAlexander Motin 	mtx_lock(&softc->lock);
280934144c2cSAlexander Motin 	softc->num_luns++;
281034144c2cSAlexander Motin 	SLIST_INSERT_HEAD(&softc->lun_list, be_lun, links);
281134144c2cSAlexander Motin 	mtx_unlock(&softc->lock);
281234144c2cSAlexander Motin 
281334144c2cSAlexander Motin 	params->req_lun_id = cbe_lun->lun_id;
281434144c2cSAlexander Motin 
2815130f4520SKenneth D. Merry 	return (retval);
2816130f4520SKenneth D. Merry 
2817130f4520SKenneth D. Merry bailout_error:
2818130f4520SKenneth D. Merry 	req->status = CTL_LUN_ERROR;
2819130f4520SKenneth D. Merry 
28209e005bbcSAlexander Motin 	if (be_lun->io_taskqueue != NULL)
28219e005bbcSAlexander Motin 		taskqueue_free(be_lun->io_taskqueue);
2822130f4520SKenneth D. Merry 	ctl_be_block_close(be_lun);
28239e005bbcSAlexander Motin 	if (be_lun->dev_path != NULL)
2824130f4520SKenneth D. Merry 		free(be_lun->dev_path, M_CTLBLK);
28258951f055SMarcelo Araujo 	nvlist_destroy(cbe_lun->options);
282675c7a1d3SAlexander Motin 	mtx_destroy(&be_lun->queue_lock);
282775c7a1d3SAlexander Motin 	mtx_destroy(&be_lun->io_lock);
2828130f4520SKenneth D. Merry 	free(be_lun, M_CTLBLK);
2829130f4520SKenneth D. Merry 
2830130f4520SKenneth D. Merry 	return (retval);
2831130f4520SKenneth D. Merry }
2832130f4520SKenneth D. Merry 
2833130f4520SKenneth D. Merry static int
2834130f4520SKenneth D. Merry ctl_be_block_rm(struct ctl_be_block_softc *softc, struct ctl_lun_req *req)
2835130f4520SKenneth D. Merry {
2836130f4520SKenneth D. Merry 	struct ctl_lun_rm_params *params;
2837130f4520SKenneth D. Merry 	struct ctl_be_block_lun *be_lun;
2838ee4ad294SAlexander Motin 	struct ctl_be_lun *cbe_lun;
2839130f4520SKenneth D. Merry 	int retval;
2840130f4520SKenneth D. Merry 
2841130f4520SKenneth D. Merry 	params = &req->reqdata.rm;
2842130f4520SKenneth D. Merry 
284334144c2cSAlexander Motin 	sx_xlock(&softc->modify_lock);
2844130f4520SKenneth D. Merry 	mtx_lock(&softc->lock);
284534144c2cSAlexander Motin 	SLIST_FOREACH(be_lun, &softc->lun_list, links) {
284634144c2cSAlexander Motin 		if (be_lun->cbe_lun.lun_id == params->lun_id) {
284734144c2cSAlexander Motin 			SLIST_REMOVE(&softc->lun_list, be_lun,
284834144c2cSAlexander Motin 			    ctl_be_block_lun, links);
284934144c2cSAlexander Motin 			softc->num_luns--;
2850130f4520SKenneth D. Merry 			break;
2851130f4520SKenneth D. Merry 		}
285234144c2cSAlexander Motin 	}
2853130f4520SKenneth D. Merry 	mtx_unlock(&softc->lock);
285434144c2cSAlexander Motin 	sx_xunlock(&softc->modify_lock);
2855130f4520SKenneth D. Merry 	if (be_lun == NULL) {
2856130f4520SKenneth D. Merry 		snprintf(req->error_str, sizeof(req->error_str),
285719720f41SAlexander Motin 			 "LUN %u is not managed by the block backend",
285819720f41SAlexander Motin 			 params->lun_id);
2859130f4520SKenneth D. Merry 		goto bailout_error;
2860130f4520SKenneth D. Merry 	}
2861ee4ad294SAlexander Motin 	cbe_lun = &be_lun->cbe_lun;
2862130f4520SKenneth D. Merry 
2863ee4ad294SAlexander Motin 	if (be_lun->vn != NULL) {
2864648dfc1aSAlexander Motin 		cbe_lun->flags |= CTL_LUN_FLAG_NO_MEDIA;
2865648dfc1aSAlexander Motin 		ctl_lun_no_media(cbe_lun);
2866ee4ad294SAlexander Motin 		taskqueue_drain_all(be_lun->io_taskqueue);
2867ee4ad294SAlexander Motin 		ctl_be_block_close(be_lun);
2868ee4ad294SAlexander Motin 	}
2869ee4ad294SAlexander Motin 
287034144c2cSAlexander Motin 	mtx_lock(&softc->lock);
287134144c2cSAlexander Motin 	be_lun->flags |= CTL_BE_BLOCK_LUN_WAITING;
287234144c2cSAlexander Motin 	mtx_unlock(&softc->lock);
287334144c2cSAlexander Motin 
287434144c2cSAlexander Motin 	retval = ctl_remove_lun(cbe_lun);
2875130f4520SKenneth D. Merry 	if (retval != 0) {
2876130f4520SKenneth D. Merry 		snprintf(req->error_str, sizeof(req->error_str),
287734144c2cSAlexander Motin 			 "error %d returned from ctl_remove_lun() for "
287819720f41SAlexander Motin 			 "LUN %d", retval, params->lun_id);
287934144c2cSAlexander Motin 		mtx_lock(&softc->lock);
288034144c2cSAlexander Motin 		be_lun->flags &= ~CTL_BE_BLOCK_LUN_WAITING;
288134144c2cSAlexander Motin 		mtx_unlock(&softc->lock);
2882130f4520SKenneth D. Merry 		goto bailout_error;
2883130f4520SKenneth D. Merry 	}
2884130f4520SKenneth D. Merry 
2885130f4520SKenneth D. Merry 	mtx_lock(&softc->lock);
2886130f4520SKenneth D. Merry 	while ((be_lun->flags & CTL_BE_BLOCK_LUN_UNCONFIGURED) == 0) {
288734144c2cSAlexander Motin 		retval = msleep(be_lun, &softc->lock, PCATCH, "ctlblockrm", 0);
2888130f4520SKenneth D. Merry 		if (retval == EINTR)
2889130f4520SKenneth D. Merry 			break;
2890130f4520SKenneth D. Merry 	}
2891130f4520SKenneth D. Merry 	be_lun->flags &= ~CTL_BE_BLOCK_LUN_WAITING;
289234144c2cSAlexander Motin 	if (be_lun->flags & CTL_BE_BLOCK_LUN_UNCONFIGURED) {
2893130f4520SKenneth D. Merry 		mtx_unlock(&softc->lock);
2894130f4520SKenneth D. Merry 		free(be_lun, M_CTLBLK);
289534144c2cSAlexander Motin 	} else {
289634144c2cSAlexander Motin 		mtx_unlock(&softc->lock);
289734144c2cSAlexander Motin 		return (EINTR);
289834144c2cSAlexander Motin 	}
2899130f4520SKenneth D. Merry 
2900130f4520SKenneth D. Merry 	req->status = CTL_LUN_OK;
2901130f4520SKenneth D. Merry 	return (0);
2902130f4520SKenneth D. Merry 
2903130f4520SKenneth D. Merry bailout_error:
2904130f4520SKenneth D. Merry 	req->status = CTL_LUN_ERROR;
2905130f4520SKenneth D. Merry 	return (0);
2906130f4520SKenneth D. Merry }
2907130f4520SKenneth D. Merry 
290881177295SEdward Tomasz Napierala static int
290981177295SEdward Tomasz Napierala ctl_be_block_modify(struct ctl_be_block_softc *softc, struct ctl_lun_req *req)
291081177295SEdward Tomasz Napierala {
291181177295SEdward Tomasz Napierala 	struct ctl_lun_modify_params *params;
291281177295SEdward Tomasz Napierala 	struct ctl_be_block_lun *be_lun;
2913a3977beaSAlexander Motin 	struct ctl_be_lun *cbe_lun;
29148951f055SMarcelo Araujo 	const char *value;
291571d8e97eSAlexander Motin 	uint64_t oldsize;
29167ac58230SAlexander Motin 	int error, wasprim;
291781177295SEdward Tomasz Napierala 
291881177295SEdward Tomasz Napierala 	params = &req->reqdata.modify;
291981177295SEdward Tomasz Napierala 
292034144c2cSAlexander Motin 	sx_xlock(&softc->modify_lock);
292181177295SEdward Tomasz Napierala 	mtx_lock(&softc->lock);
292234144c2cSAlexander Motin 	SLIST_FOREACH(be_lun, &softc->lun_list, links) {
29230bcd4ab6SAlexander Motin 		if (be_lun->cbe_lun.lun_id == params->lun_id)
292481177295SEdward Tomasz Napierala 			break;
292581177295SEdward Tomasz Napierala 	}
292681177295SEdward Tomasz Napierala 	mtx_unlock(&softc->lock);
292781177295SEdward Tomasz Napierala 	if (be_lun == NULL) {
292881177295SEdward Tomasz Napierala 		snprintf(req->error_str, sizeof(req->error_str),
292919720f41SAlexander Motin 			 "LUN %u is not managed by the block backend",
293019720f41SAlexander Motin 			 params->lun_id);
293181177295SEdward Tomasz Napierala 		goto bailout_error;
293281177295SEdward Tomasz Napierala 	}
2933a3977beaSAlexander Motin 	cbe_lun = &be_lun->cbe_lun;
293481177295SEdward Tomasz Napierala 
2935a3977beaSAlexander Motin 	if (params->lun_size_bytes != 0)
293619720f41SAlexander Motin 		be_lun->params.lun_size_bytes = params->lun_size_bytes;
29378951f055SMarcelo Araujo 
2938efeedddcSAlexander Motin 	if (req->args_nvl != NULL) {
29398951f055SMarcelo Araujo 		nvlist_destroy(cbe_lun->options);
29408951f055SMarcelo Araujo 		cbe_lun->options = nvlist_clone(req->args_nvl);
2941efeedddcSAlexander Motin 	}
294281177295SEdward Tomasz Napierala 
29437ac58230SAlexander Motin 	wasprim = (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY);
29448951f055SMarcelo Araujo 	value = dnvlist_get_string(cbe_lun->options, "ha_role", NULL);
29457ac58230SAlexander Motin 	if (value != NULL) {
29467ac58230SAlexander Motin 		if (strcmp(value, "primary") == 0)
29477ac58230SAlexander Motin 			cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY;
29487ac58230SAlexander Motin 		else
29497ac58230SAlexander Motin 			cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY;
29507ac58230SAlexander Motin 	} else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF)
29517ac58230SAlexander Motin 		cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY;
29527ac58230SAlexander Motin 	else
29537ac58230SAlexander Motin 		cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY;
29547ac58230SAlexander Motin 	if (wasprim != (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY)) {
29557ac58230SAlexander Motin 		if (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY)
29567ac58230SAlexander Motin 			ctl_lun_primary(cbe_lun);
29577ac58230SAlexander Motin 		else
29587ac58230SAlexander Motin 			ctl_lun_secondary(cbe_lun);
29597ac58230SAlexander Motin 	}
29607ac58230SAlexander Motin 
29610bcd4ab6SAlexander Motin 	oldsize = be_lun->size_blocks;
29627ac58230SAlexander Motin 	if ((cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) ||
29637ac58230SAlexander Motin 	    control_softc->ha_mode == CTL_HA_MODE_SER_ONLY) {
296419720f41SAlexander Motin 		if (be_lun->vn == NULL)
2965648dfc1aSAlexander Motin 			error = ctl_be_block_open(be_lun, req);
29667ad2a82dSMateusz Guzik 		else if (vn_isdisk_error(be_lun->vn, &error))
29674ce7a086SAlexander Motin 			error = ctl_be_block_open_dev(be_lun, req);
29683d5cb709SAlexander Motin 		else if (be_lun->vn->v_type == VREG) {
29693d5cb709SAlexander Motin 			vn_lock(be_lun->vn, LK_SHARED | LK_RETRY);
29704ce7a086SAlexander Motin 			error = ctl_be_block_open_file(be_lun, req);
2971b249ce48SMateusz Guzik 			VOP_UNLOCK(be_lun->vn);
29723d5cb709SAlexander Motin 		} else
2973b9b4269cSAlexander Motin 			error = EINVAL;
2974648dfc1aSAlexander Motin 		if ((cbe_lun->flags & CTL_LUN_FLAG_NO_MEDIA) &&
29750bcd4ab6SAlexander Motin 		    be_lun->vn != NULL) {
2976648dfc1aSAlexander Motin 			cbe_lun->flags &= ~CTL_LUN_FLAG_NO_MEDIA;
2977648dfc1aSAlexander Motin 			ctl_lun_has_media(cbe_lun);
2978648dfc1aSAlexander Motin 		} else if ((cbe_lun->flags & CTL_LUN_FLAG_NO_MEDIA) == 0 &&
2979648dfc1aSAlexander Motin 		    be_lun->vn == NULL) {
2980648dfc1aSAlexander Motin 			cbe_lun->flags |= CTL_LUN_FLAG_NO_MEDIA;
2981648dfc1aSAlexander Motin 			ctl_lun_no_media(cbe_lun);
298271d8e97eSAlexander Motin 		}
2983648dfc1aSAlexander Motin 		cbe_lun->flags &= ~CTL_LUN_FLAG_EJECTED;
29847ac58230SAlexander Motin 	} else {
29857ac58230SAlexander Motin 		if (be_lun->vn != NULL) {
2986648dfc1aSAlexander Motin 			cbe_lun->flags |= CTL_LUN_FLAG_NO_MEDIA;
2987648dfc1aSAlexander Motin 			ctl_lun_no_media(cbe_lun);
2988ee4ad294SAlexander Motin 			taskqueue_drain_all(be_lun->io_taskqueue);
29897ac58230SAlexander Motin 			error = ctl_be_block_close(be_lun);
29907ac58230SAlexander Motin 		} else
29917ac58230SAlexander Motin 			error = 0;
29927ac58230SAlexander Motin 	}
29937ac58230SAlexander Motin 	if (be_lun->size_blocks != oldsize)
29947ac58230SAlexander Motin 		ctl_lun_capacity_changed(cbe_lun);
299581177295SEdward Tomasz Napierala 
299681177295SEdward Tomasz Napierala 	/* Tell the user the exact size we ended up using */
299781177295SEdward Tomasz Napierala 	params->lun_size_bytes = be_lun->size_bytes;
299881177295SEdward Tomasz Napierala 
299934144c2cSAlexander Motin 	sx_xunlock(&softc->modify_lock);
300019720f41SAlexander Motin 	req->status = error ? CTL_LUN_WARNING : CTL_LUN_OK;
300181177295SEdward Tomasz Napierala 	return (0);
300281177295SEdward Tomasz Napierala 
300381177295SEdward Tomasz Napierala bailout_error:
300434144c2cSAlexander Motin 	sx_xunlock(&softc->modify_lock);
300581177295SEdward Tomasz Napierala 	req->status = CTL_LUN_ERROR;
300681177295SEdward Tomasz Napierala 	return (0);
300781177295SEdward Tomasz Napierala }
300881177295SEdward Tomasz Napierala 
3009130f4520SKenneth D. Merry static void
3010767300e8SAlexander Motin ctl_be_block_lun_shutdown(struct ctl_be_lun *cbe_lun)
3011130f4520SKenneth D. Merry {
3012767300e8SAlexander Motin 	struct ctl_be_block_lun *be_lun = (struct ctl_be_block_lun *)cbe_lun;
301334144c2cSAlexander Motin 	struct ctl_be_block_softc *softc = be_lun->softc;
301434144c2cSAlexander Motin 
301534144c2cSAlexander Motin 	taskqueue_drain_all(be_lun->io_taskqueue);
301634144c2cSAlexander Motin 	taskqueue_free(be_lun->io_taskqueue);
301734144c2cSAlexander Motin 	if (be_lun->disk_stats != NULL)
301834144c2cSAlexander Motin 		devstat_remove_entry(be_lun->disk_stats);
301934144c2cSAlexander Motin 	nvlist_destroy(be_lun->cbe_lun.options);
302034144c2cSAlexander Motin 	free(be_lun->dev_path, M_CTLBLK);
302134144c2cSAlexander Motin 	mtx_destroy(&be_lun->queue_lock);
302234144c2cSAlexander Motin 	mtx_destroy(&be_lun->io_lock);
3023130f4520SKenneth D. Merry 
3024130f4520SKenneth D. Merry 	mtx_lock(&softc->lock);
302534144c2cSAlexander Motin 	be_lun->flags |= CTL_BE_BLOCK_LUN_UNCONFIGURED;
302634144c2cSAlexander Motin 	if (be_lun->flags & CTL_BE_BLOCK_LUN_WAITING)
302734144c2cSAlexander Motin 		wakeup(be_lun);
302834144c2cSAlexander Motin 	else
302934144c2cSAlexander Motin 		free(be_lun, M_CTLBLK);
3030130f4520SKenneth D. Merry 	mtx_unlock(&softc->lock);
3031130f4520SKenneth D. Merry }
3032130f4520SKenneth D. Merry 
3033130f4520SKenneth D. Merry static int
3034374f12c5SJohn Baldwin ctl_be_block_scsi_config_write(union ctl_io *io)
3035130f4520SKenneth D. Merry {
3036130f4520SKenneth D. Merry 	struct ctl_be_block_lun *be_lun;
30370bcd4ab6SAlexander Motin 	struct ctl_be_lun *cbe_lun;
3038130f4520SKenneth D. Merry 	int retval;
3039130f4520SKenneth D. Merry 
3040130f4520SKenneth D. Merry 	DPRINTF("entered\n");
3041130f4520SKenneth D. Merry 
30429cbbfd2fSAlexander Motin 	cbe_lun = CTL_BACKEND_LUN(io);
3043767300e8SAlexander Motin 	be_lun = (struct ctl_be_block_lun *)cbe_lun;
3044130f4520SKenneth D. Merry 
304567cc546dSAlexander Motin 	retval = 0;
3046130f4520SKenneth D. Merry 	switch (io->scsiio.cdb[0]) {
3047130f4520SKenneth D. Merry 	case SYNCHRONIZE_CACHE:
3048130f4520SKenneth D. Merry 	case SYNCHRONIZE_CACHE_16:
3049ee7f31c0SAlexander Motin 	case WRITE_SAME_10:
3050ee7f31c0SAlexander Motin 	case WRITE_SAME_16:
3051ee7f31c0SAlexander Motin 	case UNMAP:
3052130f4520SKenneth D. Merry 		/*
3053130f4520SKenneth D. Merry 		 * The upper level CTL code will filter out any CDBs with
3054130f4520SKenneth D. Merry 		 * the immediate bit set and return the proper error.
3055130f4520SKenneth D. Merry 		 *
3056130f4520SKenneth D. Merry 		 * We don't really need to worry about what LBA range the
3057130f4520SKenneth D. Merry 		 * user asked to be synced out.  When they issue a sync
3058130f4520SKenneth D. Merry 		 * cache command, we'll sync out the whole thing.
3059130f4520SKenneth D. Merry 		 */
306075c7a1d3SAlexander Motin 		mtx_lock(&be_lun->queue_lock);
3061130f4520SKenneth D. Merry 		STAILQ_INSERT_TAIL(&be_lun->config_write_queue, &io->io_hdr,
3062130f4520SKenneth D. Merry 				   links);
306375c7a1d3SAlexander Motin 		mtx_unlock(&be_lun->queue_lock);
3064130f4520SKenneth D. Merry 		taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task);
3065130f4520SKenneth D. Merry 		break;
3066130f4520SKenneth D. Merry 	case START_STOP_UNIT: {
3067130f4520SKenneth D. Merry 		struct scsi_start_stop_unit *cdb;
3068648dfc1aSAlexander Motin 		struct ctl_lun_req req;
3069130f4520SKenneth D. Merry 
3070130f4520SKenneth D. Merry 		cdb = (struct scsi_start_stop_unit *)io->scsiio.cdb;
307166b69676SAlexander Motin 		if ((cdb->how & SSS_PC_MASK) != 0) {
307266b69676SAlexander Motin 			ctl_set_success(&io->scsiio);
307366b69676SAlexander Motin 			ctl_config_write_done(io);
307466b69676SAlexander Motin 			break;
307566b69676SAlexander Motin 		}
3076648dfc1aSAlexander Motin 		if (cdb->how & SSS_START) {
3077648dfc1aSAlexander Motin 			if ((cdb->how & SSS_LOEJ) && be_lun->vn == NULL) {
3078648dfc1aSAlexander Motin 				retval = ctl_be_block_open(be_lun, &req);
3079648dfc1aSAlexander Motin 				cbe_lun->flags &= ~CTL_LUN_FLAG_EJECTED;
3080648dfc1aSAlexander Motin 				if (retval == 0) {
3081648dfc1aSAlexander Motin 					cbe_lun->flags &= ~CTL_LUN_FLAG_NO_MEDIA;
3082648dfc1aSAlexander Motin 					ctl_lun_has_media(cbe_lun);
3083130f4520SKenneth D. Merry 				} else {
3084648dfc1aSAlexander Motin 					cbe_lun->flags |= CTL_LUN_FLAG_NO_MEDIA;
3085648dfc1aSAlexander Motin 					ctl_lun_no_media(cbe_lun);
3086130f4520SKenneth D. Merry 				}
3087648dfc1aSAlexander Motin 			}
3088648dfc1aSAlexander Motin 			ctl_start_lun(cbe_lun);
3089648dfc1aSAlexander Motin 		} else {
3090648dfc1aSAlexander Motin 			ctl_stop_lun(cbe_lun);
3091648dfc1aSAlexander Motin 			if (cdb->how & SSS_LOEJ) {
3092648dfc1aSAlexander Motin 				cbe_lun->flags |= CTL_LUN_FLAG_NO_MEDIA;
3093648dfc1aSAlexander Motin 				cbe_lun->flags |= CTL_LUN_FLAG_EJECTED;
3094648dfc1aSAlexander Motin 				ctl_lun_ejected(cbe_lun);
3095648dfc1aSAlexander Motin 				if (be_lun->vn != NULL)
3096648dfc1aSAlexander Motin 					ctl_be_block_close(be_lun);
3097648dfc1aSAlexander Motin 			}
3098648dfc1aSAlexander Motin 		}
3099648dfc1aSAlexander Motin 
3100648dfc1aSAlexander Motin 		ctl_set_success(&io->scsiio);
3101130f4520SKenneth D. Merry 		ctl_config_write_done(io);
3102130f4520SKenneth D. Merry 		break;
3103130f4520SKenneth D. Merry 	}
310491be33dcSAlexander Motin 	case PREVENT_ALLOW:
310591be33dcSAlexander Motin 		ctl_set_success(&io->scsiio);
310691be33dcSAlexander Motin 		ctl_config_write_done(io);
310791be33dcSAlexander Motin 		break;
3108130f4520SKenneth D. Merry 	default:
3109130f4520SKenneth D. Merry 		ctl_set_invalid_opcode(&io->scsiio);
3110130f4520SKenneth D. Merry 		ctl_config_write_done(io);
3111130f4520SKenneth D. Merry 		retval = CTL_RETVAL_COMPLETE;
3112130f4520SKenneth D. Merry 		break;
3113130f4520SKenneth D. Merry 	}
3114130f4520SKenneth D. Merry 
3115130f4520SKenneth D. Merry 	return (retval);
3116130f4520SKenneth D. Merry }
3117130f4520SKenneth D. Merry 
3118130f4520SKenneth D. Merry static int
3119374f12c5SJohn Baldwin ctl_be_block_nvme_config_write(union ctl_io *io)
3120374f12c5SJohn Baldwin {
3121374f12c5SJohn Baldwin 	struct ctl_be_block_lun *be_lun;
3122374f12c5SJohn Baldwin 
3123374f12c5SJohn Baldwin 	DPRINTF("entered\n");
3124374f12c5SJohn Baldwin 
3125374f12c5SJohn Baldwin 	be_lun = (struct ctl_be_block_lun *)CTL_BACKEND_LUN(io);
3126374f12c5SJohn Baldwin 
3127374f12c5SJohn Baldwin 	switch (io->nvmeio.cmd.opc) {
3128374f12c5SJohn Baldwin 	case NVME_OPC_DATASET_MANAGEMENT:
3129374f12c5SJohn Baldwin 		DSM_RANGE(io) = 0;
3130374f12c5SJohn Baldwin 		/* FALLTHROUGH */
3131374f12c5SJohn Baldwin 	case NVME_OPC_FLUSH:
3132374f12c5SJohn Baldwin 	case NVME_OPC_WRITE_UNCORRECTABLE:
3133374f12c5SJohn Baldwin 	case NVME_OPC_WRITE_ZEROES:
3134374f12c5SJohn Baldwin 		mtx_lock(&be_lun->queue_lock);
3135374f12c5SJohn Baldwin 		STAILQ_INSERT_TAIL(&be_lun->config_write_queue, &io->io_hdr,
3136374f12c5SJohn Baldwin 				   links);
3137374f12c5SJohn Baldwin 		mtx_unlock(&be_lun->queue_lock);
3138374f12c5SJohn Baldwin 		taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task);
3139374f12c5SJohn Baldwin 		break;
3140374f12c5SJohn Baldwin 	default:
3141374f12c5SJohn Baldwin 		ctl_nvme_set_invalid_opcode(&io->nvmeio);
3142374f12c5SJohn Baldwin 		ctl_config_write_done(io);
3143374f12c5SJohn Baldwin 		break;
3144374f12c5SJohn Baldwin 	}
3145374f12c5SJohn Baldwin 	return (CTL_RETVAL_COMPLETE);
3146374f12c5SJohn Baldwin }
3147374f12c5SJohn Baldwin 
3148374f12c5SJohn Baldwin static int
3149374f12c5SJohn Baldwin ctl_be_block_config_write(union ctl_io *io)
3150374f12c5SJohn Baldwin {
3151374f12c5SJohn Baldwin 	switch (io->io_hdr.io_type) {
3152374f12c5SJohn Baldwin 	case CTL_IO_SCSI:
3153374f12c5SJohn Baldwin 		return (ctl_be_block_scsi_config_write(io));
3154374f12c5SJohn Baldwin 	case CTL_IO_NVME:
3155374f12c5SJohn Baldwin 		return (ctl_be_block_nvme_config_write(io));
3156374f12c5SJohn Baldwin 	default:
3157374f12c5SJohn Baldwin 		__assert_unreachable();
3158374f12c5SJohn Baldwin 	}
3159374f12c5SJohn Baldwin }
3160374f12c5SJohn Baldwin 
3161374f12c5SJohn Baldwin static int
3162374f12c5SJohn Baldwin ctl_be_block_scsi_config_read(union ctl_io *io)
3163130f4520SKenneth D. Merry {
3164ef8daf3fSAlexander Motin 	struct ctl_be_block_lun *be_lun;
3165ef8daf3fSAlexander Motin 	int retval = 0;
3166ef8daf3fSAlexander Motin 
3167ef8daf3fSAlexander Motin 	DPRINTF("entered\n");
3168ef8daf3fSAlexander Motin 
3169767300e8SAlexander Motin 	be_lun = (struct ctl_be_block_lun *)CTL_BACKEND_LUN(io);
3170ef8daf3fSAlexander Motin 
3171ef8daf3fSAlexander Motin 	switch (io->scsiio.cdb[0]) {
3172ef8daf3fSAlexander Motin 	case SERVICE_ACTION_IN:
3173ef8daf3fSAlexander Motin 		if (io->scsiio.cdb[1] == SGLS_SERVICE_ACTION) {
3174ef8daf3fSAlexander Motin 			mtx_lock(&be_lun->queue_lock);
3175ef8daf3fSAlexander Motin 			STAILQ_INSERT_TAIL(&be_lun->config_read_queue,
3176ef8daf3fSAlexander Motin 			    &io->io_hdr, links);
3177ef8daf3fSAlexander Motin 			mtx_unlock(&be_lun->queue_lock);
3178ef8daf3fSAlexander Motin 			taskqueue_enqueue(be_lun->io_taskqueue,
3179ef8daf3fSAlexander Motin 			    &be_lun->io_task);
3180ef8daf3fSAlexander Motin 			retval = CTL_RETVAL_QUEUED;
3181ef8daf3fSAlexander Motin 			break;
3182ef8daf3fSAlexander Motin 		}
3183ef8daf3fSAlexander Motin 		ctl_set_invalid_field(&io->scsiio,
3184ef8daf3fSAlexander Motin 				      /*sks_valid*/ 1,
3185ef8daf3fSAlexander Motin 				      /*command*/ 1,
3186ef8daf3fSAlexander Motin 				      /*field*/ 1,
3187ef8daf3fSAlexander Motin 				      /*bit_valid*/ 1,
3188ef8daf3fSAlexander Motin 				      /*bit*/ 4);
3189ef8daf3fSAlexander Motin 		ctl_config_read_done(io);
3190ef8daf3fSAlexander Motin 		retval = CTL_RETVAL_COMPLETE;
3191ef8daf3fSAlexander Motin 		break;
3192ef8daf3fSAlexander Motin 	default:
3193ef8daf3fSAlexander Motin 		ctl_set_invalid_opcode(&io->scsiio);
3194ef8daf3fSAlexander Motin 		ctl_config_read_done(io);
3195ef8daf3fSAlexander Motin 		retval = CTL_RETVAL_COMPLETE;
3196ef8daf3fSAlexander Motin 		break;
3197ef8daf3fSAlexander Motin 	}
3198ef8daf3fSAlexander Motin 
3199ef8daf3fSAlexander Motin 	return (retval);
3200130f4520SKenneth D. Merry }
3201130f4520SKenneth D. Merry 
3202130f4520SKenneth D. Merry static int
3203374f12c5SJohn Baldwin ctl_be_block_nvme_config_read(union ctl_io *io)
3204374f12c5SJohn Baldwin {
3205374f12c5SJohn Baldwin 	struct ctl_be_block_lun *be_lun;
3206374f12c5SJohn Baldwin 
3207374f12c5SJohn Baldwin 	DPRINTF("entered\n");
3208374f12c5SJohn Baldwin 
3209374f12c5SJohn Baldwin 	be_lun = (struct ctl_be_block_lun *)CTL_BACKEND_LUN(io);
3210374f12c5SJohn Baldwin 
3211374f12c5SJohn Baldwin 	switch (io->nvmeio.cmd.opc) {
3212374f12c5SJohn Baldwin 	case NVME_OPC_IDENTIFY:
3213374f12c5SJohn Baldwin 	{
3214374f12c5SJohn Baldwin 		uint8_t cns;
3215374f12c5SJohn Baldwin 
3216374f12c5SJohn Baldwin 		cns = le32toh(io->nvmeio.cmd.cdw10) & 0xff;
3217374f12c5SJohn Baldwin 		switch (cns) {
3218374f12c5SJohn Baldwin 		case 0:
3219374f12c5SJohn Baldwin 		case 3:
3220374f12c5SJohn Baldwin 			mtx_lock(&be_lun->queue_lock);
3221374f12c5SJohn Baldwin 			STAILQ_INSERT_TAIL(&be_lun->config_read_queue,
3222374f12c5SJohn Baldwin 			    &io->io_hdr, links);
3223374f12c5SJohn Baldwin 			mtx_unlock(&be_lun->queue_lock);
3224374f12c5SJohn Baldwin 			taskqueue_enqueue(be_lun->io_taskqueue,
3225374f12c5SJohn Baldwin 			    &be_lun->io_task);
3226374f12c5SJohn Baldwin 			return (CTL_RETVAL_QUEUED);
3227374f12c5SJohn Baldwin 		default:
3228374f12c5SJohn Baldwin 			ctl_nvme_set_invalid_field(&io->nvmeio);
3229374f12c5SJohn Baldwin 			ctl_config_read_done(io);
3230374f12c5SJohn Baldwin 			break;
3231374f12c5SJohn Baldwin 		}
3232374f12c5SJohn Baldwin 		break;
3233374f12c5SJohn Baldwin 	}
3234374f12c5SJohn Baldwin 	default:
3235374f12c5SJohn Baldwin 		ctl_nvme_set_invalid_opcode(&io->nvmeio);
3236374f12c5SJohn Baldwin 		ctl_config_read_done(io);
3237374f12c5SJohn Baldwin 		break;
3238374f12c5SJohn Baldwin 	}
3239374f12c5SJohn Baldwin 	return (CTL_RETVAL_COMPLETE);
3240374f12c5SJohn Baldwin }
3241374f12c5SJohn Baldwin 
3242374f12c5SJohn Baldwin static int
3243374f12c5SJohn Baldwin ctl_be_block_config_read(union ctl_io *io)
3244374f12c5SJohn Baldwin {
3245374f12c5SJohn Baldwin 	switch (io->io_hdr.io_type) {
3246374f12c5SJohn Baldwin 	case CTL_IO_SCSI:
3247374f12c5SJohn Baldwin 		return (ctl_be_block_scsi_config_read(io));
3248374f12c5SJohn Baldwin 	case CTL_IO_NVME_ADMIN:
3249374f12c5SJohn Baldwin 		return (ctl_be_block_nvme_config_read(io));
3250374f12c5SJohn Baldwin 	default:
3251374f12c5SJohn Baldwin 		__assert_unreachable();
3252374f12c5SJohn Baldwin 	}
3253374f12c5SJohn Baldwin }
3254374f12c5SJohn Baldwin 
3255374f12c5SJohn Baldwin static int
3256767300e8SAlexander Motin ctl_be_block_lun_info(struct ctl_be_lun *cbe_lun, struct sbuf *sb)
3257130f4520SKenneth D. Merry {
3258767300e8SAlexander Motin 	struct ctl_be_block_lun *lun = (struct ctl_be_block_lun *)cbe_lun;
3259130f4520SKenneth D. Merry 	int retval;
3260130f4520SKenneth D. Merry 
3261519b24f0SAlexander Motin 	retval = sbuf_cat(sb, "\t<num_threads>");
3262130f4520SKenneth D. Merry 	if (retval != 0)
3263130f4520SKenneth D. Merry 		goto bailout;
3264130f4520SKenneth D. Merry 	retval = sbuf_printf(sb, "%d", lun->num_threads);
3265130f4520SKenneth D. Merry 	if (retval != 0)
3266130f4520SKenneth D. Merry 		goto bailout;
3267519b24f0SAlexander Motin 	retval = sbuf_cat(sb, "</num_threads>\n");
3268130f4520SKenneth D. Merry 
3269130f4520SKenneth D. Merry bailout:
3270130f4520SKenneth D. Merry 	return (retval);
3271130f4520SKenneth D. Merry }
3272130f4520SKenneth D. Merry 
3273c3e7ba3eSAlexander Motin static uint64_t
3274767300e8SAlexander Motin ctl_be_block_lun_attr(struct ctl_be_lun *cbe_lun, const char *attrname)
3275c3e7ba3eSAlexander Motin {
3276767300e8SAlexander Motin 	struct ctl_be_block_lun *lun = (struct ctl_be_block_lun *)cbe_lun;
3277c3e7ba3eSAlexander Motin 
3278c3e7ba3eSAlexander Motin 	if (lun->getattr == NULL)
3279c3e7ba3eSAlexander Motin 		return (UINT64_MAX);
3280c3e7ba3eSAlexander Motin 	return (lun->getattr(lun, attrname));
3281c3e7ba3eSAlexander Motin }
3282c3e7ba3eSAlexander Motin 
32830c629e28SAlexander Motin static int
3284130f4520SKenneth D. Merry ctl_be_block_init(void)
3285130f4520SKenneth D. Merry {
32860c629e28SAlexander Motin 	struct ctl_be_block_softc *softc = &backend_block_softc;
3287130f4520SKenneth D. Merry 
328834144c2cSAlexander Motin 	sx_init(&softc->modify_lock, "ctlblock modify");
328975c7a1d3SAlexander Motin 	mtx_init(&softc->lock, "ctlblock", NULL, MTX_DEF);
32900c629e28SAlexander Motin 	softc->beio_zone = uma_zcreate("beio", sizeof(struct ctl_be_block_io),
3291a0e36aeeSEdward Tomasz Napierala 	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
3292cd853791SKonstantin Belousov 	softc->bufmin_zone = uma_zcreate("ctlblockmin", CTLBLK_MIN_SEG,
32930d7fed74SAlexander Motin 	    NULL, NULL, NULL, NULL, /*align*/ 0, /*flags*/0);
3294cd853791SKonstantin Belousov 	if (CTLBLK_MIN_SEG < CTLBLK_MAX_SEG)
3295cd853791SKonstantin Belousov 		softc->bufmax_zone = uma_zcreate("ctlblockmax", CTLBLK_MAX_SEG,
32968054320eSAlexander Motin 		    NULL, NULL, NULL, NULL, /*align*/ 0, /*flags*/0);
329734144c2cSAlexander Motin 	SLIST_INIT(&softc->lun_list);
32980c629e28SAlexander Motin 	return (0);
32990c629e28SAlexander Motin }
3300130f4520SKenneth D. Merry 
33010c629e28SAlexander Motin static int
33020c629e28SAlexander Motin ctl_be_block_shutdown(void)
33030c629e28SAlexander Motin {
33040c629e28SAlexander Motin 	struct ctl_be_block_softc *softc = &backend_block_softc;
330534144c2cSAlexander Motin 	struct ctl_be_block_lun *lun;
33060c629e28SAlexander Motin 
33070c629e28SAlexander Motin 	mtx_lock(&softc->lock);
330834144c2cSAlexander Motin 	while ((lun = SLIST_FIRST(&softc->lun_list)) != NULL) {
330934144c2cSAlexander Motin 		SLIST_REMOVE_HEAD(&softc->lun_list, links);
331034144c2cSAlexander Motin 		softc->num_luns--;
33110c629e28SAlexander Motin 		/*
331234144c2cSAlexander Motin 		 * Drop our lock here.  Since ctl_remove_lun() can call
33130c629e28SAlexander Motin 		 * back into us, this could potentially lead to a recursive
33140c629e28SAlexander Motin 		 * lock of the same mutex, which would cause a hang.
33150c629e28SAlexander Motin 		 */
33160c629e28SAlexander Motin 		mtx_unlock(&softc->lock);
331734144c2cSAlexander Motin 		ctl_remove_lun(&lun->cbe_lun);
33180c629e28SAlexander Motin 		mtx_lock(&softc->lock);
33190c629e28SAlexander Motin 	}
33200c629e28SAlexander Motin 	mtx_unlock(&softc->lock);
3321cd853791SKonstantin Belousov 	uma_zdestroy(softc->bufmin_zone);
3322cd853791SKonstantin Belousov 	if (CTLBLK_MIN_SEG < CTLBLK_MAX_SEG)
3323cd853791SKonstantin Belousov 		uma_zdestroy(softc->bufmax_zone);
33240c629e28SAlexander Motin 	uma_zdestroy(softc->beio_zone);
33250c629e28SAlexander Motin 	mtx_destroy(&softc->lock);
332634144c2cSAlexander Motin 	sx_destroy(&softc->modify_lock);
33270c629e28SAlexander Motin 	return (0);
3328130f4520SKenneth D. Merry }
3329