xref: /illumos-gate/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 	if (((*ppsms) == NULL) || ((*ppsms)->sms_offset == 0)) {
874 		bzero(&sms, sizeof (sm_section_hdr_t));
875 		sms.sms_id = sms_id;
876 		if ((ret = sbd_load_section_hdr(sl, &sms)) != SBD_SUCCESS) {
877 			return (ret);
878 		} else {
879 			if ((*ppsms) == NULL) {
880 				*ppsms = (sm_section_hdr_t *)kmem_zalloc(
881 				    sms.sms_size, KM_SLEEP);
882 				alloced = 1;
883 			}
884 			bcopy(&sms, *ppsms, sizeof (sm_section_hdr_t));
885 		}
886 	}
887 
888 	ret = sbd_read_meta(sl, (*ppsms)->sms_offset, (*ppsms)->sms_size,
889 	    (uint8_t *)(*ppsms));
890 	if (ret == SBD_SUCCESS) {
891 		uint8_t s;
892 		if ((*ppsms)->sms_data_order != SMS_DATA_ORDER)
893 			sbd_swap_section_hdr(*ppsms);
894 		if ((*ppsms)->sms_id != SMS_ID_UNUSED) {
895 			s = sbd_calc_section_sum(*ppsms, (*ppsms)->sms_size);
896 			if (s != (*ppsms)->sms_chksum)
897 				ret = SBD_META_CORRUPTED;
898 		}
899 	}
900 
901 	if ((ret != SBD_SUCCESS) && alloced)
902 		kmem_free(*ppsms, sms.sms_size);
903 	return (ret);
904 }
905 
906 sbd_status_t
907 sbd_write_meta_section(sbd_lu_t *sl, sm_section_hdr_t *sms)
908 {
909 	sm_section_hdr_t t;
910 	uint64_t off, s;
911 	uint64_t unused_start;
912 	sbd_status_t ret;
913 	uint8_t *cb;
914 	int update_meta_start = 0;
915 
916 write_meta_section_again:
917 	if (sms->sms_offset) {
918 		/* Verify that size has not changed */
919 		ret = sbd_read_meta(sl, sms->sms_offset, sizeof (t),
920 		    (uint8_t *)&t);
921 		if (ret != SBD_SUCCESS)
922 			return (ret);
923 		if (t.sms_data_order != SMS_DATA_ORDER) {
924 			sbd_swap_section_hdr(&t);
925 		}
926 		if (t.sms_id != sms->sms_id) {
927 			return (SBD_INVALID_ARG);
928 		}
929 		if (t.sms_size == sms->sms_size) {
930 			return (sbd_write_meta(sl, sms->sms_offset,
931 			    sms->sms_size, (uint8_t *)sms));
932 		}
933 		t.sms_id = SMS_ID_UNUSED;
934 		/*
935 		 * For unused sections we only use chksum of the header. for
936 		 * all other sections, the chksum is for the entire section.
937 		 */
938 		t.sms_chksum = sbd_calc_section_sum(&t, sizeof (t));
939 		ret = sbd_write_meta(sl, t.sms_offset, sizeof (t),
940 		    (uint8_t *)&t);
941 		if (ret != SBD_SUCCESS)
942 			return (ret);
943 		sms->sms_offset = 0;
944 	} else {
945 		t.sms_id = sms->sms_id;
946 		t.sms_data_order = SMS_DATA_ORDER;
947 		ret = sbd_load_section_hdr(sl, &t);
948 		if (ret == SBD_SUCCESS) {
949 			sms->sms_offset = t.sms_offset;
950 			sms->sms_chksum =
951 			    sbd_calc_section_sum(sms, sms->sms_size);
952 			goto write_meta_section_again;
953 		} else if (ret != SBD_NOT_FOUND) {
954 			return (ret);
955 		}
956 	}
957 
958 	/*
959 	 * At this point we know that section does not already exist.
960 	 * find space large enough to hold the section or grow meta if
961 	 * possible.
962 	 */
963 	unused_start = 0;
964 	s = 0;
965 	for (off = sl->sl_meta_offset + sizeof (sbd_meta_start_t);
966 	    off < sl->sl_meta_size_used; off += t.sms_size) {
967 		ret = sbd_read_meta(sl, off, sizeof (t), (uint8_t *)&t);
968 		if (ret != SBD_SUCCESS)
969 			return (ret);
970 		if (t.sms_data_order != SMS_DATA_ORDER)
971 			sbd_swap_section_hdr(&t);
972 		if (t.sms_size == 0)
973 			return (SBD_META_CORRUPTED);
974 		if (t.sms_id == SMS_ID_UNUSED) {
975 			if (unused_start == 0)
976 				unused_start = off;
977 			s = t.sms_size - unused_start + off;
978 			if ((s == sms->sms_size) || (s >= (sms->sms_size +
979 			    sizeof (t)))) {
980 				break;
981 			} else {
982 				s = 0;
983 			}
984 		} else {
985 			unused_start = 0;
986 		}
987 	}
988 
989 	off = (unused_start == 0) ? sl->sl_meta_size_used : unused_start;
990 	if (s == 0) {
991 		s = sl->sl_total_meta_size - off;
992 		/* Lets see if we can expand the metadata */
993 		if (s >= sms->sms_size || !(sl->sl_flags & SL_SHARED_META)) {
994 			s = sms->sms_size;
995 			update_meta_start = 1;
996 		} else {
997 			s = 0;
998 		}
999 	}
1000 
1001 	if (s == 0)
1002 		return (SBD_ALLOC_FAILURE);
1003 
1004 	sms->sms_offset = off;
1005 	sms->sms_chksum = sbd_calc_section_sum(sms, sms->sms_size);
1006 	/*
1007 	 * Since we may have to write more than one section (current +
1008 	 * any unused), use a combined buffer.
1009 	 */
1010 	cb = kmem_zalloc(s, KM_SLEEP);
1011 	bcopy(sms, cb, sms->sms_size);
1012 	if (s > sms->sms_size) {
1013 		t.sms_offset = off + sms->sms_size;
1014 		t.sms_size = s - sms->sms_size;
1015 		t.sms_id = SMS_ID_UNUSED;
1016 		t.sms_data_order = SMS_DATA_ORDER;
1017 		t.sms_chksum = sbd_calc_section_sum(&t, sizeof (t));
1018 		bcopy(&t, cb + sms->sms_size, sizeof (t));
1019 	}
1020 	ret = sbd_write_meta(sl, off, s, cb);
1021 	kmem_free(cb, s);
1022 	if (ret != SBD_SUCCESS)
1023 		return (ret);
1024 
1025 	if (update_meta_start) {
1026 		uint64_t old_sz_used = sl->sl_meta_size_used; /* save a copy */
1027 		sl->sl_meta_size_used = off + s;
1028 		s = sl->sl_total_meta_size; /* save a copy */
1029 		if (sl->sl_total_meta_size < sl->sl_meta_size_used) {
1030 			uint64_t meta_align =
1031 			    (((uint64_t)1) << sl->sl_meta_blocksize_shift) - 1;
1032 			sl->sl_total_meta_size = (sl->sl_meta_size_used +
1033 			    meta_align) & (~meta_align);
1034 		}
1035 		ret = sbd_write_meta_start(sl, sl->sl_total_meta_size,
1036 		    sl->sl_meta_size_used);
1037 		if (ret != SBD_SUCCESS) {
1038 			sl->sl_meta_size_used = old_sz_used;
1039 			sl->sl_total_meta_size = s;
1040 		}
1041 	}
1042 	return (ret);
1043 }
1044 
1045 sbd_status_t
1046 sbd_write_lu_info(sbd_lu_t *sl)
1047 {
1048 	sbd_lu_info_1_1_t *sli;
1049 	int s;
1050 	uint8_t *p;
1051 	char *zvol_name = NULL;
1052 	sbd_status_t ret;
1053 
1054 	mutex_enter(&sl->sl_lock);
1055 
1056 	s = sl->sl_serial_no_size;
1057 	if ((sl->sl_flags & (SL_SHARED_META | SL_ZFS_META)) == 0) {
1058 		if (sl->sl_data_filename) {
1059 			s += strlen(sl->sl_data_filename) + 1;
1060 		}
1061 	}
1062 	if (sl->sl_flags & SL_ZFS_META) {
1063 		zvol_name = sbd_get_zvol_name(sl);
1064 		s += strlen(zvol_name) + 1;
1065 	}
1066 	if (sl->sl_alias) {
1067 		s += strlen(sl->sl_alias) + 1;
1068 	}
1069 	if (sl->sl_mgmt_url) {
1070 		s += strlen(sl->sl_mgmt_url) + 1;
1071 	}
1072 	sli = (sbd_lu_info_1_1_t *)kmem_zalloc(sizeof (*sli) + s, KM_SLEEP);
1073 	p = sli->sli_buf;
1074 	if ((sl->sl_flags & (SL_SHARED_META | SL_ZFS_META)) == 0) {
1075 		sli->sli_flags |= SLI_SEPARATE_META;
1076 		(void) strcpy((char *)p, sl->sl_data_filename);
1077 		sli->sli_data_fname_offset =
1078 		    (uintptr_t)p - (uintptr_t)sli->sli_buf;
1079 		sli->sli_flags |= SLI_DATA_FNAME_VALID;
1080 		p += strlen(sl->sl_data_filename) + 1;
1081 	}
1082 	if (sl->sl_flags & SL_ZFS_META) {
1083 		(void) strcpy((char *)p, zvol_name);
1084 		sli->sli_meta_fname_offset =
1085 		    (uintptr_t)p - (uintptr_t)sli->sli_buf;
1086 		sli->sli_flags |= SLI_META_FNAME_VALID | SLI_ZFS_META;
1087 		p += strlen(zvol_name) + 1;
1088 		kmem_free(zvol_name, strlen(zvol_name) + 1);
1089 		zvol_name = NULL;
1090 	}
1091 	if (sl->sl_alias) {
1092 		(void) strcpy((char *)p, sl->sl_alias);
1093 		sli->sli_alias_offset =
1094 		    (uintptr_t)p - (uintptr_t)sli->sli_buf;
1095 		sli->sli_flags |= SLI_ALIAS_VALID;
1096 		p += strlen(sl->sl_alias) + 1;
1097 	}
1098 	if (sl->sl_mgmt_url) {
1099 		(void) strcpy((char *)p, sl->sl_mgmt_url);
1100 		sli->sli_mgmt_url_offset =
1101 		    (uintptr_t)p - (uintptr_t)sli->sli_buf;
1102 		sli->sli_flags |= SLI_MGMT_URL_VALID;
1103 		p += strlen(sl->sl_mgmt_url) + 1;
1104 	}
1105 	if (sl->sl_flags & SL_WRITE_PROTECTED) {
1106 		sli->sli_flags |= SLI_WRITE_PROTECTED;
1107 	}
1108 	if (sl->sl_flags & SL_SAVED_WRITE_CACHE_DISABLE) {
1109 		sli->sli_flags |= SLI_WRITEBACK_CACHE_DISABLE;
1110 	}
1111 	if (sl->sl_flags & SL_VID_VALID) {
1112 		bcopy(sl->sl_vendor_id, sli->sli_vid, 8);
1113 		sli->sli_flags |= SLI_VID_VALID;
1114 	}
1115 	if (sl->sl_flags & SL_PID_VALID) {
1116 		bcopy(sl->sl_product_id, sli->sli_pid, 16);
1117 		sli->sli_flags |= SLI_PID_VALID;
1118 	}
1119 	if (sl->sl_flags & SL_REV_VALID) {
1120 		bcopy(sl->sl_revision, sli->sli_rev, 4);
1121 		sli->sli_flags |= SLI_REV_VALID;
1122 	}
1123 	if (sl->sl_serial_no_size) {
1124 		bcopy(sl->sl_serial_no, p, sl->sl_serial_no_size);
1125 		sli->sli_serial_size = sl->sl_serial_no_size;
1126 		sli->sli_serial_offset =
1127 		    (uintptr_t)p - (uintptr_t)sli->sli_buf;
1128 		sli->sli_flags |= SLI_SERIAL_VALID;
1129 		p += sli->sli_serial_size;
1130 	}
1131 	sli->sli_lu_size = sl->sl_lu_size;
1132 	sli->sli_data_blocksize_shift = sl->sl_data_blocksize_shift;
1133 	sli->sli_data_order = SMS_DATA_ORDER;
1134 	bcopy(sl->sl_device_id, sli->sli_device_id, 20);
1135 
1136 	sli->sli_sms_header.sms_size = sizeof (*sli) + s;
1137 	sli->sli_sms_header.sms_id = SMS_ID_LU_INFO_1_1;
1138 	sli->sli_sms_header.sms_data_order = SMS_DATA_ORDER;
1139 
1140 	mutex_exit(&sl->sl_lock);
1141 	ret = sbd_write_meta_section(sl, (sm_section_hdr_t *)sli);
1142 	kmem_free(sli, sizeof (*sli) + s);
1143 	return (ret);
1144 }
1145 
1146 int
1147 sbd_populate_and_register_lu(sbd_lu_t *sl, uint32_t *err_ret)
1148 {
1149 	stmf_lu_t *lu = sl->sl_lu;
1150 	stmf_status_t ret;
1151 
1152 	lu->lu_id = (scsi_devid_desc_t *)sl->sl_device_id;
1153 	if (sl->sl_alias) {
1154 		lu->lu_alias = sl->sl_alias;
1155 	} else {
1156 		lu->lu_alias = sl->sl_name;
1157 	}
1158 	lu->lu_lp = sbd_lp;
1159 	lu->lu_task_alloc = sbd_task_alloc;
1160 	lu->lu_new_task = sbd_new_task;
1161 	lu->lu_dbuf_xfer_done = sbd_dbuf_xfer_done;
1162 	lu->lu_send_status_done = sbd_send_status_done;
1163 	lu->lu_task_free = sbd_task_free;
1164 	lu->lu_abort = sbd_abort;
1165 	lu->lu_ctl = sbd_ctl;
1166 	lu->lu_info = sbd_info;
1167 	sl->sl_state = STMF_STATE_OFFLINE;
1168 
1169 	if ((ret = stmf_register_lu(lu)) != STMF_SUCCESS) {
1170 		stmf_trace(0, "Failed to register with framework, ret=%llx",
1171 		    ret);
1172 		if (ret == STMF_ALREADY) {
1173 			*err_ret = SBD_RET_GUID_ALREADY_REGISTERED;
1174 		}
1175 		return (EIO);
1176 	}
1177 
1178 	*err_ret = 0;
1179 	return (0);
1180 }
1181 
1182 int
1183 sbd_open_data_file(sbd_lu_t *sl, uint32_t *err_ret, int lu_size_valid,
1184     int vp_valid, int keep_open)
1185 {
1186 	int ret;
1187 	int flag;
1188 	ulong_t	nbits;
1189 	uint64_t supported_size;
1190 	vattr_t vattr;
1191 	enum vtype vt;
1192 
1193 	mutex_enter(&sl->sl_lock);
1194 	if (vp_valid) {
1195 		goto odf_over_open;
1196 	}
1197 	if (sl->sl_data_filename[0] != '/') {
1198 		*err_ret = SBD_RET_DATA_PATH_NOT_ABSOLUTE;
1199 		mutex_exit(&sl->sl_lock);
1200 		return (EINVAL);
1201 	}
1202 	if ((ret = lookupname(sl->sl_data_filename, UIO_SYSSPACE, FOLLOW,
1203 	    NULLVPP, &sl->sl_data_vp)) != 0) {
1204 		*err_ret = SBD_RET_DATA_FILE_LOOKUP_FAILED;
1205 		mutex_exit(&sl->sl_lock);
1206 		return (ret);
1207 	}
1208 	sl->sl_data_vtype = vt = sl->sl_data_vp->v_type;
1209 	VN_RELE(sl->sl_data_vp);
1210 	if ((vt != VREG) && (vt != VCHR) && (vt != VBLK)) {
1211 		*err_ret = SBD_RET_WRONG_DATA_FILE_TYPE;
1212 		mutex_exit(&sl->sl_lock);
1213 		return (EINVAL);
1214 	}
1215 	if (sl->sl_flags & SL_WRITE_PROTECTED) {
1216 		flag = FREAD | FOFFMAX;
1217 	} else {
1218 		flag = FREAD | FWRITE | FOFFMAX | FEXCL;
1219 	}
1220 	if ((ret = vn_open(sl->sl_data_filename, UIO_SYSSPACE, flag, 0,
1221 	    &sl->sl_data_vp, 0, 0)) != 0) {
1222 		*err_ret = SBD_RET_DATA_FILE_OPEN_FAILED;
1223 		mutex_exit(&sl->sl_lock);
1224 		return (ret);
1225 	}
1226 odf_over_open:
1227 	vattr.va_mask = AT_SIZE;
1228 	if ((ret = VOP_GETATTR(sl->sl_data_vp, &vattr, 0, CRED(), NULL)) != 0) {
1229 		*err_ret = SBD_RET_DATA_FILE_GETATTR_FAILED;
1230 		goto odf_close_data_and_exit;
1231 	}
1232 	if ((vt != VREG) && (vattr.va_size == 0)) {
1233 		/*
1234 		 * Its a zero byte block or char device. This cannot be
1235 		 * a raw disk.
1236 		 */
1237 		*err_ret = SBD_RET_WRONG_DATA_FILE_TYPE;
1238 		ret = EINVAL;
1239 		goto odf_close_data_and_exit;
1240 	}
1241 	/* sl_data_readable size includes any metadata. */
1242 	sl->sl_data_readable_size = vattr.va_size;
1243 	if (VOP_PATHCONF(sl->sl_data_vp, _PC_FILESIZEBITS, &nbits,
1244 	    CRED(), NULL) != 0) {
1245 		nbits = 0;
1246 	}
1247 	/* nbits cannot be greater than 64 */
1248 	sl->sl_data_fs_nbits = (uint8_t)nbits;
1249 	if (lu_size_valid) {
1250 		sl->sl_total_data_size = sl->sl_lu_size;
1251 		if (sl->sl_flags & SL_SHARED_META) {
1252 			sl->sl_total_data_size += SHARED_META_DATA_SIZE;
1253 		}
1254 		if ((nbits > 0) && (nbits < 64)) {
1255 			/*
1256 			 * The expression below is correct only if nbits is
1257 			 * positive and less than 64.
1258 			 */
1259 			supported_size = (((uint64_t)1) << nbits) - 1;
1260 			if (sl->sl_total_data_size > supported_size) {
1261 				*err_ret = SBD_RET_SIZE_NOT_SUPPORTED_BY_FS;
1262 				ret = EINVAL;
1263 				goto odf_close_data_and_exit;
1264 			}
1265 		}
1266 	} else {
1267 		sl->sl_total_data_size = vattr.va_size;
1268 		if (sl->sl_flags & SL_SHARED_META) {
1269 			if (vattr.va_size > SHARED_META_DATA_SIZE) {
1270 				sl->sl_lu_size = vattr.va_size -
1271 				    SHARED_META_DATA_SIZE;
1272 			} else {
1273 				*err_ret = SBD_RET_FILE_SIZE_ERROR;
1274 				ret = EINVAL;
1275 				goto odf_close_data_and_exit;
1276 			}
1277 		} else {
1278 			sl->sl_lu_size = vattr.va_size;
1279 		}
1280 	}
1281 	if (sl->sl_lu_size < SBD_MIN_LU_SIZE) {
1282 		*err_ret = SBD_RET_FILE_SIZE_ERROR;
1283 		ret = EINVAL;
1284 		goto odf_close_data_and_exit;
1285 	}
1286 	if (sl->sl_lu_size &
1287 	    ((((uint64_t)1) << sl->sl_data_blocksize_shift) - 1)) {
1288 		*err_ret = SBD_RET_FILE_ALIGN_ERROR;
1289 		ret = EINVAL;
1290 		goto odf_close_data_and_exit;
1291 	}
1292 	sl->sl_flags |= SL_MEDIA_LOADED;
1293 	mutex_exit(&sl->sl_lock);
1294 	return (0);
1295 
1296 odf_close_data_and_exit:
1297 	if (!keep_open) {
1298 		(void) VOP_CLOSE(sl->sl_data_vp, flag, 1, 0, CRED(), NULL);
1299 		VN_RELE(sl->sl_data_vp);
1300 	}
1301 	mutex_exit(&sl->sl_lock);
1302 	return (ret);
1303 }
1304 
1305 int
1306 sbd_close_delete_lu(sbd_lu_t *sl, int ret)
1307 {
1308 	int flag;
1309 
1310 	if (((sl->sl_flags & SL_SHARED_META) == 0) &&
1311 	    (sl->sl_flags & SL_META_OPENED)) {
1312 		if (sl->sl_flags & SL_ZFS_META) {
1313 			rw_destroy(&sl->sl_zfs_meta_lock);
1314 			if (sl->sl_zfs_meta) {
1315 				kmem_free(sl->sl_zfs_meta, ZAP_MAXVALUELEN / 2);
1316 			}
1317 		} else {
1318 			flag = FREAD | FWRITE | FOFFMAX | FEXCL;
1319 			(void) VOP_CLOSE(sl->sl_meta_vp, flag, 1, 0,
1320 			    CRED(), NULL);
1321 			VN_RELE(sl->sl_meta_vp);
1322 		}
1323 		sl->sl_flags &= ~SL_META_OPENED;
1324 	}
1325 	if (sl->sl_flags & SL_MEDIA_LOADED) {
1326 		if (sl->sl_flags & SL_WRITE_PROTECTED) {
1327 			flag = FREAD | FOFFMAX;
1328 		} else {
1329 			flag = FREAD | FWRITE | FOFFMAX | FEXCL;
1330 		}
1331 		(void) VOP_CLOSE(sl->sl_data_vp, flag, 1, 0, CRED(), NULL);
1332 		VN_RELE(sl->sl_data_vp);
1333 		sl->sl_flags &= ~SL_MEDIA_LOADED;
1334 		if (sl->sl_flags & SL_SHARED_META) {
1335 			sl->sl_flags &= ~SL_META_OPENED;
1336 		}
1337 	}
1338 	if (sl->sl_flags & SL_LINKED)
1339 		sbd_unlink_lu(sl);
1340 	mutex_destroy(&sl->sl_lock);
1341 	rw_destroy(&sl->sl_pgr->pgr_lock);
1342 	if (sl->sl_serial_no_alloc_size) {
1343 		kmem_free(sl->sl_serial_no, sl->sl_serial_no_alloc_size);
1344 	}
1345 	if (sl->sl_data_fname_alloc_size) {
1346 		kmem_free(sl->sl_data_filename, sl->sl_data_fname_alloc_size);
1347 	}
1348 	if (sl->sl_alias_alloc_size) {
1349 		kmem_free(sl->sl_alias, sl->sl_alias_alloc_size);
1350 	}
1351 	if (sl->sl_mgmt_url_alloc_size) {
1352 		kmem_free(sl->sl_mgmt_url, sl->sl_mgmt_url_alloc_size);
1353 	}
1354 	stmf_free(sl->sl_lu);
1355 	return (ret);
1356 }
1357 
1358 int
1359 sbd_create_register_lu(sbd_create_and_reg_lu_t *slu, int struct_sz,
1360     uint32_t *err_ret)
1361 {
1362 	char *namebuf;
1363 	sbd_lu_t *sl;
1364 	stmf_lu_t *lu;
1365 	sbd_status_t sret;
1366 	char *p;
1367 	int sz;
1368 	int alloc_sz;
1369 	int ret = EIO;
1370 	int flag;
1371 	int wcd = 0;
1372 	enum vtype vt;
1373 
1374 	sz = struct_sz - sizeof (sbd_create_and_reg_lu_t) + 8 + 1;
1375 
1376 	*err_ret = 0;
1377 
1378 	/* Lets validate various offsets */
1379 	if (((slu->slu_meta_fname_valid) &&
1380 	    (slu->slu_meta_fname_off >= sz)) ||
1381 	    (slu->slu_data_fname_off >= sz) ||
1382 	    ((slu->slu_alias_valid) &&
1383 	    (slu->slu_alias_off >= sz)) ||
1384 	    ((slu->slu_mgmt_url_valid) &&
1385 	    (slu->slu_mgmt_url_off >= sz)) ||
1386 	    ((slu->slu_serial_valid) &&
1387 	    ((slu->slu_serial_off + slu->slu_serial_size) >= sz))) {
1388 		return (EINVAL);
1389 	}
1390 
1391 	namebuf = kmem_zalloc(sz, KM_SLEEP);
1392 	bcopy(slu->slu_buf, namebuf, sz - 1);
1393 	namebuf[sz - 1] = 0;
1394 
1395 	alloc_sz = sizeof (sbd_lu_t) + sizeof (sbd_pgr_t);
1396 	if (slu->slu_meta_fname_valid) {
1397 		alloc_sz += strlen(namebuf + slu->slu_meta_fname_off) + 1;
1398 	}
1399 	alloc_sz += strlen(namebuf + slu->slu_data_fname_off) + 1;
1400 	if (slu->slu_alias_valid) {
1401 		alloc_sz += strlen(namebuf + slu->slu_alias_off) + 1;
1402 	}
1403 	if (slu->slu_mgmt_url_valid) {
1404 		alloc_sz += strlen(namebuf + slu->slu_mgmt_url_off) + 1;
1405 	}
1406 	if (slu->slu_serial_valid) {
1407 		alloc_sz += slu->slu_serial_size;
1408 	}
1409 
1410 	lu = (stmf_lu_t *)stmf_alloc(STMF_STRUCT_STMF_LU, alloc_sz, 0);
1411 	if (lu == NULL) {
1412 		kmem_free(namebuf, sz);
1413 		return (ENOMEM);
1414 	}
1415 	sl = (sbd_lu_t *)lu->lu_provider_private;
1416 	bzero(sl, alloc_sz);
1417 	sl->sl_lu = lu;
1418 	sl->sl_alloc_size = alloc_sz;
1419 	sl->sl_pgr = (sbd_pgr_t *)(sl + 1);
1420 	rw_init(&sl->sl_pgr->pgr_lock, NULL, RW_DRIVER, NULL);
1421 	mutex_init(&sl->sl_lock, NULL, MUTEX_DRIVER, NULL);
1422 	p = ((char *)sl) + sizeof (sbd_lu_t) + sizeof (sbd_pgr_t);
1423 	sl->sl_data_filename = p;
1424 	(void) strcpy(sl->sl_data_filename, namebuf + slu->slu_data_fname_off);
1425 	p += strlen(sl->sl_data_filename) + 1;
1426 	sl->sl_meta_offset = SBD_META_OFFSET;
1427 	if (slu->slu_meta_fname_valid) {
1428 		sl->sl_alias = sl->sl_name = sl->sl_meta_filename = p;
1429 		(void) strcpy(sl->sl_meta_filename, namebuf +
1430 		    slu->slu_meta_fname_off);
1431 		p += strlen(sl->sl_meta_filename) + 1;
1432 	} else {
1433 		sl->sl_alias = sl->sl_name = sl->sl_data_filename;
1434 		if (sbd_is_zvol(sl->sl_data_filename)) {
1435 			sl->sl_flags |= SL_ZFS_META;
1436 			sl->sl_meta_offset = 0;
1437 		} else {
1438 			sl->sl_flags |= SL_SHARED_META;
1439 			sl->sl_data_offset = SHARED_META_DATA_SIZE;
1440 			sl->sl_total_meta_size = SHARED_META_DATA_SIZE;
1441 			sl->sl_meta_size_used = 0;
1442 		}
1443 	}
1444 	if (slu->slu_alias_valid) {
1445 		sl->sl_alias = p;
1446 		(void) strcpy(p, namebuf + slu->slu_alias_off);
1447 		p += strlen(sl->sl_alias) + 1;
1448 	}
1449 	if (slu->slu_mgmt_url_valid) {
1450 		sl->sl_mgmt_url = p;
1451 		(void) strcpy(p, namebuf + slu->slu_mgmt_url_off);
1452 		p += strlen(sl->sl_mgmt_url) + 1;
1453 	}
1454 	if (slu->slu_serial_valid) {
1455 		sl->sl_serial_no = (uint8_t *)p;
1456 		bcopy(namebuf + slu->slu_serial_off, sl->sl_serial_no,
1457 		    slu->slu_serial_size);
1458 		sl->sl_serial_no_size = slu->slu_serial_size;
1459 		p += slu->slu_serial_size;
1460 	}
1461 	kmem_free(namebuf, sz);
1462 	if (slu->slu_vid_valid) {
1463 		bcopy(slu->slu_vid, sl->sl_vendor_id, 8);
1464 		sl->sl_flags |= SL_VID_VALID;
1465 	}
1466 	if (slu->slu_pid_valid) {
1467 		bcopy(slu->slu_pid, sl->sl_product_id, 16);
1468 		sl->sl_flags |= SL_PID_VALID;
1469 	}
1470 	if (slu->slu_rev_valid) {
1471 		bcopy(slu->slu_rev, sl->sl_revision, 4);
1472 		sl->sl_flags |= SL_REV_VALID;
1473 	}
1474 	if (slu->slu_write_protected) {
1475 		sl->sl_flags |= SL_WRITE_PROTECTED;
1476 	}
1477 	if (slu->slu_writeback_cache_disable) {
1478 		sl->sl_flags |= SL_WRITEBACK_CACHE_DISABLE |
1479 		    SL_SAVED_WRITE_CACHE_DISABLE;
1480 	}
1481 
1482 	if (slu->slu_blksize_valid) {
1483 		if ((slu->slu_blksize & (slu->slu_blksize - 1)) ||
1484 		    (slu->slu_blksize > (32 * 1024)) ||
1485 		    (slu->slu_blksize == 0)) {
1486 			*err_ret = SBD_RET_INVALID_BLKSIZE;
1487 			ret = EINVAL;
1488 			goto scm_err_out;
1489 		}
1490 		while ((1 << sl->sl_data_blocksize_shift) != slu->slu_blksize) {
1491 			sl->sl_data_blocksize_shift++;
1492 		}
1493 	} else {
1494 		sl->sl_data_blocksize_shift = 9;	/* 512 by default */
1495 		slu->slu_blksize = 512;
1496 	}
1497 
1498 	/* Now lets start creating meta */
1499 	sl->sl_trans_op = SL_OP_CREATE_REGISTER_LU;
1500 	if (sbd_link_lu(sl) != SBD_SUCCESS) {
1501 		*err_ret = SBD_RET_FILE_ALREADY_REGISTERED;
1502 		ret = EALREADY;
1503 		goto scm_err_out;
1504 	}
1505 
1506 	/* 1st focus on the data store */
1507 	if (slu->slu_lu_size_valid) {
1508 		sl->sl_lu_size = slu->slu_lu_size;
1509 	}
1510 	ret = sbd_open_data_file(sl, err_ret, slu->slu_lu_size_valid, 0, 0);
1511 	slu->slu_ret_filesize_nbits = sl->sl_data_fs_nbits;
1512 	slu->slu_lu_size = sl->sl_lu_size;
1513 	if (ret) {
1514 		goto scm_err_out;
1515 	}
1516 
1517 	/*
1518 	 * set write cache disable on the device
1519 	 * if it fails, we'll support it using sync/flush
1520 	 */
1521 	if (slu->slu_writeback_cache_disable) {
1522 		(void) sbd_wcd_set(1, sl);
1523 		wcd = 1;
1524 	/*
1525 	 * Attempt to set it to enable, if that fails and it was explicitly set
1526 	 * return an error, otherwise get the current setting and use that
1527 	 */
1528 	} else {
1529 		sret = sbd_wcd_set(0, sl);
1530 		if (slu->slu_writeback_cache_disable_valid &&
1531 		    sret != SBD_SUCCESS) {
1532 			*err_ret = SBD_RET_WRITE_CACHE_SET_FAILED;
1533 			ret = EFAULT;
1534 			goto scm_err_out;
1535 		}
1536 		if (sret != SBD_SUCCESS) {
1537 			sbd_wcd_get(&wcd, sl);
1538 		}
1539 	}
1540 
1541 	if (wcd) {
1542 		sl->sl_flags |= SL_WRITEBACK_CACHE_DISABLE |
1543 		    SL_SAVED_WRITE_CACHE_DISABLE;
1544 	}
1545 
1546 	if (sl->sl_flags & SL_SHARED_META) {
1547 		goto over_meta_open;
1548 	}
1549 	if (sl->sl_flags & SL_ZFS_META) {
1550 		if (sbd_create_zfs_meta_object(sl) != SBD_SUCCESS) {
1551 			*err_ret = SBD_RET_ZFS_META_CREATE_FAILED;
1552 			ret = ENOMEM;
1553 			goto scm_err_out;
1554 		}
1555 		sl->sl_meta_blocksize_shift = 0;
1556 		goto over_meta_create;
1557 	}
1558 	if ((ret = lookupname(sl->sl_meta_filename, UIO_SYSSPACE, FOLLOW,
1559 	    NULLVPP, &sl->sl_meta_vp)) != 0) {
1560 		*err_ret = SBD_RET_META_FILE_LOOKUP_FAILED;
1561 		goto scm_err_out;
1562 	}
1563 	sl->sl_meta_vtype = vt = sl->sl_meta_vp->v_type;
1564 	VN_RELE(sl->sl_meta_vp);
1565 	if ((vt != VREG) && (vt != VCHR) && (vt != VBLK)) {
1566 		*err_ret = SBD_RET_WRONG_META_FILE_TYPE;
1567 		ret = EINVAL;
1568 		goto scm_err_out;
1569 	}
1570 	if (vt == VREG) {
1571 		sl->sl_meta_blocksize_shift = 0;
1572 	} else {
1573 		sl->sl_meta_blocksize_shift = 9;
1574 	}
1575 	flag = FREAD | FWRITE | FOFFMAX | FEXCL;
1576 	if ((ret = vn_open(sl->sl_meta_filename, UIO_SYSSPACE, flag, 0,
1577 	    &sl->sl_meta_vp, 0, 0)) != 0) {
1578 		*err_ret = SBD_RET_META_FILE_OPEN_FAILED;
1579 		goto scm_err_out;
1580 	}
1581 over_meta_create:
1582 	sl->sl_total_meta_size = sl->sl_meta_offset + sizeof (sbd_meta_start_t);
1583 	sl->sl_total_meta_size +=
1584 	    (((uint64_t)1) << sl->sl_meta_blocksize_shift) - 1;
1585 	sl->sl_total_meta_size &=
1586 	    ~((((uint64_t)1) << sl->sl_meta_blocksize_shift) - 1);
1587 	sl->sl_meta_size_used = 0;
1588 over_meta_open:
1589 	sl->sl_flags |= SL_META_OPENED;
1590 
1591 	sl->sl_device_id[3] = 16;
1592 	if (slu->slu_guid_valid) {
1593 		sl->sl_device_id[0] = 0xf1;
1594 		sl->sl_device_id[1] = 3;
1595 		sl->sl_device_id[2] = 0;
1596 		bcopy(slu->slu_guid, sl->sl_device_id + 4, 16);
1597 	} else {
1598 		if (!slu->slu_company_id_valid)
1599 			slu->slu_company_id = COMPANY_ID_SUN;
1600 		if (stmf_scsilib_uniq_lu_id(slu->slu_company_id,
1601 		    (scsi_devid_desc_t *)&sl->sl_device_id[0]) !=
1602 		    STMF_SUCCESS) {
1603 			*err_ret = SBD_RET_META_CREATION_FAILED;
1604 			ret = EIO;
1605 			goto scm_err_out;
1606 		}
1607 		bcopy(sl->sl_device_id + 4, slu->slu_guid, 16);
1608 	}
1609 
1610 	/* Lets create the meta now */
1611 	if (sbd_write_meta_start(sl, sl->sl_total_meta_size,
1612 	    sizeof (sbd_meta_start_t)) != SBD_SUCCESS) {
1613 		*err_ret = SBD_RET_META_CREATION_FAILED;
1614 		ret = EIO;
1615 		goto scm_err_out;
1616 	}
1617 	sl->sl_meta_size_used = sl->sl_meta_offset + sizeof (sbd_meta_start_t);
1618 
1619 	if (sbd_write_lu_info(sl) != SBD_SUCCESS) {
1620 		*err_ret = SBD_RET_META_CREATION_FAILED;
1621 		ret = EIO;
1622 		goto scm_err_out;
1623 	}
1624 
1625 	if (sbd_pgr_meta_init(sl) != SBD_SUCCESS) {
1626 		*err_ret = SBD_RET_META_CREATION_FAILED;
1627 		ret = EIO;
1628 		goto scm_err_out;
1629 	}
1630 
1631 	ret = sbd_populate_and_register_lu(sl, err_ret);
1632 	if (ret) {
1633 		goto scm_err_out;
1634 	}
1635 
1636 	sl->sl_trans_op = SL_OP_NONE;
1637 	atomic_add_32(&sbd_lu_count, 1);
1638 	return (0);
1639 
1640 scm_err_out:
1641 	return (sbd_close_delete_lu(sl, ret));
1642 }
1643 
1644 int
1645 sbd_load_sli_1_0(sbd_lu_t *sl, uint32_t *err_ret)
1646 {
1647 	sbd_lu_info_1_0_t *sli = NULL;
1648 	sbd_status_t sret;
1649 
1650 	sret = sbd_read_meta_section(sl, (sm_section_hdr_t **)&sli,
1651 	    SMS_ID_LU_INFO_1_0);
1652 
1653 	if (sret != SBD_SUCCESS) {
1654 		*err_ret = SBD_RET_NO_META;
1655 		return (EIO);
1656 	}
1657 	if (sli->sli_data_order != SMS_DATA_ORDER) {
1658 		sbd_swap_lu_info_1_0(sli);
1659 		if (sli->sli_data_order != SMS_DATA_ORDER) {
1660 			kmem_free(sli, sli->sli_sms_header.sms_size);
1661 			*err_ret = SBD_RET_NO_META;
1662 			return (EIO);
1663 		}
1664 	}
1665 
1666 	sl->sl_flags |= SL_SHARED_META;
1667 	sl->sl_data_blocksize_shift = 9;
1668 	sl->sl_data_offset = SHARED_META_DATA_SIZE;
1669 	sl->sl_lu_size = sli->sli_total_store_size - SHARED_META_DATA_SIZE;
1670 	sl->sl_total_data_size = SHARED_META_DATA_SIZE + sl->sl_lu_size;
1671 	bcopy(sli->sli_lu_devid, sl->sl_device_id, 20);
1672 
1673 	kmem_free(sli, sli->sli_sms_header.sms_size);
1674 	return (0);
1675 }
1676 
1677 int
1678 sbd_import_lu(sbd_import_lu_t *ilu, int struct_sz, uint32_t *err_ret,
1679     int no_register, sbd_lu_t **slr)
1680 {
1681 	stmf_lu_t *lu;
1682 	sbd_lu_t *sl;
1683 	sbd_lu_info_1_1_t *sli = NULL;
1684 	int asz;
1685 	int ret = 0;
1686 	int flag;
1687 	int wcd = 0;
1688 	int data_opened;
1689 	uint16_t sli_buf_sz;
1690 	uint8_t *sli_buf_copy = NULL;
1691 	enum vtype vt;
1692 	sbd_status_t sret;
1693 
1694 	if (no_register && slr == NULL) {
1695 		return (EINVAL);
1696 	}
1697 	ilu->ilu_meta_fname[struct_sz - sizeof (*ilu) + 8 - 1] = 0;
1698 	asz = strlen(ilu->ilu_meta_fname) + 1;
1699 
1700 	lu = (stmf_lu_t *)stmf_alloc(STMF_STRUCT_STMF_LU,
1701 	    sizeof (sbd_lu_t) + sizeof (sbd_pgr_t) + asz, 0);
1702 	if (lu == NULL) {
1703 		return (ENOMEM);
1704 	}
1705 	sl = (sbd_lu_t *)lu->lu_provider_private;
1706 	bzero(sl, sizeof (*sl));
1707 	sl->sl_lu = lu;
1708 	sl->sl_pgr = (sbd_pgr_t *)(sl + 1);
1709 	sl->sl_meta_filename = ((char *)sl) + sizeof (*sl) + sizeof (sbd_pgr_t);
1710 	(void) strcpy(sl->sl_meta_filename, ilu->ilu_meta_fname);
1711 	sl->sl_name = sl->sl_meta_filename;
1712 	rw_init(&sl->sl_pgr->pgr_lock, NULL, RW_DRIVER, NULL);
1713 	mutex_init(&sl->sl_lock, NULL, MUTEX_DRIVER, NULL);
1714 	sl->sl_trans_op = SL_OP_IMPORT_LU;
1715 	/* we're only loading the metadata */
1716 	if (!no_register) {
1717 		if (sbd_link_lu(sl) != SBD_SUCCESS) {
1718 			*err_ret = SBD_RET_FILE_ALREADY_REGISTERED;
1719 			ret = EALREADY;
1720 			goto sim_err_out;
1721 		}
1722 	}
1723 	if ((ret = lookupname(sl->sl_meta_filename, UIO_SYSSPACE, FOLLOW,
1724 	    NULLVPP, &sl->sl_meta_vp)) != 0) {
1725 		*err_ret = SBD_RET_META_FILE_LOOKUP_FAILED;
1726 		goto sim_err_out;
1727 	}
1728 	if (sbd_is_zvol(sl->sl_meta_filename)) {
1729 		sl->sl_flags |= SL_ZFS_META;
1730 		sl->sl_data_filename = sl->sl_meta_filename;
1731 	}
1732 	sl->sl_meta_vtype = vt = sl->sl_meta_vp->v_type;
1733 	VN_RELE(sl->sl_meta_vp);
1734 	if ((vt != VREG) && (vt != VCHR) && (vt != VBLK)) {
1735 		*err_ret = SBD_RET_WRONG_META_FILE_TYPE;
1736 		ret = EINVAL;
1737 		goto sim_err_out;
1738 	}
1739 	if (sl->sl_flags & SL_ZFS_META) {
1740 		if (sbd_open_zfs_meta(sl) != SBD_SUCCESS) {
1741 			/* let see if metadata is in the 64k block */
1742 			sl->sl_flags &= ~SL_ZFS_META;
1743 		}
1744 	}
1745 	if (!(sl->sl_flags & SL_ZFS_META)) {
1746 		/* metadata is always writable */
1747 		flag = FREAD | FWRITE | FOFFMAX | FEXCL;
1748 		if ((ret = vn_open(sl->sl_meta_filename, UIO_SYSSPACE, flag, 0,
1749 		    &sl->sl_meta_vp, 0, 0)) != 0) {
1750 			*err_ret = SBD_RET_META_FILE_OPEN_FAILED;
1751 			goto sim_err_out;
1752 		}
1753 	}
1754 	if ((sl->sl_flags & SL_ZFS_META) || (vt == VREG)) {
1755 		sl->sl_meta_blocksize_shift = 0;
1756 	} else {
1757 		sl->sl_meta_blocksize_shift = 9;
1758 	}
1759 	sl->sl_meta_offset = (sl->sl_flags & SL_ZFS_META) ? 0 : SBD_META_OFFSET;
1760 	sl->sl_flags |= SL_META_OPENED;
1761 
1762 	sret = sbd_load_meta_start(sl);
1763 	if (sret != SBD_SUCCESS) {
1764 		if (sret == SBD_META_CORRUPTED) {
1765 			*err_ret = SBD_RET_NO_META;
1766 		} else if (sret == SBD_NOT_SUPPORTED) {
1767 			*err_ret = SBD_RET_VERSION_NOT_SUPPORTED;
1768 		} else {
1769 			*err_ret = SBD_RET_NO_META;
1770 		}
1771 		ret = EINVAL;
1772 		goto sim_err_out;
1773 	}
1774 
1775 	/* Now lets see if we can read the most recent LU info */
1776 	sret = sbd_read_meta_section(sl, (sm_section_hdr_t **)&sli,
1777 	    SMS_ID_LU_INFO_1_1);
1778 	if ((sret == SBD_NOT_FOUND) && ((sl->sl_flags & SL_ZFS_META) == 0)) {
1779 		ret = sbd_load_sli_1_0(sl, err_ret);
1780 		if (ret)
1781 			goto sim_err_out;
1782 		goto sim_sli_loaded;
1783 	}
1784 	if (sret != SBD_SUCCESS) {
1785 		*err_ret = SBD_RET_NO_META;
1786 		ret = EIO;
1787 		goto sim_err_out;
1788 	}
1789 	/* load sli 1.1 */
1790 	if (sli->sli_data_order != SMS_DATA_ORDER) {
1791 		sbd_swap_lu_info_1_1(sli);
1792 		if (sli->sli_data_order != SMS_DATA_ORDER) {
1793 			*err_ret = SBD_RET_NO_META;
1794 			ret = EIO;
1795 			goto sim_err_out;
1796 		}
1797 	}
1798 
1799 	sli_buf_sz = sli->sli_sms_header.sms_size -
1800 	    sizeof (sbd_lu_info_1_1_t) + 8;
1801 	sli_buf_copy = kmem_alloc(sli_buf_sz + 1, KM_SLEEP);
1802 	bcopy(sli->sli_buf, sli_buf_copy, sli_buf_sz);
1803 	sli_buf_copy[sli_buf_sz] = 0;
1804 
1805 	/* Make sure all the offsets are within limits */
1806 	if (((sli->sli_flags & SLI_META_FNAME_VALID) &&
1807 	    (sli->sli_meta_fname_offset > sli_buf_sz)) ||
1808 	    ((sli->sli_flags & SLI_DATA_FNAME_VALID) &&
1809 	    (sli->sli_data_fname_offset > sli_buf_sz)) ||
1810 	    ((sli->sli_flags & SLI_MGMT_URL_VALID) &&
1811 	    (sli->sli_mgmt_url_offset > sli_buf_sz)) ||
1812 	    ((sli->sli_flags & SLI_SERIAL_VALID) &&
1813 	    ((sli->sli_serial_offset + sli->sli_serial_size) > sli_buf_sz)) ||
1814 	    ((sli->sli_flags & SLI_ALIAS_VALID) &&
1815 	    (sli->sli_alias_offset > sli_buf_sz))) {
1816 		*err_ret = SBD_RET_NO_META;
1817 		ret = EIO;
1818 		goto sim_err_out;
1819 	}
1820 
1821 	if (sl->sl_flags & SL_ZFS_META) {
1822 		/* Verify that its the right zfs node and not some clone */
1823 		int same_zvol;
1824 		char *zvol_name = sbd_get_zvol_name(sl);
1825 
1826 		if ((sli->sli_flags & (SLI_ZFS_META |
1827 		    SLI_META_FNAME_VALID)) == 0) {
1828 			*err_ret = SBD_RET_NO_META;
1829 			ret = EIO;
1830 			kmem_free(zvol_name, strlen(zvol_name) + 1);
1831 			goto sim_err_out;
1832 		}
1833 		if (strcmp(zvol_name, (char *)sli_buf_copy +
1834 		    sli->sli_meta_fname_offset) != 0)
1835 			same_zvol = 0;
1836 		else
1837 			same_zvol = 1;
1838 		kmem_free(zvol_name, strlen(zvol_name) + 1);
1839 		if (!same_zvol) {
1840 			*err_ret = SBD_ZVOL_META_NAME_MISMATCH;
1841 			ret = EINVAL;
1842 			goto sim_err_out;
1843 		}
1844 	}
1845 	sl->sl_lu_size = sli->sli_lu_size;
1846 	sl->sl_data_blocksize_shift = sli->sli_data_blocksize_shift;
1847 	bcopy(sli->sli_device_id, sl->sl_device_id, 20);
1848 	if (sli->sli_flags & SLI_SERIAL_VALID) {
1849 		sl->sl_serial_no_size = sl->sl_serial_no_alloc_size =
1850 		    sli->sli_serial_size;
1851 		sl->sl_serial_no = kmem_zalloc(sli->sli_serial_size, KM_SLEEP);
1852 		bcopy(sli_buf_copy + sli->sli_serial_offset, sl->sl_serial_no,
1853 		    sl->sl_serial_no_size);
1854 	}
1855 	if (sli->sli_flags & SLI_SEPARATE_META) {
1856 		sl->sl_total_data_size = sl->sl_lu_size;
1857 		if (sli->sli_flags & SLI_DATA_FNAME_VALID) {
1858 			sl->sl_data_fname_alloc_size = strlen((char *)
1859 			    sli_buf_copy + sli->sli_data_fname_offset) + 1;
1860 			sl->sl_data_filename = kmem_zalloc(
1861 			    sl->sl_data_fname_alloc_size, KM_SLEEP);
1862 			(void) strcpy(sl->sl_data_filename,
1863 			    (char *)sli_buf_copy + sli->sli_data_fname_offset);
1864 		}
1865 	} else {
1866 		if (sl->sl_flags & SL_ZFS_META) {
1867 			sl->sl_total_data_size = sl->sl_lu_size;
1868 			sl->sl_data_offset = 0;
1869 		} else {
1870 			sl->sl_total_data_size =
1871 			    sl->sl_lu_size + SHARED_META_DATA_SIZE;
1872 			sl->sl_data_offset = SHARED_META_DATA_SIZE;
1873 			sl->sl_flags |= SL_SHARED_META;
1874 		}
1875 	}
1876 	if (sli->sli_flags & SLI_ALIAS_VALID) {
1877 		sl->sl_alias_alloc_size = strlen((char *)sli_buf_copy +
1878 		    sli->sli_alias_offset) + 1;
1879 		sl->sl_alias = kmem_alloc(sl->sl_alias_alloc_size, KM_SLEEP);
1880 		(void) strcpy(sl->sl_alias, (char *)sli_buf_copy +
1881 		    sli->sli_alias_offset);
1882 	}
1883 	if (sli->sli_flags & SLI_MGMT_URL_VALID) {
1884 		sl->sl_mgmt_url_alloc_size = strlen((char *)sli_buf_copy +
1885 		    sli->sli_mgmt_url_offset) + 1;
1886 		sl->sl_mgmt_url = kmem_alloc(sl->sl_mgmt_url_alloc_size,
1887 		    KM_SLEEP);
1888 		(void) strcpy(sl->sl_mgmt_url, (char *)sli_buf_copy +
1889 		    sli->sli_mgmt_url_offset);
1890 	}
1891 	if (sli->sli_flags & SLI_WRITE_PROTECTED) {
1892 		sl->sl_flags |= SL_WRITE_PROTECTED;
1893 	}
1894 	if (sli->sli_flags & SLI_VID_VALID) {
1895 		sl->sl_flags |= SL_VID_VALID;
1896 		bcopy(sli->sli_vid, sl->sl_vendor_id, 8);
1897 	}
1898 	if (sli->sli_flags & SLI_PID_VALID) {
1899 		sl->sl_flags |= SL_PID_VALID;
1900 		bcopy(sli->sli_pid, sl->sl_product_id, 16);
1901 	}
1902 	if (sli->sli_flags & SLI_REV_VALID) {
1903 		sl->sl_flags |= SL_REV_VALID;
1904 		bcopy(sli->sli_rev, sl->sl_revision, 4);
1905 	}
1906 	if (sli->sli_flags & SLI_WRITEBACK_CACHE_DISABLE) {
1907 		sl->sl_flags |= SL_WRITEBACK_CACHE_DISABLE;
1908 	}
1909 sim_sli_loaded:
1910 	if ((sl->sl_flags & SL_SHARED_META) == 0) {
1911 		data_opened = 0;
1912 	} else {
1913 		data_opened = 1;
1914 		sl->sl_data_filename = sl->sl_meta_filename;
1915 		sl->sl_data_vp = sl->sl_meta_vp;
1916 		sl->sl_data_vtype = sl->sl_meta_vtype;
1917 	}
1918 
1919 	sret = sbd_pgr_meta_load(sl);
1920 	if (sret != SBD_SUCCESS) {
1921 		*err_ret = SBD_RET_NO_META;
1922 		ret = EIO;
1923 		goto sim_err_out;
1924 	}
1925 
1926 	ret = sbd_open_data_file(sl, err_ret, 1, data_opened, 0);
1927 	if (ret)
1928 		goto sim_err_out;
1929 
1930 	/*
1931 	 * set write cache disable on the device
1932 	 * Note: this shouldn't fail on import unless the cache capabilities
1933 	 * of the device changed. If that happened, modify will need to
1934 	 * be used to set the cache flag appropriately after import is done.
1935 	 */
1936 	if (sl->sl_flags & SL_WRITEBACK_CACHE_DISABLE) {
1937 		(void) sbd_wcd_set(1, sl);
1938 		wcd = 1;
1939 	/*
1940 	 * if not explicitly set, attempt to set it to enable, if that fails
1941 	 * get the current setting and use that
1942 	 */
1943 	} else {
1944 		sret = sbd_wcd_set(0, sl);
1945 		if (sret != SBD_SUCCESS) {
1946 			sbd_wcd_get(&wcd, sl);
1947 		}
1948 	}
1949 
1950 	if (wcd) {
1951 		sl->sl_flags |= SL_WRITEBACK_CACHE_DISABLE |
1952 		    SL_SAVED_WRITE_CACHE_DISABLE;
1953 	}
1954 
1955 	/* we're only loading the metadata */
1956 	if (!no_register) {
1957 		ret = sbd_populate_and_register_lu(sl, err_ret);
1958 		if (ret)
1959 			goto sim_err_out;
1960 		atomic_add_32(&sbd_lu_count, 1);
1961 	}
1962 
1963 	bcopy(sl->sl_device_id + 4, ilu->ilu_ret_guid, 16);
1964 	sl->sl_trans_op = SL_OP_NONE;
1965 	if (sli) {
1966 		kmem_free(sli, sli->sli_sms_header.sms_size);
1967 		sli = NULL;
1968 	}
1969 	if (sli_buf_copy) {
1970 		kmem_free(sli_buf_copy, sli_buf_sz + 1);
1971 		sli_buf_copy = NULL;
1972 	}
1973 	if (no_register) {
1974 		*slr = sl;
1975 	}
1976 	return (0);
1977 
1978 sim_err_out:
1979 	if (sli) {
1980 		kmem_free(sli, sli->sli_sms_header.sms_size);
1981 		sli = NULL;
1982 	}
1983 	if (sli_buf_copy) {
1984 		kmem_free(sli_buf_copy, sli_buf_sz + 1);
1985 		sli_buf_copy = NULL;
1986 	}
1987 	return (sbd_close_delete_lu(sl, ret));
1988 }
1989 
1990 int
1991 sbd_modify_lu(sbd_modify_lu_t *mlu, int struct_sz, uint32_t *err_ret)
1992 {
1993 	sbd_lu_t *sl = NULL;
1994 	uint16_t alias_sz;
1995 	int ret = 0;
1996 	sbd_it_data_t *it;
1997 	sbd_status_t sret;
1998 	uint64_t old_size;
1999 	int modify_unregistered = 0;
2000 	int ua = 0;
2001 	sbd_import_lu_t *ilu;
2002 	stmf_lu_t *lu;
2003 	uint32_t ilu_sz;
2004 	uint32_t sz;
2005 
2006 	sz = struct_sz - sizeof (*mlu) + 8 + 1;
2007 
2008 	/* if there is data in the buf, null terminate it */
2009 	if (struct_sz > sizeof (*mlu)) {
2010 		mlu->mlu_buf[struct_sz - sizeof (*mlu) + 8 - 1] = 0;
2011 	}
2012 
2013 	*err_ret = 0;
2014 
2015 	/* Lets validate offsets */
2016 	if (((mlu->mlu_alias_valid) &&
2017 	    (mlu->mlu_alias_off >= sz)) ||
2018 	    ((mlu->mlu_mgmt_url_valid) &&
2019 	    (mlu->mlu_mgmt_url_off >= sz)) ||
2020 	    (mlu->mlu_by_fname) &&
2021 	    (mlu->mlu_fname_off >= sz)) {
2022 		return (EINVAL);
2023 	}
2024 
2025 	/*
2026 	 * We'll look for the device but if we don't find it registered,
2027 	 * we'll still try to modify the unregistered device.
2028 	 */
2029 	if (mlu->mlu_by_guid) {
2030 		sret = sbd_find_and_lock_lu(mlu->mlu_input_guid, NULL,
2031 		    SL_OP_MODIFY_LU, &sl);
2032 	} else if (mlu->mlu_by_fname) {
2033 		sret = sbd_find_and_lock_lu(NULL,
2034 		    (uint8_t *)&(mlu->mlu_buf[mlu->mlu_fname_off]),
2035 		    SL_OP_MODIFY_LU, &sl);
2036 	} else {
2037 		return (EINVAL);
2038 	}
2039 
2040 
2041 	if (sret != SBD_SUCCESS) {
2042 		if (sret == SBD_BUSY) {
2043 			*err_ret = SBD_RET_LU_BUSY;
2044 			return (EBUSY);
2045 		} else if (sret != SBD_NOT_FOUND) {
2046 			return (EIO);
2047 		} else if (!mlu->mlu_by_fname) {
2048 			return (EINVAL);
2049 		}
2050 		/* Okay, try to import the device */
2051 		struct_sz = max(8, strlen(&(mlu->mlu_buf[mlu->mlu_fname_off]))
2052 		    + 1);
2053 		struct_sz += sizeof (sbd_import_lu_t) - 8;
2054 		ilu_sz = struct_sz;
2055 		ilu = (sbd_import_lu_t *)kmem_zalloc(ilu_sz, KM_SLEEP);
2056 		ilu->ilu_struct_size = struct_sz;
2057 		(void) strcpy(ilu->ilu_meta_fname,
2058 		    &(mlu->mlu_buf[mlu->mlu_fname_off]));
2059 		ret = sbd_import_lu(ilu, struct_sz, err_ret, 1, &sl);
2060 		kmem_free(ilu, ilu_sz);
2061 		if (ret != SBD_SUCCESS) {
2062 			return (ENOENT);
2063 		}
2064 		modify_unregistered = 1;
2065 	}
2066 
2067 	/* check for write cache change */
2068 	if (mlu->mlu_writeback_cache_disable_valid) {
2069 		/* set wce on device */
2070 		sret = sbd_wcd_set(mlu->mlu_writeback_cache_disable, sl);
2071 		if (!mlu->mlu_writeback_cache_disable && sret != SBD_SUCCESS) {
2072 			*err_ret = SBD_RET_WRITE_CACHE_SET_FAILED;
2073 			ret = EFAULT;
2074 			goto smm_err_out;
2075 		}
2076 		mutex_enter(&sl->sl_lock);
2077 		if (!mlu->mlu_writeback_cache_disable) {
2078 			if (sl->sl_flags & SL_WRITEBACK_CACHE_DISABLE) {
2079 				ua = 1;
2080 				sl->sl_flags &= ~SL_WRITEBACK_CACHE_DISABLE;
2081 				sl->sl_flags &= ~SL_SAVED_WRITE_CACHE_DISABLE;
2082 			}
2083 		} else {
2084 			if ((sl->sl_flags & SL_WRITEBACK_CACHE_DISABLE) == 0) {
2085 				ua = 1;
2086 				sl->sl_flags |= SL_WRITEBACK_CACHE_DISABLE;
2087 				sl->sl_flags |= SL_SAVED_WRITE_CACHE_DISABLE;
2088 			}
2089 		}
2090 		for (it = sl->sl_it_list; ua && it != NULL;
2091 		    it = it->sbd_it_next) {
2092 			it->sbd_it_ua_conditions |=
2093 			    SBD_UA_MODE_PARAMETERS_CHANGED;
2094 		}
2095 		mutex_exit(&sl->sl_lock);
2096 	}
2097 	ua = 0;
2098 
2099 	if (mlu->mlu_alias_valid) {
2100 		alias_sz = strlen((char *)mlu->mlu_buf +
2101 		    mlu->mlu_alias_off) + 1;
2102 		/*
2103 		 * Use the allocated buffer or alloc a new one.
2104 		 * Don't copy into sl_alias if sl_alias_alloc_size is 0
2105 		 * otherwise or you'll be writing over the data/metadata
2106 		 * filename.
2107 		 */
2108 		mutex_enter(&sl->sl_lock);
2109 		if (sl->sl_alias_alloc_size > 0 &&
2110 		    sl->sl_alias_alloc_size < alias_sz) {
2111 			kmem_free(sl->sl_alias,
2112 			    sl->sl_alias_alloc_size);
2113 			sl->sl_alias_alloc_size = 0;
2114 		}
2115 		if (sl->sl_alias_alloc_size == 0) {
2116 			sl->sl_alias = kmem_alloc(alias_sz, KM_SLEEP);
2117 			sl->sl_alias_alloc_size = alias_sz;
2118 		}
2119 		(void) strcpy(sl->sl_alias, (char *)mlu->mlu_buf +
2120 		    mlu->mlu_alias_off);
2121 		lu = sl->sl_lu;
2122 		lu->lu_alias = sl->sl_alias;
2123 		mutex_exit(&sl->sl_lock);
2124 	}
2125 
2126 	if (mlu->mlu_mgmt_url_valid) {
2127 		uint16_t url_sz;
2128 
2129 		url_sz = strlen((char *)mlu->mlu_buf + mlu->mlu_mgmt_url_off);
2130 		if (url_sz > 0)
2131 			url_sz++;
2132 
2133 		mutex_enter(&sl->sl_lock);
2134 		if (sl->sl_mgmt_url_alloc_size > 0 &&
2135 		    (url_sz == 0 || sl->sl_mgmt_url_alloc_size < url_sz)) {
2136 			kmem_free(sl->sl_mgmt_url, sl->sl_mgmt_url_alloc_size);
2137 			sl->sl_mgmt_url = NULL;
2138 			sl->sl_mgmt_url_alloc_size = 0;
2139 		}
2140 		if (url_sz > 0) {
2141 			if (sl->sl_mgmt_url_alloc_size == 0) {
2142 				sl->sl_mgmt_url = kmem_alloc(url_sz, KM_SLEEP);
2143 				sl->sl_mgmt_url_alloc_size = url_sz;
2144 			}
2145 			(void) strcpy(sl->sl_mgmt_url, (char *)mlu->mlu_buf +
2146 			    mlu->mlu_mgmt_url_off);
2147 		}
2148 		for (it = sl->sl_it_list; it != NULL;
2149 		    it = it->sbd_it_next) {
2150 			it->sbd_it_ua_conditions |=
2151 			    SBD_UA_MODE_PARAMETERS_CHANGED;
2152 		}
2153 		mutex_exit(&sl->sl_lock);
2154 	}
2155 
2156 	if (mlu->mlu_write_protected_valid) {
2157 		mutex_enter(&sl->sl_lock);
2158 		if (mlu->mlu_write_protected) {
2159 			if ((sl->sl_flags & SL_WRITE_PROTECTED) == 0) {
2160 				ua = 1;
2161 				sl->sl_flags |= SL_WRITE_PROTECTED;
2162 			}
2163 		} else {
2164 			if (sl->sl_flags & SL_WRITE_PROTECTED) {
2165 				ua = 1;
2166 				sl->sl_flags &= ~SL_WRITE_PROTECTED;
2167 			}
2168 		}
2169 		for (it = sl->sl_it_list; ua && it != NULL;
2170 		    it = it->sbd_it_next) {
2171 			it->sbd_it_ua_conditions |=
2172 			    SBD_UA_MODE_PARAMETERS_CHANGED;
2173 		}
2174 		mutex_exit(&sl->sl_lock);
2175 	}
2176 
2177 	if (mlu->mlu_lu_size_valid) {
2178 		/*
2179 		 * validate lu size and set
2180 		 * For open file only (registered lu)
2181 		 */
2182 		mutex_enter(&sl->sl_lock);
2183 		old_size = sl->sl_lu_size;
2184 		sl->sl_lu_size = mlu->mlu_lu_size;
2185 		mutex_exit(&sl->sl_lock);
2186 		ret = sbd_open_data_file(sl, err_ret, 1, 1, 1);
2187 		if (ret) {
2188 			mutex_enter(&sl->sl_lock);
2189 			sl->sl_lu_size = old_size;
2190 			mutex_exit(&sl->sl_lock);
2191 			goto smm_err_out;
2192 		}
2193 		if (old_size != mlu->mlu_lu_size) {
2194 			mutex_enter(&sl->sl_lock);
2195 			for (it = sl->sl_it_list; it != NULL;
2196 			    it = it->sbd_it_next) {
2197 				it->sbd_it_ua_conditions |=
2198 				    SBD_UA_CAPACITY_CHANGED;
2199 			}
2200 			mutex_exit(&sl->sl_lock);
2201 		}
2202 	}
2203 
2204 	if (sbd_write_lu_info(sl) != SBD_SUCCESS) {
2205 		*err_ret = SBD_RET_META_CREATION_FAILED;
2206 		ret = EIO;
2207 	}
2208 
2209 smm_err_out:
2210 	if (modify_unregistered) {
2211 		(void) sbd_close_delete_lu(sl, 0);
2212 	} else {
2213 		sl->sl_trans_op = SL_OP_NONE;
2214 	}
2215 	return (ret);
2216 }
2217 
2218 /* ARGSUSED */
2219 int
2220 sbd_delete_locked_lu(sbd_lu_t *sl, uint32_t *err_ret,
2221     stmf_state_change_info_t *ssi)
2222 {
2223 	int i;
2224 
2225 	if ((sl->sl_state == STMF_STATE_OFFLINE) &&
2226 	    !sl->sl_state_not_acked) {
2227 		goto sdl_do_dereg;
2228 	}
2229 
2230 	if ((sl->sl_state != STMF_STATE_ONLINE) ||
2231 	    sl->sl_state_not_acked) {
2232 		return (EBUSY);
2233 	}
2234 	if (stmf_ctl(STMF_CMD_LU_OFFLINE, sl->sl_lu, ssi) != STMF_SUCCESS) {
2235 		return (EBUSY);
2236 	}
2237 
2238 	for (i = 0; i < 500; i++) {
2239 		if (sl->sl_state == STMF_STATE_OFFLINE)
2240 			break;
2241 		delay(drv_usectohz(10000));
2242 	}
2243 
2244 	if ((sl->sl_state == STMF_STATE_OFFLINE) &&
2245 	    !sl->sl_state_not_acked) {
2246 		goto sdl_do_dereg;
2247 	}
2248 
2249 	return (EBUSY);
2250 sdl_do_dereg:;
2251 	if (stmf_deregister_lu(sl->sl_lu) != STMF_SUCCESS)
2252 		return (EBUSY);
2253 	atomic_add_32(&sbd_lu_count, -1);
2254 
2255 	return (sbd_close_delete_lu(sl, 0));
2256 }
2257 
2258 int
2259 sbd_delete_lu(sbd_delete_lu_t *dlu, int struct_sz, uint32_t *err_ret)
2260 {
2261 	sbd_lu_t *sl;
2262 	sbd_status_t sret;
2263 	stmf_state_change_info_t ssi;
2264 	int ret;
2265 
2266 	if (dlu->dlu_by_meta_name) {
2267 		((char *)dlu)[struct_sz - 1] = 0;
2268 		sret = sbd_find_and_lock_lu(NULL, dlu->dlu_meta_name,
2269 		    SL_OP_DELETE_LU, &sl);
2270 	} else {
2271 		sret = sbd_find_and_lock_lu(dlu->dlu_guid, NULL,
2272 		    SL_OP_DELETE_LU, &sl);
2273 	}
2274 	if (sret != SBD_SUCCESS) {
2275 		if (sret == SBD_BUSY) {
2276 			*err_ret = SBD_RET_LU_BUSY;
2277 			return (EBUSY);
2278 		} else if (sret == SBD_NOT_FOUND) {
2279 			*err_ret = SBD_RET_NOT_FOUND;
2280 			return (ENOENT);
2281 		}
2282 		return (EIO);
2283 	}
2284 
2285 	ssi.st_rflags = STMF_RFLAG_USER_REQUEST;
2286 	ssi.st_additional_info = "sbd_delete_lu call (ioctl)";
2287 	ret = sbd_delete_locked_lu(sl, err_ret, &ssi);
2288 
2289 	if (ret) {
2290 		/* Once its locked, no need to grab mutex again */
2291 		sl->sl_trans_op = SL_OP_NONE;
2292 	}
2293 	return (ret);
2294 }
2295 
2296 sbd_status_t
2297 sbd_data_read(sbd_lu_t *sl, uint64_t offset, uint64_t size, uint8_t *buf)
2298 {
2299 	int ret;
2300 	long resid;
2301 
2302 	if ((offset + size) > sl->sl_lu_size) {
2303 		return (SBD_IO_PAST_EOF);
2304 	}
2305 
2306 	offset += sl->sl_data_offset;
2307 
2308 	if ((offset + size) > sl->sl_data_readable_size) {
2309 		uint64_t store_end;
2310 		if (offset > sl->sl_data_readable_size) {
2311 			bzero(buf, size);
2312 			return (SBD_SUCCESS);
2313 		}
2314 		store_end = sl->sl_data_readable_size - offset;
2315 		bzero(buf + store_end, size - store_end);
2316 		size = store_end;
2317 	}
2318 
2319 	DTRACE_PROBE4(backing__store__read__start, sbd_lu_t *, sl,
2320 	    uint8_t *, buf, uint64_t, size, uint64_t, offset);
2321 
2322 	ret = vn_rdwr(UIO_READ, sl->sl_data_vp, (caddr_t)buf, (ssize_t)size,
2323 	    (offset_t)offset, UIO_SYSSPACE, 0, RLIM64_INFINITY, CRED(),
2324 	    &resid);
2325 
2326 	DTRACE_PROBE5(backing__store__read__end, sbd_lu_t *, sl,
2327 	    uint8_t *, buf, uint64_t, size, uint64_t, offset,
2328 	    int, ret);
2329 
2330 over_sl_data_read:
2331 	if (ret || resid) {
2332 		stmf_trace(0, "UIO_READ failed, ret = %d, resid = %d", ret,
2333 		    resid);
2334 		return (SBD_FAILURE);
2335 	}
2336 
2337 	return (SBD_SUCCESS);
2338 }
2339 
2340 sbd_status_t
2341 sbd_data_write(sbd_lu_t *sl, uint64_t offset, uint64_t size, uint8_t *buf)
2342 {
2343 	int ret;
2344 	long resid;
2345 	sbd_status_t sret = SBD_SUCCESS;
2346 	int ioflag;
2347 
2348 	if ((offset + size) > sl->sl_lu_size) {
2349 		return (SBD_IO_PAST_EOF);
2350 	}
2351 
2352 	offset += sl->sl_data_offset;
2353 
2354 	if ((sl->sl_flags & SL_WRITEBACK_CACHE_DISABLE) &&
2355 	    (sl->sl_flags & SL_FLUSH_ON_DISABLED_WRITECACHE)) {
2356 		ioflag = FSYNC;
2357 	} else {
2358 		ioflag = 0;
2359 	}
2360 
2361 	DTRACE_PROBE4(backing__store__write__start, sbd_lu_t *, sl,
2362 	    uint8_t *, buf, uint64_t, size, uint64_t, offset);
2363 
2364 	ret = vn_rdwr(UIO_WRITE, sl->sl_data_vp, (caddr_t)buf, (ssize_t)size,
2365 	    (offset_t)offset, UIO_SYSSPACE, ioflag, RLIM64_INFINITY, CRED(),
2366 	    &resid);
2367 
2368 	DTRACE_PROBE5(backing__store__write__end, sbd_lu_t *, sl,
2369 	    uint8_t *, buf, uint64_t, size, uint64_t, offset,
2370 	    int, ret);
2371 
2372 	if ((ret == 0) && (resid == 0) &&
2373 	    (sl->sl_flags & SL_WRITEBACK_CACHE_DISABLE) &&
2374 	    (sl->sl_flags & SL_FLUSH_ON_DISABLED_WRITECACHE)) {
2375 		sret = sbd_flush_data_cache(sl, 1);
2376 	}
2377 over_sl_data_write:
2378 
2379 	if ((ret || resid) || (sret != SBD_SUCCESS)) {
2380 		return (SBD_FAILURE);
2381 	} else if ((offset + size) > sl->sl_data_readable_size) {
2382 		uint64_t old_size, new_size;
2383 
2384 		do {
2385 			old_size = sl->sl_data_readable_size;
2386 			if ((offset + size) <= old_size)
2387 				break;
2388 			new_size = offset + size;
2389 		} while (atomic_cas_64(&sl->sl_data_readable_size, old_size,
2390 		    new_size) != old_size);
2391 	}
2392 
2393 	return (SBD_SUCCESS);
2394 }
2395 
2396 int
2397 sbd_get_lu_props(sbd_lu_props_t *islp, uint32_t islp_sz,
2398     sbd_lu_props_t *oslp, uint32_t oslp_sz, uint32_t *err_ret)
2399 {
2400 	sbd_status_t sret;
2401 	sbd_lu_t *sl = NULL;
2402 	uint32_t sz;
2403 	uint16_t off;
2404 
2405 	if (islp->slp_input_guid) {
2406 		sret = sbd_find_and_lock_lu(islp->slp_guid, NULL,
2407 		    SL_OP_LU_PROPS, &sl);
2408 	} else {
2409 		((char *)islp)[islp_sz - 1] = 0;
2410 		sret = sbd_find_and_lock_lu(NULL, islp->slp_buf,
2411 		    SL_OP_LU_PROPS, &sl);
2412 	}
2413 	if (sret != SBD_SUCCESS) {
2414 		if (sret == SBD_BUSY) {
2415 			*err_ret = SBD_RET_LU_BUSY;
2416 			return (EBUSY);
2417 		} else if (sret == SBD_NOT_FOUND) {
2418 			*err_ret = SBD_RET_NOT_FOUND;
2419 			return (ENOENT);
2420 		}
2421 		return (EIO);
2422 	}
2423 
2424 	sz = strlen(sl->sl_name) + 1;
2425 	if ((sl->sl_flags & (SL_ZFS_META | SL_SHARED_META)) == 0) {
2426 		if (sl->sl_data_filename) {
2427 			sz += strlen(sl->sl_data_filename) + 1;
2428 		}
2429 	}
2430 	sz += sl->sl_serial_no_size;
2431 	if (sl->sl_alias) {
2432 		sz += strlen(sl->sl_alias) + 1;
2433 	}
2434 
2435 	if (sl->sl_mgmt_url) {
2436 		sz += strlen(sl->sl_mgmt_url) + 1;
2437 	}
2438 	bzero(oslp, sizeof (*oslp) - 8);
2439 	oslp->slp_buf_size_needed = sz;
2440 
2441 	if (sz > (oslp_sz - sizeof (*oslp) + 8)) {
2442 		sl->sl_trans_op = SL_OP_NONE;
2443 		*err_ret = SBD_RET_INSUFFICIENT_BUF_SPACE;
2444 		return (ENOMEM);
2445 	}
2446 
2447 	off = 0;
2448 	(void) strcpy((char *)oslp->slp_buf, sl->sl_name);
2449 	oslp->slp_meta_fname_off = off;
2450 	off += strlen(sl->sl_name) + 1;
2451 	if ((sl->sl_flags & (SL_ZFS_META | SL_SHARED_META)) == 0) {
2452 		oslp->slp_meta_fname_valid = 1;
2453 		oslp->slp_separate_meta = 1;
2454 		if (sl->sl_data_filename) {
2455 			oslp->slp_data_fname_valid = 1;
2456 			oslp->slp_data_fname_off = off;
2457 			(void) strcpy((char *)&oslp->slp_buf[off],
2458 			    sl->sl_data_filename);
2459 			off += strlen(sl->sl_data_filename) + 1;
2460 		}
2461 	} else {
2462 		oslp->slp_data_fname_valid = 1;
2463 		oslp->slp_data_fname_off = oslp->slp_meta_fname_off;
2464 		if (sl->sl_flags & SL_ZFS_META) {
2465 			oslp->slp_zfs_meta = 1;
2466 		}
2467 	}
2468 	if (sl->sl_alias) {
2469 		oslp->slp_alias_valid = 1;
2470 		oslp->slp_alias_off = off;
2471 		(void) strcpy((char *)&oslp->slp_buf[off], sl->sl_alias);
2472 		off += strlen(sl->sl_alias) + 1;
2473 	}
2474 	if (sl->sl_mgmt_url) {
2475 		oslp->slp_mgmt_url_valid = 1;
2476 		oslp->slp_mgmt_url_off = off;
2477 		(void) strcpy((char *)&oslp->slp_buf[off], sl->sl_mgmt_url);
2478 		off += strlen(sl->sl_mgmt_url) + 1;
2479 	}
2480 	if (sl->sl_serial_no_size) {
2481 		oslp->slp_serial_off = off;
2482 		bcopy(sl->sl_serial_no, &oslp->slp_buf[off],
2483 		    sl->sl_serial_no_size);
2484 		oslp->slp_serial_size = sl->sl_serial_no_size;
2485 		oslp->slp_serial_valid = 1;
2486 		off += sl->sl_serial_no_size;
2487 	}
2488 
2489 	oslp->slp_lu_size = sl->sl_lu_size;
2490 	oslp->slp_blksize = ((uint16_t)1) << sl->sl_data_blocksize_shift;
2491 
2492 	if (sl->sl_flags & SL_VID_VALID) {
2493 		oslp->slp_lu_vid = 1;
2494 		bcopy(sl->sl_vendor_id, oslp->slp_vid, 8);
2495 	} else {
2496 		bcopy(sbd_vendor_id, oslp->slp_vid, 8);
2497 	}
2498 	if (sl->sl_flags & SL_PID_VALID) {
2499 		oslp->slp_lu_pid = 1;
2500 		bcopy(sl->sl_product_id, oslp->slp_pid, 16);
2501 	} else {
2502 		bcopy(sbd_product_id, oslp->slp_pid, 16);
2503 	}
2504 	if (sl->sl_flags & SL_REV_VALID) {
2505 		oslp->slp_lu_rev = 1;
2506 		bcopy(sl->sl_revision, oslp->slp_rev, 4);
2507 	} else {
2508 		bcopy(sbd_revision, oslp->slp_rev, 4);
2509 	}
2510 	bcopy(sl->sl_device_id + 4, oslp->slp_guid, 16);
2511 
2512 	if (sl->sl_flags & SL_WRITEBACK_CACHE_DISABLE)
2513 		oslp->slp_writeback_cache_disable_cur = 1;
2514 	if (sl->sl_flags & SL_SAVED_WRITE_CACHE_DISABLE)
2515 		oslp->slp_writeback_cache_disable_saved = 1;
2516 	if (sl->sl_flags & SL_WRITE_PROTECTED)
2517 		oslp->slp_write_protected = 1;
2518 
2519 	sl->sl_trans_op = SL_OP_NONE;
2520 
2521 	return (0);
2522 }
2523 
2524 char *
2525 sbd_get_zvol_name(sbd_lu_t *sl)
2526 {
2527 	char *src;
2528 	char *p;
2529 
2530 	if (sl->sl_data_filename)
2531 		src = sl->sl_data_filename;
2532 	else
2533 		src = sl->sl_meta_filename;
2534 	/* There has to be a better way */
2535 	if (SBD_IS_ZVOL(src) != 0) {
2536 		ASSERT(0);
2537 	}
2538 	src += 14;
2539 	if (*src == '/')
2540 		src++;
2541 	p = (char *)kmem_alloc(strlen(src) + 1, KM_SLEEP);
2542 	(void) strcpy(p, src);
2543 	return (p);
2544 }
2545 
2546 /*
2547  * this function creates a local metadata zvol property
2548  */
2549 sbd_status_t
2550 sbd_create_zfs_meta_object(sbd_lu_t *sl)
2551 {
2552 	/*
2553 	 * -allocate 1/2 the property size, the zfs property
2554 	 *  is 8k in size and stored as ascii hex string, all
2555 	 *  we needed is 4k buffer to store the binary data.
2556 	 * -initialize reader/write lock
2557 	 */
2558 	if ((sl->sl_zfs_meta = kmem_zalloc(ZAP_MAXVALUELEN / 2, KM_SLEEP))
2559 	    == NULL)
2560 		return (SBD_FAILURE);
2561 	rw_init(&sl->sl_zfs_meta_lock, NULL, RW_DRIVER, NULL);
2562 	return (SBD_SUCCESS);
2563 }
2564 
2565 char
2566 sbd_ctoi(char c)
2567 {
2568 	if ((c >= '0') && (c <= '9'))
2569 		c -= '0';
2570 	else if ((c >= 'A') && (c <= 'F'))
2571 		c = c - 'A' + 10;
2572 	else if ((c >= 'a') && (c <= 'f'))
2573 		c = c - 'a' + 10;
2574 	else
2575 		c = -1;
2576 	return (c);
2577 }
2578 
2579 /*
2580  * read zvol property and convert to binary
2581  */
2582 sbd_status_t
2583 sbd_open_zfs_meta(sbd_lu_t *sl)
2584 {
2585 	char		*meta = NULL, cl, ch;
2586 	int		i;
2587 	char		*tmp, *ptr;
2588 	uint64_t	rc = SBD_SUCCESS;
2589 	int		len;
2590 	char		*file;
2591 
2592 	if (sbd_create_zfs_meta_object(sl) == SBD_FAILURE)
2593 		return (SBD_FAILURE);
2594 
2595 	rw_enter(&sl->sl_zfs_meta_lock, RW_WRITER);
2596 	file = sbd_get_zvol_name(sl);
2597 	if (sbd_zvolget(file, &meta)) {
2598 		rc = SBD_FAILURE;
2599 		goto done;
2600 	}
2601 	tmp = meta;
2602 	/* convert ascii hex to binary meta */
2603 	len = strlen(meta);
2604 	ptr = sl->sl_zfs_meta;
2605 	for (i = 0; i < len; i += 2) {
2606 		ch = sbd_ctoi(*tmp++);
2607 		cl = sbd_ctoi(*tmp++);
2608 		if (ch == -1 || cl == -1) {
2609 			rc = SBD_FAILURE;
2610 			break;
2611 		}
2612 		*ptr++ = (ch << 4) + cl;
2613 	}
2614 done:
2615 	rw_exit(&sl->sl_zfs_meta_lock);
2616 	if (meta)
2617 		kmem_free(meta, len + 1);
2618 	kmem_free(file, strlen(file) + 1);
2619 	return (rc);
2620 }
2621 
2622 sbd_status_t
2623 sbd_read_zfs_meta(sbd_lu_t *sl, uint8_t *buf, uint64_t sz, uint64_t off)
2624 {
2625 	ASSERT(sl->sl_zfs_meta);
2626 	rw_enter(&sl->sl_zfs_meta_lock, RW_READER);
2627 	bcopy(&sl->sl_zfs_meta[off], buf, sz);
2628 	rw_exit(&sl->sl_zfs_meta_lock);
2629 	return (SBD_SUCCESS);
2630 }
2631 
2632 sbd_status_t
2633 sbd_write_zfs_meta(sbd_lu_t *sl, uint8_t *buf, uint64_t sz, uint64_t off)
2634 {
2635 	char		*ptr, *ah_meta;
2636 	char		*dp = NULL;
2637 	int		i, num;
2638 	char		*file;
2639 
2640 	ASSERT(sl->sl_zfs_meta);
2641 	if ((off + sz) > (ZAP_MAXVALUELEN / 2 - 1)) {
2642 		return (SBD_META_CORRUPTED);
2643 	}
2644 	ptr = ah_meta = kmem_zalloc(ZAP_MAXVALUELEN, KM_SLEEP);
2645 	rw_enter(&sl->sl_zfs_meta_lock, RW_WRITER);
2646 	bcopy(buf, &sl->sl_zfs_meta[off], sz);
2647 	/* convert local copy to ascii hex */
2648 	dp = sl->sl_zfs_meta;
2649 	for (i = 0; i < sl->sl_total_meta_size; i++, dp++) {
2650 		num = ((*dp) >> 4) & 0xF;
2651 		*ah_meta++ = (num < 10) ? (num + '0') : (num + ('a' - 10));
2652 		num = (*dp) & 0xF;
2653 		*ah_meta++ = (num < 10) ? (num + '0') : (num + ('a' - 10));
2654 	}
2655 	*ah_meta = NULL;
2656 	file = sbd_get_zvol_name(sl);
2657 	if (sbd_zvolset(file, (char *)ptr)) {
2658 		rw_exit(&sl->sl_zfs_meta_lock);
2659 		kmem_free(ptr, ZAP_MAXVALUELEN);
2660 		kmem_free(file, strlen(file) + 1);
2661 		return (SBD_META_CORRUPTED);
2662 	}
2663 	rw_exit(&sl->sl_zfs_meta_lock);
2664 	kmem_free(ptr, ZAP_MAXVALUELEN);
2665 	kmem_free(file, strlen(file) + 1);
2666 	return (SBD_SUCCESS);
2667 }
2668 
2669 int
2670 sbd_is_zvol(char *path)
2671 {
2672 	int is_zfs = 0;
2673 
2674 	if (SBD_IS_ZVOL(path) == 0)
2675 		is_zfs = 1;
2676 
2677 	return (is_zfs);
2678 }
2679 
2680 /*
2681  * set write cache disable
2682  * wcd - 1 = disable, 0 = enable
2683  */
2684 sbd_status_t
2685 sbd_wcd_set(int wcd, sbd_lu_t *sl)
2686 {
2687 	/* translate to wce bit */
2688 	int wce = wcd ? 0 : 1;
2689 	int ret;
2690 	sbd_status_t sret = SBD_SUCCESS;
2691 
2692 	mutex_enter(&sl->sl_lock);
2693 	sl->sl_flags &= ~SL_WRITEBACK_CACHE_SET_UNSUPPORTED;
2694 
2695 	if (sl->sl_data_vp->v_type == VREG) {
2696 		sl->sl_flags |= SL_FLUSH_ON_DISABLED_WRITECACHE;
2697 		goto done;
2698 	}
2699 
2700 	ret = VOP_IOCTL(sl->sl_data_vp, DKIOCSETWCE, (intptr_t)&wce, FKIOCTL,
2701 	    kcred, NULL, NULL);
2702 	if (ret == 0) {
2703 		sl->sl_flags &= ~SL_WRITEBACK_CACHE_SET_UNSUPPORTED;
2704 		sl->sl_flags &= ~SL_FLUSH_ON_DISABLED_WRITECACHE;
2705 	} else {
2706 		sl->sl_flags |= SL_WRITEBACK_CACHE_SET_UNSUPPORTED;
2707 		sl->sl_flags |= SL_FLUSH_ON_DISABLED_WRITECACHE;
2708 		sret = SBD_FAILURE;
2709 		goto done;
2710 	}
2711 
2712 done:
2713 	mutex_exit(&sl->sl_lock);
2714 	return (sret);
2715 }
2716 
2717 /*
2718  * get write cache disable
2719  * wcd - 1 = disable, 0 = enable
2720  */
2721 void
2722 sbd_wcd_get(int *wcd, sbd_lu_t *sl)
2723 {
2724 	int wce;
2725 	int ret;
2726 
2727 	if (sl->sl_data_vp->v_type == VREG) {
2728 		*wcd = 0;
2729 		return;
2730 	}
2731 
2732 	ret = VOP_IOCTL(sl->sl_data_vp, DKIOCGETWCE, (intptr_t)&wce, FKIOCTL,
2733 	    kcred, NULL, NULL);
2734 	/* if write cache get failed, assume disabled */
2735 	if (ret) {
2736 		*wcd = 1;
2737 	} else {
2738 		/* translate to wcd bit */
2739 		*wcd = wce ? 0 : 1;
2740 	}
2741 }
2742 
2743 int
2744 sbd_zvolget(char *zvol_name, char **comstarprop)
2745 {
2746 	ldi_handle_t	zfs_lh;
2747 	nvlist_t	*nv = NULL, *nv2;
2748 	zfs_cmd_t	*zc;
2749 	char		*ptr;
2750 	int size = 1024;
2751 	int unused;
2752 	int rc;
2753 
2754 	if ((rc = ldi_open_by_name("/dev/zfs", FREAD | FWRITE, kcred,
2755 	    &zfs_lh, sbd_zfs_ident)) != 0) {
2756 		cmn_err(CE_WARN, "ldi_open %d", rc);
2757 		return (ENXIO);
2758 	}
2759 
2760 	zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP);
2761 	(void) strlcpy(zc->zc_name, zvol_name, sizeof (zc->zc_name));
2762 again:
2763 	zc->zc_nvlist_dst = (uint64_t)(intptr_t)kmem_alloc(size,
2764 	    KM_SLEEP);
2765 	zc->zc_nvlist_dst_size = size;
2766 	rc = ldi_ioctl(zfs_lh, ZFS_IOC_OBJSET_STATS, (intptr_t)zc,
2767 	    FKIOCTL, kcred, &unused);
2768 	/*
2769 	 * ENOMEM means the list is larger than what we've allocated
2770 	 * ldi_ioctl will fail with ENOMEM only once
2771 	 */
2772 	if (rc == ENOMEM) {
2773 		int newsize;
2774 		newsize = zc->zc_nvlist_dst_size;
2775 		kmem_free((void *)(uintptr_t)zc->zc_nvlist_dst, size);
2776 		size = newsize;
2777 		goto again;
2778 	} else if (rc != 0) {
2779 		goto out;
2780 	}
2781 	rc = nvlist_unpack((char *)(uintptr_t)zc->zc_nvlist_dst,
2782 	    zc->zc_nvlist_dst_size, &nv, 0);
2783 	ASSERT(rc == 0);	/* nvlist_unpack should not fail */
2784 	if ((rc = nvlist_lookup_nvlist(nv, "stmf_sbd_lu", &nv2)) == 0) {
2785 		rc = nvlist_lookup_string(nv2, ZPROP_VALUE, &ptr);
2786 		if (rc != 0) {
2787 			cmn_err(CE_WARN, "couldn't get value");
2788 		} else {
2789 			*comstarprop = kmem_alloc(strlen(ptr) + 1,
2790 			    KM_SLEEP);
2791 			(void) strcpy(*comstarprop, ptr);
2792 		}
2793 	}
2794 out:
2795 	if (nv != NULL)
2796 		nvlist_free(nv);
2797 	kmem_free((void *)(uintptr_t)zc->zc_nvlist_dst, size);
2798 	kmem_free(zc, sizeof (zfs_cmd_t));
2799 	(void) ldi_close(zfs_lh, FREAD|FWRITE, kcred);
2800 
2801 	return (rc);
2802 }
2803 
2804 int
2805 sbd_zvolset(char *zvol_name, char *comstarprop)
2806 {
2807 	ldi_handle_t	zfs_lh;
2808 	nvlist_t	*nv;
2809 	char		*packed = NULL;
2810 	size_t		len;
2811 	zfs_cmd_t	*zc;
2812 	int unused;
2813 	int rc;
2814 
2815 	if ((rc = ldi_open_by_name("/dev/zfs", FREAD | FWRITE, kcred,
2816 	    &zfs_lh, sbd_zfs_ident)) != 0) {
2817 		cmn_err(CE_WARN, "ldi_open %d", rc);
2818 		return (ENXIO);
2819 	}
2820 	(void) nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP);
2821 	(void) nvlist_add_string(nv, "stmf_sbd_lu", comstarprop);
2822 	if ((rc = nvlist_pack(nv, &packed, &len, NV_ENCODE_NATIVE, KM_SLEEP))) {
2823 		goto out;
2824 	}
2825 
2826 	zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP);
2827 	(void) strlcpy(zc->zc_name, zvol_name, sizeof (zc->zc_name));
2828 	zc->zc_nvlist_src = (uint64_t)(intptr_t)packed;
2829 	zc->zc_nvlist_src_size = len;
2830 	rc = ldi_ioctl(zfs_lh, ZFS_IOC_SET_PROP, (intptr_t)zc,
2831 	    FKIOCTL, kcred, &unused);
2832 	if (rc != 0) {
2833 		cmn_err(CE_NOTE, "ioctl failed %d", rc);
2834 	}
2835 	kmem_free(zc, sizeof (zfs_cmd_t));
2836 out:
2837 	nvlist_free(nv);
2838 	(void) ldi_close(zfs_lh, FREAD|FWRITE, kcred);
2839 	return (rc);
2840 }
2841