1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/conf.h>
27 #include <sys/file.h>
28 #include <sys/ddi.h>
29 #include <sys/sunddi.h>
30 #include <sys/modctl.h>
31 #include <sys/scsi/scsi.h>
32 #include <sys/scsi/impl/scsi_reset_notify.h>
33 #include <sys/disp.h>
34 #include <sys/byteorder.h>
35 #include <sys/pathname.h>
36 #include <sys/atomic.h>
37 #include <sys/nvpair.h>
38 #include <sys/fs/zfs.h>
39 #include <sys/sdt.h>
40 #include <sys/dkio.h>
41 #include <sys/zfs_ioctl.h>
42 
43 #include <stmf.h>
44 #include <lpif.h>
45 #include <stmf_ioctl.h>
46 #include <stmf_sbd.h>
47 #include <sbd_impl.h>
48 #include <stmf_sbd_ioctl.h>
49 
50 #define	SBD_IS_ZVOL(zvol)	(strncmp("/dev/zvol", zvol, 9))
51 
52 extern sbd_status_t sbd_pgr_meta_init(sbd_lu_t *sl);
53 extern sbd_status_t sbd_pgr_meta_load(sbd_lu_t *sl);
54 
55 static int sbd_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
56     void **result);
57 static int sbd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
58 static int sbd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
59 static int sbd_open(dev_t *devp, int flag, int otype, cred_t *credp);
60 static int sbd_close(dev_t dev, int flag, int otype, cred_t *credp);
61 static int stmf_sbd_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
62     cred_t *credp, int *rval);
63 void sbd_lp_cb(stmf_lu_provider_t *lp, int cmd, void *arg, uint32_t flags);
64 int sbd_create_register_lu(sbd_create_and_reg_lu_t *slu, int struct_sz,
65     uint32_t *err_ret);
66 int sbd_import_lu(sbd_import_lu_t *ilu, int struct_sz, uint32_t *err_ret,
67     int no_register, sbd_lu_t **slr);
68 int sbd_delete_lu(sbd_delete_lu_t *dlu, int struct_sz, uint32_t *err_ret);
69 int sbd_modify_lu(sbd_modify_lu_t *mlu, int struct_sz, uint32_t *err_ret);
70 int sbd_get_lu_props(sbd_lu_props_t *islp, uint32_t islp_sz,
71     sbd_lu_props_t *oslp, uint32_t oslp_sz, uint32_t *err_ret);
72 char *sbd_get_zvol_name(sbd_lu_t *sl);
73 sbd_status_t sbd_create_zfs_meta_object(sbd_lu_t *sl);
74 sbd_status_t sbd_open_zfs_meta(sbd_lu_t *sl);
75 sbd_status_t sbd_read_zfs_meta(sbd_lu_t *sl, uint8_t *buf, uint64_t sz,
76     uint64_t off);
77 sbd_status_t sbd_write_zfs_meta(sbd_lu_t *sl, uint8_t *buf, uint64_t sz,
78     uint64_t off);
79 int sbd_is_zvol(char *path);
80 int sbd_zvolget(char *zvol_name, char **comstarprop);
81 int sbd_zvolset(char *zvol_name, char *comstarprop);
82 char sbd_ctoi(char c);
83 
84 static ldi_ident_t	sbd_zfs_ident;
85 static stmf_lu_provider_t *sbd_lp;
86 static sbd_lu_t		*sbd_lu_list = NULL;
87 static kmutex_t		sbd_lock;
88 static dev_info_t	*sbd_dip;
89 static uint32_t		sbd_lu_count = 0;
90 char sbd_vendor_id[]	= "SUN     ";
91 char sbd_product_id[]	= "COMSTAR         ";
92 char sbd_revision[]	= "1.0 ";
93 static char sbd_name[] = "sbd";
94 
95 static struct cb_ops sbd_cb_ops = {
96 	sbd_open,			/* open */
97 	sbd_close,			/* close */
98 	nodev,				/* strategy */
99 	nodev,				/* print */
100 	nodev,				/* dump */
101 	nodev,				/* read */
102 	nodev,				/* write */
103 	stmf_sbd_ioctl,			/* ioctl */
104 	nodev,				/* devmap */
105 	nodev,				/* mmap */
106 	nodev,				/* segmap */
107 	nochpoll,			/* chpoll */
108 	ddi_prop_op,			/* cb_prop_op */
109 	0,				/* streamtab */
110 	D_NEW | D_MP,			/* cb_flag */
111 	CB_REV,				/* rev */
112 	nodev,				/* aread */
113 	nodev				/* awrite */
114 };
115 
116 static struct dev_ops sbd_ops = {
117 	DEVO_REV,
118 	0,
119 	sbd_getinfo,
120 	nulldev,		/* identify */
121 	nulldev,		/* probe */
122 	sbd_attach,
123 	sbd_detach,
124 	nodev,			/* reset */
125 	&sbd_cb_ops,
126 	NULL,			/* bus_ops */
127 	NULL			/* power */
128 };
129 
130 #define	SBD_NAME	"COMSTAR SBD"
131 
132 static struct modldrv modldrv = {
133 	&mod_driverops,
134 	SBD_NAME,
135 	&sbd_ops
136 };
137 
138 static struct modlinkage modlinkage = {
139 	MODREV_1,
140 	&modldrv,
141 	NULL
142 };
143 
144 int
145 _init(void)
146 {
147 	int ret;
148 
149 	ret = mod_install(&modlinkage);
150 	if (ret)
151 		return (ret);
152 	sbd_lp = (stmf_lu_provider_t *)stmf_alloc(STMF_STRUCT_LU_PROVIDER,
153 	    0, 0);
154 	sbd_lp->lp_lpif_rev = LPIF_REV_1;
155 	sbd_lp->lp_instance = 0;
156 	sbd_lp->lp_name = sbd_name;
157 	sbd_lp->lp_cb = sbd_lp_cb;
158 	sbd_zfs_ident = ldi_ident_from_anon();
159 
160 	if (stmf_register_lu_provider(sbd_lp) != STMF_SUCCESS) {
161 		(void) mod_remove(&modlinkage);
162 		stmf_free(sbd_lp);
163 		return (EINVAL);
164 	}
165 	mutex_init(&sbd_lock, NULL, MUTEX_DRIVER, NULL);
166 	return (0);
167 }
168 
169 int
170 _fini(void)
171 {
172 	int ret;
173 
174 	/*
175 	 * If we have registered lus, then make sure they are all offline
176 	 * if so then deregister them. This should drop the sbd_lu_count
177 	 * to zero.
178 	 */
179 	if (sbd_lu_count) {
180 		sbd_lu_t *slu;
181 
182 		/* See if all of them are offline */
183 		mutex_enter(&sbd_lock);
184 		for (slu = sbd_lu_list; slu != NULL; slu = slu->sl_next) {
185 			if ((slu->sl_state != STMF_STATE_OFFLINE) ||
186 			    slu->sl_state_not_acked) {
187 				mutex_exit(&sbd_lock);
188 				return (EBUSY);
189 			}
190 		}
191 		mutex_exit(&sbd_lock);
192 
193 #if 0
194 		/* ok start deregistering them */
195 		while (sbd_lu_list) {
196 			sbd_store_t *sst = sbd_lu_list->sl_sst;
197 			if (sst->sst_deregister_lu(sst) != STMF_SUCCESS)
198 				return (EBUSY);
199 		}
200 #endif
201 		return (EBUSY);
202 	}
203 	if (stmf_deregister_lu_provider(sbd_lp) != STMF_SUCCESS)
204 		return (EBUSY);
205 	ret = mod_remove(&modlinkage);
206 	if (ret != 0) {
207 		(void) stmf_register_lu_provider(sbd_lp);
208 		return (ret);
209 	}
210 	stmf_free(sbd_lp);
211 	mutex_destroy(&sbd_lock);
212 	ldi_ident_release(sbd_zfs_ident);
213 	return (0);
214 }
215 
216 int
217 _info(struct modinfo *modinfop)
218 {
219 	return (mod_info(&modlinkage, modinfop));
220 }
221 
222 /* ARGSUSED */
223 static int
224 sbd_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
225 {
226 	switch (cmd) {
227 	case DDI_INFO_DEVT2DEVINFO:
228 		*result = sbd_dip;
229 		break;
230 	case DDI_INFO_DEVT2INSTANCE:
231 		*result = (void *)(uintptr_t)ddi_get_instance(sbd_dip);
232 		break;
233 	default:
234 		return (DDI_FAILURE);
235 	}
236 
237 	return (DDI_SUCCESS);
238 }
239 
240 static int
241 sbd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
242 {
243 	switch (cmd) {
244 	case DDI_ATTACH:
245 		sbd_dip = dip;
246 
247 		if (ddi_create_minor_node(dip, "admin", S_IFCHR, 0,
248 		    DDI_NT_STMF_LP, 0) != DDI_SUCCESS) {
249 			break;
250 		}
251 		ddi_report_dev(dip);
252 		return (DDI_SUCCESS);
253 	}
254 
255 	return (DDI_FAILURE);
256 }
257 
258 static int
259 sbd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
260 {
261 	switch (cmd) {
262 	case DDI_DETACH:
263 		ddi_remove_minor_node(dip, 0);
264 		return (DDI_SUCCESS);
265 	}
266 
267 	return (DDI_FAILURE);
268 }
269 
270 /* ARGSUSED */
271 static int
272 sbd_open(dev_t *devp, int flag, int otype, cred_t *credp)
273 {
274 	if (otype != OTYP_CHR)
275 		return (EINVAL);
276 	return (0);
277 }
278 
279 /* ARGSUSED */
280 static int
281 sbd_close(dev_t dev, int flag, int otype, cred_t *credp)
282 {
283 	return (0);
284 }
285 
286 /* ARGSUSED */
287 static int
288 stmf_sbd_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
289 	cred_t *credp, int *rval)
290 {
291 	stmf_iocdata_t		*iocd;
292 	void			*ibuf	= NULL;
293 	void			*obuf	= NULL;
294 	sbd_lu_t		*nsl;
295 	int			i;
296 	int			ret;
297 
298 	if (drv_priv(credp) != 0) {
299 		return (EPERM);
300 	}
301 
302 	ret = stmf_copyin_iocdata(data, mode, &iocd, &ibuf, &obuf);
303 	if (ret)
304 		return (ret);
305 	iocd->stmf_error = 0;
306 
307 	switch (cmd) {
308 	case SBD_IOCTL_CREATE_AND_REGISTER_LU:
309 		if (iocd->stmf_ibuf_size <
310 		    (sizeof (sbd_create_and_reg_lu_t) - 8)) {
311 			ret = EFAULT;
312 			break;
313 		}
314 		if ((iocd->stmf_obuf_size == 0) ||
315 		    (iocd->stmf_obuf_size > iocd->stmf_ibuf_size)) {
316 			ret = EINVAL;
317 			break;
318 		}
319 		ret = sbd_create_register_lu((sbd_create_and_reg_lu_t *)
320 		    ibuf, iocd->stmf_ibuf_size, &iocd->stmf_error);
321 		bcopy(ibuf, obuf, iocd->stmf_obuf_size);
322 		break;
323 	case SBD_IOCTL_IMPORT_LU:
324 		if (iocd->stmf_ibuf_size <
325 		    (sizeof (sbd_import_lu_t) - 8)) {
326 			ret = EFAULT;
327 			break;
328 		}
329 		if ((iocd->stmf_obuf_size == 0) ||
330 		    (iocd->stmf_obuf_size > iocd->stmf_ibuf_size)) {
331 			ret = EINVAL;
332 			break;
333 		}
334 		ret = sbd_import_lu((sbd_import_lu_t *)ibuf,
335 		    iocd->stmf_ibuf_size, &iocd->stmf_error, 0, NULL);
336 		bcopy(ibuf, obuf, iocd->stmf_obuf_size);
337 		break;
338 	case SBD_IOCTL_DELETE_LU:
339 		if (iocd->stmf_ibuf_size < (sizeof (sbd_delete_lu_t) - 8)) {
340 			ret = EFAULT;
341 			break;
342 		}
343 		if (iocd->stmf_obuf_size) {
344 			ret = EINVAL;
345 			break;
346 		}
347 		ret = sbd_delete_lu((sbd_delete_lu_t *)ibuf,
348 		    iocd->stmf_ibuf_size, &iocd->stmf_error);
349 		break;
350 	case SBD_IOCTL_MODIFY_LU:
351 		if (iocd->stmf_ibuf_size < (sizeof (sbd_modify_lu_t) - 8)) {
352 			ret = EFAULT;
353 			break;
354 		}
355 		if (iocd->stmf_obuf_size) {
356 			ret = EINVAL;
357 			break;
358 		}
359 		ret = sbd_modify_lu((sbd_modify_lu_t *)ibuf,
360 		    iocd->stmf_ibuf_size, &iocd->stmf_error);
361 		break;
362 	case SBD_IOCTL_GET_LU_PROPS:
363 		if (iocd->stmf_ibuf_size < (sizeof (sbd_lu_props_t) - 8)) {
364 			ret = EFAULT;
365 			break;
366 		}
367 		if (iocd->stmf_obuf_size < sizeof (sbd_lu_props_t)) {
368 			ret = EINVAL;
369 			break;
370 		}
371 		ret = sbd_get_lu_props((sbd_lu_props_t *)ibuf,
372 		    iocd->stmf_ibuf_size, (sbd_lu_props_t *)obuf,
373 		    iocd->stmf_obuf_size, &iocd->stmf_error);
374 		break;
375 	case SBD_IOCTL_GET_LU_LIST:
376 		mutex_enter(&sbd_lock);
377 		iocd->stmf_obuf_max_nentries = sbd_lu_count;
378 		iocd->stmf_obuf_nentries = min((iocd->stmf_obuf_size >> 4),
379 		    sbd_lu_count);
380 		for (nsl = sbd_lu_list, i = 0; nsl &&
381 		    (i < iocd->stmf_obuf_nentries); i++, nsl = nsl->sl_next) {
382 			bcopy(nsl->sl_device_id + 4,
383 			    &(((uint8_t *)obuf)[i << 4]), 16);
384 		}
385 		mutex_exit(&sbd_lock);
386 		ret = 0;
387 		iocd->stmf_error = 0;
388 		break;
389 	default:
390 		ret = ENOTTY;
391 	}
392 
393 	if (ret == 0) {
394 		ret = stmf_copyout_iocdata(data, mode, iocd, obuf);
395 	} else if (iocd->stmf_error) {
396 		(void) stmf_copyout_iocdata(data, mode, iocd, obuf);
397 	}
398 	if (obuf) {
399 		kmem_free(obuf, iocd->stmf_obuf_size);
400 		obuf = NULL;
401 	}
402 	if (ibuf) {
403 		kmem_free(ibuf, iocd->stmf_ibuf_size);
404 		ibuf = NULL;
405 	}
406 	kmem_free(iocd, sizeof (stmf_iocdata_t));
407 	return (ret);
408 }
409 
410 /* ARGSUSED */
411 void
412 sbd_lp_cb(stmf_lu_provider_t *lp, int cmd, void *arg, uint32_t flags)
413 {
414 	nvpair_t	*np;
415 	char		*s;
416 	sbd_import_lu_t *ilu;
417 	uint32_t	ilu_sz;
418 	uint32_t	struct_sz;
419 	uint32_t	err_ret;
420 	int		iret;
421 
422 	if ((cmd != STMF_PROVIDER_DATA_UPDATED) || (arg == NULL)) {
423 		return;
424 	}
425 
426 	if ((flags & (STMF_PCB_STMF_ONLINING | STMF_PCB_PREG_COMPLETE)) == 0) {
427 		return;
428 	}
429 
430 	np = NULL;
431 	ilu_sz = 1024;
432 	ilu = (sbd_import_lu_t *)kmem_zalloc(ilu_sz, KM_SLEEP);
433 	while ((np = nvlist_next_nvpair((nvlist_t *)arg, np)) != NULL) {
434 		if (nvpair_type(np) != DATA_TYPE_STRING) {
435 			continue;
436 		}
437 		if (nvpair_value_string(np, &s) != 0) {
438 			continue;
439 		}
440 		struct_sz = max(8, strlen(s) + 1);
441 		struct_sz += sizeof (sbd_import_lu_t) - 8;
442 		if (struct_sz > ilu_sz) {
443 			kmem_free(ilu, ilu_sz);
444 			ilu_sz = struct_sz + 32;
445 			ilu = (sbd_import_lu_t *)kmem_zalloc(ilu_sz, KM_SLEEP);
446 		}
447 		ilu->ilu_struct_size = struct_sz;
448 		(void) strcpy(ilu->ilu_meta_fname, s);
449 		iret = sbd_import_lu(ilu, struct_sz, &err_ret, 0, NULL);
450 		if (iret) {
451 			stmf_trace(0, "sbd_lp_cb: import_lu failed, ret = %d, "
452 			    "err_ret = %d", iret, err_ret);
453 		} else {
454 			stmf_trace(0, "Imported the LU %s", nvpair_name(np));
455 		}
456 	}
457 
458 	if (ilu) {
459 		kmem_free(ilu, ilu_sz);
460 		ilu = NULL;
461 	}
462 }
463 
464 sbd_status_t
465 sbd_link_lu(sbd_lu_t *sl)
466 {
467 	sbd_lu_t *nsl;
468 
469 	mutex_enter(&sbd_lock);
470 	mutex_enter(&sl->sl_lock);
471 	ASSERT(sl->sl_trans_op != SL_OP_NONE);
472 
473 	if (sl->sl_flags & SL_LINKED) {
474 		mutex_exit(&sbd_lock);
475 		mutex_exit(&sl->sl_lock);
476 		return (SBD_ALREADY);
477 	}
478 	for (nsl = sbd_lu_list; nsl; nsl = nsl->sl_next) {
479 		if (strcmp(nsl->sl_name, sl->sl_name) == 0)
480 			break;
481 	}
482 	if (nsl) {
483 		mutex_exit(&sbd_lock);
484 		mutex_exit(&sl->sl_lock);
485 		return (SBD_ALREADY);
486 	}
487 	sl->sl_next = sbd_lu_list;
488 	sbd_lu_list = sl;
489 	sl->sl_flags |= SL_LINKED;
490 	mutex_exit(&sbd_lock);
491 	mutex_exit(&sl->sl_lock);
492 	return (SBD_SUCCESS);
493 }
494 
495 void
496 sbd_unlink_lu(sbd_lu_t *sl)
497 {
498 	sbd_lu_t **ppnsl;
499 
500 	mutex_enter(&sbd_lock);
501 	mutex_enter(&sl->sl_lock);
502 	ASSERT(sl->sl_trans_op != SL_OP_NONE);
503 
504 	ASSERT(sl->sl_flags & SL_LINKED);
505 	for (ppnsl = &sbd_lu_list; *ppnsl; ppnsl = &((*ppnsl)->sl_next)) {
506 		if (*ppnsl == sl)
507 			break;
508 	}
509 	ASSERT(*ppnsl);
510 	*ppnsl = (*ppnsl)->sl_next;
511 	sl->sl_flags &= ~SL_LINKED;
512 	mutex_exit(&sbd_lock);
513 	mutex_exit(&sl->sl_lock);
514 }
515 
516 sbd_status_t
517 sbd_find_and_lock_lu(uint8_t *guid, uint8_t *meta_name, uint8_t op,
518     sbd_lu_t **ppsl)
519 {
520 	sbd_lu_t *sl;
521 	int found = 0;
522 	sbd_status_t sret;
523 
524 	mutex_enter(&sbd_lock);
525 	for (sl = sbd_lu_list; sl; sl = sl->sl_next) {
526 		if (guid) {
527 			found = bcmp(sl->sl_device_id + 4, guid, 16) == 0;
528 		} else {
529 			found = strcmp(sl->sl_name, (char *)meta_name) == 0;
530 		}
531 		if (found)
532 			break;
533 	}
534 	if (!found) {
535 		mutex_exit(&sbd_lock);
536 		return (SBD_NOT_FOUND);
537 	}
538 	mutex_enter(&sl->sl_lock);
539 	if (sl->sl_trans_op == SL_OP_NONE) {
540 		sl->sl_trans_op = op;
541 		*ppsl = sl;
542 		sret = SBD_SUCCESS;
543 	} else {
544 		sret = SBD_BUSY;
545 	}
546 	mutex_exit(&sl->sl_lock);
547 	mutex_exit(&sbd_lock);
548 	return (sret);
549 }
550 
551 sbd_status_t
552 sbd_read_meta(sbd_lu_t *sl, uint64_t offset, uint64_t size, uint8_t *buf)
553 {
554 	uint64_t	meta_align;
555 	uint64_t	starting_off;
556 	uint64_t	data_off;
557 	uint64_t	ending_off;
558 	uint64_t	io_size;
559 	uint8_t		*io_buf;
560 	vnode_t		*vp;
561 	sbd_status_t	ret;
562 	ssize_t		resid;
563 	int		vret;
564 
565 	ASSERT(sl->sl_flags & SL_META_OPENED);
566 	if (sl->sl_flags & SL_SHARED_META) {
567 		meta_align = (((uint64_t)1) << sl->sl_data_blocksize_shift) - 1;
568 		vp = sl->sl_data_vp;
569 		ASSERT(vp);
570 	} else {
571 		meta_align = (((uint64_t)1) << sl->sl_meta_blocksize_shift) - 1;
572 		if ((sl->sl_flags & SL_ZFS_META) == 0) {
573 			vp = sl->sl_meta_vp;
574 			ASSERT(vp);
575 		}
576 	}
577 	starting_off = offset & ~(meta_align);
578 	data_off = offset & meta_align;
579 	ending_off = (offset + size + meta_align) & (~meta_align);
580 	if (ending_off > sl->sl_meta_size_used) {
581 		bzero(buf, size);
582 		if (starting_off >= sl->sl_meta_size_used) {
583 			return (SBD_SUCCESS);
584 		}
585 		ending_off = (sl->sl_meta_size_used + meta_align) &
586 		    (~meta_align);
587 		if (size > (ending_off - (starting_off + data_off))) {
588 			size = ending_off - (starting_off + data_off);
589 		}
590 	}
591 	io_size = ending_off - starting_off;
592 	io_buf = (uint8_t *)kmem_zalloc(io_size, KM_SLEEP);
593 	ASSERT((starting_off + io_size) <= sl->sl_total_meta_size);
594 
595 	if (sl->sl_flags & SL_ZFS_META) {
596 		if ((ret = sbd_read_zfs_meta(sl, io_buf, io_size,
597 		    starting_off)) != SBD_SUCCESS) {
598 			goto sbd_read_meta_failure;
599 		}
600 	} else {
601 		vret = vn_rdwr(UIO_READ, vp, (caddr_t)io_buf, (ssize_t)io_size,
602 		    (offset_t)starting_off, UIO_SYSSPACE, FRSYNC,
603 		    RLIM64_INFINITY, CRED(), &resid);
604 
605 		if (vret || resid) {
606 			ret = SBD_FILEIO_FAILURE | vret;
607 			goto sbd_read_meta_failure;
608 		}
609 	}
610 
611 	bcopy(io_buf + data_off, buf, size);
612 	ret = SBD_SUCCESS;
613 
614 sbd_read_meta_failure:
615 	kmem_free(io_buf, io_size);
616 	return (ret);
617 }
618 
619 sbd_status_t
620 sbd_write_meta(sbd_lu_t *sl, uint64_t offset, uint64_t size, uint8_t *buf)
621 {
622 	uint64_t	meta_align;
623 	uint64_t	starting_off;
624 	uint64_t	data_off;
625 	uint64_t	ending_off;
626 	uint64_t	io_size;
627 	uint8_t		*io_buf;
628 	vnode_t		*vp;
629 	sbd_status_t	ret;
630 	ssize_t		resid;
631 	int		vret;
632 
633 	ASSERT(sl->sl_flags & SL_META_OPENED);
634 	if (sl->sl_flags & SL_SHARED_META) {
635 		meta_align = (((uint64_t)1) << sl->sl_data_blocksize_shift) - 1;
636 		vp = sl->sl_data_vp;
637 		ASSERT(vp);
638 	} else {
639 		meta_align = (((uint64_t)1) << sl->sl_meta_blocksize_shift) - 1;
640 		if ((sl->sl_flags & SL_ZFS_META) == 0) {
641 			vp = sl->sl_meta_vp;
642 			ASSERT(vp);
643 		}
644 	}
645 	starting_off = offset & ~(meta_align);
646 	data_off = offset & meta_align;
647 	ending_off = (offset + size + meta_align) & (~meta_align);
648 	io_size = ending_off - starting_off;
649 	io_buf = (uint8_t *)kmem_zalloc(io_size, KM_SLEEP);
650 	ret = sbd_read_meta(sl, starting_off, io_size, io_buf);
651 	if (ret != SBD_SUCCESS) {
652 		goto sbd_write_meta_failure;
653 	}
654 	bcopy(buf, io_buf + data_off, size);
655 	if (sl->sl_flags & SL_ZFS_META) {
656 		if ((ret = sbd_write_zfs_meta(sl, io_buf, io_size,
657 		    starting_off)) != SBD_SUCCESS) {
658 			goto sbd_write_meta_failure;
659 		}
660 	} else {
661 		vret = vn_rdwr(UIO_WRITE, vp, (caddr_t)io_buf, (ssize_t)io_size,
662 		    (offset_t)starting_off, UIO_SYSSPACE, FDSYNC,
663 		    RLIM64_INFINITY, CRED(), &resid);
664 
665 		if (vret || resid) {
666 			ret = SBD_FILEIO_FAILURE | vret;
667 			goto sbd_write_meta_failure;
668 		}
669 	}
670 
671 	ret = SBD_SUCCESS;
672 
673 sbd_write_meta_failure:
674 	kmem_free(io_buf, io_size);
675 	return (ret);
676 }
677 
678 uint8_t
679 sbd_calc_sum(uint8_t *buf, int size)
680 {
681 	uint8_t s = 0;
682 
683 	while (size > 0)
684 		s += buf[--size];
685 
686 	return (s);
687 }
688 
689 uint8_t
690 sbd_calc_section_sum(sm_section_hdr_t *sm, uint32_t sz)
691 {
692 	uint8_t s, o;
693 
694 	o = sm->sms_chksum;
695 	sm->sms_chksum = 0;
696 	s = sbd_calc_sum((uint8_t *)sm, sz);
697 	sm->sms_chksum = o;
698 
699 	return (s);
700 }
701 
702 uint32_t
703 sbd_strlen(char *str, uint32_t maxlen)
704 {
705 	uint32_t i;
706 
707 	for (i = 0; i < maxlen; i++) {
708 		if (str[i] == 0)
709 			return (i);
710 	}
711 	return (i);
712 }
713 
714 void
715 sbd_swap_meta_start(sbd_meta_start_t *sm)
716 {
717 	if (sm->sm_magic == SBD_MAGIC)
718 		return;
719 	sm->sm_magic		= BSWAP_64(sm->sm_magic);
720 	sm->sm_meta_size	= BSWAP_64(sm->sm_meta_size);
721 	sm->sm_meta_size_used	= BSWAP_64(sm->sm_meta_size_used);
722 	sm->sm_ver_major	= BSWAP_16(sm->sm_ver_major);
723 	sm->sm_ver_minor	= BSWAP_16(sm->sm_ver_minor);
724 	sm->sm_ver_subminor	= BSWAP_16(sm->sm_ver_subminor);
725 }
726 
727 void
728 sbd_swap_section_hdr(sm_section_hdr_t *sm)
729 {
730 	if (sm->sms_data_order == SMS_DATA_ORDER)
731 		return;
732 	sm->sms_offset		= BSWAP_64(sm->sms_offset);
733 	sm->sms_size		= BSWAP_32(sm->sms_size);
734 	sm->sms_id		= BSWAP_16(sm->sms_id);
735 	sm->sms_chksum		+= SMS_DATA_ORDER - sm->sms_data_order;
736 	sm->sms_data_order	= SMS_DATA_ORDER;
737 }
738 
739 void
740 sbd_swap_lu_info_1_0(sbd_lu_info_1_0_t *sli)
741 {
742 	sbd_swap_section_hdr(&sli->sli_sms_header);
743 	if (sli->sli_data_order == SMS_DATA_ORDER)
744 		return;
745 	sli->sli_sms_header.sms_chksum	+= SMS_DATA_ORDER - sli->sli_data_order;
746 	sli->sli_data_order		= SMS_DATA_ORDER;
747 	sli->sli_total_store_size	= BSWAP_64(sli->sli_total_store_size);
748 	sli->sli_total_meta_size	= BSWAP_64(sli->sli_total_meta_size);
749 	sli->sli_lu_data_offset		= BSWAP_64(sli->sli_lu_data_offset);
750 	sli->sli_lu_data_size		= BSWAP_64(sli->sli_lu_data_size);
751 	sli->sli_flags			= BSWAP_32(sli->sli_flags);
752 	sli->sli_blocksize		= BSWAP_16(sli->sli_blocksize);
753 }
754 
755 void
756 sbd_swap_lu_info_1_1(sbd_lu_info_1_1_t *sli)
757 {
758 	sbd_swap_section_hdr(&sli->sli_sms_header);
759 	if (sli->sli_data_order == SMS_DATA_ORDER)
760 		return;
761 	sli->sli_sms_header.sms_chksum	+= SMS_DATA_ORDER - sli->sli_data_order;
762 	sli->sli_data_order		= SMS_DATA_ORDER;
763 	sli->sli_flags			= BSWAP_32(sli->sli_flags);
764 	sli->sli_lu_size		= BSWAP_64(sli->sli_lu_size);
765 	sli->sli_meta_fname_offset	= BSWAP_64(sli->sli_meta_fname_offset);
766 	sli->sli_data_fname_offset	= BSWAP_64(sli->sli_data_fname_offset);
767 	sli->sli_serial_offset		= BSWAP_64(sli->sli_serial_offset);
768 	sli->sli_alias_offset		= BSWAP_64(sli->sli_alias_offset);
769 }
770 
771 sbd_status_t
772 sbd_load_section_hdr(sbd_lu_t *sl, sm_section_hdr_t *sms)
773 {
774 	sm_section_hdr_t	h;
775 	uint64_t		st;
776 	sbd_status_t 		ret;
777 
778 	for (st = sl->sl_meta_offset + sizeof (sbd_meta_start_t);
779 	    st < sl->sl_meta_size_used; st += h.sms_size) {
780 		if ((ret = sbd_read_meta(sl, st, sizeof (sm_section_hdr_t),
781 		    (uint8_t *)&h)) != SBD_SUCCESS) {
782 			return (ret);
783 		}
784 		if (h.sms_data_order != SMS_DATA_ORDER) {
785 			sbd_swap_section_hdr(&h);
786 		}
787 		if ((h.sms_data_order != SMS_DATA_ORDER) ||
788 		    (h.sms_offset != st) || (h.sms_size < sizeof (h)) ||
789 		    ((st + h.sms_size) > sl->sl_meta_size_used)) {
790 			return (SBD_META_CORRUPTED);
791 		}
792 		if (h.sms_id == sms->sms_id) {
793 			bcopy(&h, sms, sizeof (h));
794 			return (SBD_SUCCESS);
795 		}
796 	}
797 
798 	return (SBD_NOT_FOUND);
799 }
800 
801 sbd_status_t
802 sbd_load_meta_start(sbd_lu_t *sl)
803 {
804 	sbd_meta_start_t *sm;
805 	sbd_status_t ret;
806 
807 	/* Fake meta params initially */
808 	sl->sl_total_meta_size = (uint64_t)-1;
809 	sl->sl_meta_size_used = sl->sl_meta_offset + sizeof (sbd_meta_start_t);
810 
811 	sm = kmem_zalloc(sizeof (*sm), KM_SLEEP);
812 	ret = sbd_read_meta(sl, sl->sl_meta_offset, sizeof (*sm),
813 	    (uint8_t *)sm);
814 	if (ret != SBD_SUCCESS) {
815 		goto load_meta_start_failed;
816 	}
817 
818 	if (sm->sm_magic != SBD_MAGIC) {
819 		sbd_swap_meta_start(sm);
820 	}
821 
822 	if ((sm->sm_magic != SBD_MAGIC) || (sbd_calc_sum((uint8_t *)sm,
823 	    sizeof (*sm) - 1) != sm->sm_chksum)) {
824 		ret = SBD_META_CORRUPTED;
825 		goto load_meta_start_failed;
826 	}
827 
828 	if (sm->sm_ver_major != SBD_VER_MAJOR) {
829 		ret = SBD_NOT_SUPPORTED;
830 		goto load_meta_start_failed;
831 	}
832 
833 	sl->sl_total_meta_size = sm->sm_meta_size;
834 	sl->sl_meta_size_used = sm->sm_meta_size_used;
835 	ret = SBD_SUCCESS;
836 
837 load_meta_start_failed:
838 	kmem_free(sm, sizeof (*sm));
839 	return (ret);
840 }
841 
842 sbd_status_t
843 sbd_write_meta_start(sbd_lu_t *sl, uint64_t meta_size, uint64_t meta_size_used)
844 {
845 	sbd_meta_start_t *sm;
846 	sbd_status_t ret;
847 
848 	sm = (sbd_meta_start_t *)kmem_zalloc(sizeof (sbd_meta_start_t),
849 	    KM_SLEEP);
850 
851 	sm->sm_magic = SBD_MAGIC;
852 	sm->sm_meta_size = meta_size;
853 	sm->sm_meta_size_used = meta_size_used;
854 	sm->sm_ver_major = SBD_VER_MAJOR;
855 	sm->sm_ver_minor = SBD_VER_MINOR;
856 	sm->sm_ver_subminor = SBD_VER_SUBMINOR;
857 	sm->sm_chksum = sbd_calc_sum((uint8_t *)sm, sizeof (*sm) - 1);
858 
859 	ret = sbd_write_meta(sl, sl->sl_meta_offset, sizeof (*sm),
860 	    (uint8_t *)sm);
861 	kmem_free(sm, sizeof (*sm));
862 
863 	return (ret);
864 }
865 
866 sbd_status_t
867 sbd_read_meta_section(sbd_lu_t *sl, sm_section_hdr_t **ppsms, uint16_t sms_id)
868 {
869 	sbd_status_t ret;
870 	sm_section_hdr_t sms;
871 	int alloced = 0;
872 
873 	mutex_enter(&sl->sl_metadata_lock);
874 	if (((*ppsms) == NULL) || ((*ppsms)->sms_offset == 0)) {
875 		bzero(&sms, sizeof (sm_section_hdr_t));
876 		sms.sms_id = sms_id;
877 		if ((ret = sbd_load_section_hdr(sl, &sms)) != SBD_SUCCESS) {
878 			mutex_exit(&sl->sl_metadata_lock);
879 			return (ret);
880 		} else {
881 			if ((*ppsms) == NULL) {
882 				*ppsms = (sm_section_hdr_t *)kmem_zalloc(
883 				    sms.sms_size, KM_SLEEP);
884 				alloced = 1;
885 			}
886 			bcopy(&sms, *ppsms, sizeof (sm_section_hdr_t));
887 		}
888 	}
889 
890 	ret = sbd_read_meta(sl, (*ppsms)->sms_offset, (*ppsms)->sms_size,
891 	    (uint8_t *)(*ppsms));
892 	if (ret == SBD_SUCCESS) {
893 		uint8_t s;
894 		if ((*ppsms)->sms_data_order != SMS_DATA_ORDER)
895 			sbd_swap_section_hdr(*ppsms);
896 		if ((*ppsms)->sms_id != SMS_ID_UNUSED) {
897 			s = sbd_calc_section_sum(*ppsms, (*ppsms)->sms_size);
898 			if (s != (*ppsms)->sms_chksum)
899 				ret = SBD_META_CORRUPTED;
900 		}
901 	}
902 	mutex_exit(&sl->sl_metadata_lock);
903 
904 	if ((ret != SBD_SUCCESS) && alloced)
905 		kmem_free(*ppsms, sms.sms_size);
906 	return (ret);
907 }
908 
909 sbd_status_t
910 sbd_load_section_hdr_unbuffered(sbd_lu_t *sl, sm_section_hdr_t *sms)
911 {
912 	sbd_status_t	ret;
913 
914 	/*
915 	 * Bypass buffering and re-read the meta data from permanent storage.
916 	 */
917 	if (sl->sl_flags & SL_ZFS_META) {
918 		if ((ret = sbd_open_zfs_meta(sl)) != SBD_SUCCESS) {
919 			return (ret);
920 		}
921 	}
922 	/* Re-get the meta sizes into sl */
923 	if ((ret = sbd_load_meta_start(sl)) != SBD_SUCCESS) {
924 		return (ret);
925 	}
926 	return (sbd_load_section_hdr(sl, sms));
927 }
928 
929 sbd_status_t
930 sbd_write_meta_section(sbd_lu_t *sl, sm_section_hdr_t *sms)
931 {
932 	sm_section_hdr_t t;
933 	uint64_t off, s;
934 	uint64_t unused_start;
935 	sbd_status_t ret;
936 	sbd_status_t write_meta_ret = SBD_SUCCESS;
937 	uint8_t *cb;
938 	int meta_size_changed = 0;
939 	sm_section_hdr_t sms_before_unused = {0};
940 
941 	mutex_enter(&sl->sl_metadata_lock);
942 write_meta_section_again:
943 	if (sms->sms_offset) {
944 		/*
945 		 * If the section already exists and the size is the
946 		 * same as this new data then overwrite in place. If
947 		 * the sizes are different then mark the existing as
948 		 * unused and look for free space.
949 		 */
950 		ret = sbd_read_meta(sl, sms->sms_offset, sizeof (t),
951 		    (uint8_t *)&t);
952 		if (ret != SBD_SUCCESS) {
953 			mutex_exit(&sl->sl_metadata_lock);
954 			return (ret);
955 		}
956 		if (t.sms_data_order != SMS_DATA_ORDER) {
957 			sbd_swap_section_hdr(&t);
958 		}
959 		if (t.sms_id != sms->sms_id) {
960 			mutex_exit(&sl->sl_metadata_lock);
961 			return (SBD_INVALID_ARG);
962 		}
963 		if (t.sms_size == sms->sms_size) {
964 			ret = sbd_write_meta(sl, sms->sms_offset,
965 			    sms->sms_size, (uint8_t *)sms);
966 			mutex_exit(&sl->sl_metadata_lock);
967 			return (ret);
968 		}
969 		sms_before_unused = t;
970 
971 		t.sms_id = SMS_ID_UNUSED;
972 		/*
973 		 * For unused sections we only use chksum of the header. for
974 		 * all other sections, the chksum is for the entire section.
975 		 */
976 		t.sms_chksum = sbd_calc_section_sum(&t, sizeof (t));
977 		ret = sbd_write_meta(sl, t.sms_offset, sizeof (t),
978 		    (uint8_t *)&t);
979 		if (ret != SBD_SUCCESS) {
980 			mutex_exit(&sl->sl_metadata_lock);
981 			return (ret);
982 		}
983 		sms->sms_offset = 0;
984 	} else {
985 		/* Section location is unknown, search for it. */
986 		t.sms_id = sms->sms_id;
987 		t.sms_data_order = SMS_DATA_ORDER;
988 		ret = sbd_load_section_hdr(sl, &t);
989 		if (ret == SBD_SUCCESS) {
990 			sms->sms_offset = t.sms_offset;
991 			sms->sms_chksum =
992 			    sbd_calc_section_sum(sms, sms->sms_size);
993 			goto write_meta_section_again;
994 		} else if (ret != SBD_NOT_FOUND) {
995 			mutex_exit(&sl->sl_metadata_lock);
996 			return (ret);
997 		}
998 	}
999 
1000 	/*
1001 	 * At this point we know that section does not already exist.
1002 	 * Find space large enough to hold the section or grow meta if
1003 	 * possible.
1004 	 */
1005 	unused_start = 0;
1006 	s = 0;	/* size of space found */
1007 
1008 	/*
1009 	 * Search all sections for unused space of sufficient size.
1010 	 * The first one found is taken. Contiguous unused sections
1011 	 * will be combined.
1012 	 */
1013 	for (off = sl->sl_meta_offset + sizeof (sbd_meta_start_t);
1014 	    off < sl->sl_meta_size_used; off += t.sms_size) {
1015 		ret = sbd_read_meta(sl, off, sizeof (t), (uint8_t *)&t);
1016 		if (ret != SBD_SUCCESS) {
1017 			mutex_exit(&sl->sl_metadata_lock);
1018 			return (ret);
1019 		}
1020 		if (t.sms_data_order != SMS_DATA_ORDER)
1021 			sbd_swap_section_hdr(&t);
1022 		if (t.sms_size == 0) {
1023 			mutex_exit(&sl->sl_metadata_lock);
1024 			return (SBD_META_CORRUPTED);
1025 		}
1026 		if (t.sms_id == SMS_ID_UNUSED) {
1027 			if (unused_start == 0)
1028 				unused_start = off;
1029 			/*
1030 			 * Calculate size of the unused space, break out
1031 			 * if it satisfies the requirement.
1032 			 */
1033 			s = t.sms_size - unused_start + off;
1034 			if ((s == sms->sms_size) || (s >= (sms->sms_size +
1035 			    sizeof (t)))) {
1036 				break;
1037 			} else {
1038 				s = 0;
1039 			}
1040 		} else {
1041 			unused_start = 0;
1042 		}
1043 	}
1044 
1045 	off = (unused_start == 0) ? sl->sl_meta_size_used : unused_start;
1046 	/*
1047 	 * If none found, how much room is at the end?
1048 	 * See if the data can be expanded.
1049 	 */
1050 	if (s == 0) {
1051 		s = sl->sl_total_meta_size - off;
1052 		if (s >= sms->sms_size || !(sl->sl_flags & SL_SHARED_META)) {
1053 			s = sms->sms_size;
1054 			meta_size_changed = 1;
1055 		} else {
1056 			s = 0;
1057 		}
1058 	}
1059 
1060 	if (s == 0) {
1061 		mutex_exit(&sl->sl_metadata_lock);
1062 		return (SBD_ALLOC_FAILURE);
1063 	}
1064 
1065 	sms->sms_offset = off;
1066 	sms->sms_chksum = sbd_calc_section_sum(sms, sms->sms_size);
1067 	/*
1068 	 * Since we may have to write more than one section (current +
1069 	 * any unused), use a combined buffer.
1070 	 */
1071 	cb = kmem_zalloc(s, KM_SLEEP);
1072 	bcopy(sms, cb, sms->sms_size);
1073 	if (s > sms->sms_size) {
1074 		t.sms_offset = off + sms->sms_size;
1075 		t.sms_size = s - sms->sms_size;
1076 		t.sms_id = SMS_ID_UNUSED;
1077 		t.sms_data_order = SMS_DATA_ORDER;
1078 		t.sms_chksum = sbd_calc_section_sum(&t, sizeof (t));
1079 		bcopy(&t, cb + sms->sms_size, sizeof (t));
1080 	}
1081 	/*
1082 	 * Two write events & statuses take place. Failure writing the
1083 	 * meta section takes precedence, can possibly be rolled back,
1084 	 * & gets reported. Else return status from writing the meta start.
1085 	 */
1086 	ret = SBD_SUCCESS; /* Set a default, it's not always loaded below. */
1087 	if (meta_size_changed) {
1088 		uint64_t old_meta_size;
1089 		uint64_t old_sz_used = sl->sl_meta_size_used; /* save a copy */
1090 		old_meta_size = sl->sl_total_meta_size; /* save a copy */
1091 
1092 		write_meta_ret = sbd_write_meta(sl, off, s, cb);
1093 		if (write_meta_ret == SBD_SUCCESS) {
1094 			sl->sl_meta_size_used = off + s;
1095 			if (sl->sl_total_meta_size < sl->sl_meta_size_used) {
1096 				uint64_t meta_align =
1097 				    (((uint64_t)1) <<
1098 				    sl->sl_meta_blocksize_shift) - 1;
1099 				sl->sl_total_meta_size =
1100 				    (sl->sl_meta_size_used + meta_align) &
1101 				    (~meta_align);
1102 			}
1103 			ret = sbd_write_meta_start(sl, sl->sl_total_meta_size,
1104 			    sl->sl_meta_size_used);
1105 			if (ret != SBD_SUCCESS) {
1106 				sl->sl_meta_size_used = old_sz_used;
1107 				sl->sl_total_meta_size = old_meta_size;
1108 			}
1109 		} else {
1110 			sl->sl_meta_size_used = old_sz_used;
1111 			sl->sl_total_meta_size = old_meta_size;
1112 		}
1113 	} else {
1114 		write_meta_ret = sbd_write_meta(sl, off, s, cb);
1115 	}
1116 	if ((write_meta_ret != SBD_SUCCESS) &&
1117 	    (sms_before_unused.sms_offset != 0)) {
1118 		sm_section_hdr_t new_sms;
1119 		sm_section_hdr_t *unused_sms;
1120 		/*
1121 		 * On failure writing the meta section attempt to undo
1122 		 * the change to unused.
1123 		 * Re-read the meta data from permanent storage.
1124 		 * The section id can't exist for undo to be possible.
1125 		 * Read what should be the entire old section data and
1126 		 * insure the old data's still present by validating
1127 		 * against it's old checksum.
1128 		 */
1129 		new_sms.sms_id = sms->sms_id;
1130 		new_sms.sms_data_order = SMS_DATA_ORDER;
1131 		if (sbd_load_section_hdr_unbuffered(sl, &new_sms) !=
1132 		    SBD_NOT_FOUND) {
1133 			goto done;
1134 		}
1135 		unused_sms = kmem_zalloc(sms_before_unused.sms_size, KM_SLEEP);
1136 		if (sbd_read_meta(sl, sms_before_unused.sms_offset,
1137 		    sms_before_unused.sms_size,
1138 		    (uint8_t *)unused_sms) != SBD_SUCCESS) {
1139 			goto done;
1140 		}
1141 		if (unused_sms->sms_data_order != SMS_DATA_ORDER) {
1142 			sbd_swap_section_hdr(unused_sms);
1143 		}
1144 		if (unused_sms->sms_id != SMS_ID_UNUSED) {
1145 			goto done;
1146 		}
1147 		if (unused_sms->sms_offset != sms_before_unused.sms_offset) {
1148 			goto done;
1149 		}
1150 		if (unused_sms->sms_size != sms_before_unused.sms_size) {
1151 			goto done;
1152 		}
1153 		unused_sms->sms_id = sms_before_unused.sms_id;
1154 		if (sbd_calc_section_sum(unused_sms,
1155 		    sizeof (sm_section_hdr_t)) !=
1156 		    sbd_calc_section_sum(&sms_before_unused,
1157 		    sizeof (sm_section_hdr_t))) {
1158 			goto done;
1159 		}
1160 		unused_sms->sms_chksum =
1161 		    sbd_calc_section_sum(unused_sms, unused_sms->sms_size);
1162 		if (unused_sms->sms_chksum != sms_before_unused.sms_chksum) {
1163 			goto done;
1164 		}
1165 		(void) sbd_write_meta(sl, unused_sms->sms_offset,
1166 		    sizeof (sm_section_hdr_t), (uint8_t *)unused_sms);
1167 	}
1168 done:
1169 	mutex_exit(&sl->sl_metadata_lock);
1170 	kmem_free(cb, s);
1171 	if (write_meta_ret != SBD_SUCCESS) {
1172 		return (write_meta_ret);
1173 	}
1174 	return (ret);
1175 }
1176 
1177 sbd_status_t
1178 sbd_write_lu_info(sbd_lu_t *sl)
1179 {
1180 	sbd_lu_info_1_1_t *sli;
1181 	int s;
1182 	uint8_t *p;
1183 	char *zvol_name = NULL;
1184 	sbd_status_t ret;
1185 
1186 	mutex_enter(&sl->sl_lock);
1187 
1188 	s = sl->sl_serial_no_size;
1189 	if ((sl->sl_flags & (SL_SHARED_META | SL_ZFS_META)) == 0) {
1190 		if (sl->sl_data_filename) {
1191 			s += strlen(sl->sl_data_filename) + 1;
1192 		}
1193 	}
1194 	if (sl->sl_flags & SL_ZFS_META) {
1195 		zvol_name = sbd_get_zvol_name(sl);
1196 		s += strlen(zvol_name) + 1;
1197 	}
1198 	if (sl->sl_alias) {
1199 		s += strlen(sl->sl_alias) + 1;
1200 	}
1201 	if (sl->sl_mgmt_url) {
1202 		s += strlen(sl->sl_mgmt_url) + 1;
1203 	}
1204 	sli = (sbd_lu_info_1_1_t *)kmem_zalloc(sizeof (*sli) + s, KM_SLEEP);
1205 	p = sli->sli_buf;
1206 	if ((sl->sl_flags & (SL_SHARED_META | SL_ZFS_META)) == 0) {
1207 		sli->sli_flags |= SLI_SEPARATE_META;
1208 		(void) strcpy((char *)p, sl->sl_data_filename);
1209 		sli->sli_data_fname_offset =
1210 		    (uintptr_t)p - (uintptr_t)sli->sli_buf;
1211 		sli->sli_flags |= SLI_DATA_FNAME_VALID;
1212 		p += strlen(sl->sl_data_filename) + 1;
1213 	}
1214 	if (sl->sl_flags & SL_ZFS_META) {
1215 		(void) strcpy((char *)p, zvol_name);
1216 		sli->sli_meta_fname_offset =
1217 		    (uintptr_t)p - (uintptr_t)sli->sli_buf;
1218 		sli->sli_flags |= SLI_META_FNAME_VALID | SLI_ZFS_META;
1219 		p += strlen(zvol_name) + 1;
1220 		kmem_free(zvol_name, strlen(zvol_name) + 1);
1221 		zvol_name = NULL;
1222 	}
1223 	if (sl->sl_alias) {
1224 		(void) strcpy((char *)p, sl->sl_alias);
1225 		sli->sli_alias_offset =
1226 		    (uintptr_t)p - (uintptr_t)sli->sli_buf;
1227 		sli->sli_flags |= SLI_ALIAS_VALID;
1228 		p += strlen(sl->sl_alias) + 1;
1229 	}
1230 	if (sl->sl_mgmt_url) {
1231 		(void) strcpy((char *)p, sl->sl_mgmt_url);
1232 		sli->sli_mgmt_url_offset =
1233 		    (uintptr_t)p - (uintptr_t)sli->sli_buf;
1234 		sli->sli_flags |= SLI_MGMT_URL_VALID;
1235 		p += strlen(sl->sl_mgmt_url) + 1;
1236 	}
1237 	if (sl->sl_flags & SL_WRITE_PROTECTED) {
1238 		sli->sli_flags |= SLI_WRITE_PROTECTED;
1239 	}
1240 	if (sl->sl_flags & SL_SAVED_WRITE_CACHE_DISABLE) {
1241 		sli->sli_flags |= SLI_WRITEBACK_CACHE_DISABLE;
1242 	}
1243 	if (sl->sl_flags & SL_VID_VALID) {
1244 		bcopy(sl->sl_vendor_id, sli->sli_vid, 8);
1245 		sli->sli_flags |= SLI_VID_VALID;
1246 	}
1247 	if (sl->sl_flags & SL_PID_VALID) {
1248 		bcopy(sl->sl_product_id, sli->sli_pid, 16);
1249 		sli->sli_flags |= SLI_PID_VALID;
1250 	}
1251 	if (sl->sl_flags & SL_REV_VALID) {
1252 		bcopy(sl->sl_revision, sli->sli_rev, 4);
1253 		sli->sli_flags |= SLI_REV_VALID;
1254 	}
1255 	if (sl->sl_serial_no_size) {
1256 		bcopy(sl->sl_serial_no, p, sl->sl_serial_no_size);
1257 		sli->sli_serial_size = sl->sl_serial_no_size;
1258 		sli->sli_serial_offset =
1259 		    (uintptr_t)p - (uintptr_t)sli->sli_buf;
1260 		sli->sli_flags |= SLI_SERIAL_VALID;
1261 		p += sli->sli_serial_size;
1262 	}
1263 	sli->sli_lu_size = sl->sl_lu_size;
1264 	sli->sli_data_blocksize_shift = sl->sl_data_blocksize_shift;
1265 	sli->sli_data_order = SMS_DATA_ORDER;
1266 	bcopy(sl->sl_device_id, sli->sli_device_id, 20);
1267 
1268 	sli->sli_sms_header.sms_size = sizeof (*sli) + s;
1269 	sli->sli_sms_header.sms_id = SMS_ID_LU_INFO_1_1;
1270 	sli->sli_sms_header.sms_data_order = SMS_DATA_ORDER;
1271 
1272 	mutex_exit(&sl->sl_lock);
1273 	ret = sbd_write_meta_section(sl, (sm_section_hdr_t *)sli);
1274 	kmem_free(sli, sizeof (*sli) + s);
1275 	return (ret);
1276 }
1277 
1278 int
1279 sbd_populate_and_register_lu(sbd_lu_t *sl, uint32_t *err_ret)
1280 {
1281 	stmf_lu_t *lu = sl->sl_lu;
1282 	stmf_status_t ret;
1283 
1284 	lu->lu_id = (scsi_devid_desc_t *)sl->sl_device_id;
1285 	if (sl->sl_alias) {
1286 		lu->lu_alias = sl->sl_alias;
1287 	} else {
1288 		lu->lu_alias = sl->sl_name;
1289 	}
1290 	lu->lu_lp = sbd_lp;
1291 	lu->lu_task_alloc = sbd_task_alloc;
1292 	lu->lu_new_task = sbd_new_task;
1293 	lu->lu_dbuf_xfer_done = sbd_dbuf_xfer_done;
1294 	lu->lu_send_status_done = sbd_send_status_done;
1295 	lu->lu_task_free = sbd_task_free;
1296 	lu->lu_abort = sbd_abort;
1297 	lu->lu_ctl = sbd_ctl;
1298 	lu->lu_info = sbd_info;
1299 	sl->sl_state = STMF_STATE_OFFLINE;
1300 
1301 	if ((ret = stmf_register_lu(lu)) != STMF_SUCCESS) {
1302 		stmf_trace(0, "Failed to register with framework, ret=%llx",
1303 		    ret);
1304 		if (ret == STMF_ALREADY) {
1305 			*err_ret = SBD_RET_GUID_ALREADY_REGISTERED;
1306 		}
1307 		return (EIO);
1308 	}
1309 
1310 	*err_ret = 0;
1311 	return (0);
1312 }
1313 
1314 int
1315 sbd_open_data_file(sbd_lu_t *sl, uint32_t *err_ret, int lu_size_valid,
1316     int vp_valid, int keep_open)
1317 {
1318 	int ret;
1319 	int flag;
1320 	ulong_t	nbits;
1321 	uint64_t supported_size;
1322 	vattr_t vattr;
1323 	enum vtype vt;
1324 
1325 	mutex_enter(&sl->sl_lock);
1326 	if (vp_valid) {
1327 		goto odf_over_open;
1328 	}
1329 	if (sl->sl_data_filename[0] != '/') {
1330 		*err_ret = SBD_RET_DATA_PATH_NOT_ABSOLUTE;
1331 		mutex_exit(&sl->sl_lock);
1332 		return (EINVAL);
1333 	}
1334 	if ((ret = lookupname(sl->sl_data_filename, UIO_SYSSPACE, FOLLOW,
1335 	    NULLVPP, &sl->sl_data_vp)) != 0) {
1336 		*err_ret = SBD_RET_DATA_FILE_LOOKUP_FAILED;
1337 		mutex_exit(&sl->sl_lock);
1338 		return (ret);
1339 	}
1340 	sl->sl_data_vtype = vt = sl->sl_data_vp->v_type;
1341 	VN_RELE(sl->sl_data_vp);
1342 	if ((vt != VREG) && (vt != VCHR) && (vt != VBLK)) {
1343 		*err_ret = SBD_RET_WRONG_DATA_FILE_TYPE;
1344 		mutex_exit(&sl->sl_lock);
1345 		return (EINVAL);
1346 	}
1347 	if (sl->sl_flags & SL_WRITE_PROTECTED) {
1348 		flag = FREAD | FOFFMAX;
1349 	} else {
1350 		flag = FREAD | FWRITE | FOFFMAX | FEXCL;
1351 	}
1352 	if ((ret = vn_open(sl->sl_data_filename, UIO_SYSSPACE, flag, 0,
1353 	    &sl->sl_data_vp, 0, 0)) != 0) {
1354 		*err_ret = SBD_RET_DATA_FILE_OPEN_FAILED;
1355 		mutex_exit(&sl->sl_lock);
1356 		return (ret);
1357 	}
1358 odf_over_open:
1359 	vattr.va_mask = AT_SIZE;
1360 	if ((ret = VOP_GETATTR(sl->sl_data_vp, &vattr, 0, CRED(), NULL)) != 0) {
1361 		*err_ret = SBD_RET_DATA_FILE_GETATTR_FAILED;
1362 		goto odf_close_data_and_exit;
1363 	}
1364 	if ((vt != VREG) && (vattr.va_size == 0)) {
1365 		/*
1366 		 * Its a zero byte block or char device. This cannot be
1367 		 * a raw disk.
1368 		 */
1369 		*err_ret = SBD_RET_WRONG_DATA_FILE_TYPE;
1370 		ret = EINVAL;
1371 		goto odf_close_data_and_exit;
1372 	}
1373 	/* sl_data_readable size includes any metadata. */
1374 	sl->sl_data_readable_size = vattr.va_size;
1375 	if (VOP_PATHCONF(sl->sl_data_vp, _PC_FILESIZEBITS, &nbits,
1376 	    CRED(), NULL) != 0) {
1377 		nbits = 0;
1378 	}
1379 	/* nbits cannot be greater than 64 */
1380 	sl->sl_data_fs_nbits = (uint8_t)nbits;
1381 	if (lu_size_valid) {
1382 		sl->sl_total_data_size = sl->sl_lu_size;
1383 		if (sl->sl_flags & SL_SHARED_META) {
1384 			sl->sl_total_data_size += SHARED_META_DATA_SIZE;
1385 		}
1386 		if ((nbits > 0) && (nbits < 64)) {
1387 			/*
1388 			 * The expression below is correct only if nbits is
1389 			 * positive and less than 64.
1390 			 */
1391 			supported_size = (((uint64_t)1) << nbits) - 1;
1392 			if (sl->sl_total_data_size > supported_size) {
1393 				*err_ret = SBD_RET_SIZE_NOT_SUPPORTED_BY_FS;
1394 				ret = EINVAL;
1395 				goto odf_close_data_and_exit;
1396 			}
1397 		}
1398 	} else {
1399 		sl->sl_total_data_size = vattr.va_size;
1400 		if (sl->sl_flags & SL_SHARED_META) {
1401 			if (vattr.va_size > SHARED_META_DATA_SIZE) {
1402 				sl->sl_lu_size = vattr.va_size -
1403 				    SHARED_META_DATA_SIZE;
1404 			} else {
1405 				*err_ret = SBD_RET_FILE_SIZE_ERROR;
1406 				ret = EINVAL;
1407 				goto odf_close_data_and_exit;
1408 			}
1409 		} else {
1410 			sl->sl_lu_size = vattr.va_size;
1411 		}
1412 	}
1413 	if (sl->sl_lu_size < SBD_MIN_LU_SIZE) {
1414 		*err_ret = SBD_RET_FILE_SIZE_ERROR;
1415 		ret = EINVAL;
1416 		goto odf_close_data_and_exit;
1417 	}
1418 	if (sl->sl_lu_size &
1419 	    ((((uint64_t)1) << sl->sl_data_blocksize_shift) - 1)) {
1420 		*err_ret = SBD_RET_FILE_ALIGN_ERROR;
1421 		ret = EINVAL;
1422 		goto odf_close_data_and_exit;
1423 	}
1424 	sl->sl_flags |= SL_MEDIA_LOADED;
1425 	mutex_exit(&sl->sl_lock);
1426 	return (0);
1427 
1428 odf_close_data_and_exit:
1429 	if (!keep_open) {
1430 		(void) VOP_CLOSE(sl->sl_data_vp, flag, 1, 0, CRED(), NULL);
1431 		VN_RELE(sl->sl_data_vp);
1432 	}
1433 	mutex_exit(&sl->sl_lock);
1434 	return (ret);
1435 }
1436 
1437 int
1438 sbd_close_delete_lu(sbd_lu_t *sl, int ret)
1439 {
1440 	int flag;
1441 
1442 	if (((sl->sl_flags & SL_SHARED_META) == 0) &&
1443 	    (sl->sl_flags & SL_META_OPENED)) {
1444 		if (sl->sl_flags & SL_ZFS_META) {
1445 			rw_destroy(&sl->sl_zfs_meta_lock);
1446 			if (sl->sl_zfs_meta) {
1447 				kmem_free(sl->sl_zfs_meta, ZAP_MAXVALUELEN / 2);
1448 			}
1449 		} else {
1450 			flag = FREAD | FWRITE | FOFFMAX | FEXCL;
1451 			(void) VOP_CLOSE(sl->sl_meta_vp, flag, 1, 0,
1452 			    CRED(), NULL);
1453 			VN_RELE(sl->sl_meta_vp);
1454 		}
1455 		sl->sl_flags &= ~SL_META_OPENED;
1456 	}
1457 	if (sl->sl_flags & SL_MEDIA_LOADED) {
1458 		if (sl->sl_flags & SL_WRITE_PROTECTED) {
1459 			flag = FREAD | FOFFMAX;
1460 		} else {
1461 			flag = FREAD | FWRITE | FOFFMAX | FEXCL;
1462 		}
1463 		(void) VOP_CLOSE(sl->sl_data_vp, flag, 1, 0, CRED(), NULL);
1464 		VN_RELE(sl->sl_data_vp);
1465 		sl->sl_flags &= ~SL_MEDIA_LOADED;
1466 		if (sl->sl_flags & SL_SHARED_META) {
1467 			sl->sl_flags &= ~SL_META_OPENED;
1468 		}
1469 	}
1470 	if (sl->sl_flags & SL_LINKED)
1471 		sbd_unlink_lu(sl);
1472 	mutex_destroy(&sl->sl_metadata_lock);
1473 	mutex_destroy(&sl->sl_lock);
1474 	rw_destroy(&sl->sl_pgr->pgr_lock);
1475 	if (sl->sl_serial_no_alloc_size) {
1476 		kmem_free(sl->sl_serial_no, sl->sl_serial_no_alloc_size);
1477 	}
1478 	if (sl->sl_data_fname_alloc_size) {
1479 		kmem_free(sl->sl_data_filename, sl->sl_data_fname_alloc_size);
1480 	}
1481 	if (sl->sl_alias_alloc_size) {
1482 		kmem_free(sl->sl_alias, sl->sl_alias_alloc_size);
1483 	}
1484 	if (sl->sl_mgmt_url_alloc_size) {
1485 		kmem_free(sl->sl_mgmt_url, sl->sl_mgmt_url_alloc_size);
1486 	}
1487 	stmf_free(sl->sl_lu);
1488 	return (ret);
1489 }
1490 
1491 int
1492 sbd_create_register_lu(sbd_create_and_reg_lu_t *slu, int struct_sz,
1493     uint32_t *err_ret)
1494 {
1495 	char *namebuf;
1496 	sbd_lu_t *sl;
1497 	stmf_lu_t *lu;
1498 	sbd_status_t sret;
1499 	char *p;
1500 	int sz;
1501 	int alloc_sz;
1502 	int ret = EIO;
1503 	int flag;
1504 	int wcd = 0;
1505 	enum vtype vt;
1506 
1507 	sz = struct_sz - sizeof (sbd_create_and_reg_lu_t) + 8 + 1;
1508 
1509 	*err_ret = 0;
1510 
1511 	/* Lets validate various offsets */
1512 	if (((slu->slu_meta_fname_valid) &&
1513 	    (slu->slu_meta_fname_off >= sz)) ||
1514 	    (slu->slu_data_fname_off >= sz) ||
1515 	    ((slu->slu_alias_valid) &&
1516 	    (slu->slu_alias_off >= sz)) ||
1517 	    ((slu->slu_mgmt_url_valid) &&
1518 	    (slu->slu_mgmt_url_off >= sz)) ||
1519 	    ((slu->slu_serial_valid) &&
1520 	    ((slu->slu_serial_off + slu->slu_serial_size) >= sz))) {
1521 		return (EINVAL);
1522 	}
1523 
1524 	namebuf = kmem_zalloc(sz, KM_SLEEP);
1525 	bcopy(slu->slu_buf, namebuf, sz - 1);
1526 	namebuf[sz - 1] = 0;
1527 
1528 	alloc_sz = sizeof (sbd_lu_t) + sizeof (sbd_pgr_t);
1529 	if (slu->slu_meta_fname_valid) {
1530 		alloc_sz += strlen(namebuf + slu->slu_meta_fname_off) + 1;
1531 	}
1532 	alloc_sz += strlen(namebuf + slu->slu_data_fname_off) + 1;
1533 	if (slu->slu_alias_valid) {
1534 		alloc_sz += strlen(namebuf + slu->slu_alias_off) + 1;
1535 	}
1536 	if (slu->slu_mgmt_url_valid) {
1537 		alloc_sz += strlen(namebuf + slu->slu_mgmt_url_off) + 1;
1538 	}
1539 	if (slu->slu_serial_valid) {
1540 		alloc_sz += slu->slu_serial_size;
1541 	}
1542 
1543 	lu = (stmf_lu_t *)stmf_alloc(STMF_STRUCT_STMF_LU, alloc_sz, 0);
1544 	if (lu == NULL) {
1545 		kmem_free(namebuf, sz);
1546 		return (ENOMEM);
1547 	}
1548 	sl = (sbd_lu_t *)lu->lu_provider_private;
1549 	bzero(sl, alloc_sz);
1550 	sl->sl_lu = lu;
1551 	sl->sl_alloc_size = alloc_sz;
1552 	sl->sl_pgr = (sbd_pgr_t *)(sl + 1);
1553 	rw_init(&sl->sl_pgr->pgr_lock, NULL, RW_DRIVER, NULL);
1554 	mutex_init(&sl->sl_lock, NULL, MUTEX_DRIVER, NULL);
1555 	mutex_init(&sl->sl_metadata_lock, NULL, MUTEX_DRIVER, NULL);
1556 	p = ((char *)sl) + sizeof (sbd_lu_t) + sizeof (sbd_pgr_t);
1557 	sl->sl_data_filename = p;
1558 	(void) strcpy(sl->sl_data_filename, namebuf + slu->slu_data_fname_off);
1559 	p += strlen(sl->sl_data_filename) + 1;
1560 	sl->sl_meta_offset = SBD_META_OFFSET;
1561 	if (slu->slu_meta_fname_valid) {
1562 		sl->sl_alias = sl->sl_name = sl->sl_meta_filename = p;
1563 		(void) strcpy(sl->sl_meta_filename, namebuf +
1564 		    slu->slu_meta_fname_off);
1565 		p += strlen(sl->sl_meta_filename) + 1;
1566 	} else {
1567 		sl->sl_alias = sl->sl_name = sl->sl_data_filename;
1568 		if (sbd_is_zvol(sl->sl_data_filename)) {
1569 			sl->sl_flags |= SL_ZFS_META;
1570 			sl->sl_meta_offset = 0;
1571 		} else {
1572 			sl->sl_flags |= SL_SHARED_META;
1573 			sl->sl_data_offset = SHARED_META_DATA_SIZE;
1574 			sl->sl_total_meta_size = SHARED_META_DATA_SIZE;
1575 			sl->sl_meta_size_used = 0;
1576 		}
1577 	}
1578 	if (slu->slu_alias_valid) {
1579 		sl->sl_alias = p;
1580 		(void) strcpy(p, namebuf + slu->slu_alias_off);
1581 		p += strlen(sl->sl_alias) + 1;
1582 	}
1583 	if (slu->slu_mgmt_url_valid) {
1584 		sl->sl_mgmt_url = p;
1585 		(void) strcpy(p, namebuf + slu->slu_mgmt_url_off);
1586 		p += strlen(sl->sl_mgmt_url) + 1;
1587 	}
1588 	if (slu->slu_serial_valid) {
1589 		sl->sl_serial_no = (uint8_t *)p;
1590 		bcopy(namebuf + slu->slu_serial_off, sl->sl_serial_no,
1591 		    slu->slu_serial_size);
1592 		sl->sl_serial_no_size = slu->slu_serial_size;
1593 		p += slu->slu_serial_size;
1594 	}
1595 	kmem_free(namebuf, sz);
1596 	if (slu->slu_vid_valid) {
1597 		bcopy(slu->slu_vid, sl->sl_vendor_id, 8);
1598 		sl->sl_flags |= SL_VID_VALID;
1599 	}
1600 	if (slu->slu_pid_valid) {
1601 		bcopy(slu->slu_pid, sl->sl_product_id, 16);
1602 		sl->sl_flags |= SL_PID_VALID;
1603 	}
1604 	if (slu->slu_rev_valid) {
1605 		bcopy(slu->slu_rev, sl->sl_revision, 4);
1606 		sl->sl_flags |= SL_REV_VALID;
1607 	}
1608 	if (slu->slu_write_protected) {
1609 		sl->sl_flags |= SL_WRITE_PROTECTED;
1610 	}
1611 	if (slu->slu_writeback_cache_disable) {
1612 		sl->sl_flags |= SL_WRITEBACK_CACHE_DISABLE |
1613 		    SL_SAVED_WRITE_CACHE_DISABLE;
1614 	}
1615 
1616 	if (slu->slu_blksize_valid) {
1617 		if ((slu->slu_blksize & (slu->slu_blksize - 1)) ||
1618 		    (slu->slu_blksize > (32 * 1024)) ||
1619 		    (slu->slu_blksize == 0)) {
1620 			*err_ret = SBD_RET_INVALID_BLKSIZE;
1621 			ret = EINVAL;
1622 			goto scm_err_out;
1623 		}
1624 		while ((1 << sl->sl_data_blocksize_shift) != slu->slu_blksize) {
1625 			sl->sl_data_blocksize_shift++;
1626 		}
1627 	} else {
1628 		sl->sl_data_blocksize_shift = 9;	/* 512 by default */
1629 		slu->slu_blksize = 512;
1630 	}
1631 
1632 	/* Now lets start creating meta */
1633 	sl->sl_trans_op = SL_OP_CREATE_REGISTER_LU;
1634 	if (sbd_link_lu(sl) != SBD_SUCCESS) {
1635 		*err_ret = SBD_RET_FILE_ALREADY_REGISTERED;
1636 		ret = EALREADY;
1637 		goto scm_err_out;
1638 	}
1639 
1640 	/* 1st focus on the data store */
1641 	if (slu->slu_lu_size_valid) {
1642 		sl->sl_lu_size = slu->slu_lu_size;
1643 	}
1644 	ret = sbd_open_data_file(sl, err_ret, slu->slu_lu_size_valid, 0, 0);
1645 	slu->slu_ret_filesize_nbits = sl->sl_data_fs_nbits;
1646 	slu->slu_lu_size = sl->sl_lu_size;
1647 	if (ret) {
1648 		goto scm_err_out;
1649 	}
1650 
1651 	/*
1652 	 * set write cache disable on the device
1653 	 * if it fails, we'll support it using sync/flush
1654 	 */
1655 	if (slu->slu_writeback_cache_disable) {
1656 		(void) sbd_wcd_set(1, sl);
1657 		wcd = 1;
1658 	/*
1659 	 * Attempt to set it to enable, if that fails and it was explicitly set
1660 	 * return an error, otherwise get the current setting and use that
1661 	 */
1662 	} else {
1663 		sret = sbd_wcd_set(0, sl);
1664 		if (slu->slu_writeback_cache_disable_valid &&
1665 		    sret != SBD_SUCCESS) {
1666 			*err_ret = SBD_RET_WRITE_CACHE_SET_FAILED;
1667 			ret = EFAULT;
1668 			goto scm_err_out;
1669 		}
1670 		if (sret != SBD_SUCCESS) {
1671 			sbd_wcd_get(&wcd, sl);
1672 		}
1673 	}
1674 
1675 	if (wcd) {
1676 		sl->sl_flags |= SL_WRITEBACK_CACHE_DISABLE |
1677 		    SL_SAVED_WRITE_CACHE_DISABLE;
1678 	}
1679 
1680 	if (sl->sl_flags & SL_SHARED_META) {
1681 		goto over_meta_open;
1682 	}
1683 	if (sl->sl_flags & SL_ZFS_META) {
1684 		if (sbd_create_zfs_meta_object(sl) != SBD_SUCCESS) {
1685 			*err_ret = SBD_RET_ZFS_META_CREATE_FAILED;
1686 			ret = ENOMEM;
1687 			goto scm_err_out;
1688 		}
1689 		sl->sl_meta_blocksize_shift = 0;
1690 		goto over_meta_create;
1691 	}
1692 	if ((ret = lookupname(sl->sl_meta_filename, UIO_SYSSPACE, FOLLOW,
1693 	    NULLVPP, &sl->sl_meta_vp)) != 0) {
1694 		*err_ret = SBD_RET_META_FILE_LOOKUP_FAILED;
1695 		goto scm_err_out;
1696 	}
1697 	sl->sl_meta_vtype = vt = sl->sl_meta_vp->v_type;
1698 	VN_RELE(sl->sl_meta_vp);
1699 	if ((vt != VREG) && (vt != VCHR) && (vt != VBLK)) {
1700 		*err_ret = SBD_RET_WRONG_META_FILE_TYPE;
1701 		ret = EINVAL;
1702 		goto scm_err_out;
1703 	}
1704 	if (vt == VREG) {
1705 		sl->sl_meta_blocksize_shift = 0;
1706 	} else {
1707 		sl->sl_meta_blocksize_shift = 9;
1708 	}
1709 	flag = FREAD | FWRITE | FOFFMAX | FEXCL;
1710 	if ((ret = vn_open(sl->sl_meta_filename, UIO_SYSSPACE, flag, 0,
1711 	    &sl->sl_meta_vp, 0, 0)) != 0) {
1712 		*err_ret = SBD_RET_META_FILE_OPEN_FAILED;
1713 		goto scm_err_out;
1714 	}
1715 over_meta_create:
1716 	sl->sl_total_meta_size = sl->sl_meta_offset + sizeof (sbd_meta_start_t);
1717 	sl->sl_total_meta_size +=
1718 	    (((uint64_t)1) << sl->sl_meta_blocksize_shift) - 1;
1719 	sl->sl_total_meta_size &=
1720 	    ~((((uint64_t)1) << sl->sl_meta_blocksize_shift) - 1);
1721 	sl->sl_meta_size_used = 0;
1722 over_meta_open:
1723 	sl->sl_flags |= SL_META_OPENED;
1724 
1725 	sl->sl_device_id[3] = 16;
1726 	if (slu->slu_guid_valid) {
1727 		sl->sl_device_id[0] = 0xf1;
1728 		sl->sl_device_id[1] = 3;
1729 		sl->sl_device_id[2] = 0;
1730 		bcopy(slu->slu_guid, sl->sl_device_id + 4, 16);
1731 	} else {
1732 		if (!slu->slu_company_id_valid)
1733 			slu->slu_company_id = COMPANY_ID_SUN;
1734 		if (stmf_scsilib_uniq_lu_id(slu->slu_company_id,
1735 		    (scsi_devid_desc_t *)&sl->sl_device_id[0]) !=
1736 		    STMF_SUCCESS) {
1737 			*err_ret = SBD_RET_META_CREATION_FAILED;
1738 			ret = EIO;
1739 			goto scm_err_out;
1740 		}
1741 		bcopy(sl->sl_device_id + 4, slu->slu_guid, 16);
1742 	}
1743 
1744 	/* Lets create the meta now */
1745 	mutex_enter(&sl->sl_metadata_lock);
1746 	if (sbd_write_meta_start(sl, sl->sl_total_meta_size,
1747 	    sizeof (sbd_meta_start_t)) != SBD_SUCCESS) {
1748 		mutex_exit(&sl->sl_metadata_lock);
1749 		*err_ret = SBD_RET_META_CREATION_FAILED;
1750 		ret = EIO;
1751 		goto scm_err_out;
1752 	}
1753 	mutex_exit(&sl->sl_metadata_lock);
1754 	sl->sl_meta_size_used = sl->sl_meta_offset + sizeof (sbd_meta_start_t);
1755 
1756 	if (sbd_write_lu_info(sl) != SBD_SUCCESS) {
1757 		*err_ret = SBD_RET_META_CREATION_FAILED;
1758 		ret = EIO;
1759 		goto scm_err_out;
1760 	}
1761 
1762 	if (sbd_pgr_meta_init(sl) != SBD_SUCCESS) {
1763 		*err_ret = SBD_RET_META_CREATION_FAILED;
1764 		ret = EIO;
1765 		goto scm_err_out;
1766 	}
1767 
1768 	ret = sbd_populate_and_register_lu(sl, err_ret);
1769 	if (ret) {
1770 		goto scm_err_out;
1771 	}
1772 
1773 	sl->sl_trans_op = SL_OP_NONE;
1774 	atomic_add_32(&sbd_lu_count, 1);
1775 	return (0);
1776 
1777 scm_err_out:
1778 	return (sbd_close_delete_lu(sl, ret));
1779 }
1780 
1781 int
1782 sbd_load_sli_1_0(sbd_lu_t *sl, uint32_t *err_ret)
1783 {
1784 	sbd_lu_info_1_0_t *sli = NULL;
1785 	sbd_status_t sret;
1786 
1787 	sret = sbd_read_meta_section(sl, (sm_section_hdr_t **)&sli,
1788 	    SMS_ID_LU_INFO_1_0);
1789 
1790 	if (sret != SBD_SUCCESS) {
1791 		*err_ret = SBD_RET_NO_META;
1792 		return (EIO);
1793 	}
1794 	if (sli->sli_data_order != SMS_DATA_ORDER) {
1795 		sbd_swap_lu_info_1_0(sli);
1796 		if (sli->sli_data_order != SMS_DATA_ORDER) {
1797 			kmem_free(sli, sli->sli_sms_header.sms_size);
1798 			*err_ret = SBD_RET_NO_META;
1799 			return (EIO);
1800 		}
1801 	}
1802 
1803 	sl->sl_flags |= SL_SHARED_META;
1804 	sl->sl_data_blocksize_shift = 9;
1805 	sl->sl_data_offset = SHARED_META_DATA_SIZE;
1806 	sl->sl_lu_size = sli->sli_total_store_size - SHARED_META_DATA_SIZE;
1807 	sl->sl_total_data_size = SHARED_META_DATA_SIZE + sl->sl_lu_size;
1808 	bcopy(sli->sli_lu_devid, sl->sl_device_id, 20);
1809 
1810 	kmem_free(sli, sli->sli_sms_header.sms_size);
1811 	return (0);
1812 }
1813 
1814 int
1815 sbd_import_lu(sbd_import_lu_t *ilu, int struct_sz, uint32_t *err_ret,
1816     int no_register, sbd_lu_t **slr)
1817 {
1818 	stmf_lu_t *lu;
1819 	sbd_lu_t *sl;
1820 	sbd_lu_info_1_1_t *sli = NULL;
1821 	int asz;
1822 	int ret = 0;
1823 	int flag;
1824 	int wcd = 0;
1825 	int data_opened;
1826 	uint16_t sli_buf_sz;
1827 	uint8_t *sli_buf_copy = NULL;
1828 	enum vtype vt;
1829 	sbd_status_t sret;
1830 
1831 	if (no_register && slr == NULL) {
1832 		return (EINVAL);
1833 	}
1834 	ilu->ilu_meta_fname[struct_sz - sizeof (*ilu) + 8 - 1] = 0;
1835 	asz = strlen(ilu->ilu_meta_fname) + 1;
1836 
1837 	lu = (stmf_lu_t *)stmf_alloc(STMF_STRUCT_STMF_LU,
1838 	    sizeof (sbd_lu_t) + sizeof (sbd_pgr_t) + asz, 0);
1839 	if (lu == NULL) {
1840 		return (ENOMEM);
1841 	}
1842 	sl = (sbd_lu_t *)lu->lu_provider_private;
1843 	bzero(sl, sizeof (*sl));
1844 	sl->sl_lu = lu;
1845 	sl->sl_pgr = (sbd_pgr_t *)(sl + 1);
1846 	sl->sl_meta_filename = ((char *)sl) + sizeof (*sl) + sizeof (sbd_pgr_t);
1847 	(void) strcpy(sl->sl_meta_filename, ilu->ilu_meta_fname);
1848 	sl->sl_name = sl->sl_meta_filename;
1849 	rw_init(&sl->sl_pgr->pgr_lock, NULL, RW_DRIVER, NULL);
1850 	mutex_init(&sl->sl_lock, NULL, MUTEX_DRIVER, NULL);
1851 	mutex_init(&sl->sl_metadata_lock, NULL, MUTEX_DRIVER, NULL);
1852 	sl->sl_trans_op = SL_OP_IMPORT_LU;
1853 	/* we're only loading the metadata */
1854 	if (!no_register) {
1855 		if (sbd_link_lu(sl) != SBD_SUCCESS) {
1856 			*err_ret = SBD_RET_FILE_ALREADY_REGISTERED;
1857 			ret = EALREADY;
1858 			goto sim_err_out;
1859 		}
1860 	}
1861 	if ((ret = lookupname(sl->sl_meta_filename, UIO_SYSSPACE, FOLLOW,
1862 	    NULLVPP, &sl->sl_meta_vp)) != 0) {
1863 		*err_ret = SBD_RET_META_FILE_LOOKUP_FAILED;
1864 		goto sim_err_out;
1865 	}
1866 	if (sbd_is_zvol(sl->sl_meta_filename)) {
1867 		sl->sl_flags |= SL_ZFS_META;
1868 		sl->sl_data_filename = sl->sl_meta_filename;
1869 	}
1870 	sl->sl_meta_vtype = vt = sl->sl_meta_vp->v_type;
1871 	VN_RELE(sl->sl_meta_vp);
1872 	if ((vt != VREG) && (vt != VCHR) && (vt != VBLK)) {
1873 		*err_ret = SBD_RET_WRONG_META_FILE_TYPE;
1874 		ret = EINVAL;
1875 		goto sim_err_out;
1876 	}
1877 	if (sl->sl_flags & SL_ZFS_META) {
1878 		if (sbd_open_zfs_meta(sl) != SBD_SUCCESS) {
1879 			/* let see if metadata is in the 64k block */
1880 			sl->sl_flags &= ~SL_ZFS_META;
1881 		}
1882 	}
1883 	if (!(sl->sl_flags & SL_ZFS_META)) {
1884 		/* metadata is always writable */
1885 		flag = FREAD | FWRITE | FOFFMAX | FEXCL;
1886 		if ((ret = vn_open(sl->sl_meta_filename, UIO_SYSSPACE, flag, 0,
1887 		    &sl->sl_meta_vp, 0, 0)) != 0) {
1888 			*err_ret = SBD_RET_META_FILE_OPEN_FAILED;
1889 			goto sim_err_out;
1890 		}
1891 	}
1892 	if ((sl->sl_flags & SL_ZFS_META) || (vt == VREG)) {
1893 		sl->sl_meta_blocksize_shift = 0;
1894 	} else {
1895 		sl->sl_meta_blocksize_shift = 9;
1896 	}
1897 	sl->sl_meta_offset = (sl->sl_flags & SL_ZFS_META) ? 0 : SBD_META_OFFSET;
1898 	sl->sl_flags |= SL_META_OPENED;
1899 
1900 	mutex_enter(&sl->sl_metadata_lock);
1901 	sret = sbd_load_meta_start(sl);
1902 	mutex_exit(&sl->sl_metadata_lock);
1903 	if (sret != SBD_SUCCESS) {
1904 		if (sret == SBD_META_CORRUPTED) {
1905 			*err_ret = SBD_RET_NO_META;
1906 		} else if (sret == SBD_NOT_SUPPORTED) {
1907 			*err_ret = SBD_RET_VERSION_NOT_SUPPORTED;
1908 		} else {
1909 			*err_ret = SBD_RET_NO_META;
1910 		}
1911 		ret = EINVAL;
1912 		goto sim_err_out;
1913 	}
1914 
1915 	/* Now lets see if we can read the most recent LU info */
1916 	sret = sbd_read_meta_section(sl, (sm_section_hdr_t **)&sli,
1917 	    SMS_ID_LU_INFO_1_1);
1918 	if ((sret == SBD_NOT_FOUND) && ((sl->sl_flags & SL_ZFS_META) == 0)) {
1919 		ret = sbd_load_sli_1_0(sl, err_ret);
1920 		if (ret)
1921 			goto sim_err_out;
1922 		goto sim_sli_loaded;
1923 	}
1924 	if (sret != SBD_SUCCESS) {
1925 		*err_ret = SBD_RET_NO_META;
1926 		ret = EIO;
1927 		goto sim_err_out;
1928 	}
1929 	/* load sli 1.1 */
1930 	if (sli->sli_data_order != SMS_DATA_ORDER) {
1931 		sbd_swap_lu_info_1_1(sli);
1932 		if (sli->sli_data_order != SMS_DATA_ORDER) {
1933 			*err_ret = SBD_RET_NO_META;
1934 			ret = EIO;
1935 			goto sim_err_out;
1936 		}
1937 	}
1938 
1939 	sli_buf_sz = sli->sli_sms_header.sms_size -
1940 	    sizeof (sbd_lu_info_1_1_t) + 8;
1941 	sli_buf_copy = kmem_alloc(sli_buf_sz + 1, KM_SLEEP);
1942 	bcopy(sli->sli_buf, sli_buf_copy, sli_buf_sz);
1943 	sli_buf_copy[sli_buf_sz] = 0;
1944 
1945 	/* Make sure all the offsets are within limits */
1946 	if (((sli->sli_flags & SLI_META_FNAME_VALID) &&
1947 	    (sli->sli_meta_fname_offset > sli_buf_sz)) ||
1948 	    ((sli->sli_flags & SLI_DATA_FNAME_VALID) &&
1949 	    (sli->sli_data_fname_offset > sli_buf_sz)) ||
1950 	    ((sli->sli_flags & SLI_MGMT_URL_VALID) &&
1951 	    (sli->sli_mgmt_url_offset > sli_buf_sz)) ||
1952 	    ((sli->sli_flags & SLI_SERIAL_VALID) &&
1953 	    ((sli->sli_serial_offset + sli->sli_serial_size) > sli_buf_sz)) ||
1954 	    ((sli->sli_flags & SLI_ALIAS_VALID) &&
1955 	    (sli->sli_alias_offset > sli_buf_sz))) {
1956 		*err_ret = SBD_RET_NO_META;
1957 		ret = EIO;
1958 		goto sim_err_out;
1959 	}
1960 
1961 	sl->sl_lu_size = sli->sli_lu_size;
1962 	sl->sl_data_blocksize_shift = sli->sli_data_blocksize_shift;
1963 	bcopy(sli->sli_device_id, sl->sl_device_id, 20);
1964 	if (sli->sli_flags & SLI_SERIAL_VALID) {
1965 		sl->sl_serial_no_size = sl->sl_serial_no_alloc_size =
1966 		    sli->sli_serial_size;
1967 		sl->sl_serial_no = kmem_zalloc(sli->sli_serial_size, KM_SLEEP);
1968 		bcopy(sli_buf_copy + sli->sli_serial_offset, sl->sl_serial_no,
1969 		    sl->sl_serial_no_size);
1970 	}
1971 	if (sli->sli_flags & SLI_SEPARATE_META) {
1972 		sl->sl_total_data_size = sl->sl_lu_size;
1973 		if (sli->sli_flags & SLI_DATA_FNAME_VALID) {
1974 			sl->sl_data_fname_alloc_size = strlen((char *)
1975 			    sli_buf_copy + sli->sli_data_fname_offset) + 1;
1976 			sl->sl_data_filename = kmem_zalloc(
1977 			    sl->sl_data_fname_alloc_size, KM_SLEEP);
1978 			(void) strcpy(sl->sl_data_filename,
1979 			    (char *)sli_buf_copy + sli->sli_data_fname_offset);
1980 		}
1981 	} else {
1982 		if (sl->sl_flags & SL_ZFS_META) {
1983 			sl->sl_total_data_size = sl->sl_lu_size;
1984 			sl->sl_data_offset = 0;
1985 		} else {
1986 			sl->sl_total_data_size =
1987 			    sl->sl_lu_size + SHARED_META_DATA_SIZE;
1988 			sl->sl_data_offset = SHARED_META_DATA_SIZE;
1989 			sl->sl_flags |= SL_SHARED_META;
1990 		}
1991 	}
1992 	if (sli->sli_flags & SLI_ALIAS_VALID) {
1993 		sl->sl_alias_alloc_size = strlen((char *)sli_buf_copy +
1994 		    sli->sli_alias_offset) + 1;
1995 		sl->sl_alias = kmem_alloc(sl->sl_alias_alloc_size, KM_SLEEP);
1996 		(void) strcpy(sl->sl_alias, (char *)sli_buf_copy +
1997 		    sli->sli_alias_offset);
1998 	}
1999 	if (sli->sli_flags & SLI_MGMT_URL_VALID) {
2000 		sl->sl_mgmt_url_alloc_size = strlen((char *)sli_buf_copy +
2001 		    sli->sli_mgmt_url_offset) + 1;
2002 		sl->sl_mgmt_url = kmem_alloc(sl->sl_mgmt_url_alloc_size,
2003 		    KM_SLEEP);
2004 		(void) strcpy(sl->sl_mgmt_url, (char *)sli_buf_copy +
2005 		    sli->sli_mgmt_url_offset);
2006 	}
2007 	if (sli->sli_flags & SLI_WRITE_PROTECTED) {
2008 		sl->sl_flags |= SL_WRITE_PROTECTED;
2009 	}
2010 	if (sli->sli_flags & SLI_VID_VALID) {
2011 		sl->sl_flags |= SL_VID_VALID;
2012 		bcopy(sli->sli_vid, sl->sl_vendor_id, 8);
2013 	}
2014 	if (sli->sli_flags & SLI_PID_VALID) {
2015 		sl->sl_flags |= SL_PID_VALID;
2016 		bcopy(sli->sli_pid, sl->sl_product_id, 16);
2017 	}
2018 	if (sli->sli_flags & SLI_REV_VALID) {
2019 		sl->sl_flags |= SL_REV_VALID;
2020 		bcopy(sli->sli_rev, sl->sl_revision, 4);
2021 	}
2022 	if (sli->sli_flags & SLI_WRITEBACK_CACHE_DISABLE) {
2023 		sl->sl_flags |= SL_WRITEBACK_CACHE_DISABLE;
2024 	}
2025 sim_sli_loaded:
2026 	if ((sl->sl_flags & SL_SHARED_META) == 0) {
2027 		data_opened = 0;
2028 	} else {
2029 		data_opened = 1;
2030 		sl->sl_data_filename = sl->sl_meta_filename;
2031 		sl->sl_data_vp = sl->sl_meta_vp;
2032 		sl->sl_data_vtype = sl->sl_meta_vtype;
2033 	}
2034 
2035 	sret = sbd_pgr_meta_load(sl);
2036 	if (sret != SBD_SUCCESS) {
2037 		*err_ret = SBD_RET_NO_META;
2038 		ret = EIO;
2039 		goto sim_err_out;
2040 	}
2041 
2042 	ret = sbd_open_data_file(sl, err_ret, 1, data_opened, 0);
2043 	if (ret)
2044 		goto sim_err_out;
2045 
2046 	/*
2047 	 * set write cache disable on the device
2048 	 * Note: this shouldn't fail on import unless the cache capabilities
2049 	 * of the device changed. If that happened, modify will need to
2050 	 * be used to set the cache flag appropriately after import is done.
2051 	 */
2052 	if (sl->sl_flags & SL_WRITEBACK_CACHE_DISABLE) {
2053 		(void) sbd_wcd_set(1, sl);
2054 		wcd = 1;
2055 	/*
2056 	 * if not explicitly set, attempt to set it to enable, if that fails
2057 	 * get the current setting and use that
2058 	 */
2059 	} else {
2060 		sret = sbd_wcd_set(0, sl);
2061 		if (sret != SBD_SUCCESS) {
2062 			sbd_wcd_get(&wcd, sl);
2063 		}
2064 	}
2065 
2066 	if (wcd) {
2067 		sl->sl_flags |= SL_WRITEBACK_CACHE_DISABLE |
2068 		    SL_SAVED_WRITE_CACHE_DISABLE;
2069 	}
2070 
2071 	/* we're only loading the metadata */
2072 	if (!no_register) {
2073 		ret = sbd_populate_and_register_lu(sl, err_ret);
2074 		if (ret)
2075 			goto sim_err_out;
2076 		atomic_add_32(&sbd_lu_count, 1);
2077 	}
2078 
2079 	bcopy(sl->sl_device_id + 4, ilu->ilu_ret_guid, 16);
2080 	sl->sl_trans_op = SL_OP_NONE;
2081 	if (sli) {
2082 		kmem_free(sli, sli->sli_sms_header.sms_size);
2083 		sli = NULL;
2084 	}
2085 	if (sli_buf_copy) {
2086 		kmem_free(sli_buf_copy, sli_buf_sz + 1);
2087 		sli_buf_copy = NULL;
2088 	}
2089 	if (no_register) {
2090 		*slr = sl;
2091 	}
2092 	return (0);
2093 
2094 sim_err_out:
2095 	if (sli) {
2096 		kmem_free(sli, sli->sli_sms_header.sms_size);
2097 		sli = NULL;
2098 	}
2099 	if (sli_buf_copy) {
2100 		kmem_free(sli_buf_copy, sli_buf_sz + 1);
2101 		sli_buf_copy = NULL;
2102 	}
2103 	return (sbd_close_delete_lu(sl, ret));
2104 }
2105 
2106 int
2107 sbd_modify_lu(sbd_modify_lu_t *mlu, int struct_sz, uint32_t *err_ret)
2108 {
2109 	sbd_lu_t *sl = NULL;
2110 	uint16_t alias_sz;
2111 	int ret = 0;
2112 	sbd_it_data_t *it;
2113 	sbd_status_t sret;
2114 	uint64_t old_size;
2115 	int modify_unregistered = 0;
2116 	int ua = 0;
2117 	sbd_import_lu_t *ilu;
2118 	stmf_lu_t *lu;
2119 	uint32_t ilu_sz;
2120 	uint32_t sz;
2121 
2122 	sz = struct_sz - sizeof (*mlu) + 8 + 1;
2123 
2124 	/* if there is data in the buf, null terminate it */
2125 	if (struct_sz > sizeof (*mlu)) {
2126 		mlu->mlu_buf[struct_sz - sizeof (*mlu) + 8 - 1] = 0;
2127 	}
2128 
2129 	*err_ret = 0;
2130 
2131 	/* Lets validate offsets */
2132 	if (((mlu->mlu_alias_valid) &&
2133 	    (mlu->mlu_alias_off >= sz)) ||
2134 	    ((mlu->mlu_mgmt_url_valid) &&
2135 	    (mlu->mlu_mgmt_url_off >= sz)) ||
2136 	    (mlu->mlu_by_fname) &&
2137 	    (mlu->mlu_fname_off >= sz)) {
2138 		return (EINVAL);
2139 	}
2140 
2141 	/*
2142 	 * We'll look for the device but if we don't find it registered,
2143 	 * we'll still try to modify the unregistered device.
2144 	 */
2145 	if (mlu->mlu_by_guid) {
2146 		sret = sbd_find_and_lock_lu(mlu->mlu_input_guid, NULL,
2147 		    SL_OP_MODIFY_LU, &sl);
2148 	} else if (mlu->mlu_by_fname) {
2149 		sret = sbd_find_and_lock_lu(NULL,
2150 		    (uint8_t *)&(mlu->mlu_buf[mlu->mlu_fname_off]),
2151 		    SL_OP_MODIFY_LU, &sl);
2152 	} else {
2153 		return (EINVAL);
2154 	}
2155 
2156 
2157 	if (sret != SBD_SUCCESS) {
2158 		if (sret == SBD_BUSY) {
2159 			*err_ret = SBD_RET_LU_BUSY;
2160 			return (EBUSY);
2161 		} else if (sret != SBD_NOT_FOUND) {
2162 			return (EIO);
2163 		} else if (!mlu->mlu_by_fname) {
2164 			return (EINVAL);
2165 		}
2166 		/* Okay, try to import the device */
2167 		struct_sz = max(8, strlen(&(mlu->mlu_buf[mlu->mlu_fname_off]))
2168 		    + 1);
2169 		struct_sz += sizeof (sbd_import_lu_t) - 8;
2170 		ilu_sz = struct_sz;
2171 		ilu = (sbd_import_lu_t *)kmem_zalloc(ilu_sz, KM_SLEEP);
2172 		ilu->ilu_struct_size = struct_sz;
2173 		(void) strcpy(ilu->ilu_meta_fname,
2174 		    &(mlu->mlu_buf[mlu->mlu_fname_off]));
2175 		ret = sbd_import_lu(ilu, struct_sz, err_ret, 1, &sl);
2176 		kmem_free(ilu, ilu_sz);
2177 		if (ret != SBD_SUCCESS) {
2178 			return (ENOENT);
2179 		}
2180 		modify_unregistered = 1;
2181 	}
2182 
2183 	/* check for write cache change */
2184 	if (mlu->mlu_writeback_cache_disable_valid) {
2185 		/* set wce on device */
2186 		sret = sbd_wcd_set(mlu->mlu_writeback_cache_disable, sl);
2187 		if (!mlu->mlu_writeback_cache_disable && sret != SBD_SUCCESS) {
2188 			*err_ret = SBD_RET_WRITE_CACHE_SET_FAILED;
2189 			ret = EFAULT;
2190 			goto smm_err_out;
2191 		}
2192 		mutex_enter(&sl->sl_lock);
2193 		if (!mlu->mlu_writeback_cache_disable) {
2194 			if (sl->sl_flags & SL_WRITEBACK_CACHE_DISABLE) {
2195 				ua = 1;
2196 				sl->sl_flags &= ~SL_WRITEBACK_CACHE_DISABLE;
2197 				sl->sl_flags &= ~SL_SAVED_WRITE_CACHE_DISABLE;
2198 			}
2199 		} else {
2200 			if ((sl->sl_flags & SL_WRITEBACK_CACHE_DISABLE) == 0) {
2201 				ua = 1;
2202 				sl->sl_flags |= SL_WRITEBACK_CACHE_DISABLE;
2203 				sl->sl_flags |= SL_SAVED_WRITE_CACHE_DISABLE;
2204 			}
2205 		}
2206 		for (it = sl->sl_it_list; ua && it != NULL;
2207 		    it = it->sbd_it_next) {
2208 			it->sbd_it_ua_conditions |=
2209 			    SBD_UA_MODE_PARAMETERS_CHANGED;
2210 		}
2211 		mutex_exit(&sl->sl_lock);
2212 	}
2213 	ua = 0;
2214 
2215 	if (mlu->mlu_alias_valid) {
2216 		alias_sz = strlen((char *)mlu->mlu_buf +
2217 		    mlu->mlu_alias_off) + 1;
2218 		/*
2219 		 * Use the allocated buffer or alloc a new one.
2220 		 * Don't copy into sl_alias if sl_alias_alloc_size is 0
2221 		 * otherwise or you'll be writing over the data/metadata
2222 		 * filename.
2223 		 */
2224 		mutex_enter(&sl->sl_lock);
2225 		if (sl->sl_alias_alloc_size > 0 &&
2226 		    sl->sl_alias_alloc_size < alias_sz) {
2227 			kmem_free(sl->sl_alias,
2228 			    sl->sl_alias_alloc_size);
2229 			sl->sl_alias_alloc_size = 0;
2230 		}
2231 		if (sl->sl_alias_alloc_size == 0) {
2232 			sl->sl_alias = kmem_alloc(alias_sz, KM_SLEEP);
2233 			sl->sl_alias_alloc_size = alias_sz;
2234 		}
2235 		(void) strcpy(sl->sl_alias, (char *)mlu->mlu_buf +
2236 		    mlu->mlu_alias_off);
2237 		lu = sl->sl_lu;
2238 		lu->lu_alias = sl->sl_alias;
2239 		mutex_exit(&sl->sl_lock);
2240 	}
2241 
2242 	if (mlu->mlu_mgmt_url_valid) {
2243 		uint16_t url_sz;
2244 
2245 		url_sz = strlen((char *)mlu->mlu_buf + mlu->mlu_mgmt_url_off);
2246 		if (url_sz > 0)
2247 			url_sz++;
2248 
2249 		mutex_enter(&sl->sl_lock);
2250 		if (sl->sl_mgmt_url_alloc_size > 0 &&
2251 		    (url_sz == 0 || sl->sl_mgmt_url_alloc_size < url_sz)) {
2252 			kmem_free(sl->sl_mgmt_url, sl->sl_mgmt_url_alloc_size);
2253 			sl->sl_mgmt_url = NULL;
2254 			sl->sl_mgmt_url_alloc_size = 0;
2255 		}
2256 		if (url_sz > 0) {
2257 			if (sl->sl_mgmt_url_alloc_size == 0) {
2258 				sl->sl_mgmt_url = kmem_alloc(url_sz, KM_SLEEP);
2259 				sl->sl_mgmt_url_alloc_size = url_sz;
2260 			}
2261 			(void) strcpy(sl->sl_mgmt_url, (char *)mlu->mlu_buf +
2262 			    mlu->mlu_mgmt_url_off);
2263 		}
2264 		for (it = sl->sl_it_list; it != NULL;
2265 		    it = it->sbd_it_next) {
2266 			it->sbd_it_ua_conditions |=
2267 			    SBD_UA_MODE_PARAMETERS_CHANGED;
2268 		}
2269 		mutex_exit(&sl->sl_lock);
2270 	}
2271 
2272 	if (mlu->mlu_write_protected_valid) {
2273 		mutex_enter(&sl->sl_lock);
2274 		if (mlu->mlu_write_protected) {
2275 			if ((sl->sl_flags & SL_WRITE_PROTECTED) == 0) {
2276 				ua = 1;
2277 				sl->sl_flags |= SL_WRITE_PROTECTED;
2278 			}
2279 		} else {
2280 			if (sl->sl_flags & SL_WRITE_PROTECTED) {
2281 				ua = 1;
2282 				sl->sl_flags &= ~SL_WRITE_PROTECTED;
2283 			}
2284 		}
2285 		for (it = sl->sl_it_list; ua && it != NULL;
2286 		    it = it->sbd_it_next) {
2287 			it->sbd_it_ua_conditions |=
2288 			    SBD_UA_MODE_PARAMETERS_CHANGED;
2289 		}
2290 		mutex_exit(&sl->sl_lock);
2291 	}
2292 
2293 	if (mlu->mlu_lu_size_valid) {
2294 		/*
2295 		 * validate lu size and set
2296 		 * For open file only (registered lu)
2297 		 */
2298 		mutex_enter(&sl->sl_lock);
2299 		old_size = sl->sl_lu_size;
2300 		sl->sl_lu_size = mlu->mlu_lu_size;
2301 		mutex_exit(&sl->sl_lock);
2302 		ret = sbd_open_data_file(sl, err_ret, 1, 1, 1);
2303 		if (ret) {
2304 			mutex_enter(&sl->sl_lock);
2305 			sl->sl_lu_size = old_size;
2306 			mutex_exit(&sl->sl_lock);
2307 			goto smm_err_out;
2308 		}
2309 		if (old_size != mlu->mlu_lu_size) {
2310 			mutex_enter(&sl->sl_lock);
2311 			for (it = sl->sl_it_list; it != NULL;
2312 			    it = it->sbd_it_next) {
2313 				it->sbd_it_ua_conditions |=
2314 				    SBD_UA_CAPACITY_CHANGED;
2315 			}
2316 			mutex_exit(&sl->sl_lock);
2317 		}
2318 	}
2319 
2320 	if (sbd_write_lu_info(sl) != SBD_SUCCESS) {
2321 		*err_ret = SBD_RET_META_CREATION_FAILED;
2322 		ret = EIO;
2323 	}
2324 
2325 smm_err_out:
2326 	if (modify_unregistered) {
2327 		(void) sbd_close_delete_lu(sl, 0);
2328 	} else {
2329 		sl->sl_trans_op = SL_OP_NONE;
2330 	}
2331 	return (ret);
2332 }
2333 
2334 /* ARGSUSED */
2335 int
2336 sbd_delete_locked_lu(sbd_lu_t *sl, uint32_t *err_ret,
2337     stmf_state_change_info_t *ssi)
2338 {
2339 	int i;
2340 
2341 	if ((sl->sl_state == STMF_STATE_OFFLINE) &&
2342 	    !sl->sl_state_not_acked) {
2343 		goto sdl_do_dereg;
2344 	}
2345 
2346 	if ((sl->sl_state != STMF_STATE_ONLINE) ||
2347 	    sl->sl_state_not_acked) {
2348 		return (EBUSY);
2349 	}
2350 	if (stmf_ctl(STMF_CMD_LU_OFFLINE, sl->sl_lu, ssi) != STMF_SUCCESS) {
2351 		return (EBUSY);
2352 	}
2353 
2354 	for (i = 0; i < 500; i++) {
2355 		if (sl->sl_state == STMF_STATE_OFFLINE)
2356 			break;
2357 		delay(drv_usectohz(10000));
2358 	}
2359 
2360 	if ((sl->sl_state == STMF_STATE_OFFLINE) &&
2361 	    !sl->sl_state_not_acked) {
2362 		goto sdl_do_dereg;
2363 	}
2364 
2365 	return (EBUSY);
2366 sdl_do_dereg:;
2367 	if (stmf_deregister_lu(sl->sl_lu) != STMF_SUCCESS)
2368 		return (EBUSY);
2369 	atomic_add_32(&sbd_lu_count, -1);
2370 
2371 	return (sbd_close_delete_lu(sl, 0));
2372 }
2373 
2374 int
2375 sbd_delete_lu(sbd_delete_lu_t *dlu, int struct_sz, uint32_t *err_ret)
2376 {
2377 	sbd_lu_t *sl;
2378 	sbd_status_t sret;
2379 	stmf_state_change_info_t ssi;
2380 	int ret;
2381 
2382 	if (dlu->dlu_by_meta_name) {
2383 		((char *)dlu)[struct_sz - 1] = 0;
2384 		sret = sbd_find_and_lock_lu(NULL, dlu->dlu_meta_name,
2385 		    SL_OP_DELETE_LU, &sl);
2386 	} else {
2387 		sret = sbd_find_and_lock_lu(dlu->dlu_guid, NULL,
2388 		    SL_OP_DELETE_LU, &sl);
2389 	}
2390 	if (sret != SBD_SUCCESS) {
2391 		if (sret == SBD_BUSY) {
2392 			*err_ret = SBD_RET_LU_BUSY;
2393 			return (EBUSY);
2394 		} else if (sret == SBD_NOT_FOUND) {
2395 			*err_ret = SBD_RET_NOT_FOUND;
2396 			return (ENOENT);
2397 		}
2398 		return (EIO);
2399 	}
2400 
2401 	ssi.st_rflags = STMF_RFLAG_USER_REQUEST;
2402 	ssi.st_additional_info = "sbd_delete_lu call (ioctl)";
2403 	ret = sbd_delete_locked_lu(sl, err_ret, &ssi);
2404 
2405 	if (ret) {
2406 		/* Once its locked, no need to grab mutex again */
2407 		sl->sl_trans_op = SL_OP_NONE;
2408 	}
2409 	return (ret);
2410 }
2411 
2412 sbd_status_t
2413 sbd_data_read(sbd_lu_t *sl, uint64_t offset, uint64_t size, uint8_t *buf)
2414 {
2415 	int ret;
2416 	long resid;
2417 
2418 	if ((offset + size) > sl->sl_lu_size) {
2419 		return (SBD_IO_PAST_EOF);
2420 	}
2421 
2422 	offset += sl->sl_data_offset;
2423 
2424 	if ((offset + size) > sl->sl_data_readable_size) {
2425 		uint64_t store_end;
2426 		if (offset > sl->sl_data_readable_size) {
2427 			bzero(buf, size);
2428 			return (SBD_SUCCESS);
2429 		}
2430 		store_end = sl->sl_data_readable_size - offset;
2431 		bzero(buf + store_end, size - store_end);
2432 		size = store_end;
2433 	}
2434 
2435 	DTRACE_PROBE4(backing__store__read__start, sbd_lu_t *, sl,
2436 	    uint8_t *, buf, uint64_t, size, uint64_t, offset);
2437 
2438 	ret = vn_rdwr(UIO_READ, sl->sl_data_vp, (caddr_t)buf, (ssize_t)size,
2439 	    (offset_t)offset, UIO_SYSSPACE, 0, RLIM64_INFINITY, CRED(),
2440 	    &resid);
2441 
2442 	DTRACE_PROBE5(backing__store__read__end, sbd_lu_t *, sl,
2443 	    uint8_t *, buf, uint64_t, size, uint64_t, offset,
2444 	    int, ret);
2445 
2446 over_sl_data_read:
2447 	if (ret || resid) {
2448 		stmf_trace(0, "UIO_READ failed, ret = %d, resid = %d", ret,
2449 		    resid);
2450 		return (SBD_FAILURE);
2451 	}
2452 
2453 	return (SBD_SUCCESS);
2454 }
2455 
2456 sbd_status_t
2457 sbd_data_write(sbd_lu_t *sl, uint64_t offset, uint64_t size, uint8_t *buf)
2458 {
2459 	int ret;
2460 	long resid;
2461 	sbd_status_t sret = SBD_SUCCESS;
2462 	int ioflag;
2463 
2464 	if ((offset + size) > sl->sl_lu_size) {
2465 		return (SBD_IO_PAST_EOF);
2466 	}
2467 
2468 	offset += sl->sl_data_offset;
2469 
2470 	if ((sl->sl_flags & SL_WRITEBACK_CACHE_DISABLE) &&
2471 	    (sl->sl_flags & SL_FLUSH_ON_DISABLED_WRITECACHE)) {
2472 		ioflag = FSYNC;
2473 	} else {
2474 		ioflag = 0;
2475 	}
2476 
2477 	DTRACE_PROBE4(backing__store__write__start, sbd_lu_t *, sl,
2478 	    uint8_t *, buf, uint64_t, size, uint64_t, offset);
2479 
2480 	ret = vn_rdwr(UIO_WRITE, sl->sl_data_vp, (caddr_t)buf, (ssize_t)size,
2481 	    (offset_t)offset, UIO_SYSSPACE, ioflag, RLIM64_INFINITY, CRED(),
2482 	    &resid);
2483 
2484 	DTRACE_PROBE5(backing__store__write__end, sbd_lu_t *, sl,
2485 	    uint8_t *, buf, uint64_t, size, uint64_t, offset,
2486 	    int, ret);
2487 
2488 	if ((ret == 0) && (resid == 0) &&
2489 	    (sl->sl_flags & SL_WRITEBACK_CACHE_DISABLE) &&
2490 	    (sl->sl_flags & SL_FLUSH_ON_DISABLED_WRITECACHE)) {
2491 		sret = sbd_flush_data_cache(sl, 1);
2492 	}
2493 over_sl_data_write:
2494 
2495 	if ((ret || resid) || (sret != SBD_SUCCESS)) {
2496 		return (SBD_FAILURE);
2497 	} else if ((offset + size) > sl->sl_data_readable_size) {
2498 		uint64_t old_size, new_size;
2499 
2500 		do {
2501 			old_size = sl->sl_data_readable_size;
2502 			if ((offset + size) <= old_size)
2503 				break;
2504 			new_size = offset + size;
2505 		} while (atomic_cas_64(&sl->sl_data_readable_size, old_size,
2506 		    new_size) != old_size);
2507 	}
2508 
2509 	return (SBD_SUCCESS);
2510 }
2511 
2512 int
2513 sbd_get_lu_props(sbd_lu_props_t *islp, uint32_t islp_sz,
2514     sbd_lu_props_t *oslp, uint32_t oslp_sz, uint32_t *err_ret)
2515 {
2516 	sbd_status_t sret;
2517 	sbd_lu_t *sl = NULL;
2518 	uint32_t sz;
2519 	uint16_t off;
2520 
2521 	if (islp->slp_input_guid) {
2522 		sret = sbd_find_and_lock_lu(islp->slp_guid, NULL,
2523 		    SL_OP_LU_PROPS, &sl);
2524 	} else {
2525 		((char *)islp)[islp_sz - 1] = 0;
2526 		sret = sbd_find_and_lock_lu(NULL, islp->slp_buf,
2527 		    SL_OP_LU_PROPS, &sl);
2528 	}
2529 	if (sret != SBD_SUCCESS) {
2530 		if (sret == SBD_BUSY) {
2531 			*err_ret = SBD_RET_LU_BUSY;
2532 			return (EBUSY);
2533 		} else if (sret == SBD_NOT_FOUND) {
2534 			*err_ret = SBD_RET_NOT_FOUND;
2535 			return (ENOENT);
2536 		}
2537 		return (EIO);
2538 	}
2539 
2540 	sz = strlen(sl->sl_name) + 1;
2541 	if ((sl->sl_flags & (SL_ZFS_META | SL_SHARED_META)) == 0) {
2542 		if (sl->sl_data_filename) {
2543 			sz += strlen(sl->sl_data_filename) + 1;
2544 		}
2545 	}
2546 	sz += sl->sl_serial_no_size;
2547 	if (sl->sl_alias) {
2548 		sz += strlen(sl->sl_alias) + 1;
2549 	}
2550 
2551 	if (sl->sl_mgmt_url) {
2552 		sz += strlen(sl->sl_mgmt_url) + 1;
2553 	}
2554 	bzero(oslp, sizeof (*oslp) - 8);
2555 	oslp->slp_buf_size_needed = sz;
2556 
2557 	if (sz > (oslp_sz - sizeof (*oslp) + 8)) {
2558 		sl->sl_trans_op = SL_OP_NONE;
2559 		*err_ret = SBD_RET_INSUFFICIENT_BUF_SPACE;
2560 		return (ENOMEM);
2561 	}
2562 
2563 	off = 0;
2564 	(void) strcpy((char *)oslp->slp_buf, sl->sl_name);
2565 	oslp->slp_meta_fname_off = off;
2566 	off += strlen(sl->sl_name) + 1;
2567 	if ((sl->sl_flags & (SL_ZFS_META | SL_SHARED_META)) == 0) {
2568 		oslp->slp_meta_fname_valid = 1;
2569 		oslp->slp_separate_meta = 1;
2570 		if (sl->sl_data_filename) {
2571 			oslp->slp_data_fname_valid = 1;
2572 			oslp->slp_data_fname_off = off;
2573 			(void) strcpy((char *)&oslp->slp_buf[off],
2574 			    sl->sl_data_filename);
2575 			off += strlen(sl->sl_data_filename) + 1;
2576 		}
2577 	} else {
2578 		oslp->slp_data_fname_valid = 1;
2579 		oslp->slp_data_fname_off = oslp->slp_meta_fname_off;
2580 		if (sl->sl_flags & SL_ZFS_META) {
2581 			oslp->slp_zfs_meta = 1;
2582 		}
2583 	}
2584 	if (sl->sl_alias) {
2585 		oslp->slp_alias_valid = 1;
2586 		oslp->slp_alias_off = off;
2587 		(void) strcpy((char *)&oslp->slp_buf[off], sl->sl_alias);
2588 		off += strlen(sl->sl_alias) + 1;
2589 	}
2590 	if (sl->sl_mgmt_url) {
2591 		oslp->slp_mgmt_url_valid = 1;
2592 		oslp->slp_mgmt_url_off = off;
2593 		(void) strcpy((char *)&oslp->slp_buf[off], sl->sl_mgmt_url);
2594 		off += strlen(sl->sl_mgmt_url) + 1;
2595 	}
2596 	if (sl->sl_serial_no_size) {
2597 		oslp->slp_serial_off = off;
2598 		bcopy(sl->sl_serial_no, &oslp->slp_buf[off],
2599 		    sl->sl_serial_no_size);
2600 		oslp->slp_serial_size = sl->sl_serial_no_size;
2601 		oslp->slp_serial_valid = 1;
2602 		off += sl->sl_serial_no_size;
2603 	}
2604 
2605 	oslp->slp_lu_size = sl->sl_lu_size;
2606 	oslp->slp_blksize = ((uint16_t)1) << sl->sl_data_blocksize_shift;
2607 
2608 	if (sl->sl_flags & SL_VID_VALID) {
2609 		oslp->slp_lu_vid = 1;
2610 		bcopy(sl->sl_vendor_id, oslp->slp_vid, 8);
2611 	} else {
2612 		bcopy(sbd_vendor_id, oslp->slp_vid, 8);
2613 	}
2614 	if (sl->sl_flags & SL_PID_VALID) {
2615 		oslp->slp_lu_pid = 1;
2616 		bcopy(sl->sl_product_id, oslp->slp_pid, 16);
2617 	} else {
2618 		bcopy(sbd_product_id, oslp->slp_pid, 16);
2619 	}
2620 	if (sl->sl_flags & SL_REV_VALID) {
2621 		oslp->slp_lu_rev = 1;
2622 		bcopy(sl->sl_revision, oslp->slp_rev, 4);
2623 	} else {
2624 		bcopy(sbd_revision, oslp->slp_rev, 4);
2625 	}
2626 	bcopy(sl->sl_device_id + 4, oslp->slp_guid, 16);
2627 
2628 	if (sl->sl_flags & SL_WRITEBACK_CACHE_DISABLE)
2629 		oslp->slp_writeback_cache_disable_cur = 1;
2630 	if (sl->sl_flags & SL_SAVED_WRITE_CACHE_DISABLE)
2631 		oslp->slp_writeback_cache_disable_saved = 1;
2632 	if (sl->sl_flags & SL_WRITE_PROTECTED)
2633 		oslp->slp_write_protected = 1;
2634 
2635 	sl->sl_trans_op = SL_OP_NONE;
2636 
2637 	return (0);
2638 }
2639 
2640 char *
2641 sbd_get_zvol_name(sbd_lu_t *sl)
2642 {
2643 	char *src;
2644 	char *p;
2645 
2646 	if (sl->sl_data_filename)
2647 		src = sl->sl_data_filename;
2648 	else
2649 		src = sl->sl_meta_filename;
2650 	/* There has to be a better way */
2651 	if (SBD_IS_ZVOL(src) != 0) {
2652 		ASSERT(0);
2653 	}
2654 	src += 14;
2655 	if (*src == '/')
2656 		src++;
2657 	p = (char *)kmem_alloc(strlen(src) + 1, KM_SLEEP);
2658 	(void) strcpy(p, src);
2659 	return (p);
2660 }
2661 
2662 /*
2663  * this function creates a local metadata zvol property
2664  */
2665 sbd_status_t
2666 sbd_create_zfs_meta_object(sbd_lu_t *sl)
2667 {
2668 	/*
2669 	 * -allocate 1/2 the property size, the zfs property
2670 	 *  is 8k in size and stored as ascii hex string, all
2671 	 *  we needed is 4k buffer to store the binary data.
2672 	 * -initialize reader/write lock
2673 	 */
2674 	if ((sl->sl_zfs_meta = kmem_zalloc(ZAP_MAXVALUELEN / 2, KM_SLEEP))
2675 	    == NULL)
2676 		return (SBD_FAILURE);
2677 	rw_init(&sl->sl_zfs_meta_lock, NULL, RW_DRIVER, NULL);
2678 	return (SBD_SUCCESS);
2679 }
2680 
2681 char
2682 sbd_ctoi(char c)
2683 {
2684 	if ((c >= '0') && (c <= '9'))
2685 		c -= '0';
2686 	else if ((c >= 'A') && (c <= 'F'))
2687 		c = c - 'A' + 10;
2688 	else if ((c >= 'a') && (c <= 'f'))
2689 		c = c - 'a' + 10;
2690 	else
2691 		c = -1;
2692 	return (c);
2693 }
2694 
2695 /*
2696  * read zvol property and convert to binary
2697  */
2698 sbd_status_t
2699 sbd_open_zfs_meta(sbd_lu_t *sl)
2700 {
2701 	char		*meta = NULL, cl, ch;
2702 	int		i;
2703 	char		*tmp, *ptr;
2704 	uint64_t	rc = SBD_SUCCESS;
2705 	int		len;
2706 	char		*file;
2707 
2708 	if (sl->sl_zfs_meta == NULL) {
2709 		if (sbd_create_zfs_meta_object(sl) == SBD_FAILURE)
2710 			return (SBD_FAILURE);
2711 	} else {
2712 		bzero(sl->sl_zfs_meta, (ZAP_MAXVALUELEN / 2));
2713 	}
2714 
2715 	rw_enter(&sl->sl_zfs_meta_lock, RW_WRITER);
2716 	file = sbd_get_zvol_name(sl);
2717 	if (sbd_zvolget(file, &meta)) {
2718 		rc = SBD_FAILURE;
2719 		goto done;
2720 	}
2721 	tmp = meta;
2722 	/* convert ascii hex to binary meta */
2723 	len = strlen(meta);
2724 	ptr = sl->sl_zfs_meta;
2725 	for (i = 0; i < len; i += 2) {
2726 		ch = sbd_ctoi(*tmp++);
2727 		cl = sbd_ctoi(*tmp++);
2728 		if (ch == -1 || cl == -1) {
2729 			rc = SBD_FAILURE;
2730 			break;
2731 		}
2732 		*ptr++ = (ch << 4) + cl;
2733 	}
2734 done:
2735 	rw_exit(&sl->sl_zfs_meta_lock);
2736 	if (meta)
2737 		kmem_free(meta, len + 1);
2738 	kmem_free(file, strlen(file) + 1);
2739 	return (rc);
2740 }
2741 
2742 sbd_status_t
2743 sbd_read_zfs_meta(sbd_lu_t *sl, uint8_t *buf, uint64_t sz, uint64_t off)
2744 {
2745 	ASSERT(sl->sl_zfs_meta);
2746 	rw_enter(&sl->sl_zfs_meta_lock, RW_READER);
2747 	bcopy(&sl->sl_zfs_meta[off], buf, sz);
2748 	rw_exit(&sl->sl_zfs_meta_lock);
2749 	return (SBD_SUCCESS);
2750 }
2751 
2752 sbd_status_t
2753 sbd_write_zfs_meta(sbd_lu_t *sl, uint8_t *buf, uint64_t sz, uint64_t off)
2754 {
2755 	char		*ptr, *ah_meta;
2756 	char		*dp = NULL;
2757 	int		i, num;
2758 	char		*file;
2759 
2760 	ASSERT(sl->sl_zfs_meta);
2761 	if ((off + sz) > (ZAP_MAXVALUELEN / 2 - 1)) {
2762 		return (SBD_META_CORRUPTED);
2763 	}
2764 	if ((off + sz) > sl->sl_meta_size_used) {
2765 		sl->sl_meta_size_used = off + sz;
2766 		if (sl->sl_total_meta_size < sl->sl_meta_size_used) {
2767 			uint64_t meta_align =
2768 			    (((uint64_t)1) << sl->sl_meta_blocksize_shift) - 1;
2769 			sl->sl_total_meta_size = (sl->sl_meta_size_used +
2770 			    meta_align) & (~meta_align);
2771 		}
2772 	}
2773 	ptr = ah_meta = kmem_zalloc(ZAP_MAXVALUELEN, KM_SLEEP);
2774 	rw_enter(&sl->sl_zfs_meta_lock, RW_WRITER);
2775 	bcopy(buf, &sl->sl_zfs_meta[off], sz);
2776 	/* convert local copy to ascii hex */
2777 	dp = sl->sl_zfs_meta;
2778 	for (i = 0; i < sl->sl_total_meta_size; i++, dp++) {
2779 		num = ((*dp) >> 4) & 0xF;
2780 		*ah_meta++ = (num < 10) ? (num + '0') : (num + ('a' - 10));
2781 		num = (*dp) & 0xF;
2782 		*ah_meta++ = (num < 10) ? (num + '0') : (num + ('a' - 10));
2783 	}
2784 	*ah_meta = NULL;
2785 	file = sbd_get_zvol_name(sl);
2786 	if (sbd_zvolset(file, (char *)ptr)) {
2787 		rw_exit(&sl->sl_zfs_meta_lock);
2788 		kmem_free(ptr, ZAP_MAXVALUELEN);
2789 		kmem_free(file, strlen(file) + 1);
2790 		return (SBD_META_CORRUPTED);
2791 	}
2792 	rw_exit(&sl->sl_zfs_meta_lock);
2793 	kmem_free(ptr, ZAP_MAXVALUELEN);
2794 	kmem_free(file, strlen(file) + 1);
2795 	return (SBD_SUCCESS);
2796 }
2797 
2798 int
2799 sbd_is_zvol(char *path)
2800 {
2801 	int is_zfs = 0;
2802 
2803 	if (SBD_IS_ZVOL(path) == 0)
2804 		is_zfs = 1;
2805 
2806 	return (is_zfs);
2807 }
2808 
2809 /*
2810  * set write cache disable
2811  * wcd - 1 = disable, 0 = enable
2812  */
2813 sbd_status_t
2814 sbd_wcd_set(int wcd, sbd_lu_t *sl)
2815 {
2816 	/* translate to wce bit */
2817 	int wce = wcd ? 0 : 1;
2818 	int ret;
2819 	sbd_status_t sret = SBD_SUCCESS;
2820 
2821 	mutex_enter(&sl->sl_lock);
2822 	sl->sl_flags &= ~SL_WRITEBACK_CACHE_SET_UNSUPPORTED;
2823 
2824 	if (sl->sl_data_vp->v_type == VREG) {
2825 		sl->sl_flags |= SL_FLUSH_ON_DISABLED_WRITECACHE;
2826 		goto done;
2827 	}
2828 
2829 	ret = VOP_IOCTL(sl->sl_data_vp, DKIOCSETWCE, (intptr_t)&wce, FKIOCTL,
2830 	    kcred, NULL, NULL);
2831 	if (ret == 0) {
2832 		sl->sl_flags &= ~SL_WRITEBACK_CACHE_SET_UNSUPPORTED;
2833 		sl->sl_flags &= ~SL_FLUSH_ON_DISABLED_WRITECACHE;
2834 	} else {
2835 		sl->sl_flags |= SL_WRITEBACK_CACHE_SET_UNSUPPORTED;
2836 		sl->sl_flags |= SL_FLUSH_ON_DISABLED_WRITECACHE;
2837 		sret = SBD_FAILURE;
2838 		goto done;
2839 	}
2840 
2841 done:
2842 	mutex_exit(&sl->sl_lock);
2843 	return (sret);
2844 }
2845 
2846 /*
2847  * get write cache disable
2848  * wcd - 1 = disable, 0 = enable
2849  */
2850 void
2851 sbd_wcd_get(int *wcd, sbd_lu_t *sl)
2852 {
2853 	int wce;
2854 	int ret;
2855 
2856 	if (sl->sl_data_vp->v_type == VREG) {
2857 		*wcd = 0;
2858 		return;
2859 	}
2860 
2861 	ret = VOP_IOCTL(sl->sl_data_vp, DKIOCGETWCE, (intptr_t)&wce, FKIOCTL,
2862 	    kcred, NULL, NULL);
2863 	/* if write cache get failed, assume disabled */
2864 	if (ret) {
2865 		*wcd = 1;
2866 	} else {
2867 		/* translate to wcd bit */
2868 		*wcd = wce ? 0 : 1;
2869 	}
2870 }
2871 
2872 int
2873 sbd_zvolget(char *zvol_name, char **comstarprop)
2874 {
2875 	ldi_handle_t	zfs_lh;
2876 	nvlist_t	*nv = NULL, *nv2;
2877 	zfs_cmd_t	*zc;
2878 	char		*ptr;
2879 	int size = 1024;
2880 	int unused;
2881 	int rc;
2882 
2883 	if ((rc = ldi_open_by_name("/dev/zfs", FREAD | FWRITE, kcred,
2884 	    &zfs_lh, sbd_zfs_ident)) != 0) {
2885 		cmn_err(CE_WARN, "ldi_open %d", rc);
2886 		return (ENXIO);
2887 	}
2888 
2889 	zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP);
2890 	(void) strlcpy(zc->zc_name, zvol_name, sizeof (zc->zc_name));
2891 again:
2892 	zc->zc_nvlist_dst = (uint64_t)(intptr_t)kmem_alloc(size,
2893 	    KM_SLEEP);
2894 	zc->zc_nvlist_dst_size = size;
2895 	rc = ldi_ioctl(zfs_lh, ZFS_IOC_OBJSET_STATS, (intptr_t)zc,
2896 	    FKIOCTL, kcred, &unused);
2897 	/*
2898 	 * ENOMEM means the list is larger than what we've allocated
2899 	 * ldi_ioctl will fail with ENOMEM only once
2900 	 */
2901 	if (rc == ENOMEM) {
2902 		int newsize;
2903 		newsize = zc->zc_nvlist_dst_size;
2904 		kmem_free((void *)(uintptr_t)zc->zc_nvlist_dst, size);
2905 		size = newsize;
2906 		goto again;
2907 	} else if (rc != 0) {
2908 		goto out;
2909 	}
2910 	rc = nvlist_unpack((char *)(uintptr_t)zc->zc_nvlist_dst,
2911 	    zc->zc_nvlist_dst_size, &nv, 0);
2912 	ASSERT(rc == 0);	/* nvlist_unpack should not fail */
2913 	if ((rc = nvlist_lookup_nvlist(nv, "stmf_sbd_lu", &nv2)) == 0) {
2914 		rc = nvlist_lookup_string(nv2, ZPROP_VALUE, &ptr);
2915 		if (rc != 0) {
2916 			cmn_err(CE_WARN, "couldn't get value");
2917 		} else {
2918 			*comstarprop = kmem_alloc(strlen(ptr) + 1,
2919 			    KM_SLEEP);
2920 			(void) strcpy(*comstarprop, ptr);
2921 		}
2922 	}
2923 out:
2924 	if (nv != NULL)
2925 		nvlist_free(nv);
2926 	kmem_free((void *)(uintptr_t)zc->zc_nvlist_dst, size);
2927 	kmem_free(zc, sizeof (zfs_cmd_t));
2928 	(void) ldi_close(zfs_lh, FREAD|FWRITE, kcred);
2929 
2930 	return (rc);
2931 }
2932 
2933 int
2934 sbd_zvolset(char *zvol_name, char *comstarprop)
2935 {
2936 	ldi_handle_t	zfs_lh;
2937 	nvlist_t	*nv;
2938 	char		*packed = NULL;
2939 	size_t		len;
2940 	zfs_cmd_t	*zc;
2941 	int unused;
2942 	int rc;
2943 
2944 	if ((rc = ldi_open_by_name("/dev/zfs", FREAD | FWRITE, kcred,
2945 	    &zfs_lh, sbd_zfs_ident)) != 0) {
2946 		cmn_err(CE_WARN, "ldi_open %d", rc);
2947 		return (ENXIO);
2948 	}
2949 	(void) nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP);
2950 	(void) nvlist_add_string(nv, "stmf_sbd_lu", comstarprop);
2951 	if ((rc = nvlist_pack(nv, &packed, &len, NV_ENCODE_NATIVE, KM_SLEEP))) {
2952 		goto out;
2953 	}
2954 
2955 	zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP);
2956 	(void) strlcpy(zc->zc_name, zvol_name, sizeof (zc->zc_name));
2957 	zc->zc_nvlist_src = (uint64_t)(intptr_t)packed;
2958 	zc->zc_nvlist_src_size = len;
2959 	rc = ldi_ioctl(zfs_lh, ZFS_IOC_SET_PROP, (intptr_t)zc,
2960 	    FKIOCTL, kcred, &unused);
2961 	if (rc != 0) {
2962 		cmn_err(CE_NOTE, "ioctl failed %d", rc);
2963 	}
2964 	kmem_free(zc, sizeof (zfs_cmd_t));
2965 	if (packed)
2966 		kmem_free(packed, len);
2967 out:
2968 	nvlist_free(nv);
2969 	(void) ldi_close(zfs_lh, FREAD|FWRITE, kcred);
2970 	return (rc);
2971 }
2972