xref: /titanic_50/usr/src/uts/sun4v/io/vdc.c (revision 8e6a2a040587479821d1e682a28bcef7e75f19a6)
11ae08745Sheppo /*
21ae08745Sheppo  * CDDL HEADER START
31ae08745Sheppo  *
41ae08745Sheppo  * The contents of this file are subject to the terms of the
51ae08745Sheppo  * Common Development and Distribution License (the "License").
61ae08745Sheppo  * You may not use this file except in compliance with the License.
71ae08745Sheppo  *
81ae08745Sheppo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91ae08745Sheppo  * or http://www.opensolaris.org/os/licensing.
101ae08745Sheppo  * See the License for the specific language governing permissions
111ae08745Sheppo  * and limitations under the License.
121ae08745Sheppo  *
131ae08745Sheppo  * When distributing Covered Code, include this CDDL HEADER in each
141ae08745Sheppo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151ae08745Sheppo  * If applicable, add the following below this CDDL HEADER, with the
161ae08745Sheppo  * fields enclosed by brackets "[]" replaced with your own identifying
171ae08745Sheppo  * information: Portions Copyright [yyyy] [name of copyright owner]
181ae08745Sheppo  *
191ae08745Sheppo  * CDDL HEADER END
201ae08745Sheppo  */
211ae08745Sheppo 
221ae08745Sheppo /*
231ae08745Sheppo  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
241ae08745Sheppo  * Use is subject to license terms.
251ae08745Sheppo  */
261ae08745Sheppo 
271ae08745Sheppo #pragma ident	"%Z%%M%	%I%	%E% SMI"
281ae08745Sheppo 
291ae08745Sheppo /*
301ae08745Sheppo  * LDoms virtual disk client (vdc) device driver
311ae08745Sheppo  *
321ae08745Sheppo  * This driver runs on a guest logical domain and communicates with the virtual
331ae08745Sheppo  * disk server (vds) driver running on the service domain which is exporting
341ae08745Sheppo  * virtualized "disks" to the guest logical domain.
351ae08745Sheppo  *
361ae08745Sheppo  * The driver can be divided into four sections:
371ae08745Sheppo  *
381ae08745Sheppo  * 1) generic device driver housekeeping
391ae08745Sheppo  *	_init, _fini, attach, detach, ops structures, etc.
401ae08745Sheppo  *
411ae08745Sheppo  * 2) communication channel setup
421ae08745Sheppo  *	Setup the communications link over the LDC channel that vdc uses to
431ae08745Sheppo  *	talk to the vDisk server. Initialise the descriptor ring which
441ae08745Sheppo  *	allows the LDC clients to transfer data via memory mappings.
451ae08745Sheppo  *
461ae08745Sheppo  * 3) Support exported to upper layers (filesystems, etc)
471ae08745Sheppo  *	The upper layers call into vdc via strategy(9E) and DKIO(7I)
481ae08745Sheppo  *	ioctl calls. vdc will copy the data to be written to the descriptor
491ae08745Sheppo  *	ring or maps the buffer to store the data read by the vDisk
501ae08745Sheppo  *	server into the descriptor ring. It then sends a message to the
511ae08745Sheppo  *	vDisk server requesting it to complete the operation.
521ae08745Sheppo  *
531ae08745Sheppo  * 4) Handling responses from vDisk server.
541ae08745Sheppo  *	The vDisk server will ACK some or all of the messages vdc sends to it
551ae08745Sheppo  *	(this is configured during the handshake). Upon receipt of an ACK
561ae08745Sheppo  *	vdc will check the descriptor ring and signal to the upper layer
571ae08745Sheppo  *	code waiting on the IO.
581ae08745Sheppo  */
591ae08745Sheppo 
601ae08745Sheppo #include <sys/conf.h>
611ae08745Sheppo #include <sys/disp.h>
621ae08745Sheppo #include <sys/ddi.h>
631ae08745Sheppo #include <sys/dkio.h>
641ae08745Sheppo #include <sys/efi_partition.h>
651ae08745Sheppo #include <sys/fcntl.h>
661ae08745Sheppo #include <sys/file.h>
671ae08745Sheppo #include <sys/mach_descrip.h>
681ae08745Sheppo #include <sys/modctl.h>
691ae08745Sheppo #include <sys/mdeg.h>
701ae08745Sheppo #include <sys/note.h>
711ae08745Sheppo #include <sys/open.h>
721ae08745Sheppo #include <sys/stat.h>
731ae08745Sheppo #include <sys/sunddi.h>
741ae08745Sheppo #include <sys/types.h>
751ae08745Sheppo #include <sys/promif.h>
761ae08745Sheppo #include <sys/vtoc.h>
771ae08745Sheppo #include <sys/archsystm.h>
781ae08745Sheppo #include <sys/sysmacros.h>
791ae08745Sheppo 
801ae08745Sheppo #include <sys/cdio.h>
811ae08745Sheppo #include <sys/dktp/cm.h>
821ae08745Sheppo #include <sys/dktp/fdisk.h>
831ae08745Sheppo #include <sys/scsi/generic/sense.h>
841ae08745Sheppo #include <sys/scsi/impl/uscsi.h>	/* Needed for defn of USCSICMD ioctl */
851ae08745Sheppo #include <sys/scsi/targets/sddef.h>
861ae08745Sheppo 
871ae08745Sheppo #include <sys/ldoms.h>
881ae08745Sheppo #include <sys/ldc.h>
891ae08745Sheppo #include <sys/vio_common.h>
901ae08745Sheppo #include <sys/vio_mailbox.h>
911ae08745Sheppo #include <sys/vdsk_common.h>
921ae08745Sheppo #include <sys/vdsk_mailbox.h>
931ae08745Sheppo #include <sys/vdc.h>
941ae08745Sheppo 
951ae08745Sheppo /*
961ae08745Sheppo  * function prototypes
971ae08745Sheppo  */
981ae08745Sheppo 
991ae08745Sheppo /* standard driver functions */
1001ae08745Sheppo static int	vdc_open(dev_t *dev, int flag, int otyp, cred_t *cred);
1011ae08745Sheppo static int	vdc_close(dev_t dev, int flag, int otyp, cred_t *cred);
1021ae08745Sheppo static int	vdc_strategy(struct buf *buf);
1031ae08745Sheppo static int	vdc_print(dev_t dev, char *str);
1041ae08745Sheppo static int	vdc_dump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk);
1051ae08745Sheppo static int	vdc_read(dev_t dev, struct uio *uio, cred_t *cred);
1061ae08745Sheppo static int	vdc_write(dev_t dev, struct uio *uio, cred_t *cred);
1071ae08745Sheppo static int	vdc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
1081ae08745Sheppo 			cred_t *credp, int *rvalp);
1091ae08745Sheppo static int	vdc_aread(dev_t dev, struct aio_req *aio, cred_t *cred);
1101ae08745Sheppo static int	vdc_awrite(dev_t dev, struct aio_req *aio, cred_t *cred);
1111ae08745Sheppo 
1121ae08745Sheppo static int	vdc_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
1131ae08745Sheppo 			void *arg, void **resultp);
1141ae08745Sheppo static int	vdc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
1151ae08745Sheppo static int	vdc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
1161ae08745Sheppo 
1171ae08745Sheppo /* setup */
1180a55fbb7Slm66018 static int	vdc_send(vdc_t *vdc, caddr_t pkt, size_t *msglen);
1191ae08745Sheppo static int	vdc_do_ldc_init(vdc_t *vdc);
1201ae08745Sheppo static int	vdc_start_ldc_connection(vdc_t *vdc);
1211ae08745Sheppo static int	vdc_create_device_nodes(vdc_t *vdc);
1221ae08745Sheppo static int	vdc_create_device_nodes_props(vdc_t *vdc);
1231ae08745Sheppo static int	vdc_get_ldc_id(dev_info_t *dip, uint64_t *ldc_id);
1240a55fbb7Slm66018 static int	vdc_do_ldc_up(vdc_t *vdc);
1251ae08745Sheppo static void	vdc_terminate_ldc(vdc_t *vdc);
1261ae08745Sheppo static int	vdc_init_descriptor_ring(vdc_t *vdc);
1271ae08745Sheppo static void	vdc_destroy_descriptor_ring(vdc_t *vdc);
1281ae08745Sheppo 
1291ae08745Sheppo /* handshake with vds */
1301ae08745Sheppo static void		vdc_init_handshake_negotiation(void *arg);
1310a55fbb7Slm66018 static int		vdc_init_ver_negotiation(vdc_t *vdc, vio_ver_t ver);
1321ae08745Sheppo static int		vdc_init_attr_negotiation(vdc_t *vdc);
1331ae08745Sheppo static int		vdc_init_dring_negotiate(vdc_t *vdc);
1341ae08745Sheppo static void		vdc_reset_connection(vdc_t *vdc, boolean_t resetldc);
1351ae08745Sheppo static boolean_t	vdc_is_able_to_tx_data(vdc_t *vdc, int flag);
1360a55fbb7Slm66018 static boolean_t	vdc_is_supported_version(vio_ver_msg_t *ver_msg);
1371ae08745Sheppo 
1380a55fbb7Slm66018 /* processing incoming messages from vDisk server */
1391ae08745Sheppo static void	vdc_process_msg_thread(vdc_t *vdc);
1401ae08745Sheppo static void	vdc_process_msg(void *arg);
1410a55fbb7Slm66018 static void	vdc_do_process_msg(vdc_t *vdc);
1420a55fbb7Slm66018 static uint_t	vdc_handle_cb(uint64_t event, caddr_t arg);
1431ae08745Sheppo static int	vdc_process_ctrl_msg(vdc_t *vdc, vio_msg_t msg);
1441ae08745Sheppo static int	vdc_process_data_msg(vdc_t *vdc, vio_msg_t msg);
1451ae08745Sheppo static int	vdc_process_err_msg(vdc_t *vdc, vio_msg_t msg);
1460a55fbb7Slm66018 static int	vdc_handle_ver_msg(vdc_t *vdc, vio_ver_msg_t *ver_msg);
1470a55fbb7Slm66018 static int	vdc_handle_attr_msg(vdc_t *vdc, vd_attr_msg_t *attr_msg);
1480a55fbb7Slm66018 static int	vdc_handle_dring_reg_msg(vdc_t *vdc, vio_dring_reg_msg_t *msg);
1491ae08745Sheppo static int	vdc_get_next_dring_entry_id(vdc_t *vdc, uint_t needed);
1501ae08745Sheppo static int	vdc_populate_descriptor(vdc_t *vdc, caddr_t addr,
1511ae08745Sheppo 			size_t nbytes, int op, uint64_t arg, uint64_t slice);
1521ae08745Sheppo static int	vdc_wait_for_descriptor_update(vdc_t *vdc, uint_t idx,
1531ae08745Sheppo 			vio_dring_msg_t dmsg);
1541ae08745Sheppo static int	vdc_depopulate_descriptor(vdc_t *vdc, uint_t idx);
1551ae08745Sheppo static int	vdc_get_response(vdc_t *vdc, int start, int end);
1561ae08745Sheppo static int	vdc_populate_mem_hdl(vdc_t *vdc, uint_t idx,
1571ae08745Sheppo 			caddr_t addr, size_t nbytes, int operation);
1581ae08745Sheppo static boolean_t vdc_verify_seq_num(vdc_t *vdc, vio_dring_msg_t *dring_msg, int
1591ae08745Sheppo 			num_msgs);
1601ae08745Sheppo 
1611ae08745Sheppo /* dkio */
1621ae08745Sheppo static int	vd_process_ioctl(dev_t dev, int cmd, caddr_t arg, int mode);
1631ae08745Sheppo static int	vdc_create_fake_geometry(vdc_t *vdc);
1640a55fbb7Slm66018 static int	vdc_setup_disk_layout(vdc_t *vdc);
1650a55fbb7Slm66018 static int	vdc_null_copy_func(void *from, void *to, int mode, int dir);
1660a55fbb7Slm66018 static int	vdc_get_vtoc_convert(void *from, void *to, int mode, int dir);
1670a55fbb7Slm66018 static int	vdc_set_vtoc_convert(void *from, void *to, int mode, int dir);
1680a55fbb7Slm66018 static int	vdc_get_geom_convert(void *from, void *to, int mode, int dir);
1690a55fbb7Slm66018 static int	vdc_set_geom_convert(void *from, void *to, int mode, int dir);
1700a55fbb7Slm66018 static int	vdc_uscsicmd_convert(void *from, void *to, int mode, int dir);
1711ae08745Sheppo 
1721ae08745Sheppo /*
1731ae08745Sheppo  * Module variables
1741ae08745Sheppo  */
1751ae08745Sheppo uint64_t	vdc_hz_timeout;
1761ae08745Sheppo uint64_t	vdc_usec_timeout = VDC_USEC_TIMEOUT_MIN;
1771ae08745Sheppo uint64_t	vdc_dump_usec_timeout = VDC_USEC_TIMEOUT_MIN / 300;
1781ae08745Sheppo static int	vdc_retries = VDC_RETRIES;
1791ae08745Sheppo static int	vdc_dump_retries = VDC_RETRIES * 10;
1801ae08745Sheppo 
1811ae08745Sheppo /* Soft state pointer */
1821ae08745Sheppo static void	*vdc_state;
1831ae08745Sheppo 
1841ae08745Sheppo /* variable level controlling the verbosity of the error/debug messages */
1851ae08745Sheppo int	vdc_msglevel = 0;
1861ae08745Sheppo 
1870a55fbb7Slm66018 /*
1880a55fbb7Slm66018  * Supported vDisk protocol version pairs.
1890a55fbb7Slm66018  *
1900a55fbb7Slm66018  * The first array entry is the latest and preferred version.
1910a55fbb7Slm66018  */
1920a55fbb7Slm66018 static const vio_ver_t	vdc_version[] = {{1, 0}};
1931ae08745Sheppo 
1941ae08745Sheppo static void
1951ae08745Sheppo vdc_msg(const char *format, ...)
1961ae08745Sheppo {
1971ae08745Sheppo 	va_list	args;
1981ae08745Sheppo 
1991ae08745Sheppo 	va_start(args, format);
2001ae08745Sheppo 	vcmn_err(CE_CONT, format, args);
2011ae08745Sheppo 	va_end(args);
2021ae08745Sheppo }
2031ae08745Sheppo 
2041ae08745Sheppo static struct cb_ops vdc_cb_ops = {
2051ae08745Sheppo 	vdc_open,	/* cb_open */
2061ae08745Sheppo 	vdc_close,	/* cb_close */
2071ae08745Sheppo 	vdc_strategy,	/* cb_strategy */
2081ae08745Sheppo 	vdc_print,	/* cb_print */
2091ae08745Sheppo 	vdc_dump,	/* cb_dump */
2101ae08745Sheppo 	vdc_read,	/* cb_read */
2111ae08745Sheppo 	vdc_write,	/* cb_write */
2121ae08745Sheppo 	vdc_ioctl,	/* cb_ioctl */
2131ae08745Sheppo 	nodev,		/* cb_devmap */
2141ae08745Sheppo 	nodev,		/* cb_mmap */
2151ae08745Sheppo 	nodev,		/* cb_segmap */
2161ae08745Sheppo 	nochpoll,	/* cb_chpoll */
2171ae08745Sheppo 	ddi_prop_op,	/* cb_prop_op */
2181ae08745Sheppo 	NULL,		/* cb_str */
2191ae08745Sheppo 	D_MP | D_64BIT,	/* cb_flag */
2201ae08745Sheppo 	CB_REV,		/* cb_rev */
2211ae08745Sheppo 	vdc_aread,	/* cb_aread */
2221ae08745Sheppo 	vdc_awrite	/* cb_awrite */
2231ae08745Sheppo };
2241ae08745Sheppo 
2251ae08745Sheppo static struct dev_ops vdc_ops = {
2261ae08745Sheppo 	DEVO_REV,	/* devo_rev */
2271ae08745Sheppo 	0,		/* devo_refcnt */
2281ae08745Sheppo 	vdc_getinfo,	/* devo_getinfo */
2291ae08745Sheppo 	nulldev,	/* devo_identify */
2301ae08745Sheppo 	nulldev,	/* devo_probe */
2311ae08745Sheppo 	vdc_attach,	/* devo_attach */
2321ae08745Sheppo 	vdc_detach,	/* devo_detach */
2331ae08745Sheppo 	nodev,		/* devo_reset */
2341ae08745Sheppo 	&vdc_cb_ops,	/* devo_cb_ops */
2351ae08745Sheppo 	NULL,		/* devo_bus_ops */
2361ae08745Sheppo 	nulldev		/* devo_power */
2371ae08745Sheppo };
2381ae08745Sheppo 
2391ae08745Sheppo static struct modldrv modldrv = {
2401ae08745Sheppo 	&mod_driverops,
2411ae08745Sheppo 	"virtual disk client %I%",
2421ae08745Sheppo 	&vdc_ops,
2431ae08745Sheppo };
2441ae08745Sheppo 
2451ae08745Sheppo static struct modlinkage modlinkage = {
2461ae08745Sheppo 	MODREV_1,
2471ae08745Sheppo 	&modldrv,
2481ae08745Sheppo 	NULL
2491ae08745Sheppo };
2501ae08745Sheppo 
2511ae08745Sheppo /* -------------------------------------------------------------------------- */
2521ae08745Sheppo 
2531ae08745Sheppo /*
2541ae08745Sheppo  * Device Driver housekeeping and setup
2551ae08745Sheppo  */
2561ae08745Sheppo 
2571ae08745Sheppo int
2581ae08745Sheppo _init(void)
2591ae08745Sheppo {
2601ae08745Sheppo 	int	status;
2611ae08745Sheppo 
2621ae08745Sheppo 	if ((status = ddi_soft_state_init(&vdc_state, sizeof (vdc_t), 1)) != 0)
2631ae08745Sheppo 		return (status);
2641ae08745Sheppo 	if ((status = mod_install(&modlinkage)) != 0)
2651ae08745Sheppo 		ddi_soft_state_fini(&vdc_state);
2661ae08745Sheppo 	return (status);
2671ae08745Sheppo }
2681ae08745Sheppo 
2691ae08745Sheppo int
2701ae08745Sheppo _info(struct modinfo *modinfop)
2711ae08745Sheppo {
2721ae08745Sheppo 	return (mod_info(&modlinkage, modinfop));
2731ae08745Sheppo }
2741ae08745Sheppo 
2751ae08745Sheppo int
2761ae08745Sheppo _fini(void)
2771ae08745Sheppo {
2781ae08745Sheppo 	int	status;
2791ae08745Sheppo 
2801ae08745Sheppo 	if ((status = mod_remove(&modlinkage)) != 0)
2811ae08745Sheppo 		return (status);
2821ae08745Sheppo 	ddi_soft_state_fini(&vdc_state);
2831ae08745Sheppo 	return (0);
2841ae08745Sheppo }
2851ae08745Sheppo 
2861ae08745Sheppo static int
2871ae08745Sheppo vdc_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,  void *arg, void **resultp)
2881ae08745Sheppo {
2891ae08745Sheppo 	_NOTE(ARGUNUSED(dip))
2901ae08745Sheppo 
2911ae08745Sheppo 	int	instance = SDUNIT(getminor((dev_t)arg));
2921ae08745Sheppo 	vdc_t	*vdc = NULL;
2931ae08745Sheppo 
2941ae08745Sheppo 	switch (cmd) {
2951ae08745Sheppo 	case DDI_INFO_DEVT2DEVINFO:
2961ae08745Sheppo 		if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) {
2971ae08745Sheppo 			*resultp = NULL;
2981ae08745Sheppo 			return (DDI_FAILURE);
2991ae08745Sheppo 		}
3001ae08745Sheppo 		*resultp = vdc->dip;
3011ae08745Sheppo 		return (DDI_SUCCESS);
3021ae08745Sheppo 	case DDI_INFO_DEVT2INSTANCE:
3031ae08745Sheppo 		*resultp = (void *)(uintptr_t)instance;
3041ae08745Sheppo 		return (DDI_SUCCESS);
3051ae08745Sheppo 	default:
3061ae08745Sheppo 		*resultp = NULL;
3071ae08745Sheppo 		return (DDI_FAILURE);
3081ae08745Sheppo 	}
3091ae08745Sheppo }
3101ae08745Sheppo 
3111ae08745Sheppo static int
3121ae08745Sheppo vdc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
3131ae08745Sheppo {
3141ae08745Sheppo 	int	instance;
3151ae08745Sheppo 	int	rv;
3161ae08745Sheppo 	uint_t	retries = 0;
3171ae08745Sheppo 	vdc_t	*vdc = NULL;
3181ae08745Sheppo 
3191ae08745Sheppo 	switch (cmd) {
3201ae08745Sheppo 	case DDI_DETACH:
3211ae08745Sheppo 		/* the real work happens below */
3221ae08745Sheppo 		break;
3231ae08745Sheppo 	case DDI_SUSPEND:
3241ae08745Sheppo 		/* nothing to do for this non-device */
3251ae08745Sheppo 		return (DDI_SUCCESS);
3261ae08745Sheppo 	default:
3271ae08745Sheppo 		return (DDI_FAILURE);
3281ae08745Sheppo 	}
3291ae08745Sheppo 
3301ae08745Sheppo 	ASSERT(cmd == DDI_DETACH);
3311ae08745Sheppo 	instance = ddi_get_instance(dip);
3321ae08745Sheppo 	PR1("%s[%d] Entered\n", __func__, instance);
3331ae08745Sheppo 
3341ae08745Sheppo 	if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) {
3351ae08745Sheppo 		vdc_msg("%s[%d]:  Could not get state structure.",
3361ae08745Sheppo 		    __func__, instance);
3371ae08745Sheppo 		return (DDI_FAILURE);
3381ae08745Sheppo 	}
3391ae08745Sheppo 
3401ae08745Sheppo 	if (vdc->open) {
3411ae08745Sheppo 		PR0("%s[%d]: Cannot detach: device is open",
3421ae08745Sheppo 				__func__, instance);
3431ae08745Sheppo 		return (DDI_FAILURE);
3441ae08745Sheppo 	}
3451ae08745Sheppo 
3461ae08745Sheppo 	PR0("%s[%d] proceeding...\n", __func__, instance);
3471ae08745Sheppo 
3481ae08745Sheppo 	/*
3491ae08745Sheppo 	 * try and disable callbacks to prevent another handshake
3501ae08745Sheppo 	 */
3511ae08745Sheppo 	rv = ldc_set_cb_mode(vdc->ldc_handle, LDC_CB_DISABLE);
3521ae08745Sheppo 	PR0("%s[%d] callback disabled (rv=%d)\n", __func__, instance, rv);
3531ae08745Sheppo 
3541ae08745Sheppo 	/*
3551ae08745Sheppo 	 * Prevent any more attempts to start a handshake with the vdisk
3561ae08745Sheppo 	 * server and tear down the existing connection.
3571ae08745Sheppo 	 */
3581ae08745Sheppo 	mutex_enter(&vdc->lock);
3591ae08745Sheppo 	vdc->initialized |= VDC_HANDSHAKE_STOP;
3601ae08745Sheppo 	vdc_reset_connection(vdc, B_TRUE);
3611ae08745Sheppo 	mutex_exit(&vdc->lock);
3621ae08745Sheppo 
3631ae08745Sheppo 	if (vdc->initialized & VDC_THREAD) {
3641ae08745Sheppo 		mutex_enter(&vdc->msg_proc_lock);
3651ae08745Sheppo 		vdc->msg_proc_thr_state = VDC_THR_STOP;
3661ae08745Sheppo 		vdc->msg_pending = B_TRUE;
3671ae08745Sheppo 		cv_signal(&vdc->msg_proc_cv);
3681ae08745Sheppo 
3691ae08745Sheppo 		while (vdc->msg_proc_thr_state != VDC_THR_DONE) {
3701ae08745Sheppo 			PR0("%s[%d]: Waiting for thread to exit\n",
3711ae08745Sheppo 				__func__, instance);
3721ae08745Sheppo 			rv = cv_timedwait(&vdc->msg_proc_cv,
3731ae08745Sheppo 				&vdc->msg_proc_lock, VD_GET_TIMEOUT_HZ(1));
3741ae08745Sheppo 			if ((rv == -1) && (retries++ > vdc_retries))
3751ae08745Sheppo 				break;
3761ae08745Sheppo 		}
3771ae08745Sheppo 		mutex_exit(&vdc->msg_proc_lock);
3781ae08745Sheppo 	}
3791ae08745Sheppo 
3801ae08745Sheppo 	mutex_enter(&vdc->lock);
3811ae08745Sheppo 
3821ae08745Sheppo 	if (vdc->initialized & VDC_DRING)
3831ae08745Sheppo 		vdc_destroy_descriptor_ring(vdc);
3841ae08745Sheppo 
3851ae08745Sheppo 	if (vdc->initialized & VDC_LDC)
3861ae08745Sheppo 		vdc_terminate_ldc(vdc);
3871ae08745Sheppo 
3881ae08745Sheppo 	mutex_exit(&vdc->lock);
3891ae08745Sheppo 
3901ae08745Sheppo 	if (vdc->initialized & VDC_MINOR) {
3911ae08745Sheppo 		ddi_prop_remove_all(dip);
3921ae08745Sheppo 		ddi_remove_minor_node(dip, NULL);
3931ae08745Sheppo 	}
3941ae08745Sheppo 
3951ae08745Sheppo 	if (vdc->initialized & VDC_LOCKS) {
3961ae08745Sheppo 		mutex_destroy(&vdc->lock);
3971ae08745Sheppo 		mutex_destroy(&vdc->attach_lock);
3981ae08745Sheppo 		mutex_destroy(&vdc->msg_proc_lock);
3991ae08745Sheppo 		mutex_destroy(&vdc->dring_lock);
4001ae08745Sheppo 		cv_destroy(&vdc->cv);
4011ae08745Sheppo 		cv_destroy(&vdc->attach_cv);
4021ae08745Sheppo 		cv_destroy(&vdc->msg_proc_cv);
4031ae08745Sheppo 	}
4041ae08745Sheppo 
4051ae08745Sheppo 	if (vdc->minfo)
4061ae08745Sheppo 		kmem_free(vdc->minfo, sizeof (struct dk_minfo));
4071ae08745Sheppo 
4081ae08745Sheppo 	if (vdc->cinfo)
4091ae08745Sheppo 		kmem_free(vdc->cinfo, sizeof (struct dk_cinfo));
4101ae08745Sheppo 
4111ae08745Sheppo 	if (vdc->vtoc)
4121ae08745Sheppo 		kmem_free(vdc->vtoc, sizeof (struct vtoc));
4131ae08745Sheppo 
4140a55fbb7Slm66018 	if (vdc->label)
4150a55fbb7Slm66018 		kmem_free(vdc->label, DK_LABEL_SIZE);
4160a55fbb7Slm66018 
4171ae08745Sheppo 	if (vdc->initialized & VDC_SOFT_STATE)
4181ae08745Sheppo 		ddi_soft_state_free(vdc_state, instance);
4191ae08745Sheppo 
4201ae08745Sheppo 	PR0("%s[%d] End %p\n", __func__, instance, vdc);
4211ae08745Sheppo 
4221ae08745Sheppo 	return (DDI_SUCCESS);
4231ae08745Sheppo }
4241ae08745Sheppo 
4251ae08745Sheppo 
4261ae08745Sheppo static int
4271ae08745Sheppo vdc_do_attach(dev_info_t *dip)
4281ae08745Sheppo {
4291ae08745Sheppo 	int		instance;
4301ae08745Sheppo 	vdc_t		*vdc = NULL;
4311ae08745Sheppo 	int		status;
4321ae08745Sheppo 	uint_t		retries = 0;
4331ae08745Sheppo 
4341ae08745Sheppo 	ASSERT(dip != NULL);
4351ae08745Sheppo 
4361ae08745Sheppo 	instance = ddi_get_instance(dip);
4371ae08745Sheppo 	if (ddi_soft_state_zalloc(vdc_state, instance) != DDI_SUCCESS) {
4381ae08745Sheppo 		vdc_msg("%s:(%d): Couldn't alloc state structure",
4391ae08745Sheppo 		    __func__, instance);
4401ae08745Sheppo 		return (DDI_FAILURE);
4411ae08745Sheppo 	}
4421ae08745Sheppo 
4431ae08745Sheppo 	if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) {
4441ae08745Sheppo 		vdc_msg("%s:(%d): Could not get state structure.",
4451ae08745Sheppo 		    __func__, instance);
4461ae08745Sheppo 		return (DDI_FAILURE);
4471ae08745Sheppo 	}
4481ae08745Sheppo 
4491ae08745Sheppo 	/*
4501ae08745Sheppo 	 * We assign the value to initialized in this case to zero out the
4511ae08745Sheppo 	 * variable and then set bits in it to indicate what has been done
4521ae08745Sheppo 	 */
4531ae08745Sheppo 	vdc->initialized = VDC_SOFT_STATE;
4541ae08745Sheppo 
4551ae08745Sheppo 	vdc_hz_timeout = drv_usectohz(vdc_usec_timeout);
4561ae08745Sheppo 
4571ae08745Sheppo 	vdc->dip	= dip;
4581ae08745Sheppo 	vdc->instance	= instance;
4591ae08745Sheppo 	vdc->open	= 0;
4601ae08745Sheppo 	vdc->vdisk_type	= VD_DISK_TYPE_UNK;
4611ae08745Sheppo 	vdc->state	= VD_STATE_INIT;
4621ae08745Sheppo 	vdc->ldc_state	= 0;
4631ae08745Sheppo 	vdc->session_id = 0;
4641ae08745Sheppo 	vdc->block_size = DEV_BSIZE;
465*8e6a2a04Slm66018 	vdc->max_xfer_sz = maxphys / DEV_BSIZE;
4661ae08745Sheppo 
4671ae08745Sheppo 	vdc->vtoc = NULL;
4681ae08745Sheppo 	vdc->cinfo = NULL;
4691ae08745Sheppo 	vdc->minfo = NULL;
4701ae08745Sheppo 
4711ae08745Sheppo 	mutex_init(&vdc->lock, NULL, MUTEX_DRIVER, NULL);
4721ae08745Sheppo 	mutex_init(&vdc->attach_lock, NULL, MUTEX_DRIVER, NULL);
4731ae08745Sheppo 	mutex_init(&vdc->msg_proc_lock, NULL, MUTEX_DRIVER, NULL);
4741ae08745Sheppo 	mutex_init(&vdc->dring_lock, NULL, MUTEX_DRIVER, NULL);
4751ae08745Sheppo 	cv_init(&vdc->cv, NULL, CV_DRIVER, NULL);
4761ae08745Sheppo 	cv_init(&vdc->attach_cv, NULL, CV_DRIVER, NULL);
4771ae08745Sheppo 	cv_init(&vdc->msg_proc_cv, NULL, CV_DRIVER, NULL);
4781ae08745Sheppo 	vdc->initialized |= VDC_LOCKS;
4791ae08745Sheppo 
4801ae08745Sheppo 	vdc->msg_pending = B_FALSE;
4811ae08745Sheppo 	vdc->msg_proc_thr_id = thread_create(NULL, 0, vdc_process_msg_thread,
4821ae08745Sheppo 		vdc, 0, &p0, TS_RUN, minclsyspri);
4831ae08745Sheppo 	if (vdc->msg_proc_thr_id == NULL) {
4841ae08745Sheppo 		cmn_err(CE_NOTE, "[%d] Failed to create msg processing thread",
4851ae08745Sheppo 				instance);
4861ae08745Sheppo 		return (DDI_FAILURE);
4871ae08745Sheppo 	}
4881ae08745Sheppo 	vdc->initialized |= VDC_THREAD;
4891ae08745Sheppo 
4901ae08745Sheppo 	/* initialise LDC channel which will be used to communicate with vds */
4911ae08745Sheppo 	if (vdc_do_ldc_init(vdc) != 0) {
4921ae08745Sheppo 		cmn_err(CE_NOTE, "[%d] Couldn't initialize LDC", instance);
4931ae08745Sheppo 		return (DDI_FAILURE);
4941ae08745Sheppo 	}
4951ae08745Sheppo 
4961ae08745Sheppo 	/* Bring up connection with vds via LDC */
4971ae08745Sheppo 	status = vdc_start_ldc_connection(vdc);
4981ae08745Sheppo 	if (status != 0) {
4991ae08745Sheppo 		vdc_msg("%s[%d]  Could not start LDC", __func__, instance);
5001ae08745Sheppo 		return (DDI_FAILURE);
5011ae08745Sheppo 	}
5021ae08745Sheppo 
5031ae08745Sheppo 	/*
5041ae08745Sheppo 	 * We need to wait until the handshake has completed before leaving
5051ae08745Sheppo 	 * the attach(). This is to allow the device node(s) to be created
5061ae08745Sheppo 	 * and the first usage of the filesystem to succeed.
5071ae08745Sheppo 	 */
5081ae08745Sheppo 	mutex_enter(&vdc->attach_lock);
5091ae08745Sheppo 	while ((vdc->ldc_state != LDC_UP) ||
5101ae08745Sheppo 		(vdc->state != VD_STATE_DATA)) {
5111ae08745Sheppo 
5121ae08745Sheppo 		PR0("%s[%d] handshake in progress [VD %d (LDC %d)]\n",
5131ae08745Sheppo 			__func__, instance, vdc->state, vdc->ldc_state);
5141ae08745Sheppo 
5151ae08745Sheppo 		status = cv_timedwait(&vdc->attach_cv, &vdc->attach_lock,
5161ae08745Sheppo 				VD_GET_TIMEOUT_HZ(1));
5171ae08745Sheppo 		if (status == -1) {
5181ae08745Sheppo 			if (retries >= vdc_retries) {
5191ae08745Sheppo 				PR0("%s[%d] Give up handshake wait.\n",
5201ae08745Sheppo 						__func__, instance);
5211ae08745Sheppo 				mutex_exit(&vdc->attach_lock);
5221ae08745Sheppo 				return (DDI_FAILURE);
5231ae08745Sheppo 			} else {
5241ae08745Sheppo 				PR0("%s[%d] Retry #%d for handshake.\n",
5251ae08745Sheppo 						__func__, instance, retries);
5260a55fbb7Slm66018 				vdc_init_handshake_negotiation(vdc);
5271ae08745Sheppo 				retries++;
5281ae08745Sheppo 			}
5291ae08745Sheppo 		}
5301ae08745Sheppo 	}
5311ae08745Sheppo 	mutex_exit(&vdc->attach_lock);
5321ae08745Sheppo 
5330a55fbb7Slm66018 	/*
5340a55fbb7Slm66018 	 * Once the handshake is complete, we can use the DRing to send
5350a55fbb7Slm66018 	 * requests to the vDisk server to calculate the geometry and
5360a55fbb7Slm66018 	 * VTOC of the "disk"
5370a55fbb7Slm66018 	 */
5380a55fbb7Slm66018 	status = vdc_setup_disk_layout(vdc);
5390a55fbb7Slm66018 	if (status != 0) {
5400a55fbb7Slm66018 		cmn_err(CE_NOTE, "[%d] Failed to discover disk layout (err%d)",
5410a55fbb7Slm66018 				vdc->instance, status);
5421ae08745Sheppo 	}
5431ae08745Sheppo 
5441ae08745Sheppo 	/*
5451ae08745Sheppo 	 * Now that we have the device info we can create the
5461ae08745Sheppo 	 * device nodes and properties
5471ae08745Sheppo 	 */
5481ae08745Sheppo 	status = vdc_create_device_nodes(vdc);
5491ae08745Sheppo 	if (status) {
5501ae08745Sheppo 		cmn_err(CE_NOTE, "[%d] Failed to create device nodes",
5511ae08745Sheppo 				instance);
5521ae08745Sheppo 		return (status);
5531ae08745Sheppo 	}
5541ae08745Sheppo 	status = vdc_create_device_nodes_props(vdc);
5551ae08745Sheppo 	if (status) {
5561ae08745Sheppo 		cmn_err(CE_NOTE, "[%d] Failed to create device nodes"
5570a55fbb7Slm66018 				" properties (%d)", instance, status);
5581ae08745Sheppo 		return (status);
5591ae08745Sheppo 	}
5601ae08745Sheppo 
5611ae08745Sheppo 	ddi_report_dev(dip);
5621ae08745Sheppo 
5631ae08745Sheppo 	PR0("%s[%d] Attach completed\n", __func__, instance);
5641ae08745Sheppo 	return (status);
5651ae08745Sheppo }
5661ae08745Sheppo 
5671ae08745Sheppo static int
5681ae08745Sheppo vdc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
5691ae08745Sheppo {
5701ae08745Sheppo 	int	status;
5711ae08745Sheppo 
5721ae08745Sheppo 	switch (cmd) {
5731ae08745Sheppo 	case DDI_ATTACH:
5741ae08745Sheppo 		if ((status = vdc_do_attach(dip)) != 0)
5751ae08745Sheppo 			(void) vdc_detach(dip, DDI_DETACH);
5761ae08745Sheppo 		return (status);
5771ae08745Sheppo 	case DDI_RESUME:
5781ae08745Sheppo 		/* nothing to do for this non-device */
5791ae08745Sheppo 		return (DDI_SUCCESS);
5801ae08745Sheppo 	default:
5811ae08745Sheppo 		return (DDI_FAILURE);
5821ae08745Sheppo 	}
5831ae08745Sheppo }
5841ae08745Sheppo 
5851ae08745Sheppo static int
5861ae08745Sheppo vdc_do_ldc_init(vdc_t *vdc)
5871ae08745Sheppo {
5881ae08745Sheppo 	int			status = 0;
5891ae08745Sheppo 	ldc_status_t		ldc_state;
5901ae08745Sheppo 	ldc_attr_t		ldc_attr;
5911ae08745Sheppo 	uint64_t		ldc_id = 0;
5921ae08745Sheppo 	dev_info_t		*dip = NULL;
5931ae08745Sheppo 
5941ae08745Sheppo 	ASSERT(vdc != NULL);
5951ae08745Sheppo 
5961ae08745Sheppo 	dip = vdc->dip;
5971ae08745Sheppo 	vdc->initialized |= VDC_LDC;
5981ae08745Sheppo 
5991ae08745Sheppo 	if ((status = vdc_get_ldc_id(dip, &ldc_id)) != 0) {
6001ae08745Sheppo 		vdc_msg("%s:  Failed to get <ldc_id> property\n", __func__);
6011ae08745Sheppo 		return (EIO);
6021ae08745Sheppo 	}
6031ae08745Sheppo 	vdc->ldc_id = ldc_id;
6041ae08745Sheppo 
6051ae08745Sheppo 	ldc_attr.devclass = LDC_DEV_BLK;
6061ae08745Sheppo 	ldc_attr.instance = vdc->instance;
6071ae08745Sheppo 	ldc_attr.mode = LDC_MODE_UNRELIABLE;	/* unreliable transport */
6081ae08745Sheppo 	ldc_attr.qlen = VD_LDC_QLEN;
6091ae08745Sheppo 
6101ae08745Sheppo 	if ((vdc->initialized & VDC_LDC_INIT) == 0) {
6111ae08745Sheppo 		status = ldc_init(ldc_id, &ldc_attr, &vdc->ldc_handle);
6121ae08745Sheppo 		if (status != 0) {
6131ae08745Sheppo 			cmn_err(CE_NOTE, "[%d] ldc_init(chan %ld) returned %d",
6141ae08745Sheppo 					vdc->instance, ldc_id, status);
6151ae08745Sheppo 			return (status);
6161ae08745Sheppo 		}
6171ae08745Sheppo 		vdc->initialized |= VDC_LDC_INIT;
6181ae08745Sheppo 	}
6191ae08745Sheppo 	status = ldc_status(vdc->ldc_handle, &ldc_state);
6201ae08745Sheppo 	if (status != 0) {
6211ae08745Sheppo 		vdc_msg("Cannot discover LDC status [err=%d].", status);
6221ae08745Sheppo 		return (status);
6231ae08745Sheppo 	}
6241ae08745Sheppo 	vdc->ldc_state = ldc_state;
6251ae08745Sheppo 
6261ae08745Sheppo 	if ((vdc->initialized & VDC_LDC_CB) == 0) {
6271ae08745Sheppo 		status = ldc_reg_callback(vdc->ldc_handle, vdc_handle_cb,
6281ae08745Sheppo 		    (caddr_t)vdc);
6291ae08745Sheppo 		if (status != 0) {
6301ae08745Sheppo 			vdc_msg("%s: ldc_reg_callback()=%d", __func__, status);
6311ae08745Sheppo 			return (status);
6321ae08745Sheppo 		}
6331ae08745Sheppo 		vdc->initialized |= VDC_LDC_CB;
6341ae08745Sheppo 	}
6351ae08745Sheppo 
6361ae08745Sheppo 	vdc->initialized |= VDC_LDC;
6371ae08745Sheppo 
6381ae08745Sheppo 	/*
6391ae08745Sheppo 	 * At this stage we have initialised LDC, we will now try and open
6401ae08745Sheppo 	 * the connection.
6411ae08745Sheppo 	 */
6421ae08745Sheppo 	if (vdc->ldc_state == LDC_INIT) {
6431ae08745Sheppo 		status = ldc_open(vdc->ldc_handle);
6441ae08745Sheppo 		if (status != 0) {
6451ae08745Sheppo 			cmn_err(CE_NOTE, "[%d] ldc_open(chan %ld) returned %d",
6461ae08745Sheppo 					vdc->instance, vdc->ldc_id, status);
6471ae08745Sheppo 			return (status);
6481ae08745Sheppo 		}
6491ae08745Sheppo 		vdc->initialized |= VDC_LDC_OPEN;
6501ae08745Sheppo 	}
6511ae08745Sheppo 
6521ae08745Sheppo 	return (status);
6531ae08745Sheppo }
6541ae08745Sheppo 
6551ae08745Sheppo static int
6561ae08745Sheppo vdc_start_ldc_connection(vdc_t *vdc)
6571ae08745Sheppo {
6581ae08745Sheppo 	int		status = 0;
6591ae08745Sheppo 
6601ae08745Sheppo 	ASSERT(vdc != NULL);
6611ae08745Sheppo 
6621ae08745Sheppo 	mutex_enter(&vdc->lock);
6631ae08745Sheppo 
6641ae08745Sheppo 	if (vdc->ldc_state == LDC_UP) {
6651ae08745Sheppo 		PR0("%s:  LDC is already UP ..\n", __func__);
6661ae08745Sheppo 		mutex_exit(&vdc->lock);
6671ae08745Sheppo 		return (0);
6681ae08745Sheppo 	}
6691ae08745Sheppo 
6700a55fbb7Slm66018 	status = vdc_do_ldc_up(vdc);
6711ae08745Sheppo 
6721ae08745Sheppo 	PR0("%s[%d] Finished bringing up LDC\n", __func__, vdc->instance);
6731ae08745Sheppo 
6741ae08745Sheppo 	mutex_exit(&vdc->lock);
6751ae08745Sheppo 
6761ae08745Sheppo 	return (status);
6771ae08745Sheppo }
6781ae08745Sheppo 
6791ae08745Sheppo 
6801ae08745Sheppo /*
6811ae08745Sheppo  * Function:
6821ae08745Sheppo  *	vdc_create_device_nodes
6831ae08745Sheppo  *
6841ae08745Sheppo  * Description:
6851ae08745Sheppo  *	This function creates the block and character device nodes under
6861ae08745Sheppo  *	/devices along with the node properties. It is called as part of
6871ae08745Sheppo  *	the attach(9E) of the instance during the handshake with vds after
6881ae08745Sheppo  *	vds has sent the attributes to vdc.
6891ae08745Sheppo  *
6901ae08745Sheppo  *	If the device is of type VD_DISK_TYPE_SLICE then the minor node
6911ae08745Sheppo  *	of 2 is used in keeping with the Solaris convention that slice 2
6921ae08745Sheppo  *	refers to a whole disk. Slices start at 'a'
6931ae08745Sheppo  *
6941ae08745Sheppo  * Parameters:
6951ae08745Sheppo  *	vdc 		- soft state pointer
6961ae08745Sheppo  *
6971ae08745Sheppo  * Return Values
6981ae08745Sheppo  *	0		- Success
6991ae08745Sheppo  *	EIO		- Failed to create node
7001ae08745Sheppo  *	EINVAL		- Unknown type of disk exported
7011ae08745Sheppo  */
7021ae08745Sheppo static int
7031ae08745Sheppo vdc_create_device_nodes(vdc_t *vdc)
7041ae08745Sheppo {
7051ae08745Sheppo 	/* uses NNNN which is OK as long as # of disks <= 10000 */
7061ae08745Sheppo 	char		name[sizeof ("disk@NNNN:s,raw")];
7071ae08745Sheppo 	dev_info_t	*dip = NULL;
7081ae08745Sheppo 	int		instance;
7091ae08745Sheppo 	int		num_slices = 1;
7101ae08745Sheppo 	int		i;
7111ae08745Sheppo 
7121ae08745Sheppo 	ASSERT(vdc != NULL);
7131ae08745Sheppo 
7141ae08745Sheppo 	instance = vdc->instance;
7151ae08745Sheppo 	dip = vdc->dip;
7161ae08745Sheppo 
7171ae08745Sheppo 	switch (vdc->vdisk_type) {
7181ae08745Sheppo 	case VD_DISK_TYPE_DISK:
7191ae08745Sheppo 		num_slices = V_NUMPAR;
7201ae08745Sheppo 		break;
7211ae08745Sheppo 	case VD_DISK_TYPE_SLICE:
7221ae08745Sheppo 		num_slices = 1;
7231ae08745Sheppo 		break;
7241ae08745Sheppo 	case VD_DISK_TYPE_UNK:
7251ae08745Sheppo 	default:
7261ae08745Sheppo 		return (EINVAL);
7271ae08745Sheppo 	}
7281ae08745Sheppo 
7291ae08745Sheppo 	for (i = 0; i < num_slices; i++) {
7301ae08745Sheppo 		(void) snprintf(name, sizeof (name), "%c", 'a' + i);
7311ae08745Sheppo 		if (ddi_create_minor_node(dip, name, S_IFBLK,
7321ae08745Sheppo 		    VD_MAKE_DEV(instance, i), DDI_NT_BLOCK, 0) != DDI_SUCCESS) {
7331ae08745Sheppo 			vdc_msg("%s[%d]: Couldn't add block node %s.",
7341ae08745Sheppo 				__func__, instance, name);
7351ae08745Sheppo 			return (EIO);
7361ae08745Sheppo 		}
7371ae08745Sheppo 
7381ae08745Sheppo 		/* if any device node is created we set this flag */
7391ae08745Sheppo 		vdc->initialized |= VDC_MINOR;
7401ae08745Sheppo 
7411ae08745Sheppo 		(void) snprintf(name, sizeof (name), "%c%s",
7421ae08745Sheppo 			'a' + i, ",raw");
7431ae08745Sheppo 		if (ddi_create_minor_node(dip, name, S_IFCHR,
7441ae08745Sheppo 		    VD_MAKE_DEV(instance, i), DDI_NT_BLOCK, 0) != DDI_SUCCESS) {
7451ae08745Sheppo 			vdc_msg("%s[%d]:  Could not add raw node %s.",
7461ae08745Sheppo 				__func__, instance, name);
7471ae08745Sheppo 			return (EIO);
7481ae08745Sheppo 		}
7491ae08745Sheppo 	}
7501ae08745Sheppo 
7511ae08745Sheppo 	return (0);
7521ae08745Sheppo }
7531ae08745Sheppo 
7541ae08745Sheppo /*
7551ae08745Sheppo  * Function:
7561ae08745Sheppo  *	vdc_create_device_nodes_props
7571ae08745Sheppo  *
7581ae08745Sheppo  * Description:
7591ae08745Sheppo  *	This function creates the block and character device nodes under
7601ae08745Sheppo  *	/devices along with the node properties. It is called as part of
7611ae08745Sheppo  *	the attach(9E) of the instance during the handshake with vds after
7621ae08745Sheppo  *	vds has sent the attributes to vdc.
7631ae08745Sheppo  *
7641ae08745Sheppo  * Parameters:
7651ae08745Sheppo  *	vdc 		- soft state pointer
7661ae08745Sheppo  *
7671ae08745Sheppo  * Return Values
7681ae08745Sheppo  *	0		- Success
7691ae08745Sheppo  *	EIO		- Failed to create device node property
7701ae08745Sheppo  *	EINVAL		- Unknown type of disk exported
7711ae08745Sheppo  */
7721ae08745Sheppo static int
7731ae08745Sheppo vdc_create_device_nodes_props(vdc_t *vdc)
7741ae08745Sheppo {
7751ae08745Sheppo 	dev_info_t	*dip = NULL;
7761ae08745Sheppo 	int		instance;
7771ae08745Sheppo 	int		num_slices = 1;
7781ae08745Sheppo 	int64_t		size = 0;
7791ae08745Sheppo 	dev_t		dev;
7801ae08745Sheppo 	int		rv;
7811ae08745Sheppo 	int		i;
7821ae08745Sheppo 
7831ae08745Sheppo 	ASSERT(vdc != NULL);
7841ae08745Sheppo 
7851ae08745Sheppo 	instance = vdc->instance;
7861ae08745Sheppo 	dip = vdc->dip;
7871ae08745Sheppo 
7881ae08745Sheppo 	if ((vdc->vtoc == NULL) || (vdc->vtoc->v_sanity != VTOC_SANE)) {
7891ae08745Sheppo 		cmn_err(CE_NOTE, "![%d] Could not create device node property."
7901ae08745Sheppo 				" No VTOC available", instance);
7911ae08745Sheppo 		return (ENXIO);
7921ae08745Sheppo 	}
7931ae08745Sheppo 
7941ae08745Sheppo 	switch (vdc->vdisk_type) {
7951ae08745Sheppo 	case VD_DISK_TYPE_DISK:
7961ae08745Sheppo 		num_slices = V_NUMPAR;
7971ae08745Sheppo 		break;
7981ae08745Sheppo 	case VD_DISK_TYPE_SLICE:
7991ae08745Sheppo 		num_slices = 1;
8001ae08745Sheppo 		break;
8011ae08745Sheppo 	case VD_DISK_TYPE_UNK:
8021ae08745Sheppo 	default:
8031ae08745Sheppo 		return (EINVAL);
8041ae08745Sheppo 	}
8051ae08745Sheppo 
8061ae08745Sheppo 	for (i = 0; i < num_slices; i++) {
8071ae08745Sheppo 		dev = makedevice(ddi_driver_major(dip),
8081ae08745Sheppo 			VD_MAKE_DEV(instance, i));
8091ae08745Sheppo 
8101ae08745Sheppo 		size = vdc->vtoc->v_part[i].p_size * vdc->vtoc->v_sectorsz;
8111ae08745Sheppo 		PR0("%s[%d] sz %ld (%ld Mb)  p_size %lx\n",
8121ae08745Sheppo 				__func__, instance, size, size / (1024 * 1024),
8131ae08745Sheppo 				vdc->vtoc->v_part[i].p_size);
8141ae08745Sheppo 
8151ae08745Sheppo 		rv = ddi_prop_update_int64(dev, dip, VDC_SIZE_PROP_NAME, size);
8161ae08745Sheppo 		if (rv != DDI_PROP_SUCCESS) {
8171ae08745Sheppo 			vdc_msg("%s:(%d): Couldn't add \"%s\" [%d]\n",
8181ae08745Sheppo 				__func__, instance, VDC_SIZE_PROP_NAME, size);
8191ae08745Sheppo 			return (EIO);
8201ae08745Sheppo 		}
8211ae08745Sheppo 
8221ae08745Sheppo 		rv = ddi_prop_update_int64(dev, dip, VDC_NBLOCKS_PROP_NAME,
8231ae08745Sheppo 			lbtodb(size));
8241ae08745Sheppo 		if (rv != DDI_PROP_SUCCESS) {
8251ae08745Sheppo 			vdc_msg("%s:(%d): Couldn't add \"%s\" [%d]\n", __func__,
8261ae08745Sheppo 				instance, VDC_NBLOCKS_PROP_NAME, lbtodb(size));
8271ae08745Sheppo 			return (EIO);
8281ae08745Sheppo 		}
8291ae08745Sheppo 	}
8301ae08745Sheppo 
8311ae08745Sheppo 	return (0);
8321ae08745Sheppo }
8331ae08745Sheppo 
8341ae08745Sheppo static int
8351ae08745Sheppo vdc_open(dev_t *dev, int flag, int otyp, cred_t *cred)
8361ae08745Sheppo {
8371ae08745Sheppo 	_NOTE(ARGUNUSED(cred))
8381ae08745Sheppo 
8391ae08745Sheppo 	int		instance;
8401ae08745Sheppo 	vdc_t		*vdc;
8411ae08745Sheppo 
8421ae08745Sheppo 	ASSERT(dev != NULL);
8431ae08745Sheppo 	instance = SDUNIT(getminor(*dev));
8441ae08745Sheppo 
8451ae08745Sheppo 	PR0("%s[%d] minor = %d flag = %x, otyp = %x\n", __func__, instance,
8461ae08745Sheppo 			getminor(*dev), flag, otyp);
8471ae08745Sheppo 
8481ae08745Sheppo 	if ((otyp != OTYP_CHR) && (otyp != OTYP_BLK))
8491ae08745Sheppo 		return (EINVAL);
8501ae08745Sheppo 
8511ae08745Sheppo 	if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) {
8521ae08745Sheppo 		vdc_msg("%s[%d] Could not get state.", __func__, instance);
8531ae08745Sheppo 		return (ENXIO);
8541ae08745Sheppo 	}
8551ae08745Sheppo 
8561ae08745Sheppo 	/*
8571ae08745Sheppo 	 * Check to see if we can communicate with vds
8581ae08745Sheppo 	 */
8590a55fbb7Slm66018 	if (!vdc_is_able_to_tx_data(vdc, flag)) {
8601ae08745Sheppo 		PR0("%s[%d] Not ready to transmit data\n", __func__, instance);
8611ae08745Sheppo 		return (ENOLINK);
8621ae08745Sheppo 	}
8631ae08745Sheppo 
8641ae08745Sheppo 	mutex_enter(&vdc->lock);
8651ae08745Sheppo 	vdc->open++;
8661ae08745Sheppo 	mutex_exit(&vdc->lock);
8671ae08745Sheppo 
8681ae08745Sheppo 	return (0);
8691ae08745Sheppo }
8701ae08745Sheppo 
8711ae08745Sheppo static int
8721ae08745Sheppo vdc_close(dev_t dev, int flag, int otyp, cred_t *cred)
8731ae08745Sheppo {
8741ae08745Sheppo 	_NOTE(ARGUNUSED(cred))
8751ae08745Sheppo 
8761ae08745Sheppo 	int	instance;
8771ae08745Sheppo 	vdc_t	*vdc;
8781ae08745Sheppo 
8791ae08745Sheppo 	instance = SDUNIT(getminor(dev));
8801ae08745Sheppo 
8811ae08745Sheppo 	PR0("%s[%d] flag = %x, otyp = %x\n", __func__, instance, flag, otyp);
8821ae08745Sheppo 
8831ae08745Sheppo 	if ((otyp != OTYP_CHR) && (otyp != OTYP_BLK))
8841ae08745Sheppo 		return (EINVAL);
8851ae08745Sheppo 
8861ae08745Sheppo 	if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) {
8871ae08745Sheppo 		vdc_msg("%s[%d] Could not get state.", __func__, instance);
8881ae08745Sheppo 		return (ENXIO);
8891ae08745Sheppo 	}
8901ae08745Sheppo 
8911ae08745Sheppo 	/*
8921ae08745Sheppo 	 * Check to see if we can communicate with vds
8931ae08745Sheppo 	 */
8940a55fbb7Slm66018 	if (!vdc_is_able_to_tx_data(vdc, 0)) {
8951ae08745Sheppo 		PR0("%s[%d] Not ready to transmit data\n", __func__, instance);
8961ae08745Sheppo 		return (ETIMEDOUT);
8971ae08745Sheppo 	}
8981ae08745Sheppo 
8991ae08745Sheppo 	if (vdc->dkio_flush_pending) {
9001ae08745Sheppo 		PR0("%s[%d]: Cannot detach: %d outstanding DKIO flushes",
9011ae08745Sheppo 			__func__, instance, vdc->dkio_flush_pending);
9021ae08745Sheppo 		return (EBUSY);
9031ae08745Sheppo 	}
9041ae08745Sheppo 
9051ae08745Sheppo 	/*
9061ae08745Sheppo 	 * Should not need the mutex here, since the framework should protect
9071ae08745Sheppo 	 * against more opens on this device, but just in case.
9081ae08745Sheppo 	 */
9091ae08745Sheppo 	mutex_enter(&vdc->lock);
9101ae08745Sheppo 	vdc->open--;
9111ae08745Sheppo 	mutex_exit(&vdc->lock);
9121ae08745Sheppo 
9131ae08745Sheppo 	return (0);
9141ae08745Sheppo }
9151ae08745Sheppo 
9161ae08745Sheppo static int
9171ae08745Sheppo vdc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
9181ae08745Sheppo {
9191ae08745Sheppo 	_NOTE(ARGUNUSED(credp))
9201ae08745Sheppo 	_NOTE(ARGUNUSED(rvalp))
9211ae08745Sheppo 
9221ae08745Sheppo 	return (vd_process_ioctl(dev, cmd, (caddr_t)arg, mode));
9231ae08745Sheppo }
9241ae08745Sheppo 
9251ae08745Sheppo static int
9261ae08745Sheppo vdc_print(dev_t dev, char *str)
9271ae08745Sheppo {
9281ae08745Sheppo 	cmn_err(CE_NOTE, "vdc%d:  %s", SDUNIT(getminor(dev)), str);
9291ae08745Sheppo 	return (0);
9301ae08745Sheppo }
9311ae08745Sheppo 
9321ae08745Sheppo static int
9331ae08745Sheppo vdc_dump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk)
9341ae08745Sheppo {
9351ae08745Sheppo 	int			rv = 0;
9361ae08745Sheppo 	size_t			nbytes = (nblk * DEV_BSIZE);
9371ae08745Sheppo 	int			instance = SDUNIT(getminor(dev));
9381ae08745Sheppo 	vdc_t			*vdc;
9391ae08745Sheppo 
9401ae08745Sheppo 	if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) {
9411ae08745Sheppo 		vdc_msg("%s (%d):  Could not get state.", __func__, instance);
9421ae08745Sheppo 		return (ENXIO);
9431ae08745Sheppo 	}
9441ae08745Sheppo 
9451ae08745Sheppo 	rv = vdc_populate_descriptor(vdc, addr, nbytes, VD_OP_BWRITE,
9461ae08745Sheppo 					blkno, SDPART(getminor(dev)));
9471ae08745Sheppo 
9481ae08745Sheppo 	PR1("%s: status=%d\n", __func__, rv);
9491ae08745Sheppo 
9501ae08745Sheppo 	return (rv);
9511ae08745Sheppo }
9521ae08745Sheppo 
9531ae08745Sheppo /* -------------------------------------------------------------------------- */
9541ae08745Sheppo 
9551ae08745Sheppo /*
9561ae08745Sheppo  * Disk access routines
9571ae08745Sheppo  *
9581ae08745Sheppo  */
9591ae08745Sheppo 
9601ae08745Sheppo /*
9611ae08745Sheppo  * vdc_strategy()
9621ae08745Sheppo  *
9631ae08745Sheppo  * Return Value:
9641ae08745Sheppo  *	0:	As per strategy(9E), the strategy() function must return 0
9651ae08745Sheppo  *		[ bioerror(9f) sets b_flags to the proper error code ]
9661ae08745Sheppo  */
9671ae08745Sheppo static int
9681ae08745Sheppo vdc_strategy(struct buf *buf)
9691ae08745Sheppo {
9701ae08745Sheppo 	int		rv = -1;
9711ae08745Sheppo 	vdc_t		*vdc = NULL;
9721ae08745Sheppo 	int		instance = SDUNIT(getminor(buf->b_edev));
9731ae08745Sheppo 	int	op = (buf->b_flags & B_READ) ? VD_OP_BREAD : VD_OP_BWRITE;
9741ae08745Sheppo 
9751ae08745Sheppo 	PR1("%s: %s %ld bytes at block %ld : b_addr=0x%p",
9761ae08745Sheppo 	    __func__, (buf->b_flags & B_READ) ? "Read" : "Write",
9771ae08745Sheppo 	    buf->b_bcount, buf->b_lblkno, buf->b_un.b_addr);
9781ae08745Sheppo 
9791ae08745Sheppo 	if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) {
9801ae08745Sheppo 		vdc_msg("%s[%d]:  Could not get state.", __func__, instance);
9811ae08745Sheppo 		bioerror(buf, ENXIO);
9821ae08745Sheppo 		biodone(buf);
9831ae08745Sheppo 		return (0);
9841ae08745Sheppo 	}
9851ae08745Sheppo 
9861ae08745Sheppo 	ASSERT(buf->b_bcount <= (vdc->max_xfer_sz * vdc->block_size));
9871ae08745Sheppo 
9880a55fbb7Slm66018 	if (!vdc_is_able_to_tx_data(vdc, O_NONBLOCK)) {
9891ae08745Sheppo 		vdc_msg("%s: Not ready to transmit data", __func__);
9901ae08745Sheppo 		bioerror(buf, ENXIO);
9911ae08745Sheppo 		biodone(buf);
9921ae08745Sheppo 		return (0);
9931ae08745Sheppo 	}
9941ae08745Sheppo 	bp_mapin(buf);
9951ae08745Sheppo 
9961ae08745Sheppo 	rv = vdc_populate_descriptor(vdc, buf->b_un.b_addr, buf->b_bcount, op,
9971ae08745Sheppo 			buf->b_lblkno, SDPART(getminor(buf->b_edev)));
9981ae08745Sheppo 
9991ae08745Sheppo 	PR1("%s: status=%d", __func__, rv);
10001ae08745Sheppo 	bioerror(buf, rv);
10011ae08745Sheppo 	biodone(buf);
10021ae08745Sheppo 	return (0);
10031ae08745Sheppo }
10041ae08745Sheppo 
10051ae08745Sheppo 
10061ae08745Sheppo static int
10071ae08745Sheppo vdc_read(dev_t dev, struct uio *uio, cred_t *cred)
10081ae08745Sheppo {
10091ae08745Sheppo 	_NOTE(ARGUNUSED(cred))
10101ae08745Sheppo 
10111ae08745Sheppo 	PR1("vdc_read():  Entered");
10121ae08745Sheppo 	return (physio(vdc_strategy, NULL, dev, B_READ, minphys, uio));
10131ae08745Sheppo }
10141ae08745Sheppo 
10151ae08745Sheppo static int
10161ae08745Sheppo vdc_write(dev_t dev, struct uio *uio, cred_t *cred)
10171ae08745Sheppo {
10181ae08745Sheppo 	_NOTE(ARGUNUSED(cred))
10191ae08745Sheppo 
10201ae08745Sheppo 	PR1("vdc_write():  Entered");
10211ae08745Sheppo 	return (physio(vdc_strategy, NULL, dev, B_WRITE, minphys, uio));
10221ae08745Sheppo }
10231ae08745Sheppo 
10241ae08745Sheppo static int
10251ae08745Sheppo vdc_aread(dev_t dev, struct aio_req *aio, cred_t *cred)
10261ae08745Sheppo {
10271ae08745Sheppo 	_NOTE(ARGUNUSED(cred))
10281ae08745Sheppo 
10291ae08745Sheppo 	PR1("vdc_aread():  Entered");
10301ae08745Sheppo 	return (aphysio(vdc_strategy, anocancel, dev, B_READ, minphys, aio));
10311ae08745Sheppo }
10321ae08745Sheppo 
10331ae08745Sheppo static int
10341ae08745Sheppo vdc_awrite(dev_t dev, struct aio_req *aio, cred_t *cred)
10351ae08745Sheppo {
10361ae08745Sheppo 	_NOTE(ARGUNUSED(cred))
10371ae08745Sheppo 
10381ae08745Sheppo 	PR1("vdc_awrite():  Entered");
10391ae08745Sheppo 	return (aphysio(vdc_strategy, anocancel, dev, B_WRITE, minphys, aio));
10401ae08745Sheppo }
10411ae08745Sheppo 
10421ae08745Sheppo 
10431ae08745Sheppo /* -------------------------------------------------------------------------- */
10441ae08745Sheppo 
10451ae08745Sheppo /*
10461ae08745Sheppo  * Handshake support
10471ae08745Sheppo  */
10481ae08745Sheppo 
10491ae08745Sheppo /*
10501ae08745Sheppo  * vdc_init_handshake_negotiation
10511ae08745Sheppo  *
10521ae08745Sheppo  * Description:
10531ae08745Sheppo  *	This function is called to trigger the handshake negotiations between
10541ae08745Sheppo  *	the client (vdc) and the server (vds). It may be called multiple times.
10551ae08745Sheppo  *
10561ae08745Sheppo  * Parameters:
10571ae08745Sheppo  *	vdc - soft state pointer
10581ae08745Sheppo  */
10591ae08745Sheppo static void
10601ae08745Sheppo vdc_init_handshake_negotiation(void *arg)
10611ae08745Sheppo {
10621ae08745Sheppo 	vdc_t		*vdc = (vdc_t *)(void *)arg;
10630a55fbb7Slm66018 	ldc_status_t	ldc_state;
10641ae08745Sheppo 	vd_state_t	state;
10650a55fbb7Slm66018 	int		status;
10661ae08745Sheppo 
10671ae08745Sheppo 	ASSERT(vdc != NULL);
10681ae08745Sheppo 
10690a55fbb7Slm66018 	PR0("[%d] Initializing vdc<->vds handshake\n", vdc->instance);
10700a55fbb7Slm66018 
10710a55fbb7Slm66018 	/* get LDC state */
10720a55fbb7Slm66018 	status = ldc_status(vdc->ldc_handle, &ldc_state);
10730a55fbb7Slm66018 	if (status != 0) {
10740a55fbb7Slm66018 		cmn_err(CE_NOTE, "[%d] Couldn't get LDC status: err=%d",
10750a55fbb7Slm66018 				vdc->instance, status);
10760a55fbb7Slm66018 		return;
10770a55fbb7Slm66018 	}
10781ae08745Sheppo 
10791ae08745Sheppo 	/*
10800a55fbb7Slm66018 	 * If the LDC connection is not UP we bring it up now and return.
10810a55fbb7Slm66018 	 * The handshake will be started again when the callback is
10820a55fbb7Slm66018 	 * triggered due to the UP event.
10830a55fbb7Slm66018 	 */
10840a55fbb7Slm66018 	if (ldc_state != LDC_UP) {
10850a55fbb7Slm66018 		PR0("[%d] Triggering an LDC_UP and returning\n", vdc->instance);
10860a55fbb7Slm66018 		(void) vdc_do_ldc_up(vdc);
10870a55fbb7Slm66018 		return;
10880a55fbb7Slm66018 	}
10890a55fbb7Slm66018 
10900a55fbb7Slm66018 	mutex_enter(&vdc->lock);
10910a55fbb7Slm66018 	/*
10921ae08745Sheppo 	 * Do not continue if another thread has triggered a handshake which
10930a55fbb7Slm66018 	 * has not been reset or detach() has stopped further handshakes.
10941ae08745Sheppo 	 */
10951ae08745Sheppo 	if (vdc->initialized & (VDC_HANDSHAKE | VDC_HANDSHAKE_STOP)) {
10961ae08745Sheppo 		PR0("%s[%d] Negotiation not triggered. [init=%x]\n",
10971ae08745Sheppo 			__func__, vdc->instance, vdc->initialized);
10981ae08745Sheppo 		mutex_exit(&vdc->lock);
10991ae08745Sheppo 		return;
11001ae08745Sheppo 	}
11011ae08745Sheppo 
11020a55fbb7Slm66018 	if (vdc->hshake_cnt++ > vdc_retries) {
11030a55fbb7Slm66018 		cmn_err(CE_NOTE, "[%d] Failed repeatedly to complete handshake"
11040a55fbb7Slm66018 				"with vDisk server", vdc->instance);
11050a55fbb7Slm66018 		mutex_exit(&vdc->lock);
11060a55fbb7Slm66018 		return;
11070a55fbb7Slm66018 	}
11081ae08745Sheppo 
11091ae08745Sheppo 	vdc->initialized |= VDC_HANDSHAKE;
11100a55fbb7Slm66018 	vdc->ldc_state = ldc_state;
11111ae08745Sheppo 
11121ae08745Sheppo 	state = vdc->state;
11131ae08745Sheppo 
11141ae08745Sheppo 	if (state == VD_STATE_INIT) {
11150a55fbb7Slm66018 		/*
11160a55fbb7Slm66018 		 * Set the desired version parameter to the first entry in the
11170a55fbb7Slm66018 		 * version array. If this specific version is not supported,
11180a55fbb7Slm66018 		 * the response handling code will step down the version number
11190a55fbb7Slm66018 		 * to the next array entry and deal with it accordingly.
11200a55fbb7Slm66018 		 */
11210a55fbb7Slm66018 		(void) vdc_init_ver_negotiation(vdc, vdc_version[0]);
11221ae08745Sheppo 	} else if (state == VD_STATE_VER) {
11231ae08745Sheppo 		(void) vdc_init_attr_negotiation(vdc);
11241ae08745Sheppo 	} else if (state == VD_STATE_ATTR) {
11251ae08745Sheppo 		(void) vdc_init_dring_negotiate(vdc);
11261ae08745Sheppo 	} else if (state == VD_STATE_DATA) {
11271ae08745Sheppo 		/*
11281ae08745Sheppo 		 * nothing to do - we have already completed the negotiation
11291ae08745Sheppo 		 * and we can transmit data when ready.
11301ae08745Sheppo 		 */
11311ae08745Sheppo 		PR0("%s[%d] Negotiation triggered after handshake completed",
11321ae08745Sheppo 			__func__, vdc->instance);
11331ae08745Sheppo 	}
11341ae08745Sheppo 
11351ae08745Sheppo 	mutex_exit(&vdc->lock);
11361ae08745Sheppo }
11371ae08745Sheppo 
11380a55fbb7Slm66018 /*
11390a55fbb7Slm66018  * Function:
11400a55fbb7Slm66018  *	vdc_init_ver_negotiation()
11410a55fbb7Slm66018  *
11420a55fbb7Slm66018  * Description:
11430a55fbb7Slm66018  *
11440a55fbb7Slm66018  * Arguments:
11450a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
11460a55fbb7Slm66018  *
11470a55fbb7Slm66018  * Return Code:
11480a55fbb7Slm66018  *	0	- Success
11490a55fbb7Slm66018  */
11501ae08745Sheppo static int
11510a55fbb7Slm66018 vdc_init_ver_negotiation(vdc_t *vdc, vio_ver_t ver)
11521ae08745Sheppo {
11531ae08745Sheppo 	vio_ver_msg_t	pkt;
11541ae08745Sheppo 	size_t		msglen = sizeof (pkt);
11551ae08745Sheppo 	int		status = -1;
11561ae08745Sheppo 
11571ae08745Sheppo 	PR0("%s: Entered.\n", __func__);
11581ae08745Sheppo 
11591ae08745Sheppo 	ASSERT(vdc != NULL);
11601ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
11611ae08745Sheppo 
11621ae08745Sheppo 	/*
11631ae08745Sheppo 	 * set the Session ID to a unique value
11641ae08745Sheppo 	 * (the lower 32 bits of the clock tick)
11651ae08745Sheppo 	 */
11661ae08745Sheppo 	vdc->session_id = ((uint32_t)gettick() & 0xffffffff);
11671ae08745Sheppo 
11681ae08745Sheppo 	pkt.tag.vio_msgtype = VIO_TYPE_CTRL;
11691ae08745Sheppo 	pkt.tag.vio_subtype = VIO_SUBTYPE_INFO;
11701ae08745Sheppo 	pkt.tag.vio_subtype_env = VIO_VER_INFO;
11711ae08745Sheppo 	pkt.tag.vio_sid = vdc->session_id;
11721ae08745Sheppo 	pkt.dev_class = VDEV_DISK;
11730a55fbb7Slm66018 	pkt.ver_major = ver.major;
11740a55fbb7Slm66018 	pkt.ver_minor = ver.minor;
11751ae08745Sheppo 
11760a55fbb7Slm66018 	status = vdc_send(vdc, (caddr_t)&pkt, &msglen);
11771ae08745Sheppo 	PR0("%s: vdc_send(status = %d)\n", __func__, status);
11781ae08745Sheppo 
11791ae08745Sheppo 	if ((status != 0) || (msglen != sizeof (vio_ver_msg_t))) {
11801ae08745Sheppo 		PR0("%s[%d] vdc_send failed: id(%lx) rv(%d) size(%d)\n",
11811ae08745Sheppo 				__func__, vdc->instance, vdc->ldc_handle,
11821ae08745Sheppo 				status, msglen);
11831ae08745Sheppo 		if (msglen != sizeof (vio_ver_msg_t))
11841ae08745Sheppo 			status = ENOMSG;
11851ae08745Sheppo 	}
11861ae08745Sheppo 
11871ae08745Sheppo 	return (status);
11881ae08745Sheppo }
11891ae08745Sheppo 
11900a55fbb7Slm66018 /*
11910a55fbb7Slm66018  * Function:
11920a55fbb7Slm66018  *	vdc_init_attr_negotiation()
11930a55fbb7Slm66018  *
11940a55fbb7Slm66018  * Description:
11950a55fbb7Slm66018  *
11960a55fbb7Slm66018  * Arguments:
11970a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
11980a55fbb7Slm66018  *
11990a55fbb7Slm66018  * Return Code:
12000a55fbb7Slm66018  *	0	- Success
12010a55fbb7Slm66018  */
12021ae08745Sheppo static int
12031ae08745Sheppo vdc_init_attr_negotiation(vdc_t *vdc)
12041ae08745Sheppo {
12051ae08745Sheppo 	vd_attr_msg_t	pkt;
12061ae08745Sheppo 	size_t		msglen = sizeof (pkt);
12071ae08745Sheppo 	int		status;
12081ae08745Sheppo 
12091ae08745Sheppo 	ASSERT(vdc != NULL);
12101ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
12111ae08745Sheppo 
12121ae08745Sheppo 	PR0("%s[%d] entered\n", __func__, vdc->instance);
12131ae08745Sheppo 
12141ae08745Sheppo 	/* fill in tag */
12151ae08745Sheppo 	pkt.tag.vio_msgtype = VIO_TYPE_CTRL;
12161ae08745Sheppo 	pkt.tag.vio_subtype = VIO_SUBTYPE_INFO;
12171ae08745Sheppo 	pkt.tag.vio_subtype_env = VIO_ATTR_INFO;
12181ae08745Sheppo 	pkt.tag.vio_sid = vdc->session_id;
12191ae08745Sheppo 	/* fill in payload */
12201ae08745Sheppo 	pkt.max_xfer_sz = vdc->max_xfer_sz;
12211ae08745Sheppo 	pkt.vdisk_block_size = vdc->block_size;
12221ae08745Sheppo 	pkt.xfer_mode = VIO_DRING_MODE;
12231ae08745Sheppo 	pkt.operations = 0;	/* server will set bits of valid operations */
12241ae08745Sheppo 	pkt.vdisk_type = 0;	/* server will set to valid device type */
12251ae08745Sheppo 	pkt.vdisk_size = 0;	/* server will set to valid size */
12261ae08745Sheppo 
12270a55fbb7Slm66018 	status = vdc_send(vdc, (caddr_t)&pkt, &msglen);
12281ae08745Sheppo 	PR0("%s: vdc_send(status = %d)\n", __func__, status);
12291ae08745Sheppo 
12301ae08745Sheppo 	if ((status != 0) || (msglen != sizeof (vio_ver_msg_t))) {
12311ae08745Sheppo 		PR0("%s[%d] ldc_write failed: id(%lx) rv(%d) size (%d)\n",
12321ae08745Sheppo 			__func__, vdc->instance, vdc->ldc_handle,
12331ae08745Sheppo 			status, msglen);
12341ae08745Sheppo 		if (msglen != sizeof (vio_ver_msg_t))
12351ae08745Sheppo 			status = ENOMSG;
12361ae08745Sheppo 	}
12371ae08745Sheppo 
12381ae08745Sheppo 	return (status);
12391ae08745Sheppo }
12401ae08745Sheppo 
12410a55fbb7Slm66018 /*
12420a55fbb7Slm66018  * Function:
12430a55fbb7Slm66018  *	vdc_init_dring_negotiate()
12440a55fbb7Slm66018  *
12450a55fbb7Slm66018  * Description:
12460a55fbb7Slm66018  *
12470a55fbb7Slm66018  * Arguments:
12480a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
12490a55fbb7Slm66018  *
12500a55fbb7Slm66018  * Return Code:
12510a55fbb7Slm66018  *	0	- Success
12520a55fbb7Slm66018  */
12531ae08745Sheppo static int
12541ae08745Sheppo vdc_init_dring_negotiate(vdc_t *vdc)
12551ae08745Sheppo {
12561ae08745Sheppo 	vio_dring_reg_msg_t	pkt;
12571ae08745Sheppo 	size_t			msglen = sizeof (pkt);
12581ae08745Sheppo 	int			status = -1;
12591ae08745Sheppo 
12601ae08745Sheppo 	ASSERT(vdc != NULL);
12611ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
12621ae08745Sheppo 
12631ae08745Sheppo 	status = vdc_init_descriptor_ring(vdc);
12641ae08745Sheppo 	if (status != 0) {
12651ae08745Sheppo 		cmn_err(CE_CONT, "[%d] Failed to init DRing (status = %d)\n",
12661ae08745Sheppo 				vdc->instance, status);
12670a55fbb7Slm66018 		vdc_destroy_descriptor_ring(vdc);
12681ae08745Sheppo 		vdc_reset_connection(vdc, B_FALSE);
12691ae08745Sheppo 		return (status);
12701ae08745Sheppo 	}
12710a55fbb7Slm66018 	PR0("%s[%d] Init of descriptor ring completed (status = %d)\n",
12720a55fbb7Slm66018 			__func__, vdc->instance, status);
12731ae08745Sheppo 
12741ae08745Sheppo 	/* fill in tag */
12751ae08745Sheppo 	pkt.tag.vio_msgtype = VIO_TYPE_CTRL;
12761ae08745Sheppo 	pkt.tag.vio_subtype = VIO_SUBTYPE_INFO;
12771ae08745Sheppo 	pkt.tag.vio_subtype_env = VIO_DRING_REG;
12781ae08745Sheppo 	pkt.tag.vio_sid = vdc->session_id;
12791ae08745Sheppo 	/* fill in payload */
12801ae08745Sheppo 	pkt.dring_ident = 0;
12811ae08745Sheppo 	pkt.num_descriptors = VD_DRING_LEN;
12821ae08745Sheppo 	pkt.descriptor_size = VD_DRING_ENTRY_SZ;
12831ae08745Sheppo 	pkt.options = (VIO_TX_DRING | VIO_RX_DRING);
12841ae08745Sheppo 	pkt.ncookies = vdc->dring_cookie_count;
12851ae08745Sheppo 	pkt.cookie[0] = vdc->dring_cookie[0];	/* for now just one cookie */
12861ae08745Sheppo 
12870a55fbb7Slm66018 	status = vdc_send(vdc, (caddr_t)&pkt, &msglen);
12881ae08745Sheppo 	if (status != 0) {
12891ae08745Sheppo 		PR0("%s[%d] Failed to register DRing (status = %d)\n",
12901ae08745Sheppo 				__func__, vdc->instance, status);
12911ae08745Sheppo 		vdc_reset_connection(vdc, B_FALSE);
12921ae08745Sheppo 	}
12931ae08745Sheppo 
12941ae08745Sheppo 	return (status);
12951ae08745Sheppo }
12961ae08745Sheppo 
12971ae08745Sheppo 
12981ae08745Sheppo /* -------------------------------------------------------------------------- */
12991ae08745Sheppo 
13001ae08745Sheppo /*
13011ae08745Sheppo  * LDC helper routines
13021ae08745Sheppo  */
13031ae08745Sheppo 
13041ae08745Sheppo /*
13051ae08745Sheppo  * Function:
13061ae08745Sheppo  *	vdc_send()
13071ae08745Sheppo  *
13081ae08745Sheppo  * Description:
13091ae08745Sheppo  *	The function encapsulates the call to write a message using LDC.
13101ae08745Sheppo  *	If LDC indicates that the call failed due to the queue being full,
13111ae08745Sheppo  *	we retry the ldc_write() [ up to 'vdc_retries' time ], otherwise
13121ae08745Sheppo  *	we return the error returned by LDC.
13131ae08745Sheppo  *
13141ae08745Sheppo  * Arguments:
13151ae08745Sheppo  *	ldc_handle	- LDC handle for the channel this instance of vdc uses
13161ae08745Sheppo  *	pkt		- address of LDC message to be sent
13171ae08745Sheppo  *	msglen		- the size of the message being sent. When the function
13181ae08745Sheppo  *			  returns, this contains the number of bytes written.
13191ae08745Sheppo  *
13201ae08745Sheppo  * Return Code:
13211ae08745Sheppo  *	0		- Success.
13221ae08745Sheppo  *	EINVAL		- pkt or msglen were NULL
13231ae08745Sheppo  *	ECONNRESET	- The connection was not up.
13241ae08745Sheppo  *	EWOULDBLOCK	- LDC queue is full
13251ae08745Sheppo  *	xxx		- other error codes returned by ldc_write
13261ae08745Sheppo  */
13271ae08745Sheppo static int
13280a55fbb7Slm66018 vdc_send(vdc_t *vdc, caddr_t pkt, size_t *msglen)
13291ae08745Sheppo {
13301ae08745Sheppo 	size_t	size = 0;
13311ae08745Sheppo 	int	retries = 0;
13321ae08745Sheppo 	int	status = 0;
13331ae08745Sheppo 
13340a55fbb7Slm66018 	ASSERT(vdc != NULL);
13350a55fbb7Slm66018 	ASSERT(mutex_owned(&vdc->lock));
13361ae08745Sheppo 	ASSERT(msglen != NULL);
13371ae08745Sheppo 	ASSERT(*msglen != 0);
13381ae08745Sheppo 
13391ae08745Sheppo 	do {
13401ae08745Sheppo 		size = *msglen;
13410a55fbb7Slm66018 		status = ldc_write(vdc->ldc_handle, pkt, &size);
13421ae08745Sheppo 	} while (status == EWOULDBLOCK && retries++ < vdc_retries);
13431ae08745Sheppo 
13440a55fbb7Slm66018 	/* if LDC had serious issues --- reset vdc state */
13450a55fbb7Slm66018 	if (status == EIO || status == ECONNRESET) {
13460a55fbb7Slm66018 		vdc_reset_connection(vdc, B_TRUE);
13470a55fbb7Slm66018 	}
13480a55fbb7Slm66018 
13491ae08745Sheppo 	/* return the last size written */
13501ae08745Sheppo 	*msglen = size;
13511ae08745Sheppo 
13521ae08745Sheppo 	return (status);
13531ae08745Sheppo }
13541ae08745Sheppo 
13551ae08745Sheppo /*
13561ae08745Sheppo  * Function:
13571ae08745Sheppo  *	vdc_get_ldc_id()
13581ae08745Sheppo  *
13591ae08745Sheppo  * Description:
13601ae08745Sheppo  *	This function gets the 'ldc-id' for this particular instance of vdc.
13611ae08745Sheppo  *	The id returned is the guest domain channel endpoint LDC uses for
13621ae08745Sheppo  *	communication with vds.
13631ae08745Sheppo  *
13641ae08745Sheppo  * Arguments:
13651ae08745Sheppo  *	dip	- dev info pointer for this instance of the device driver.
13661ae08745Sheppo  *	ldc_id	- pointer to variable used to return the 'ldc-id' found.
13671ae08745Sheppo  *
13681ae08745Sheppo  * Return Code:
13691ae08745Sheppo  *	0	- Success.
13701ae08745Sheppo  *	ENOENT	- Expected node or property did not exist.
13711ae08745Sheppo  *	ENXIO	- Unexpected error communicating with MD framework
13721ae08745Sheppo  */
13731ae08745Sheppo static int
13741ae08745Sheppo vdc_get_ldc_id(dev_info_t *dip, uint64_t *ldc_id)
13751ae08745Sheppo {
13761ae08745Sheppo 	int		status = ENOENT;
13771ae08745Sheppo 	char		*node_name = NULL;
13781ae08745Sheppo 	md_t		*mdp = NULL;
13791ae08745Sheppo 	int		num_nodes;
13801ae08745Sheppo 	int		num_vdevs;
13811ae08745Sheppo 	int		num_chans;
13821ae08745Sheppo 	mde_cookie_t	rootnode;
13831ae08745Sheppo 	mde_cookie_t	*listp = NULL;
13841ae08745Sheppo 	mde_cookie_t	*chanp = NULL;
13851ae08745Sheppo 	boolean_t	found_inst = B_FALSE;
13861ae08745Sheppo 	int		listsz;
13871ae08745Sheppo 	int		idx;
13881ae08745Sheppo 	uint64_t	md_inst;
13891ae08745Sheppo 	int		obp_inst;
13901ae08745Sheppo 	int		instance = ddi_get_instance(dip);
13911ae08745Sheppo 
13921ae08745Sheppo 	ASSERT(ldc_id != NULL);
13931ae08745Sheppo 	*ldc_id = 0;
13941ae08745Sheppo 
13951ae08745Sheppo 	/*
13961ae08745Sheppo 	 * Get the OBP instance number for comparison with the MD instance
13971ae08745Sheppo 	 *
13981ae08745Sheppo 	 * The "cfg-handle" property of a vdc node in an MD contains the MD's
13991ae08745Sheppo 	 * notion of "instance", or unique identifier, for that node; OBP
14001ae08745Sheppo 	 * stores the value of the "cfg-handle" MD property as the value of
14011ae08745Sheppo 	 * the "reg" property on the node in the device tree it builds from
14021ae08745Sheppo 	 * the MD and passes to Solaris.  Thus, we look up the devinfo node's
14031ae08745Sheppo 	 * "reg" property value to uniquely identify this device instance.
14041ae08745Sheppo 	 * If the "reg" property cannot be found, the device tree state is
14051ae08745Sheppo 	 * presumably so broken that there is no point in continuing.
14061ae08745Sheppo 	 */
14071ae08745Sheppo 	if (!ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, OBP_REG)) {
14081ae08745Sheppo 		cmn_err(CE_WARN, "'%s' property does not exist", OBP_REG);
14091ae08745Sheppo 		return (ENOENT);
14101ae08745Sheppo 	}
14111ae08745Sheppo 	obp_inst = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
14121ae08745Sheppo 			OBP_REG, -1);
14131ae08745Sheppo 	PR1("%s[%d]: OBP inst=%d\n", __func__, instance, obp_inst);
14141ae08745Sheppo 
14151ae08745Sheppo 	/*
14161ae08745Sheppo 	 * We now walk the MD nodes and if an instance of a vdc node matches
14171ae08745Sheppo 	 * the instance got from OBP we get the ldc-id property.
14181ae08745Sheppo 	 */
14191ae08745Sheppo 	if ((mdp = md_get_handle()) == NULL) {
14201ae08745Sheppo 		cmn_err(CE_WARN, "unable to init machine description");
14211ae08745Sheppo 		return (ENXIO);
14221ae08745Sheppo 	}
14231ae08745Sheppo 
14241ae08745Sheppo 	num_nodes = md_node_count(mdp);
14251ae08745Sheppo 	ASSERT(num_nodes > 0);
14261ae08745Sheppo 
14271ae08745Sheppo 	listsz = num_nodes * sizeof (mde_cookie_t);
14281ae08745Sheppo 
14291ae08745Sheppo 	/* allocate memory for nodes */
14301ae08745Sheppo 	listp = kmem_zalloc(listsz, KM_SLEEP);
14311ae08745Sheppo 	chanp = kmem_zalloc(listsz, KM_SLEEP);
14321ae08745Sheppo 
14331ae08745Sheppo 	rootnode = md_root_node(mdp);
14341ae08745Sheppo 	ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE);
14351ae08745Sheppo 
14361ae08745Sheppo 	/*
14371ae08745Sheppo 	 * Search for all the virtual devices, we will then check to see which
14381ae08745Sheppo 	 * ones are disk nodes.
14391ae08745Sheppo 	 */
14401ae08745Sheppo 	num_vdevs = md_scan_dag(mdp, rootnode,
14411ae08745Sheppo 			md_find_name(mdp, VDC_MD_VDEV_NAME),
14421ae08745Sheppo 			md_find_name(mdp, "fwd"), listp);
14431ae08745Sheppo 
14441ae08745Sheppo 	if (num_vdevs <= 0) {
14451ae08745Sheppo 		cmn_err(CE_NOTE, "No '%s' node found", VDC_MD_VDEV_NAME);
14461ae08745Sheppo 		status = ENOENT;
14471ae08745Sheppo 		goto done;
14481ae08745Sheppo 	}
14491ae08745Sheppo 
14501ae08745Sheppo 	PR1("%s[%d] num_vdevs=%d\n", __func__, instance, num_vdevs);
14511ae08745Sheppo 	for (idx = 0; idx < num_vdevs; idx++) {
14521ae08745Sheppo 		status = md_get_prop_str(mdp, listp[idx], "name", &node_name);
14531ae08745Sheppo 		if ((status != 0) || (node_name == NULL)) {
14541ae08745Sheppo 			cmn_err(CE_NOTE, "Unable to get name of node type '%s'"
14551ae08745Sheppo 					": err %d", VDC_MD_VDEV_NAME, status);
14561ae08745Sheppo 			continue;
14571ae08745Sheppo 		}
14581ae08745Sheppo 
14591ae08745Sheppo 		PR1("%s[%d] Found node %s\n", __func__, instance, node_name);
14601ae08745Sheppo 		if (strcmp(VDC_MD_DISK_NAME, node_name) == 0) {
14611ae08745Sheppo 			status = md_get_prop_val(mdp, listp[idx],
14621ae08745Sheppo 					VDC_MD_CFG_HDL, &md_inst);
14631ae08745Sheppo 			PR1("%s[%d] vdc inst# in MD=%d\n",
14641ae08745Sheppo 					__func__, instance, md_inst);
14651ae08745Sheppo 			if ((status == 0) && (md_inst == obp_inst)) {
14661ae08745Sheppo 				found_inst = B_TRUE;
14671ae08745Sheppo 				break;
14681ae08745Sheppo 			}
14691ae08745Sheppo 		}
14701ae08745Sheppo 	}
14711ae08745Sheppo 
14720a55fbb7Slm66018 	if (!found_inst) {
14731ae08745Sheppo 		cmn_err(CE_NOTE, "Unable to find correct '%s' node",
14741ae08745Sheppo 				VDC_MD_DISK_NAME);
14751ae08745Sheppo 		status = ENOENT;
14761ae08745Sheppo 		goto done;
14771ae08745Sheppo 	}
14781ae08745Sheppo 	PR0("%s[%d] MD inst=%d\n", __func__, instance, md_inst);
14791ae08745Sheppo 
14801ae08745Sheppo 	/* get the channels for this node */
14811ae08745Sheppo 	num_chans = md_scan_dag(mdp, listp[idx],
14821ae08745Sheppo 			md_find_name(mdp, VDC_MD_CHAN_NAME),
14831ae08745Sheppo 			md_find_name(mdp, "fwd"), chanp);
14841ae08745Sheppo 
14851ae08745Sheppo 	/* expecting at least one channel */
14861ae08745Sheppo 	if (num_chans <= 0) {
14871ae08745Sheppo 		cmn_err(CE_NOTE, "No '%s' node for '%s' port",
14881ae08745Sheppo 				VDC_MD_CHAN_NAME, VDC_MD_VDEV_NAME);
14891ae08745Sheppo 		status = ENOENT;
14901ae08745Sheppo 		goto done;
14911ae08745Sheppo 
14921ae08745Sheppo 	} else if (num_chans != 1) {
14931ae08745Sheppo 		PR0("%s[%d] Expected 1 '%s' node for '%s' port, found %d\n",
14941ae08745Sheppo 			__func__, instance, VDC_MD_CHAN_NAME, VDC_MD_VDEV_NAME,
14951ae08745Sheppo 			num_chans);
14961ae08745Sheppo 	}
14971ae08745Sheppo 
14981ae08745Sheppo 	/*
14991ae08745Sheppo 	 * We use the first channel found (index 0), irrespective of how
15001ae08745Sheppo 	 * many are there in total.
15011ae08745Sheppo 	 */
15021ae08745Sheppo 	if (md_get_prop_val(mdp, chanp[0], VDC_ID_PROP, ldc_id) != 0) {
15031ae08745Sheppo 		cmn_err(CE_NOTE, "Channel '%s' property not found",
15041ae08745Sheppo 				VDC_ID_PROP);
15051ae08745Sheppo 		status = ENOENT;
15061ae08745Sheppo 	}
15071ae08745Sheppo 
15081ae08745Sheppo 	PR0("%s[%d] LDC id is 0x%lx\n", __func__, instance, *ldc_id);
15091ae08745Sheppo 
15101ae08745Sheppo done:
15111ae08745Sheppo 	if (chanp)
15121ae08745Sheppo 		kmem_free(chanp, listsz);
15131ae08745Sheppo 	if (listp)
15141ae08745Sheppo 		kmem_free(listp, listsz);
15151ae08745Sheppo 
15161ae08745Sheppo 	(void) md_fini_handle(mdp);
15171ae08745Sheppo 
15181ae08745Sheppo 	return (status);
15191ae08745Sheppo }
15201ae08745Sheppo 
15210a55fbb7Slm66018 static int
15220a55fbb7Slm66018 vdc_do_ldc_up(vdc_t *vdc)
15230a55fbb7Slm66018 {
15240a55fbb7Slm66018 	int	status;
15250a55fbb7Slm66018 
15260a55fbb7Slm66018 	PR0("[%d] Bringing up channel %x\n", vdc->instance, vdc->ldc_id);
15270a55fbb7Slm66018 
15280a55fbb7Slm66018 	if ((status = ldc_up(vdc->ldc_handle)) != 0) {
15290a55fbb7Slm66018 		switch (status) {
15300a55fbb7Slm66018 		case ECONNREFUSED:	/* listener not ready at other end */
15310a55fbb7Slm66018 			PR0("%s: ldc_up(%d,...) return %d\n",
15320a55fbb7Slm66018 					__func__, vdc->ldc_id, status);
15330a55fbb7Slm66018 			status = 0;
15340a55fbb7Slm66018 			break;
15350a55fbb7Slm66018 		default:
15360a55fbb7Slm66018 			cmn_err(CE_NOTE, "[%d] Failed to bring up LDC: "
15370a55fbb7Slm66018 					"channel=%ld, err=%d",
15380a55fbb7Slm66018 					vdc->instance, vdc->ldc_id, status);
15390a55fbb7Slm66018 		}
15400a55fbb7Slm66018 	}
15410a55fbb7Slm66018 
15420a55fbb7Slm66018 	return (status);
15430a55fbb7Slm66018 }
15440a55fbb7Slm66018 
15451ae08745Sheppo 
15461ae08745Sheppo /*
15471ae08745Sheppo  * vdc_is_able_to_tx_data()
15481ae08745Sheppo  *
15491ae08745Sheppo  * Description:
15501ae08745Sheppo  *	This function checks if we are able to send data to the
15511ae08745Sheppo  *	vDisk server (vds). The LDC connection needs to be up and
15521ae08745Sheppo  *	vdc & vds need to have completed the handshake negotiation.
15531ae08745Sheppo  *
15541ae08745Sheppo  * Parameters:
15551ae08745Sheppo  *	vdc 		- soft state pointer
15561ae08745Sheppo  *	flag		- flag to indicate if we can block or not
15571ae08745Sheppo  *			  [ If O_NONBLOCK or O_NDELAY (which are defined in
15581ae08745Sheppo  *			    open(2)) are set then do not block)
15591ae08745Sheppo  *
15601ae08745Sheppo  * Return Values
15611ae08745Sheppo  *	B_TRUE		- can talk to vds
15621ae08745Sheppo  *	B_FALSE		- unable to talk to vds
15631ae08745Sheppo  */
15641ae08745Sheppo static boolean_t
15651ae08745Sheppo vdc_is_able_to_tx_data(vdc_t *vdc, int flag)
15661ae08745Sheppo {
15671ae08745Sheppo 	vd_state_t	state;
15681ae08745Sheppo 	uint32_t	ldc_state;
15691ae08745Sheppo 	uint_t		retries = 0;
15701ae08745Sheppo 	int		rv = -1;
15711ae08745Sheppo 
15721ae08745Sheppo 	ASSERT(vdc != NULL);
15731ae08745Sheppo 
15741ae08745Sheppo 	mutex_enter(&vdc->lock);
15751ae08745Sheppo 	state = vdc->state;
15761ae08745Sheppo 	ldc_state = vdc->ldc_state;
15771ae08745Sheppo 	mutex_exit(&vdc->lock);
15781ae08745Sheppo 
15791ae08745Sheppo 	if ((state == VD_STATE_DATA) && (ldc_state == LDC_UP))
15801ae08745Sheppo 		return (B_TRUE);
15811ae08745Sheppo 
15821ae08745Sheppo 	if ((flag & O_NONBLOCK) || (flag & O_NDELAY)) {
15831ae08745Sheppo 		PR0("%s[%d] Not ready to tx - state %d LDC state %d\n",
15841ae08745Sheppo 			__func__, vdc->instance, state, ldc_state);
15851ae08745Sheppo 		return (B_FALSE);
15861ae08745Sheppo 	}
15871ae08745Sheppo 
15881ae08745Sheppo 	/*
15891ae08745Sheppo 	 * We want to check and see if any negotiations triggered earlier
15901ae08745Sheppo 	 * have succeeded. We are prepared to wait a little while in case
15911ae08745Sheppo 	 * they are still in progress.
15921ae08745Sheppo 	 */
15931ae08745Sheppo 	mutex_enter(&vdc->lock);
15941ae08745Sheppo 	while ((vdc->ldc_state != LDC_UP) || (vdc->state != VD_STATE_DATA)) {
15951ae08745Sheppo 		PR0("%s: Waiting for connection at state %d (LDC state %d)\n",
15961ae08745Sheppo 			__func__, vdc->state, vdc->ldc_state);
15971ae08745Sheppo 
15981ae08745Sheppo 		rv = cv_timedwait(&vdc->cv, &vdc->lock,
15991ae08745Sheppo 			VD_GET_TIMEOUT_HZ(retries));
16001ae08745Sheppo 
16011ae08745Sheppo 		/*
16021ae08745Sheppo 		 * An rv of -1 indicates that we timed out without the LDC
16031ae08745Sheppo 		 * state changing so it looks like the other side (vdc) is
16041ae08745Sheppo 		 * not yet ready/responding.
16051ae08745Sheppo 		 *
16061ae08745Sheppo 		 * Any other value of rv indicates that the LDC triggered an
16071ae08745Sheppo 		 * interrupt so we just loop again, check the handshake state
16081ae08745Sheppo 		 * and keep waiting if necessary.
16091ae08745Sheppo 		 */
16101ae08745Sheppo 		if (rv == -1) {
16111ae08745Sheppo 			if (retries >= vdc_retries) {
16121ae08745Sheppo 				PR0("%s[%d] handshake wait timed out.\n",
16131ae08745Sheppo 						__func__, vdc->instance);
16141ae08745Sheppo 				mutex_exit(&vdc->lock);
16151ae08745Sheppo 				return (B_FALSE);
16161ae08745Sheppo 			} else {
16171ae08745Sheppo 				PR1("%s[%d] Retry #%d for handshake timedout\n",
16181ae08745Sheppo 					__func__, vdc->instance, retries);
16191ae08745Sheppo 				retries++;
16201ae08745Sheppo 			}
16211ae08745Sheppo 		}
16221ae08745Sheppo 	}
16231ae08745Sheppo 
16241ae08745Sheppo 	ASSERT(vdc->ldc_state == LDC_UP);
16251ae08745Sheppo 	ASSERT(vdc->state == VD_STATE_DATA);
16261ae08745Sheppo 
16271ae08745Sheppo 	mutex_exit(&vdc->lock);
16281ae08745Sheppo 
16291ae08745Sheppo 	return (B_TRUE);
16301ae08745Sheppo }
16311ae08745Sheppo 
16321ae08745Sheppo 
16330a55fbb7Slm66018 /*
16340a55fbb7Slm66018  * Function:
16350a55fbb7Slm66018  *	vdc_terminate_ldc()
16360a55fbb7Slm66018  *
16370a55fbb7Slm66018  * Description:
16380a55fbb7Slm66018  *
16390a55fbb7Slm66018  * Arguments:
16400a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
16410a55fbb7Slm66018  *
16420a55fbb7Slm66018  * Return Code:
16430a55fbb7Slm66018  *	None
16440a55fbb7Slm66018  */
16451ae08745Sheppo static void
16461ae08745Sheppo vdc_terminate_ldc(vdc_t *vdc)
16471ae08745Sheppo {
16481ae08745Sheppo 	int	instance = ddi_get_instance(vdc->dip);
16491ae08745Sheppo 
16501ae08745Sheppo 	ASSERT(vdc != NULL);
16511ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
16521ae08745Sheppo 
16531ae08745Sheppo 	PR0("%s[%d] initialized=%x\n", __func__, instance, vdc->initialized);
16541ae08745Sheppo 
16551ae08745Sheppo 	if (vdc->initialized & VDC_LDC_OPEN) {
16561ae08745Sheppo 		PR0("%s[%d]: ldc_close()\n", __func__, instance);
16571ae08745Sheppo 		(void) ldc_close(vdc->ldc_handle);
16581ae08745Sheppo 	}
16591ae08745Sheppo 	if (vdc->initialized & VDC_LDC_CB) {
16601ae08745Sheppo 		PR0("%s[%d]: ldc_unreg_callback()\n", __func__, instance);
16611ae08745Sheppo 		(void) ldc_unreg_callback(vdc->ldc_handle);
16621ae08745Sheppo 	}
16631ae08745Sheppo 	if (vdc->initialized & VDC_LDC) {
16641ae08745Sheppo 		PR0("%s[%d]: ldc_fini()\n", __func__, instance);
16651ae08745Sheppo 		(void) ldc_fini(vdc->ldc_handle);
16661ae08745Sheppo 		vdc->ldc_handle = NULL;
16671ae08745Sheppo 	}
16681ae08745Sheppo 
16691ae08745Sheppo 	vdc->initialized &= ~(VDC_LDC | VDC_LDC_CB | VDC_LDC_OPEN);
16701ae08745Sheppo }
16711ae08745Sheppo 
16720a55fbb7Slm66018 /*
16730a55fbb7Slm66018  * Function:
16740a55fbb7Slm66018  *	vdc_reset_connection()
16750a55fbb7Slm66018  *
16760a55fbb7Slm66018  * Description:
16770a55fbb7Slm66018  *
16780a55fbb7Slm66018  * Arguments:
16790a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
16800a55fbb7Slm66018  *	reset_ldc - Flag whether or not to reset the LDC connection also.
16810a55fbb7Slm66018  *
16820a55fbb7Slm66018  * Return Code:
16830a55fbb7Slm66018  *	None
16840a55fbb7Slm66018  */
16851ae08745Sheppo static void
16861ae08745Sheppo vdc_reset_connection(vdc_t *vdc, boolean_t reset_ldc)
16871ae08745Sheppo {
16881ae08745Sheppo 	int	status;
16891ae08745Sheppo 
16901ae08745Sheppo 	ASSERT(vdc != NULL);
16911ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
16921ae08745Sheppo 
16931ae08745Sheppo 	PR0("%s[%d] Entered\n", __func__, vdc->instance);
16941ae08745Sheppo 
16951ae08745Sheppo 	vdc->state = VD_STATE_INIT;
16961ae08745Sheppo 
16970a55fbb7Slm66018 	if (reset_ldc) {
16981ae08745Sheppo 		status = ldc_reset(vdc->ldc_handle);
16991ae08745Sheppo 		PR0("%s[%d]  ldc_reset() = %d\n",
17001ae08745Sheppo 				__func__, vdc->instance, status);
17011ae08745Sheppo 	}
17021ae08745Sheppo 
17031ae08745Sheppo 	vdc->initialized &= ~VDC_HANDSHAKE;
17041ae08745Sheppo 	PR0("%s[%d] init=%x\n", __func__, vdc->instance, vdc->initialized);
17051ae08745Sheppo }
17061ae08745Sheppo 
17071ae08745Sheppo /* -------------------------------------------------------------------------- */
17081ae08745Sheppo 
17091ae08745Sheppo /*
17101ae08745Sheppo  * Descriptor Ring helper routines
17111ae08745Sheppo  */
17121ae08745Sheppo 
17130a55fbb7Slm66018 /*
17140a55fbb7Slm66018  * Function:
17150a55fbb7Slm66018  *	vdc_init_descriptor_ring()
17160a55fbb7Slm66018  *
17170a55fbb7Slm66018  * Description:
17180a55fbb7Slm66018  *
17190a55fbb7Slm66018  * Arguments:
17200a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
17210a55fbb7Slm66018  *
17220a55fbb7Slm66018  * Return Code:
17230a55fbb7Slm66018  *	0	- Success
17240a55fbb7Slm66018  */
17251ae08745Sheppo static int
17261ae08745Sheppo vdc_init_descriptor_ring(vdc_t *vdc)
17271ae08745Sheppo {
17281ae08745Sheppo 	vd_dring_entry_t	*dep = NULL;	/* DRing Entry pointer */
17290a55fbb7Slm66018 	int	status = 0;
17301ae08745Sheppo 	int	i;
17311ae08745Sheppo 
17320a55fbb7Slm66018 	PR0("%s[%d] initialized=%x\n",
17330a55fbb7Slm66018 			__func__, vdc->instance, vdc->initialized);
17341ae08745Sheppo 
17351ae08745Sheppo 	ASSERT(vdc != NULL);
17361ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
17371ae08745Sheppo 	ASSERT(vdc->ldc_handle != NULL);
17381ae08745Sheppo 
17390a55fbb7Slm66018 	if ((vdc->initialized & VDC_DRING_INIT) == 0) {
17400a55fbb7Slm66018 		PR0("%s[%d] ldc_mem_dring_create\n", __func__, vdc->instance);
17411ae08745Sheppo 		status = ldc_mem_dring_create(VD_DRING_LEN, VD_DRING_ENTRY_SZ,
17421ae08745Sheppo 				&vdc->ldc_dring_hdl);
17431ae08745Sheppo 		if ((vdc->ldc_dring_hdl == NULL) || (status != 0)) {
17441ae08745Sheppo 			PR0("%s: Failed to create a descriptor ring", __func__);
17451ae08745Sheppo 			return (status);
17461ae08745Sheppo 		}
17471ae08745Sheppo 		vdc->dring_entry_size = VD_DRING_ENTRY_SZ;
17481ae08745Sheppo 		vdc->dring_len = VD_DRING_LEN;
17490a55fbb7Slm66018 		vdc->initialized |= VDC_DRING_INIT;
17500a55fbb7Slm66018 	}
17511ae08745Sheppo 
17520a55fbb7Slm66018 	if ((vdc->initialized & VDC_DRING_BOUND) == 0) {
17530a55fbb7Slm66018 		PR0("%s[%d] ldc_mem_dring_bind\n", __func__, vdc->instance);
17540a55fbb7Slm66018 		vdc->dring_cookie =
17550a55fbb7Slm66018 			kmem_zalloc(sizeof (ldc_mem_cookie_t), KM_SLEEP);
17561ae08745Sheppo 
17571ae08745Sheppo 		status = ldc_mem_dring_bind(vdc->ldc_handle, vdc->ldc_dring_hdl,
17580a55fbb7Slm66018 				LDC_SHADOW_MAP, LDC_MEM_RW,
17590a55fbb7Slm66018 				&vdc->dring_cookie[0],
17601ae08745Sheppo 				&vdc->dring_cookie_count);
17611ae08745Sheppo 		if (status != 0) {
17620a55fbb7Slm66018 			PR0("%s: Failed to bind descriptor ring (%p) "
17630a55fbb7Slm66018 				"to channel (%p)\n",
17641ae08745Sheppo 				__func__, vdc->ldc_dring_hdl, vdc->ldc_handle);
17651ae08745Sheppo 			return (status);
17661ae08745Sheppo 		}
17671ae08745Sheppo 		ASSERT(vdc->dring_cookie_count == 1);
17681ae08745Sheppo 		vdc->initialized |= VDC_DRING_BOUND;
17690a55fbb7Slm66018 	}
17701ae08745Sheppo 
17711ae08745Sheppo 	status = ldc_mem_dring_info(vdc->ldc_dring_hdl, &vdc->dring_mem_info);
17721ae08745Sheppo 	if (status != 0) {
17731ae08745Sheppo 		PR0("%s: Failed to get info for descriptor ring (%p)\n",
17741ae08745Sheppo 			__func__, vdc->ldc_dring_hdl);
17751ae08745Sheppo 		return (status);
17761ae08745Sheppo 	}
17771ae08745Sheppo 
17780a55fbb7Slm66018 	if ((vdc->initialized & VDC_DRING_LOCAL) == 0) {
17790a55fbb7Slm66018 		PR0("%s[%d] local dring\n", __func__, vdc->instance);
17800a55fbb7Slm66018 
17811ae08745Sheppo 		/* Allocate the local copy of this dring */
17820a55fbb7Slm66018 		vdc->local_dring =
17830a55fbb7Slm66018 			kmem_zalloc(VD_DRING_LEN * sizeof (vdc_local_desc_t),
17841ae08745Sheppo 						KM_SLEEP);
17851ae08745Sheppo 		vdc->initialized |= VDC_DRING_LOCAL;
17860a55fbb7Slm66018 	}
17871ae08745Sheppo 
17881ae08745Sheppo 	/*
17890a55fbb7Slm66018 	 * Mark all DRing entries as free and initialize the private
17900a55fbb7Slm66018 	 * descriptor's memory handles. If any entry is initialized,
17910a55fbb7Slm66018 	 * we need to free it later so we set the bit in 'initialized'
17920a55fbb7Slm66018 	 * at the start.
17931ae08745Sheppo 	 */
17941ae08745Sheppo 	vdc->initialized |= VDC_DRING_ENTRY;
17951ae08745Sheppo 	for (i = 0; i < VD_DRING_LEN; i++) {
17961ae08745Sheppo 		dep = VDC_GET_DRING_ENTRY_PTR(vdc, i);
17971ae08745Sheppo 		dep->hdr.dstate = VIO_DESC_FREE;
17981ae08745Sheppo 
17991ae08745Sheppo 		status = ldc_mem_alloc_handle(vdc->ldc_handle,
18001ae08745Sheppo 				&vdc->local_dring[i].desc_mhdl);
18011ae08745Sheppo 		if (status != 0) {
18021ae08745Sheppo 			cmn_err(CE_NOTE, "![%d] Failed to alloc mem handle for"
18031ae08745Sheppo 					" descriptor %d", vdc->instance, i);
18041ae08745Sheppo 			return (status);
18051ae08745Sheppo 		}
18061ae08745Sheppo 		vdc->local_dring[i].flags = VIO_DESC_FREE;
18071ae08745Sheppo 		vdc->local_dring[i].dep = dep;
18081ae08745Sheppo 
18091ae08745Sheppo 		mutex_init(&vdc->local_dring[i].lock, NULL, MUTEX_DRIVER, NULL);
18101ae08745Sheppo 		cv_init(&vdc->local_dring[i].cv, NULL, CV_DRIVER, NULL);
18111ae08745Sheppo 	}
18121ae08745Sheppo 
18131ae08745Sheppo 	/*
18141ae08745Sheppo 	 * We init the index of the last DRing entry used. Since the code to
18151ae08745Sheppo 	 * get the next available entry increments it before selecting one,
18161ae08745Sheppo 	 * we set it to the last DRing entry so that it wraps around to zero
18171ae08745Sheppo 	 * for the 1st entry to be used.
18181ae08745Sheppo 	 */
18191ae08745Sheppo 	vdc->dring_curr_idx = VD_DRING_LEN - 1;
18201ae08745Sheppo 
18211ae08745Sheppo 	return (status);
18221ae08745Sheppo }
18231ae08745Sheppo 
18240a55fbb7Slm66018 /*
18250a55fbb7Slm66018  * Function:
18260a55fbb7Slm66018  *	vdc_destroy_descriptor_ring()
18270a55fbb7Slm66018  *
18280a55fbb7Slm66018  * Description:
18290a55fbb7Slm66018  *
18300a55fbb7Slm66018  * Arguments:
18310a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
18320a55fbb7Slm66018  *
18330a55fbb7Slm66018  * Return Code:
18340a55fbb7Slm66018  *	None
18350a55fbb7Slm66018  */
18361ae08745Sheppo static void
18371ae08745Sheppo vdc_destroy_descriptor_ring(vdc_t *vdc)
18381ae08745Sheppo {
18390a55fbb7Slm66018 	vdc_local_desc_t	*ldep = NULL;	/* Local Dring Entry Pointer */
18401ae08745Sheppo 	ldc_mem_handle_t	mhdl = NULL;
18411ae08745Sheppo 	int			status = -1;
18421ae08745Sheppo 	int			i;	/* loop */
18431ae08745Sheppo 
18441ae08745Sheppo 	ASSERT(vdc != NULL);
18451ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
18461ae08745Sheppo 	ASSERT(vdc->state == VD_STATE_INIT);
18471ae08745Sheppo 
18481ae08745Sheppo 	PR0("%s: Entered\n", __func__);
18491ae08745Sheppo 
18501ae08745Sheppo 	if (vdc->initialized & VDC_DRING_ENTRY) {
18510a55fbb7Slm66018 		PR0("[%d] Removing Local DRing entries\n", vdc->instance);
18521ae08745Sheppo 		for (i = 0; i < VD_DRING_LEN; i++) {
18530a55fbb7Slm66018 			ldep = &vdc->local_dring[i];
18540a55fbb7Slm66018 			mhdl = ldep->desc_mhdl;
18551ae08745Sheppo 
18560a55fbb7Slm66018 			if (mhdl == NULL)
18570a55fbb7Slm66018 				continue;
18580a55fbb7Slm66018 
18591ae08745Sheppo 			(void) ldc_mem_free_handle(mhdl);
18600a55fbb7Slm66018 			mutex_destroy(&ldep->lock);
18610a55fbb7Slm66018 			cv_destroy(&ldep->cv);
18621ae08745Sheppo 		}
18631ae08745Sheppo 		vdc->initialized &= ~VDC_DRING_ENTRY;
18641ae08745Sheppo 	}
18651ae08745Sheppo 
18661ae08745Sheppo 	if (vdc->initialized & VDC_DRING_LOCAL) {
18670a55fbb7Slm66018 		PR0("[%d] Freeing Local DRing\n", vdc->instance);
18681ae08745Sheppo 		kmem_free(vdc->local_dring,
18691ae08745Sheppo 				VD_DRING_LEN * sizeof (vdc_local_desc_t));
18701ae08745Sheppo 		vdc->initialized &= ~VDC_DRING_LOCAL;
18711ae08745Sheppo 	}
18721ae08745Sheppo 
18731ae08745Sheppo 	if (vdc->initialized & VDC_DRING_BOUND) {
18740a55fbb7Slm66018 		PR0("[%d] Unbinding DRing\n", vdc->instance);
18751ae08745Sheppo 		status = ldc_mem_dring_unbind(vdc->ldc_dring_hdl);
18761ae08745Sheppo 		if (status == 0) {
18771ae08745Sheppo 			vdc->initialized &= ~VDC_DRING_BOUND;
18781ae08745Sheppo 		} else {
18791ae08745Sheppo 			vdc_msg("%s: Failed to unbind Descriptor Ring (%lx)\n",
18801ae08745Sheppo 				vdc->ldc_dring_hdl);
18811ae08745Sheppo 		}
18821ae08745Sheppo 	}
18831ae08745Sheppo 
18841ae08745Sheppo 	if (vdc->initialized & VDC_DRING_INIT) {
18850a55fbb7Slm66018 		PR0("[%d] Destroying DRing\n", vdc->instance);
18861ae08745Sheppo 		status = ldc_mem_dring_destroy(vdc->ldc_dring_hdl);
18871ae08745Sheppo 		if (status == 0) {
18881ae08745Sheppo 			vdc->ldc_dring_hdl = NULL;
18891ae08745Sheppo 			bzero(&vdc->dring_mem_info, sizeof (ldc_mem_info_t));
18901ae08745Sheppo 			vdc->initialized &= ~VDC_DRING_INIT;
18911ae08745Sheppo 		} else {
18921ae08745Sheppo 			vdc_msg("%s: Failed to destroy Descriptor Ring (%lx)\n",
18931ae08745Sheppo 					vdc->ldc_dring_hdl);
18941ae08745Sheppo 		}
18951ae08745Sheppo 	}
18961ae08745Sheppo }
18971ae08745Sheppo 
18981ae08745Sheppo /*
18991ae08745Sheppo  * vdc_get_next_dring_entry_idx()
19001ae08745Sheppo  *
19011ae08745Sheppo  * Description:
19021ae08745Sheppo  *	This function gets the index of the next Descriptor Ring entry available
19031ae08745Sheppo  *
19041ae08745Sheppo  * Return Value:
19051ae08745Sheppo  *	0 <= rv < VD_DRING_LEN		Next available slot
19061ae08745Sheppo  *	-1 				DRing is full
19071ae08745Sheppo  */
19081ae08745Sheppo static int
19091ae08745Sheppo vdc_get_next_dring_entry_idx(vdc_t *vdc, uint_t num_slots_needed)
19101ae08745Sheppo {
19111ae08745Sheppo 	_NOTE(ARGUNUSED(num_slots_needed))
19121ae08745Sheppo 
19131ae08745Sheppo 	vd_dring_entry_t	*dep = NULL;	/* Dring Entry Pointer */
19141ae08745Sheppo 	int			idx = -1;
19151ae08745Sheppo 	int			start_idx = 0;
19161ae08745Sheppo 
19171ae08745Sheppo 	ASSERT(vdc != NULL);
19181ae08745Sheppo 	ASSERT(vdc->dring_len == VD_DRING_LEN);
19191ae08745Sheppo 	ASSERT(vdc->dring_curr_idx >= 0);
19201ae08745Sheppo 	ASSERT(vdc->dring_curr_idx < VD_DRING_LEN);
19211ae08745Sheppo 	ASSERT(mutex_owned(&vdc->dring_lock));
19221ae08745Sheppo 
19231ae08745Sheppo 	/* Start at the last entry used */
19241ae08745Sheppo 	idx = start_idx = vdc->dring_curr_idx;
19251ae08745Sheppo 
19261ae08745Sheppo 	/*
19271ae08745Sheppo 	 * Loop through Descriptor Ring checking for a free entry until we reach
19281ae08745Sheppo 	 * the entry we started at. We should never come close to filling the
19291ae08745Sheppo 	 * Ring at any stage, instead this is just to prevent an entry which
19301ae08745Sheppo 	 * gets into an inconsistent state (e.g. due to a request timing out)
19311ae08745Sheppo 	 * from blocking progress.
19321ae08745Sheppo 	 */
19331ae08745Sheppo 	do {
19341ae08745Sheppo 		/* Get the next entry after the last known index tried */
19351ae08745Sheppo 		idx = (idx + 1) % VD_DRING_LEN;
19361ae08745Sheppo 
19371ae08745Sheppo 		dep = VDC_GET_DRING_ENTRY_PTR(vdc, idx);
19381ae08745Sheppo 		ASSERT(dep != NULL);
19391ae08745Sheppo 
19401ae08745Sheppo 		if (dep->hdr.dstate == VIO_DESC_FREE) {
19411ae08745Sheppo 			ASSERT(idx >= 0);
19421ae08745Sheppo 			ASSERT(idx < VD_DRING_LEN);
19431ae08745Sheppo 			vdc->dring_curr_idx = idx;
19441ae08745Sheppo 			return (idx);
19451ae08745Sheppo 
19461ae08745Sheppo 		} else if (dep->hdr.dstate == VIO_DESC_READY) {
19471ae08745Sheppo 			PR0("%s: Entry %d waiting to be accepted\n",
19481ae08745Sheppo 					__func__, idx);
19491ae08745Sheppo 			continue;
19501ae08745Sheppo 
19511ae08745Sheppo 		} else if (dep->hdr.dstate == VIO_DESC_ACCEPTED) {
19521ae08745Sheppo 			PR0("%s: Entry %d waiting to be processed\n",
19531ae08745Sheppo 					__func__, idx);
19541ae08745Sheppo 			continue;
19551ae08745Sheppo 
19561ae08745Sheppo 		} else if (dep->hdr.dstate == VIO_DESC_DONE) {
19571ae08745Sheppo 			PR0("%s: Entry %d done but not marked free\n",
19581ae08745Sheppo 					__func__, idx);
19591ae08745Sheppo 
19601ae08745Sheppo 			/*
19611ae08745Sheppo 			 * If we are currently panicking, interrupts are
19621ae08745Sheppo 			 * disabled and we will not be getting ACKs from the
19631ae08745Sheppo 			 * vDisk server so we mark the descriptor ring entries
19641ae08745Sheppo 			 * as FREE here instead of in the ACK handler.
19651ae08745Sheppo 			 */
19661ae08745Sheppo 			if (panicstr) {
19671ae08745Sheppo 				(void) vdc_depopulate_descriptor(vdc, idx);
19681ae08745Sheppo 				dep->hdr.dstate = VIO_DESC_FREE;
19691ae08745Sheppo 				vdc->local_dring[idx].flags = VIO_DESC_FREE;
19701ae08745Sheppo 			}
19711ae08745Sheppo 			continue;
19721ae08745Sheppo 
19731ae08745Sheppo 		} else {
19741ae08745Sheppo 			vdc_msg("Public Descriptor Ring entry corrupted");
19751ae08745Sheppo 			mutex_enter(&vdc->lock);
19760a55fbb7Slm66018 			vdc_reset_connection(vdc, B_FALSE);
19771ae08745Sheppo 			mutex_exit(&vdc->lock);
19781ae08745Sheppo 			return (-1);
19791ae08745Sheppo 		}
19801ae08745Sheppo 
19811ae08745Sheppo 	} while (idx != start_idx);
19821ae08745Sheppo 
19831ae08745Sheppo 	return (-1);
19841ae08745Sheppo }
19851ae08745Sheppo 
19861ae08745Sheppo /*
19871ae08745Sheppo  * Function:
19881ae08745Sheppo  *	vdc_populate_descriptor
19891ae08745Sheppo  *
19901ae08745Sheppo  * Description:
19911ae08745Sheppo  *	This routine writes the data to be transmitted to vds into the
19921ae08745Sheppo  *	descriptor, notifies vds that the ring has been updated and
19931ae08745Sheppo  *	then waits for the request to be processed.
19941ae08745Sheppo  *
19951ae08745Sheppo  * Arguments:
19961ae08745Sheppo  *	vdc	- the soft state pointer
19971ae08745Sheppo  *	addr	- start address of memory region.
19981ae08745Sheppo  *	nbytes	- number of bytes to read/write
19991ae08745Sheppo  *	operation - operation we want vds to perform (VD_OP_XXX)
20001ae08745Sheppo  *	arg	- parameter to be sent to server (depends on VD_OP_XXX type)
20011ae08745Sheppo  *			. mode for ioctl(9e)
20021ae08745Sheppo  *			. LP64 diskaddr_t (block I/O)
20031ae08745Sheppo  *	slice	- the disk slice this request is for
20041ae08745Sheppo  *
20051ae08745Sheppo  * Return Codes:
20061ae08745Sheppo  *	0
20071ae08745Sheppo  *	EAGAIN
20081ae08745Sheppo  *		EFAULT
20091ae08745Sheppo  *		ENXIO
20101ae08745Sheppo  *		EIO
20111ae08745Sheppo  */
20121ae08745Sheppo static int
20131ae08745Sheppo vdc_populate_descriptor(vdc_t *vdc, caddr_t addr, size_t nbytes, int operation,
20141ae08745Sheppo 				uint64_t arg, uint64_t slice)
20151ae08745Sheppo {
20161ae08745Sheppo 	vdc_local_desc_t *local_dep = NULL;	/* Local Dring Entry Pointer */
20171ae08745Sheppo 	vd_dring_entry_t *dep = NULL;		/* Dring Entry Pointer */
20181ae08745Sheppo 	int			idx = 0;	/* Index of DRing entry used */
20191ae08745Sheppo 	vio_dring_msg_t		dmsg;
20201ae08745Sheppo 	size_t			msglen = sizeof (dmsg);
20211ae08745Sheppo 	int			retries = 0;
2022*8e6a2a04Slm66018 	int			rv;
20231ae08745Sheppo 
20241ae08745Sheppo 	ASSERT(vdc != NULL);
20251ae08745Sheppo 	ASSERT(slice < V_NUMPAR);
20261ae08745Sheppo 
20271ae08745Sheppo 	/*
20281ae08745Sheppo 	 * Get next available DRing entry.
20291ae08745Sheppo 	 */
20301ae08745Sheppo 	mutex_enter(&vdc->dring_lock);
20311ae08745Sheppo 	idx = vdc_get_next_dring_entry_idx(vdc, 1);
20321ae08745Sheppo 	if (idx == -1) {
20331ae08745Sheppo 		mutex_exit(&vdc->dring_lock);
20341ae08745Sheppo 		vdc_msg("%s[%d]: no descriptor ring entry avail, seq=%d\n",
20351ae08745Sheppo 				__func__, vdc->instance, vdc->seq_num);
20361ae08745Sheppo 
20371ae08745Sheppo 		/*
20381ae08745Sheppo 		 * Since strategy should not block we don't wait for the DRing
20391ae08745Sheppo 		 * to empty and instead return
20401ae08745Sheppo 		 */
20411ae08745Sheppo 		return (EAGAIN);
20421ae08745Sheppo 	}
20431ae08745Sheppo 
20441ae08745Sheppo 	ASSERT(idx < VD_DRING_LEN);
20451ae08745Sheppo 	local_dep = &vdc->local_dring[idx];
20461ae08745Sheppo 	dep = local_dep->dep;
20471ae08745Sheppo 	ASSERT(dep != NULL);
20481ae08745Sheppo 
20491ae08745Sheppo 	/*
20501ae08745Sheppo 	 * Wait for anybody still using the DRing entry to finish.
20511ae08745Sheppo 	 * (e.g. still waiting for vds to respond to a request)
20521ae08745Sheppo 	 */
20531ae08745Sheppo 	mutex_enter(&local_dep->lock);
20541ae08745Sheppo 
20551ae08745Sheppo 	switch (operation) {
20561ae08745Sheppo 	case VD_OP_BREAD:
20571ae08745Sheppo 	case VD_OP_BWRITE:
20581ae08745Sheppo 		PR1("buf=%p, block=%lx, nbytes=%lx\n", addr, arg, nbytes);
20591ae08745Sheppo 		dep->payload.addr = (diskaddr_t)arg;
20601ae08745Sheppo 		rv = vdc_populate_mem_hdl(vdc, idx, addr, nbytes, operation);
20611ae08745Sheppo 		break;
20621ae08745Sheppo 
20631ae08745Sheppo 	case VD_OP_GET_VTOC:
20641ae08745Sheppo 	case VD_OP_SET_VTOC:
20651ae08745Sheppo 	case VD_OP_GET_DISKGEOM:
20661ae08745Sheppo 	case VD_OP_SET_DISKGEOM:
20671ae08745Sheppo 	case VD_OP_SCSICMD:
20681ae08745Sheppo 		if (nbytes > 0) {
20691ae08745Sheppo 			rv = vdc_populate_mem_hdl(vdc, idx, addr, nbytes,
20701ae08745Sheppo 							operation);
20711ae08745Sheppo 		}
20721ae08745Sheppo 		break;
2073*8e6a2a04Slm66018 
2074*8e6a2a04Slm66018 	case VD_OP_FLUSH:
2075*8e6a2a04Slm66018 	case VD_OP_GET_WCE:
2076*8e6a2a04Slm66018 	case VD_OP_SET_WCE:
2077*8e6a2a04Slm66018 		rv = 0;		/* nothing to bind */
2078*8e6a2a04Slm66018 		break;
2079*8e6a2a04Slm66018 
20801ae08745Sheppo 	default:
20811ae08745Sheppo 		cmn_err(CE_NOTE, "[%d] Unsupported vDisk operation [%d]\n",
20821ae08745Sheppo 				vdc->instance, operation);
20831ae08745Sheppo 		rv = EINVAL;
20841ae08745Sheppo 	}
20851ae08745Sheppo 
20861ae08745Sheppo 	if (rv != 0) {
20871ae08745Sheppo 		mutex_exit(&local_dep->lock);
20881ae08745Sheppo 		mutex_exit(&vdc->dring_lock);
20891ae08745Sheppo 		return (rv);
20901ae08745Sheppo 	}
20911ae08745Sheppo 
20921ae08745Sheppo 	/*
20931ae08745Sheppo 	 * fill in the data details into the DRing
20941ae08745Sheppo 	 */
20951ae08745Sheppo 	dep->payload.req_id = VDC_GET_NEXT_REQ_ID(vdc);
20961ae08745Sheppo 	dep->payload.operation = operation;
20971ae08745Sheppo 	dep->payload.nbytes = nbytes;
20981ae08745Sheppo 	dep->payload.status = EINPROGRESS;	/* vds will set valid value */
20991ae08745Sheppo 	dep->payload.slice = slice;
21001ae08745Sheppo 	dep->hdr.dstate = VIO_DESC_READY;
21011ae08745Sheppo 	dep->hdr.ack = 1;		/* request an ACK for every message */
21021ae08745Sheppo 
21031ae08745Sheppo 	local_dep->flags = VIO_DESC_READY;
21041ae08745Sheppo 	local_dep->addr = addr;
21051ae08745Sheppo 
21061ae08745Sheppo 	/*
21071ae08745Sheppo 	 * Send a msg with the DRing details to vds
21081ae08745Sheppo 	 */
21091ae08745Sheppo 	VIO_INIT_DRING_DATA_TAG(dmsg);
21101ae08745Sheppo 	VDC_INIT_DRING_DATA_MSG_IDS(dmsg, vdc);
21111ae08745Sheppo 	dmsg.dring_ident = vdc->dring_ident;
21121ae08745Sheppo 	dmsg.start_idx = idx;
21131ae08745Sheppo 	dmsg.end_idx = idx;
21141ae08745Sheppo 
21151ae08745Sheppo 	PR1("ident=0x%llx, st=%d, end=%d, seq=%d req=%d dep=%p\n",
21161ae08745Sheppo 			vdc->dring_ident, dmsg.start_idx, dmsg.end_idx,
21171ae08745Sheppo 			dmsg.seq_num, dep->payload.req_id, dep);
21181ae08745Sheppo 
21190a55fbb7Slm66018 	mutex_enter(&vdc->lock);
2120*8e6a2a04Slm66018 	rv = vdc_send(vdc, (caddr_t)&dmsg, &msglen);
21210a55fbb7Slm66018 	mutex_exit(&vdc->lock);
2122*8e6a2a04Slm66018 	PR1("%s[%d]: ldc_write() rv=%d\n", __func__, vdc->instance, rv);
2123*8e6a2a04Slm66018 	if (rv != 0) {
21241ae08745Sheppo 		mutex_exit(&local_dep->lock);
21251ae08745Sheppo 		mutex_exit(&vdc->dring_lock);
2126*8e6a2a04Slm66018 		vdc_msg("%s: ldc_write(%d)\n", __func__, rv);
21271ae08745Sheppo 		return (EAGAIN);
21281ae08745Sheppo 	}
21291ae08745Sheppo 
21301ae08745Sheppo 	/*
21310a55fbb7Slm66018 	 * If the message was successfully sent, we increment the sequence
21320a55fbb7Slm66018 	 * number to be used by the next message
21330a55fbb7Slm66018 	 */
21340a55fbb7Slm66018 	vdc->seq_num++;
21350a55fbb7Slm66018 
21360a55fbb7Slm66018 	/*
21371ae08745Sheppo 	 * XXX - potential performance enhancement (Investigate at a later date)
21381ae08745Sheppo 	 *
21391ae08745Sheppo 	 * for calls from strategy(9E), instead of waiting for a response from
21401ae08745Sheppo 	 * vds, we could return at this stage and let the ACK handling code
21411ae08745Sheppo 	 * trigger the biodone(9F)
21421ae08745Sheppo 	 */
21431ae08745Sheppo 
21441ae08745Sheppo 	/*
21451ae08745Sheppo 	 * When a guest is panicking, the completion of requests needs to be
21461ae08745Sheppo 	 * handled differently because interrupts are disabled and vdc
21471ae08745Sheppo 	 * will not get messages. We have to poll for the messages instead.
21481ae08745Sheppo 	 */
21491ae08745Sheppo 	if (ddi_in_panic()) {
21501ae08745Sheppo 		int start = 0;
21511ae08745Sheppo 		retries = 0;
21521ae08745Sheppo 		for (;;) {
21531ae08745Sheppo 			msglen = sizeof (dmsg);
2154*8e6a2a04Slm66018 			rv = ldc_read(vdc->ldc_handle, (caddr_t)&dmsg,
21551ae08745Sheppo 					&msglen);
2156*8e6a2a04Slm66018 			if (rv) {
2157*8e6a2a04Slm66018 				rv = EINVAL;
21581ae08745Sheppo 				break;
21591ae08745Sheppo 			}
21601ae08745Sheppo 
21611ae08745Sheppo 			/*
21621ae08745Sheppo 			 * if there are no packets wait and check again
21631ae08745Sheppo 			 */
2164*8e6a2a04Slm66018 			if ((rv == 0) && (msglen == 0)) {
21651ae08745Sheppo 				if (retries++ > vdc_dump_retries) {
21661ae08745Sheppo 					PR0("[%d] Giving up waiting, idx %d\n",
21671ae08745Sheppo 							vdc->instance, idx);
2168*8e6a2a04Slm66018 					rv = EAGAIN;
21691ae08745Sheppo 					break;
21701ae08745Sheppo 				}
21711ae08745Sheppo 
21721ae08745Sheppo 				PR1("Waiting for next packet @ %d\n", idx);
21731ae08745Sheppo 				delay(drv_usectohz(vdc_dump_usec_timeout));
21741ae08745Sheppo 				continue;
21751ae08745Sheppo 			}
21761ae08745Sheppo 
21771ae08745Sheppo 			/*
21781ae08745Sheppo 			 * Ignore all messages that are not ACKs/NACKs to
21791ae08745Sheppo 			 * DRing requests.
21801ae08745Sheppo 			 */
21811ae08745Sheppo 			if ((dmsg.tag.vio_msgtype != VIO_TYPE_DATA) ||
21821ae08745Sheppo 			    (dmsg.tag.vio_subtype_env != VIO_DRING_DATA)) {
21831ae08745Sheppo 				PR0("discarding pkt: type=%d sub=%d env=%d\n",
21841ae08745Sheppo 					dmsg.tag.vio_msgtype,
21851ae08745Sheppo 					dmsg.tag.vio_subtype,
21861ae08745Sheppo 					dmsg.tag.vio_subtype_env);
21871ae08745Sheppo 				continue;
21881ae08745Sheppo 			}
21891ae08745Sheppo 
21901ae08745Sheppo 			/*
21911ae08745Sheppo 			 * set the appropriate return value for the
21921ae08745Sheppo 			 * current request.
21931ae08745Sheppo 			 */
21941ae08745Sheppo 			switch (dmsg.tag.vio_subtype) {
21951ae08745Sheppo 			case VIO_SUBTYPE_ACK:
2196*8e6a2a04Slm66018 				rv = 0;
21971ae08745Sheppo 				break;
21981ae08745Sheppo 			case VIO_SUBTYPE_NACK:
2199*8e6a2a04Slm66018 				rv = EAGAIN;
22001ae08745Sheppo 				break;
22011ae08745Sheppo 			default:
22021ae08745Sheppo 				continue;
22031ae08745Sheppo 			}
22041ae08745Sheppo 
22051ae08745Sheppo 			start = dmsg.start_idx;
22061ae08745Sheppo 			if (start >= VD_DRING_LEN) {
22071ae08745Sheppo 				PR0("[%d] Bogus ack data : start %d\n",
22081ae08745Sheppo 					vdc->instance, start);
22091ae08745Sheppo 				continue;
22101ae08745Sheppo 			}
22111ae08745Sheppo 
22121ae08745Sheppo 			dep = VDC_GET_DRING_ENTRY_PTR(vdc, start);
22131ae08745Sheppo 
22141ae08745Sheppo 			PR1("[%d] Dumping start=%d idx=%d state=%d\n",
22151ae08745Sheppo 				vdc->instance, start, idx, dep->hdr.dstate);
22161ae08745Sheppo 
22171ae08745Sheppo 			if (dep->hdr.dstate != VIO_DESC_DONE) {
22181ae08745Sheppo 				PR0("[%d] Entry @ %d - state !DONE %d\n",
22191ae08745Sheppo 					vdc->instance, start, dep->hdr.dstate);
22201ae08745Sheppo 				continue;
22211ae08745Sheppo 			}
22221ae08745Sheppo 
22231ae08745Sheppo 			(void) vdc_depopulate_descriptor(vdc, start);
22241ae08745Sheppo 
22251ae08745Sheppo 			/*
22261ae08745Sheppo 			 * We want to process all Dring entries up to
22271ae08745Sheppo 			 * the current one so that we can return an
22281ae08745Sheppo 			 * error with the correct request.
22291ae08745Sheppo 			 */
22301ae08745Sheppo 			if (idx > start) {
22311ae08745Sheppo 				PR0("[%d] Looping: start %d, idx %d\n",
22321ae08745Sheppo 						vdc->instance, idx, start);
22331ae08745Sheppo 				continue;
22341ae08745Sheppo 			}
22351ae08745Sheppo 
22361ae08745Sheppo 			/* exit - all outstanding requests are completed */
22371ae08745Sheppo 			break;
22381ae08745Sheppo 		}
22391ae08745Sheppo 
22401ae08745Sheppo 		mutex_exit(&local_dep->lock);
22411ae08745Sheppo 		mutex_exit(&vdc->dring_lock);
22421ae08745Sheppo 
2243*8e6a2a04Slm66018 		return (rv);
22441ae08745Sheppo 	}
22451ae08745Sheppo 
22461ae08745Sheppo 	/*
22471ae08745Sheppo 	 * Now watch the DRing entries we modified to get the response
22481ae08745Sheppo 	 * from vds.
22491ae08745Sheppo 	 */
2250*8e6a2a04Slm66018 	rv = vdc_wait_for_descriptor_update(vdc, idx, dmsg);
2251*8e6a2a04Slm66018 	if (rv == ETIMEDOUT) {
22521ae08745Sheppo 		/* debug info when dumping state on vds side */
22531ae08745Sheppo 		dep->payload.status = ECANCELED;
22541ae08745Sheppo 	}
22551ae08745Sheppo 
2256*8e6a2a04Slm66018 	rv = vdc_depopulate_descriptor(vdc, idx);
2257*8e6a2a04Slm66018 	PR1("%s[%d] Status=%d\n", __func__, vdc->instance, rv);
22581ae08745Sheppo 
22591ae08745Sheppo 	mutex_exit(&local_dep->lock);
22601ae08745Sheppo 	mutex_exit(&vdc->dring_lock);
22611ae08745Sheppo 
2262*8e6a2a04Slm66018 	return (rv);
22631ae08745Sheppo }
22641ae08745Sheppo 
22650a55fbb7Slm66018 /*
22660a55fbb7Slm66018  * Function:
22670a55fbb7Slm66018  *	vdc_wait_for_descriptor_update()
22680a55fbb7Slm66018  *
22690a55fbb7Slm66018  * Description:
22700a55fbb7Slm66018  *
22710a55fbb7Slm66018  * Arguments:
22720a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
22730a55fbb7Slm66018  *	idx	- Index of the Descriptor Ring entry being modified
22740a55fbb7Slm66018  *	dmsg	- LDC message sent by vDisk server
22750a55fbb7Slm66018  *
22760a55fbb7Slm66018  * Return Code:
22770a55fbb7Slm66018  *	0	- Success
22780a55fbb7Slm66018  */
22791ae08745Sheppo static int
22801ae08745Sheppo vdc_wait_for_descriptor_update(vdc_t *vdc, uint_t idx, vio_dring_msg_t dmsg)
22811ae08745Sheppo {
22821ae08745Sheppo 	vd_dring_entry_t *dep = NULL;		/* Dring Entry Pointer */
22831ae08745Sheppo 	vdc_local_desc_t *local_dep = NULL;	/* Local Dring Entry Pointer */
22841ae08745Sheppo 	size_t	msglen = sizeof (dmsg);
22851ae08745Sheppo 	int	retries = 0;
22860a55fbb7Slm66018 	int	status = 0;
22871ae08745Sheppo 	int	rv = 0;
22881ae08745Sheppo 
22891ae08745Sheppo 	ASSERT(vdc != NULL);
22900a55fbb7Slm66018 	ASSERT(mutex_owned(&vdc->dring_lock));
22911ae08745Sheppo 	ASSERT(idx < VD_DRING_LEN);
22921ae08745Sheppo 	local_dep = &vdc->local_dring[idx];
22931ae08745Sheppo 	ASSERT(local_dep != NULL);
22941ae08745Sheppo 	dep = local_dep->dep;
22951ae08745Sheppo 	ASSERT(dep != NULL);
22961ae08745Sheppo 
22971ae08745Sheppo 	while (dep->hdr.dstate != VIO_DESC_DONE) {
22981ae08745Sheppo 		rv = cv_timedwait(&local_dep->cv, &local_dep->lock,
22991ae08745Sheppo 			VD_GET_TIMEOUT_HZ(retries));
23001ae08745Sheppo 		if (rv == -1) {
23011ae08745Sheppo 			/*
23021ae08745Sheppo 			 * If they persist in ignoring us we'll storm off in a
23031ae08745Sheppo 			 * huff and return ETIMEDOUT to the upper layers.
23041ae08745Sheppo 			 */
23051ae08745Sheppo 			if (retries >= vdc_retries) {
23061ae08745Sheppo 				PR0("%s: Finished waiting on entry %d\n",
23071ae08745Sheppo 					__func__, idx);
23081ae08745Sheppo 				status = ETIMEDOUT;
23091ae08745Sheppo 				break;
23101ae08745Sheppo 			} else {
23111ae08745Sheppo 				retries++;
23121ae08745Sheppo 				PR0("%s[%d]: Timeout #%d on entry %d "
23131ae08745Sheppo 				    "[seq %d][req %d]\n", __func__,
23141ae08745Sheppo 				    vdc->instance,
23151ae08745Sheppo 				    retries, idx, dmsg.seq_num,
23161ae08745Sheppo 				    dep->payload.req_id);
23171ae08745Sheppo 			}
23181ae08745Sheppo 
23191ae08745Sheppo 			if (dep->hdr.dstate & VIO_DESC_ACCEPTED) {
23201ae08745Sheppo 				PR0("%s[%d]: vds has accessed entry %d [seq %d]"
23211ae08745Sheppo 				    "[req %d] but not ack'ed it yet\n",
23221ae08745Sheppo 				    __func__, vdc->instance, idx, dmsg.seq_num,
23231ae08745Sheppo 				    dep->payload.req_id);
23241ae08745Sheppo 				continue;
23251ae08745Sheppo 			}
23261ae08745Sheppo 
23271ae08745Sheppo 			/*
23281ae08745Sheppo 			 * we resend the message as it may have been dropped
23291ae08745Sheppo 			 * and have never made it to the other side (vds).
23301ae08745Sheppo 			 * (We reuse the original message but update seq ID)
23311ae08745Sheppo 			 */
23321ae08745Sheppo 			VDC_INIT_DRING_DATA_MSG_IDS(dmsg, vdc);
23331ae08745Sheppo 			retries = 0;
23340a55fbb7Slm66018 			mutex_enter(&vdc->lock);
23350a55fbb7Slm66018 			status = vdc_send(vdc, (caddr_t)&dmsg, &msglen);
23360a55fbb7Slm66018 			mutex_exit(&vdc->lock);
23371ae08745Sheppo 			if (status != 0) {
23381ae08745Sheppo 				vdc_msg("%s: Error (%d) while resending after "
23391ae08745Sheppo 					"timeout\n", __func__, status);
23401ae08745Sheppo 				status = ETIMEDOUT;
23411ae08745Sheppo 				break;
23421ae08745Sheppo 			}
23430a55fbb7Slm66018 			/*
23440a55fbb7Slm66018 			 * If the message was successfully sent, we increment
23450a55fbb7Slm66018 			 * the sequence number to be used by the next message.
23460a55fbb7Slm66018 			 */
23470a55fbb7Slm66018 			vdc->seq_num++;
23481ae08745Sheppo 		}
23491ae08745Sheppo 	}
23501ae08745Sheppo 
23511ae08745Sheppo 	return (status);
23521ae08745Sheppo }
23531ae08745Sheppo 
23541ae08745Sheppo static int
23551ae08745Sheppo vdc_get_response(vdc_t *vdc, int start, int end)
23561ae08745Sheppo {
23571ae08745Sheppo 	vdc_local_desc_t	*ldep = NULL;	/* Local Dring Entry Pointer */
23581ae08745Sheppo 	vd_dring_entry_t	*dep = NULL;	/* Dring Entry Pointer */
23591ae08745Sheppo 	int			status = ENXIO;
23601ae08745Sheppo 	int			idx = -1;
23611ae08745Sheppo 
23621ae08745Sheppo 	ASSERT(vdc != NULL);
23631ae08745Sheppo 	ASSERT(start >= 0);
23641ae08745Sheppo 	ASSERT(start <= VD_DRING_LEN);
23651ae08745Sheppo 	ASSERT(start >= -1);
23661ae08745Sheppo 	ASSERT(start <= VD_DRING_LEN);
23671ae08745Sheppo 
23681ae08745Sheppo 	idx = start;
23691ae08745Sheppo 	ldep = &vdc->local_dring[idx];
23701ae08745Sheppo 	ASSERT(ldep != NULL);
23711ae08745Sheppo 	dep = ldep->dep;
23721ae08745Sheppo 	ASSERT(dep != NULL);
23731ae08745Sheppo 
23741ae08745Sheppo 	PR0("%s[%d] DRING entry=%d status=%d\n", __func__, vdc->instance,
23751ae08745Sheppo 			idx, VIO_GET_DESC_STATE(dep->hdr.dstate));
23761ae08745Sheppo 	while (VIO_GET_DESC_STATE(dep->hdr.dstate) == VIO_DESC_DONE) {
23771ae08745Sheppo 		if ((end != -1) && (idx > end))
23781ae08745Sheppo 			return (0);
23791ae08745Sheppo 
23801ae08745Sheppo 		switch (ldep->operation) {
23811ae08745Sheppo 		case VD_OP_BREAD:
23821ae08745Sheppo 		case VD_OP_BWRITE:
23831ae08745Sheppo 			/* call bioxxx */
23841ae08745Sheppo 			break;
23851ae08745Sheppo 		default:
23861ae08745Sheppo 			/* signal waiter */
23871ae08745Sheppo 			break;
23881ae08745Sheppo 		}
23891ae08745Sheppo 
23901ae08745Sheppo 		/* Clear the DRing entry */
23911ae08745Sheppo 		status = vdc_depopulate_descriptor(vdc, idx);
23921ae08745Sheppo 		PR0("%s[%d] Status=%d\n", __func__, vdc->instance, status);
23931ae08745Sheppo 
23941ae08745Sheppo 		/* loop accounting to get next DRing entry */
23951ae08745Sheppo 		idx++;
23961ae08745Sheppo 		ldep = &vdc->local_dring[idx];
23971ae08745Sheppo 		dep = ldep->dep;
23981ae08745Sheppo 	}
23991ae08745Sheppo 
24001ae08745Sheppo 	return (status);
24011ae08745Sheppo }
24021ae08745Sheppo 
24030a55fbb7Slm66018 /*
24040a55fbb7Slm66018  * Function:
24050a55fbb7Slm66018  *	vdc_depopulate_descriptor()
24060a55fbb7Slm66018  *
24070a55fbb7Slm66018  * Description:
24080a55fbb7Slm66018  *
24090a55fbb7Slm66018  * Arguments:
24100a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
24110a55fbb7Slm66018  *	idx	- Index of the Descriptor Ring entry being modified
24120a55fbb7Slm66018  *
24130a55fbb7Slm66018  * Return Code:
24140a55fbb7Slm66018  *	0	- Success
24150a55fbb7Slm66018  */
24161ae08745Sheppo static int
24171ae08745Sheppo vdc_depopulate_descriptor(vdc_t *vdc, uint_t idx)
24181ae08745Sheppo {
24191ae08745Sheppo 	vd_dring_entry_t *dep = NULL;		/* Dring Entry Pointer */
24201ae08745Sheppo 	vdc_local_desc_t *ldep = NULL;		/* Local Dring Entry Pointer */
24211ae08745Sheppo 	int		status = ENXIO;
2422*8e6a2a04Slm66018 	int		operation;
2423*8e6a2a04Slm66018 	int		rv = 0;
24241ae08745Sheppo 
24251ae08745Sheppo 	ASSERT(vdc != NULL);
24261ae08745Sheppo 	ASSERT(idx < VD_DRING_LEN);
24271ae08745Sheppo 	ldep = &vdc->local_dring[idx];
24281ae08745Sheppo 	ASSERT(ldep != NULL);
24291ae08745Sheppo 	dep = ldep->dep;
24301ae08745Sheppo 	ASSERT(dep != NULL);
24311ae08745Sheppo 
24321ae08745Sheppo 	status = dep->payload.status;
2433*8e6a2a04Slm66018 	operation = dep->payload.operation;
24341ae08745Sheppo 	VDC_MARK_DRING_ENTRY_FREE(vdc, idx);
24351ae08745Sheppo 	ldep = &vdc->local_dring[idx];
24361ae08745Sheppo 	VIO_SET_DESC_STATE(ldep->flags, VIO_DESC_FREE);
24371ae08745Sheppo 
2438*8e6a2a04Slm66018 	/* the DKIO W$ operations never bind handles so we can return now */
2439*8e6a2a04Slm66018 	if ((operation == VD_OP_FLUSH) ||
2440*8e6a2a04Slm66018 	    (operation == VD_OP_GET_WCE) ||
2441*8e6a2a04Slm66018 	    (operation == VD_OP_SET_WCE))
2442*8e6a2a04Slm66018 		return (status);
2443*8e6a2a04Slm66018 
24441ae08745Sheppo 	/*
24451ae08745Sheppo 	 * If the upper layer passed in a misaligned address we copied the
24461ae08745Sheppo 	 * data into an aligned buffer before sending it to LDC - we now
24471ae08745Sheppo 	 * copy it back to the original buffer.
24481ae08745Sheppo 	 */
24491ae08745Sheppo 	if (ldep->align_addr) {
24501ae08745Sheppo 		ASSERT(ldep->addr != NULL);
24511ae08745Sheppo 		ASSERT(dep->payload.nbytes > 0);
24521ae08745Sheppo 
24531ae08745Sheppo 		bcopy(ldep->align_addr, ldep->addr, dep->payload.nbytes);
24541ae08745Sheppo 		kmem_free(ldep->align_addr,
24551ae08745Sheppo 				sizeof (caddr_t) * dep->payload.nbytes);
24561ae08745Sheppo 		ldep->align_addr = NULL;
24571ae08745Sheppo 	}
24581ae08745Sheppo 
2459*8e6a2a04Slm66018 	rv = ldc_mem_unbind_handle(ldep->desc_mhdl);
2460*8e6a2a04Slm66018 	if (rv != 0) {
24611ae08745Sheppo 		cmn_err(CE_NOTE, "[%d] unbind mem hdl 0x%lx @ idx %d failed:%d",
2462*8e6a2a04Slm66018 				vdc->instance, ldep->desc_mhdl, idx, rv);
2463*8e6a2a04Slm66018 		/*
2464*8e6a2a04Slm66018 		 * The error returned by the vDisk server is more informative
2465*8e6a2a04Slm66018 		 * and thus has a higher priority but if it isn't set we ensure
2466*8e6a2a04Slm66018 		 * that this function returns an error.
2467*8e6a2a04Slm66018 		 */
2468*8e6a2a04Slm66018 		if (status == 0)
2469*8e6a2a04Slm66018 			status = EINVAL;
24701ae08745Sheppo 	}
24711ae08745Sheppo 
24721ae08745Sheppo 	return (status);
24731ae08745Sheppo }
24741ae08745Sheppo 
24750a55fbb7Slm66018 /*
24760a55fbb7Slm66018  * Function:
24770a55fbb7Slm66018  *	vdc_populate_mem_hdl()
24780a55fbb7Slm66018  *
24790a55fbb7Slm66018  * Description:
24800a55fbb7Slm66018  *
24810a55fbb7Slm66018  * Arguments:
24820a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
24830a55fbb7Slm66018  *	idx	- Index of the Descriptor Ring entry being modified
24840a55fbb7Slm66018  *	addr	- virtual address being mapped in
24850a55fbb7Slm66018  *	nybtes	- number of bytes in 'addr'
24860a55fbb7Slm66018  *	operation - the vDisk operation being performed (VD_OP_xxx)
24870a55fbb7Slm66018  *
24880a55fbb7Slm66018  * Return Code:
24890a55fbb7Slm66018  *	0	- Success
24900a55fbb7Slm66018  */
24911ae08745Sheppo static int
24921ae08745Sheppo vdc_populate_mem_hdl(vdc_t *vdc, uint_t idx, caddr_t addr, size_t nbytes,
24931ae08745Sheppo 			int operation)
24941ae08745Sheppo {
24951ae08745Sheppo 	vd_dring_entry_t	*dep = NULL;
24961ae08745Sheppo 	vdc_local_desc_t	*ldep = NULL;
24971ae08745Sheppo 	ldc_mem_handle_t	mhdl;
24981ae08745Sheppo 	caddr_t			vaddr;
24991ae08745Sheppo 	int			perm = LDC_MEM_RW;
25001ae08745Sheppo 	int			rv = 0;
25011ae08745Sheppo 	int			i;
25021ae08745Sheppo 
25031ae08745Sheppo 	ASSERT(vdc != NULL);
25041ae08745Sheppo 	ASSERT(idx < VD_DRING_LEN);
25051ae08745Sheppo 
25061ae08745Sheppo 	dep = VDC_GET_DRING_ENTRY_PTR(vdc, idx);
25071ae08745Sheppo 	ldep = &vdc->local_dring[idx];
25081ae08745Sheppo 	mhdl = ldep->desc_mhdl;
25091ae08745Sheppo 
25101ae08745Sheppo 	switch (operation) {
25111ae08745Sheppo 	case VD_OP_BREAD:
25121ae08745Sheppo 		perm = LDC_MEM_W;
25131ae08745Sheppo 		break;
25141ae08745Sheppo 
25151ae08745Sheppo 	case VD_OP_BWRITE:
25161ae08745Sheppo 		perm = LDC_MEM_R;
25171ae08745Sheppo 		break;
25181ae08745Sheppo 
25191ae08745Sheppo 	case VD_OP_GET_VTOC:
25201ae08745Sheppo 	case VD_OP_SET_VTOC:
25211ae08745Sheppo 	case VD_OP_GET_DISKGEOM:
25221ae08745Sheppo 	case VD_OP_SET_DISKGEOM:
25231ae08745Sheppo 	case VD_OP_SCSICMD:
25241ae08745Sheppo 		perm = LDC_MEM_RW;
25251ae08745Sheppo 		break;
25261ae08745Sheppo 
25271ae08745Sheppo 	default:
25281ae08745Sheppo 		ASSERT(0);	/* catch bad programming in vdc */
25291ae08745Sheppo 	}
25301ae08745Sheppo 
25311ae08745Sheppo 	/*
25321ae08745Sheppo 	 * LDC expects any addresses passed in to be 8-byte aligned. We need
25331ae08745Sheppo 	 * to copy the contents of any misaligned buffers to a newly allocated
25341ae08745Sheppo 	 * buffer and bind it instead (and copy the the contents back to the
25351ae08745Sheppo 	 * original buffer passed in when depopulating the descriptor)
25361ae08745Sheppo 	 */
25371ae08745Sheppo 	vaddr = addr;
25381ae08745Sheppo 	if (((uint64_t)addr & 0x7) != 0) {
25391ae08745Sheppo 		ldep->align_addr =
25401ae08745Sheppo 			kmem_zalloc(sizeof (caddr_t) * nbytes, KM_SLEEP);
25411ae08745Sheppo 		PR0("%s[%d] Misaligned address %lx reallocating "
25421ae08745Sheppo 		    "(buf=%lx entry=%d)\n",
25431ae08745Sheppo 		    __func__, vdc->instance, addr, ldep->align_addr, idx);
25441ae08745Sheppo 		bcopy(addr, ldep->align_addr, nbytes);
25451ae08745Sheppo 		vaddr = ldep->align_addr;
25461ae08745Sheppo 	}
25471ae08745Sheppo 
25481ae08745Sheppo 	rv = ldc_mem_bind_handle(mhdl, vaddr, P2ROUNDUP(nbytes, 8),
25491ae08745Sheppo 		vdc->dring_mem_info.mtype, perm, &dep->payload.cookie[0],
25501ae08745Sheppo 		&dep->payload.ncookies);
25511ae08745Sheppo 	PR1("%s[%d] bound mem handle; ncookies=%d\n",
25521ae08745Sheppo 			__func__, vdc->instance, dep->payload.ncookies);
25531ae08745Sheppo 	if (rv != 0) {
25541ae08745Sheppo 		vdc_msg("%s[%d] failed to ldc_mem_bind_handle "
25551ae08745Sheppo 		    "(mhdl=%lx, buf=%lx entry=%d err=%d)\n",
25561ae08745Sheppo 		    __func__, vdc->instance, mhdl, addr, idx, rv);
25571ae08745Sheppo 		if (ldep->align_addr) {
25581ae08745Sheppo 			kmem_free(ldep->align_addr,
25591ae08745Sheppo 					sizeof (caddr_t) * dep->payload.nbytes);
25601ae08745Sheppo 			ldep->align_addr = NULL;
25611ae08745Sheppo 		}
25621ae08745Sheppo 		return (EAGAIN);
25631ae08745Sheppo 	}
25641ae08745Sheppo 
25651ae08745Sheppo 	/*
25661ae08745Sheppo 	 * Get the other cookies (if any).
25671ae08745Sheppo 	 */
25681ae08745Sheppo 	for (i = 1; i < dep->payload.ncookies; i++) {
25691ae08745Sheppo 		rv = ldc_mem_nextcookie(mhdl, &dep->payload.cookie[i]);
25701ae08745Sheppo 		if (rv != 0) {
25711ae08745Sheppo 			(void) ldc_mem_unbind_handle(mhdl);
25721ae08745Sheppo 			vdc_msg("%s: failed to get next cookie(mhdl=%lx "
25731ae08745Sheppo 				"cnum=%d), err=%d", __func__, mhdl, i, rv);
25741ae08745Sheppo 			if (ldep->align_addr) {
25751ae08745Sheppo 				kmem_free(ldep->align_addr,
25761ae08745Sheppo 					sizeof (caddr_t) * dep->payload.nbytes);
25771ae08745Sheppo 				ldep->align_addr = NULL;
25781ae08745Sheppo 			}
25791ae08745Sheppo 			return (EAGAIN);
25801ae08745Sheppo 		}
25811ae08745Sheppo 	}
25821ae08745Sheppo 
25831ae08745Sheppo 	return (rv);
25841ae08745Sheppo }
25851ae08745Sheppo 
25861ae08745Sheppo /*
25871ae08745Sheppo  * Interrupt handlers for messages from LDC
25881ae08745Sheppo  */
25891ae08745Sheppo 
25900a55fbb7Slm66018 /*
25910a55fbb7Slm66018  * Function:
25920a55fbb7Slm66018  *	vdc_handle_cb()
25930a55fbb7Slm66018  *
25940a55fbb7Slm66018  * Description:
25950a55fbb7Slm66018  *
25960a55fbb7Slm66018  * Arguments:
25970a55fbb7Slm66018  *	event	- Type of event (LDC_EVT_xxx) that triggered the callback
25980a55fbb7Slm66018  *	arg	- soft state pointer for this instance of the device driver.
25990a55fbb7Slm66018  *
26000a55fbb7Slm66018  * Return Code:
26010a55fbb7Slm66018  *	0	- Success
26020a55fbb7Slm66018  */
26031ae08745Sheppo static uint_t
26041ae08745Sheppo vdc_handle_cb(uint64_t event, caddr_t arg)
26051ae08745Sheppo {
26061ae08745Sheppo 	ldc_status_t	ldc_state;
26071ae08745Sheppo 	int		rv = 0;
26081ae08745Sheppo 
26091ae08745Sheppo 	vdc_t	*vdc = (vdc_t *)(void *)arg;
26101ae08745Sheppo 
26111ae08745Sheppo 	ASSERT(vdc != NULL);
26121ae08745Sheppo 
26131ae08745Sheppo 	PR1("%s[%d] event=%x seqID=%d\n",
26141ae08745Sheppo 			__func__, vdc->instance, event, vdc->seq_num);
26151ae08745Sheppo 
26161ae08745Sheppo 	/*
26171ae08745Sheppo 	 * Depending on the type of event that triggered this callback,
26181ae08745Sheppo 	 * we modify the handhske state or read the data.
26191ae08745Sheppo 	 *
26201ae08745Sheppo 	 * NOTE: not done as a switch() as event could be triggered by
26211ae08745Sheppo 	 * a state change and a read request. Also the ordering	of the
26221ae08745Sheppo 	 * check for the event types is deliberate.
26231ae08745Sheppo 	 */
26241ae08745Sheppo 	if (event & LDC_EVT_UP) {
26251ae08745Sheppo 		PR0("%s[%d] Received LDC_EVT_UP\n", __func__, vdc->instance);
26261ae08745Sheppo 
26271ae08745Sheppo 		/* get LDC state */
26281ae08745Sheppo 		rv = ldc_status(vdc->ldc_handle, &ldc_state);
26291ae08745Sheppo 		if (rv != 0) {
26301ae08745Sheppo 			cmn_err(CE_NOTE, "[%d] Couldn't get LDC status %d",
26311ae08745Sheppo 					vdc->instance, rv);
26320a55fbb7Slm66018 			mutex_enter(&vdc->lock);
26331ae08745Sheppo 			vdc_reset_connection(vdc, B_TRUE);
26340a55fbb7Slm66018 			mutex_exit(&vdc->lock);
26351ae08745Sheppo 			return (LDC_SUCCESS);
26361ae08745Sheppo 		}
26371ae08745Sheppo 
26381ae08745Sheppo 		/*
26391ae08745Sheppo 		 * Reset the transaction sequence numbers when LDC comes up.
26401ae08745Sheppo 		 * We then kick off the handshake negotiation with the vDisk
26411ae08745Sheppo 		 * server.
26421ae08745Sheppo 		 */
26431ae08745Sheppo 		mutex_enter(&vdc->lock);
26440a55fbb7Slm66018 		vdc->seq_num = 1;
26451ae08745Sheppo 		vdc->seq_num_reply = 0;
26461ae08745Sheppo 		vdc->ldc_state = ldc_state;
26471ae08745Sheppo 		ASSERT(ldc_state == LDC_UP);
26481ae08745Sheppo 		mutex_exit(&vdc->lock);
26491ae08745Sheppo 
26501ae08745Sheppo 		vdc_init_handshake_negotiation(vdc);
26511ae08745Sheppo 
26521ae08745Sheppo 		ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0);
26531ae08745Sheppo 	}
26541ae08745Sheppo 
26551ae08745Sheppo 	if (event & LDC_EVT_READ) {
26561ae08745Sheppo 		/*
26571ae08745Sheppo 		 * Wake up the worker thread to process the message
26581ae08745Sheppo 		 */
26591ae08745Sheppo 		mutex_enter(&vdc->msg_proc_lock);
26601ae08745Sheppo 		vdc->msg_pending = B_TRUE;
26611ae08745Sheppo 		cv_signal(&vdc->msg_proc_cv);
26621ae08745Sheppo 		mutex_exit(&vdc->msg_proc_lock);
26631ae08745Sheppo 
26641ae08745Sheppo 		ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0);
26651ae08745Sheppo 
26661ae08745Sheppo 		/* that's all we have to do - no need to handle DOWN/RESET */
26671ae08745Sheppo 		return (LDC_SUCCESS);
26681ae08745Sheppo 	}
26691ae08745Sheppo 
26701ae08745Sheppo 	if (event & LDC_EVT_RESET) {
26711ae08745Sheppo 		PR0("%s[%d] Recvd LDC RESET event\n", __func__, vdc->instance);
26720a55fbb7Slm66018 
26730a55fbb7Slm66018 		/* get LDC state */
26740a55fbb7Slm66018 		rv = ldc_status(vdc->ldc_handle, &ldc_state);
26750a55fbb7Slm66018 		if (rv != 0) {
26760a55fbb7Slm66018 			cmn_err(CE_NOTE, "[%d] Couldn't get LDC status %d",
26770a55fbb7Slm66018 					vdc->instance, rv);
26780a55fbb7Slm66018 			ldc_state = LDC_OPEN;
26790a55fbb7Slm66018 		}
26800a55fbb7Slm66018 		mutex_enter(&vdc->lock);
26810a55fbb7Slm66018 		vdc->ldc_state = ldc_state;
26820a55fbb7Slm66018 		vdc_reset_connection(vdc, B_FALSE);
26830a55fbb7Slm66018 		mutex_exit(&vdc->lock);
26840a55fbb7Slm66018 
26850a55fbb7Slm66018 		vdc_init_handshake_negotiation(vdc);
26861ae08745Sheppo 	}
26871ae08745Sheppo 
26881ae08745Sheppo 	if (event & LDC_EVT_DOWN) {
26891ae08745Sheppo 		PR0("%s[%d] Recvd LDC DOWN event\n", __func__, vdc->instance);
26901ae08745Sheppo 
26911ae08745Sheppo 		/* get LDC state */
26921ae08745Sheppo 		rv = ldc_status(vdc->ldc_handle, &ldc_state);
26931ae08745Sheppo 		if (rv != 0) {
26941ae08745Sheppo 			cmn_err(CE_NOTE, "[%d] Couldn't get LDC status %d",
26951ae08745Sheppo 					vdc->instance, rv);
26961ae08745Sheppo 			ldc_state = LDC_OPEN;
26971ae08745Sheppo 		}
26981ae08745Sheppo 		mutex_enter(&vdc->lock);
26991ae08745Sheppo 		vdc->ldc_state = ldc_state;
27001ae08745Sheppo 		vdc_reset_connection(vdc, B_TRUE);
27010a55fbb7Slm66018 		mutex_exit(&vdc->lock);
27021ae08745Sheppo 	}
27031ae08745Sheppo 
27041ae08745Sheppo 	if (event & ~(LDC_EVT_UP | LDC_EVT_RESET | LDC_EVT_DOWN | LDC_EVT_READ))
27051ae08745Sheppo 		cmn_err(CE_NOTE, "![%d] Unexpected LDC event (%lx) received",
27061ae08745Sheppo 				vdc->instance, event);
27071ae08745Sheppo 
27081ae08745Sheppo 	return (LDC_SUCCESS);
27091ae08745Sheppo }
27101ae08745Sheppo 
27111ae08745Sheppo /* -------------------------------------------------------------------------- */
27121ae08745Sheppo 
27131ae08745Sheppo /*
27141ae08745Sheppo  * The following functions process the incoming messages from vds
27151ae08745Sheppo  */
27161ae08745Sheppo 
27171ae08745Sheppo 
27180a55fbb7Slm66018 /*
27190a55fbb7Slm66018  * Function:
27200a55fbb7Slm66018  *	vdc_process_msg_thread()
27210a55fbb7Slm66018  *
27220a55fbb7Slm66018  * Description:
27230a55fbb7Slm66018  *
27240a55fbb7Slm66018  * Arguments:
27250a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
27260a55fbb7Slm66018  *
27270a55fbb7Slm66018  * Return Code:
27280a55fbb7Slm66018  *	None
27290a55fbb7Slm66018  */
27301ae08745Sheppo static void
27311ae08745Sheppo vdc_process_msg_thread(vdc_t *vdc)
27321ae08745Sheppo {
27331ae08745Sheppo 	int		status = 0;
27341ae08745Sheppo 	boolean_t	q_is_empty = B_TRUE;
27351ae08745Sheppo 
27361ae08745Sheppo 	ASSERT(vdc != NULL);
27371ae08745Sheppo 
27381ae08745Sheppo 	mutex_enter(&vdc->msg_proc_lock);
27391ae08745Sheppo 	PR0("%s[%d]: Starting\n", __func__, vdc->instance);
27401ae08745Sheppo 
27411ae08745Sheppo 	vdc->msg_proc_thr_state = VDC_THR_RUNNING;
27421ae08745Sheppo 
27431ae08745Sheppo 	while (vdc->msg_proc_thr_state == VDC_THR_RUNNING) {
27441ae08745Sheppo 
27451ae08745Sheppo 		PR1("%s[%d] Waiting\n", __func__, vdc->instance);
27460a55fbb7Slm66018 		while (!vdc->msg_pending)
27471ae08745Sheppo 			cv_wait(&vdc->msg_proc_cv, &vdc->msg_proc_lock);
27481ae08745Sheppo 
27491ae08745Sheppo 		PR1("%s[%d] Message Received\n", __func__, vdc->instance);
27501ae08745Sheppo 
27511ae08745Sheppo 		/* check if there is data */
27521ae08745Sheppo 		status = ldc_chkq(vdc->ldc_handle, &q_is_empty);
27531ae08745Sheppo 		if ((status != 0) &&
27541ae08745Sheppo 		    (vdc->msg_proc_thr_state == VDC_THR_RUNNING)) {
27551ae08745Sheppo 			cmn_err(CE_NOTE, "[%d] Unable to communicate with vDisk"
27561ae08745Sheppo 					" server. Cannot check LDC queue: %d",
27571ae08745Sheppo 					vdc->instance, status);
27581ae08745Sheppo 			mutex_enter(&vdc->lock);
27590a55fbb7Slm66018 			vdc_reset_connection(vdc, B_FALSE);
27601ae08745Sheppo 			mutex_exit(&vdc->lock);
27611ae08745Sheppo 			vdc->msg_proc_thr_state = VDC_THR_STOP;
27621ae08745Sheppo 			continue;
27631ae08745Sheppo 		}
27641ae08745Sheppo 
27650a55fbb7Slm66018 		if (!q_is_empty) {
27661ae08745Sheppo 			PR1("%s: new pkt(s) available\n", __func__);
27671ae08745Sheppo 			vdc_process_msg(vdc);
27681ae08745Sheppo 		}
27691ae08745Sheppo 
27701ae08745Sheppo 		vdc->msg_pending = B_FALSE;
27711ae08745Sheppo 	}
27721ae08745Sheppo 
27731ae08745Sheppo 	PR0("Message processing thread stopped\n");
27741ae08745Sheppo 	vdc->msg_pending = B_FALSE;
27751ae08745Sheppo 	vdc->msg_proc_thr_state = VDC_THR_DONE;
27761ae08745Sheppo 	cv_signal(&vdc->msg_proc_cv);
27771ae08745Sheppo 	mutex_exit(&vdc->msg_proc_lock);
27781ae08745Sheppo 	thread_exit();
27791ae08745Sheppo }
27801ae08745Sheppo 
27811ae08745Sheppo 
27821ae08745Sheppo /*
27831ae08745Sheppo  * Function:
27841ae08745Sheppo  *	vdc_process_msg()
27851ae08745Sheppo  *
27861ae08745Sheppo  * Description:
27871ae08745Sheppo  *	This function is called by the message processing thread each time it
27881ae08745Sheppo  *	is triggered when LDC sends an interrupt to indicate that there are
27891ae08745Sheppo  *	more packets on the queue. When it is called it will continue to loop
27901ae08745Sheppo  *	and read the messages until there are no more left of the queue. If it
27911ae08745Sheppo  *	encounters an invalid sized message it will drop it and check the next
27921ae08745Sheppo  *	message.
27931ae08745Sheppo  *
27941ae08745Sheppo  * Arguments:
27951ae08745Sheppo  *	arg	- soft state pointer for this instance of the device driver.
27961ae08745Sheppo  *
27971ae08745Sheppo  * Return Code:
27981ae08745Sheppo  *	None.
27991ae08745Sheppo  */
28001ae08745Sheppo static void
28011ae08745Sheppo vdc_process_msg(void *arg)
28021ae08745Sheppo {
28031ae08745Sheppo 	vdc_t		*vdc = (vdc_t *)(void *)arg;
28041ae08745Sheppo 	vio_msg_t	vio_msg;
28051ae08745Sheppo 	size_t		nbytes = sizeof (vio_msg);
28061ae08745Sheppo 	int		status;
28071ae08745Sheppo 
28081ae08745Sheppo 	ASSERT(vdc != NULL);
28091ae08745Sheppo 
28101ae08745Sheppo 	mutex_enter(&vdc->lock);
28111ae08745Sheppo 
28121ae08745Sheppo 	PR1("%s\n", __func__);
28131ae08745Sheppo 
28141ae08745Sheppo 	for (;;) {
28151ae08745Sheppo 
28161ae08745Sheppo 		/* read all messages - until no more left */
28171ae08745Sheppo 		status = ldc_read(vdc->ldc_handle, (caddr_t)&vio_msg, &nbytes);
28181ae08745Sheppo 
28191ae08745Sheppo 		if (status) {
28201ae08745Sheppo 			vdc_msg("%s: ldc_read() failed = %d", __func__, status);
28211ae08745Sheppo 
28221ae08745Sheppo 			/* if status is ECONNRESET --- reset vdc state */
28231ae08745Sheppo 			if (status == EIO || status == ECONNRESET) {
28240a55fbb7Slm66018 				vdc_reset_connection(vdc, B_TRUE);
28251ae08745Sheppo 			}
28261ae08745Sheppo 
28271ae08745Sheppo 			mutex_exit(&vdc->lock);
28281ae08745Sheppo 			return;
28291ae08745Sheppo 		}
28301ae08745Sheppo 
28311ae08745Sheppo 		if ((nbytes > 0) && (nbytes < sizeof (vio_msg_tag_t))) {
28321ae08745Sheppo 			cmn_err(CE_CONT, "![%d] Expect %lu bytes; recv'd %lu\n",
28331ae08745Sheppo 				vdc->instance, sizeof (vio_msg_tag_t), nbytes);
28341ae08745Sheppo 			mutex_exit(&vdc->lock);
28351ae08745Sheppo 			return;
28361ae08745Sheppo 		}
28371ae08745Sheppo 
28381ae08745Sheppo 		if (nbytes == 0) {
28391ae08745Sheppo 			PR2("%s[%d]: ldc_read() done..\n",
28401ae08745Sheppo 					__func__, vdc->instance);
28411ae08745Sheppo 			mutex_exit(&vdc->lock);
28421ae08745Sheppo 			return;
28431ae08745Sheppo 		}
28441ae08745Sheppo 
28451ae08745Sheppo 		PR1("%s[%d] (%x/%x/%x)\n", __func__, vdc->instance,
28461ae08745Sheppo 		    vio_msg.tag.vio_msgtype,
28471ae08745Sheppo 		    vio_msg.tag.vio_subtype,
28481ae08745Sheppo 		    vio_msg.tag.vio_subtype_env);
28491ae08745Sheppo 
28501ae08745Sheppo 		/*
28511ae08745Sheppo 		 * Verify the Session ID of the message
28521ae08745Sheppo 		 *
28531ae08745Sheppo 		 * Every message after the Version has been negotiated should
28541ae08745Sheppo 		 * have the correct session ID set.
28551ae08745Sheppo 		 */
28561ae08745Sheppo 		if ((vio_msg.tag.vio_sid != vdc->session_id) &&
28571ae08745Sheppo 		    (vio_msg.tag.vio_subtype_env != VIO_VER_INFO)) {
28580a55fbb7Slm66018 			cmn_err(CE_NOTE, "[%d] Invalid SID 0x%x, expect 0x%lx",
28590a55fbb7Slm66018 				vdc->instance, vio_msg.tag.vio_sid,
28601ae08745Sheppo 				vdc->session_id);
28611ae08745Sheppo 			vdc_reset_connection(vdc, B_FALSE);
28621ae08745Sheppo 			mutex_exit(&vdc->lock);
28631ae08745Sheppo 			return;
28641ae08745Sheppo 		}
28651ae08745Sheppo 
28661ae08745Sheppo 		switch (vio_msg.tag.vio_msgtype) {
28671ae08745Sheppo 		case VIO_TYPE_CTRL:
28681ae08745Sheppo 			status = vdc_process_ctrl_msg(vdc, vio_msg);
28691ae08745Sheppo 			break;
28701ae08745Sheppo 		case VIO_TYPE_DATA:
28711ae08745Sheppo 			status = vdc_process_data_msg(vdc, vio_msg);
28721ae08745Sheppo 			break;
28731ae08745Sheppo 		case VIO_TYPE_ERR:
28741ae08745Sheppo 			status = vdc_process_err_msg(vdc, vio_msg);
28751ae08745Sheppo 			break;
28761ae08745Sheppo 		default:
28771ae08745Sheppo 			PR1("%s", __func__);
28781ae08745Sheppo 			status = EINVAL;
28791ae08745Sheppo 			break;
28801ae08745Sheppo 		}
28811ae08745Sheppo 
28821ae08745Sheppo 		if (status != 0) {
28831ae08745Sheppo 			PR0("%s[%d] Error (%d) occcurred processing msg\n",
28841ae08745Sheppo 					__func__, vdc->instance, status);
28851ae08745Sheppo 			vdc_reset_connection(vdc, B_FALSE);
28861ae08745Sheppo 		}
28871ae08745Sheppo 	}
28881ae08745Sheppo 	_NOTE(NOTREACHED)
28891ae08745Sheppo }
28901ae08745Sheppo 
28911ae08745Sheppo /*
28921ae08745Sheppo  * Function:
28931ae08745Sheppo  *	vdc_process_ctrl_msg()
28941ae08745Sheppo  *
28951ae08745Sheppo  * Description:
28961ae08745Sheppo  *	This function is called by the message processing thread each time
28971ae08745Sheppo  *	an LDC message with a msgtype of VIO_TYPE_CTRL is received.
28981ae08745Sheppo  *
28991ae08745Sheppo  * Arguments:
29001ae08745Sheppo  *	vdc	- soft state pointer for this instance of the device driver.
29011ae08745Sheppo  *	msg	- the LDC message sent by vds
29021ae08745Sheppo  *
29031ae08745Sheppo  * Return Codes:
29041ae08745Sheppo  *	0	- Success.
29051ae08745Sheppo  *	EPROTO	- A message was received which shouldn't have happened according
29061ae08745Sheppo  *		  to the protocol
29071ae08745Sheppo  *	ENOTSUP	- An action which is allowed according to the protocol but which
29081ae08745Sheppo  *		  isn't (or doesn't need to be) implemented yet.
29091ae08745Sheppo  *	EINVAL	- An invalid value was returned as part of a message.
29101ae08745Sheppo  */
29111ae08745Sheppo static int
29121ae08745Sheppo vdc_process_ctrl_msg(vdc_t *vdc, vio_msg_t msg)
29131ae08745Sheppo {
29141ae08745Sheppo 	int			status = -1;
29151ae08745Sheppo 
29161ae08745Sheppo 	ASSERT(msg.tag.vio_msgtype == VIO_TYPE_CTRL);
29171ae08745Sheppo 	ASSERT(vdc != NULL);
29181ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
29191ae08745Sheppo 
29201ae08745Sheppo 	/* Depending on which state we are in; process the message */
29211ae08745Sheppo 	switch (vdc->state) {
29221ae08745Sheppo 	case VD_STATE_INIT:
29230a55fbb7Slm66018 		status = vdc_handle_ver_msg(vdc, (vio_ver_msg_t *)&msg);
29240a55fbb7Slm66018 		break;
29250a55fbb7Slm66018 
29260a55fbb7Slm66018 	case VD_STATE_VER:
29270a55fbb7Slm66018 		status = vdc_handle_attr_msg(vdc, (vd_attr_msg_t *)&msg);
29280a55fbb7Slm66018 		break;
29290a55fbb7Slm66018 
29300a55fbb7Slm66018 	case VD_STATE_ATTR:
29310a55fbb7Slm66018 		status = vdc_handle_dring_reg_msg(vdc,
29320a55fbb7Slm66018 				(vio_dring_reg_msg_t *)&msg);
29330a55fbb7Slm66018 		break;
29340a55fbb7Slm66018 
29350a55fbb7Slm66018 	case VD_STATE_RDX:
29360a55fbb7Slm66018 		if (msg.tag.vio_subtype_env != VIO_RDX) {
29371ae08745Sheppo 			status = EPROTO;
29381ae08745Sheppo 			break;
29391ae08745Sheppo 		}
29401ae08745Sheppo 
29410a55fbb7Slm66018 		PR0("%s: Received RDX - handshake successful\n", __func__);
29421ae08745Sheppo 
29430a55fbb7Slm66018 		vdc->hshake_cnt = 0;	/* reset failed handshake count */
29440a55fbb7Slm66018 		status = 0;
29450a55fbb7Slm66018 		vdc->state = VD_STATE_DATA;
29460a55fbb7Slm66018 
29470a55fbb7Slm66018 		cv_broadcast(&vdc->attach_cv);
29480a55fbb7Slm66018 		break;
29490a55fbb7Slm66018 
29500a55fbb7Slm66018 	case VD_STATE_DATA:
29510a55fbb7Slm66018 	default:
29520a55fbb7Slm66018 		cmn_err(CE_NOTE, "[%d] Unexpected handshake state %d",
29530a55fbb7Slm66018 				vdc->instance, vdc->state);
29541ae08745Sheppo 		status = EPROTO;
29551ae08745Sheppo 		break;
29560a55fbb7Slm66018 	}
29571ae08745Sheppo 
29580a55fbb7Slm66018 	return (status);
29590a55fbb7Slm66018 }
29600a55fbb7Slm66018 
29610a55fbb7Slm66018 
29620a55fbb7Slm66018 /*
29630a55fbb7Slm66018  * Function:
29640a55fbb7Slm66018  *	vdc_process_data_msg()
29650a55fbb7Slm66018  *
29660a55fbb7Slm66018  * Description:
29670a55fbb7Slm66018  *	This function is called by the message processing thread each time
29680a55fbb7Slm66018  *	a message with a msgtype of VIO_TYPE_DATA is received. It will either
29690a55fbb7Slm66018  *	be an ACK or NACK from vds[1] which vdc handles as follows.
29700a55fbb7Slm66018  *		ACK	- wake up the waiting thread
29710a55fbb7Slm66018  *		NACK	- resend any messages necessary
29720a55fbb7Slm66018  *
29730a55fbb7Slm66018  *	[1] Although the message format allows it, vds should not send a
29740a55fbb7Slm66018  *	    VIO_SUBTYPE_INFO message to vdc asking it to read data; if for
29750a55fbb7Slm66018  *	    some bizarre reason it does, vdc will reset the connection.
29760a55fbb7Slm66018  *
29770a55fbb7Slm66018  * Arguments:
29780a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
29790a55fbb7Slm66018  *	msg	- the LDC message sent by vds
29800a55fbb7Slm66018  *
29810a55fbb7Slm66018  * Return Code:
29820a55fbb7Slm66018  *	0	- Success.
29830a55fbb7Slm66018  *	> 0	- error value returned by LDC
29840a55fbb7Slm66018  */
29850a55fbb7Slm66018 static int
29860a55fbb7Slm66018 vdc_process_data_msg(vdc_t *vdc, vio_msg_t msg)
29870a55fbb7Slm66018 {
29880a55fbb7Slm66018 	int			status = 0;
29890a55fbb7Slm66018 	vdc_local_desc_t	*local_dep = NULL;
29900a55fbb7Slm66018 	vio_dring_msg_t		*dring_msg = NULL;
29910a55fbb7Slm66018 	uint_t			num_msgs;
29920a55fbb7Slm66018 	uint_t			start;
29930a55fbb7Slm66018 	uint_t			end;
29940a55fbb7Slm66018 	uint_t			i;
29950a55fbb7Slm66018 
29960a55fbb7Slm66018 	ASSERT(msg.tag.vio_msgtype == VIO_TYPE_DATA);
29970a55fbb7Slm66018 	ASSERT(vdc != NULL);
29980a55fbb7Slm66018 	ASSERT(mutex_owned(&vdc->lock));
29990a55fbb7Slm66018 
30000a55fbb7Slm66018 	dring_msg = (vio_dring_msg_t *)&msg;
30010a55fbb7Slm66018 
30020a55fbb7Slm66018 	/*
30030a55fbb7Slm66018 	 * Check to see if the message has bogus data
30040a55fbb7Slm66018 	 */
30050a55fbb7Slm66018 	start = dring_msg->start_idx;
30060a55fbb7Slm66018 	end = dring_msg->end_idx;
30070a55fbb7Slm66018 	if ((start >= VD_DRING_LEN) || (end >= VD_DRING_LEN)) {
30080a55fbb7Slm66018 		vdc_msg("%s: Bogus ACK data : start %d, end %d\n",
30090a55fbb7Slm66018 			__func__, start, end);
30100a55fbb7Slm66018 		return (EPROTO);
30110a55fbb7Slm66018 	}
30120a55fbb7Slm66018 
30130a55fbb7Slm66018 	/*
30140a55fbb7Slm66018 	 * calculate the number of messages that vds ACK'ed
30150a55fbb7Slm66018 	 *
30160a55fbb7Slm66018 	 * Assumes, (like the rest of vdc) that there is a 1:1 mapping
30170a55fbb7Slm66018 	 * between requests and Dring entries.
30180a55fbb7Slm66018 	 */
30190a55fbb7Slm66018 	num_msgs = (end >= start) ?
30200a55fbb7Slm66018 			(end - start + 1) :
30210a55fbb7Slm66018 			(VD_DRING_LEN - start + end + 1);
30220a55fbb7Slm66018 
30230a55fbb7Slm66018 	/*
30240a55fbb7Slm66018 	 * Verify that the sequence number is what vdc expects.
30250a55fbb7Slm66018 	 */
30260a55fbb7Slm66018 	if (!vdc_verify_seq_num(vdc, dring_msg, num_msgs)) {
30270a55fbb7Slm66018 		return (ENXIO);
30280a55fbb7Slm66018 	}
30290a55fbb7Slm66018 
30300a55fbb7Slm66018 	/*
30310a55fbb7Slm66018 	 * Wake the thread waiting for each DRing entry ACK'ed
30320a55fbb7Slm66018 	 */
30330a55fbb7Slm66018 	for (i = 0; i < num_msgs; i++) {
30340a55fbb7Slm66018 		int idx = (start + i) % VD_DRING_LEN;
30350a55fbb7Slm66018 
30360a55fbb7Slm66018 		local_dep = &vdc->local_dring[idx];
30370a55fbb7Slm66018 		mutex_enter(&local_dep->lock);
30380a55fbb7Slm66018 		cv_signal(&local_dep->cv);
30390a55fbb7Slm66018 		mutex_exit(&local_dep->lock);
30400a55fbb7Slm66018 	}
30410a55fbb7Slm66018 
30420a55fbb7Slm66018 	if (msg.tag.vio_subtype == VIO_SUBTYPE_NACK) {
30430a55fbb7Slm66018 		PR0("%s: DATA NACK\n", __func__);
30440a55fbb7Slm66018 		VDC_DUMP_DRING_MSG(dring_msg);
30450a55fbb7Slm66018 		vdc_reset_connection(vdc, B_FALSE);
30460a55fbb7Slm66018 
30470a55fbb7Slm66018 		/* we need to drop the lock to trigger the handshake */
30480a55fbb7Slm66018 		mutex_exit(&vdc->lock);
30490a55fbb7Slm66018 		vdc_init_handshake_negotiation(vdc);
30500a55fbb7Slm66018 		mutex_enter(&vdc->lock);
30510a55fbb7Slm66018 	} else if (msg.tag.vio_subtype == VIO_SUBTYPE_INFO) {
30520a55fbb7Slm66018 		status = EPROTO;
30530a55fbb7Slm66018 	}
30540a55fbb7Slm66018 
30550a55fbb7Slm66018 	return (status);
30560a55fbb7Slm66018 }
30570a55fbb7Slm66018 
30580a55fbb7Slm66018 /*
30590a55fbb7Slm66018  * Function:
30600a55fbb7Slm66018  *	vdc_process_err_msg()
30610a55fbb7Slm66018  *
30620a55fbb7Slm66018  * NOTE: No error messages are used as part of the vDisk protocol
30630a55fbb7Slm66018  */
30640a55fbb7Slm66018 static int
30650a55fbb7Slm66018 vdc_process_err_msg(vdc_t *vdc, vio_msg_t msg)
30660a55fbb7Slm66018 {
30670a55fbb7Slm66018 	_NOTE(ARGUNUSED(vdc))
30680a55fbb7Slm66018 	_NOTE(ARGUNUSED(msg))
30690a55fbb7Slm66018 
30700a55fbb7Slm66018 	ASSERT(msg.tag.vio_msgtype == VIO_TYPE_ERR);
30710a55fbb7Slm66018 	cmn_err(CE_NOTE, "[%d] Got an ERR msg", vdc->instance);
30720a55fbb7Slm66018 
30730a55fbb7Slm66018 	return (ENOTSUP);
30740a55fbb7Slm66018 }
30750a55fbb7Slm66018 
30760a55fbb7Slm66018 /*
30770a55fbb7Slm66018  * Function:
30780a55fbb7Slm66018  *	vdc_handle_ver_msg()
30790a55fbb7Slm66018  *
30800a55fbb7Slm66018  * Description:
30810a55fbb7Slm66018  *
30820a55fbb7Slm66018  * Arguments:
30830a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
30840a55fbb7Slm66018  *	ver_msg	- LDC message sent by vDisk server
30850a55fbb7Slm66018  *
30860a55fbb7Slm66018  * Return Code:
30870a55fbb7Slm66018  *	0	- Success
30880a55fbb7Slm66018  */
30890a55fbb7Slm66018 static int
30900a55fbb7Slm66018 vdc_handle_ver_msg(vdc_t *vdc, vio_ver_msg_t *ver_msg)
30910a55fbb7Slm66018 {
30920a55fbb7Slm66018 	int status = 0;
30930a55fbb7Slm66018 
30940a55fbb7Slm66018 	ASSERT(vdc != NULL);
30950a55fbb7Slm66018 	ASSERT(mutex_owned(&vdc->lock));
30960a55fbb7Slm66018 
30970a55fbb7Slm66018 	if (ver_msg->tag.vio_subtype_env != VIO_VER_INFO) {
30980a55fbb7Slm66018 		return (EPROTO);
30990a55fbb7Slm66018 	}
31000a55fbb7Slm66018 
31010a55fbb7Slm66018 	if (ver_msg->dev_class != VDEV_DISK_SERVER) {
31020a55fbb7Slm66018 		return (EINVAL);
31030a55fbb7Slm66018 	}
31040a55fbb7Slm66018 
31050a55fbb7Slm66018 	switch (ver_msg->tag.vio_subtype) {
31060a55fbb7Slm66018 	case VIO_SUBTYPE_ACK:
31070a55fbb7Slm66018 		/*
31080a55fbb7Slm66018 		 * We check to see if the version returned is indeed supported
31090a55fbb7Slm66018 		 * (The server may have also adjusted the minor number downwards
31100a55fbb7Slm66018 		 * and if so 'ver_msg' will contain the actual version agreed)
31110a55fbb7Slm66018 		 */
31120a55fbb7Slm66018 		if (vdc_is_supported_version(ver_msg)) {
31130a55fbb7Slm66018 			vdc->ver.major = ver_msg->ver_major;
31140a55fbb7Slm66018 			vdc->ver.minor = ver_msg->ver_minor;
31150a55fbb7Slm66018 			ASSERT(vdc->ver.major > 0);
31160a55fbb7Slm66018 
31170a55fbb7Slm66018 			vdc->state = VD_STATE_VER;
31180a55fbb7Slm66018 			status = vdc_init_attr_negotiation(vdc);
31190a55fbb7Slm66018 		} else {
31200a55fbb7Slm66018 			status = EPROTO;
31210a55fbb7Slm66018 		}
31220a55fbb7Slm66018 		break;
31230a55fbb7Slm66018 
31240a55fbb7Slm66018 	case VIO_SUBTYPE_NACK:
31250a55fbb7Slm66018 		/*
31260a55fbb7Slm66018 		 * call vdc_is_supported_version() which will return the next
31270a55fbb7Slm66018 		 * supported version (if any) in 'ver_msg'
31280a55fbb7Slm66018 		 */
31290a55fbb7Slm66018 		(void) vdc_is_supported_version(ver_msg);
31300a55fbb7Slm66018 		if (ver_msg->ver_major > 0) {
31310a55fbb7Slm66018 			size_t len = sizeof (*ver_msg);
31320a55fbb7Slm66018 
31330a55fbb7Slm66018 			ASSERT(vdc->ver.major > 0);
31340a55fbb7Slm66018 
31350a55fbb7Slm66018 			/* reset the necessary fields and resend */
31360a55fbb7Slm66018 			ver_msg->tag.vio_subtype = VIO_SUBTYPE_INFO;
31370a55fbb7Slm66018 			ver_msg->dev_class = VDEV_DISK;
31380a55fbb7Slm66018 
31390a55fbb7Slm66018 			status = vdc_send(vdc, (caddr_t)ver_msg, &len);
31400a55fbb7Slm66018 			PR0("[%d] Resend VER info (LDC status = %d)\n",
31410a55fbb7Slm66018 					vdc->instance, status);
31420a55fbb7Slm66018 			if (len != sizeof (*ver_msg))
31430a55fbb7Slm66018 				status = EBADMSG;
31440a55fbb7Slm66018 		} else {
31450a55fbb7Slm66018 			cmn_err(CE_NOTE, "[%d] No common version with "
31460a55fbb7Slm66018 					"vDisk server", vdc->instance);
31470a55fbb7Slm66018 			status = ENOTSUP;
31480a55fbb7Slm66018 		}
31490a55fbb7Slm66018 
31500a55fbb7Slm66018 		break;
31511ae08745Sheppo 	case VIO_SUBTYPE_INFO:
31521ae08745Sheppo 		/*
31531ae08745Sheppo 		 * Handle the case where vds starts handshake
31541ae08745Sheppo 		 * (for now only vdc is the instigatior)
31551ae08745Sheppo 		 */
31561ae08745Sheppo 		status = ENOTSUP;
31571ae08745Sheppo 		break;
31581ae08745Sheppo 
31591ae08745Sheppo 	default:
31600a55fbb7Slm66018 		status = EINVAL;
31611ae08745Sheppo 		break;
31621ae08745Sheppo 	}
31631ae08745Sheppo 
31640a55fbb7Slm66018 	return (status);
31650a55fbb7Slm66018 }
31660a55fbb7Slm66018 
31670a55fbb7Slm66018 /*
31680a55fbb7Slm66018  * Function:
31690a55fbb7Slm66018  *	vdc_handle_attr_msg()
31700a55fbb7Slm66018  *
31710a55fbb7Slm66018  * Description:
31720a55fbb7Slm66018  *
31730a55fbb7Slm66018  * Arguments:
31740a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
31750a55fbb7Slm66018  *	attr_msg	- LDC message sent by vDisk server
31760a55fbb7Slm66018  *
31770a55fbb7Slm66018  * Return Code:
31780a55fbb7Slm66018  *	0	- Success
31790a55fbb7Slm66018  */
31800a55fbb7Slm66018 static int
31810a55fbb7Slm66018 vdc_handle_attr_msg(vdc_t *vdc, vd_attr_msg_t *attr_msg)
31820a55fbb7Slm66018 {
31830a55fbb7Slm66018 	int status = 0;
31840a55fbb7Slm66018 
31850a55fbb7Slm66018 	ASSERT(vdc != NULL);
31860a55fbb7Slm66018 	ASSERT(mutex_owned(&vdc->lock));
31870a55fbb7Slm66018 
31880a55fbb7Slm66018 	if (attr_msg->tag.vio_subtype_env != VIO_ATTR_INFO) {
31890a55fbb7Slm66018 		return (EPROTO);
31900a55fbb7Slm66018 	}
31910a55fbb7Slm66018 
31920a55fbb7Slm66018 	switch (attr_msg->tag.vio_subtype) {
31931ae08745Sheppo 	case VIO_SUBTYPE_ACK:
31941ae08745Sheppo 		/*
31951ae08745Sheppo 		 * We now verify the attributes sent by vds.
31961ae08745Sheppo 		 */
31971ae08745Sheppo 		vdc->vdisk_size = attr_msg->vdisk_size;
31981ae08745Sheppo 		vdc->vdisk_type = attr_msg->vdisk_type;
31991ae08745Sheppo 
32001ae08745Sheppo 		if ((attr_msg->max_xfer_sz != vdc->max_xfer_sz) ||
32011ae08745Sheppo 		    (attr_msg->vdisk_block_size != vdc->block_size)) {
32021ae08745Sheppo 			/*
32031ae08745Sheppo 			 * Future support: step down to the block size
32041ae08745Sheppo 			 * and max transfer size suggested by the
32051ae08745Sheppo 			 * server. (If this value is less than 128K
32061ae08745Sheppo 			 * then multiple Dring entries per request
32071ae08745Sheppo 			 * would need to be implemented)
32081ae08745Sheppo 			 */
32091ae08745Sheppo 			cmn_err(CE_NOTE, "[%d] Couldn't process block "
32100a55fbb7Slm66018 				"attributes from vds", vdc->instance);
32111ae08745Sheppo 			status = EINVAL;
32121ae08745Sheppo 			break;
32131ae08745Sheppo 		}
32141ae08745Sheppo 
32151ae08745Sheppo 		if ((attr_msg->xfer_mode != VIO_DRING_MODE) ||
32161ae08745Sheppo 		    (attr_msg->vdisk_size > INT64_MAX) ||
32171ae08745Sheppo 		    (attr_msg->vdisk_type > VD_DISK_TYPE_DISK)) {
32181ae08745Sheppo 			vdc_msg("%s[%d] Couldn't process attrs "
32191ae08745Sheppo 			    "from vds", __func__, vdc->instance);
32201ae08745Sheppo 			status = EINVAL;
32211ae08745Sheppo 			break;
32221ae08745Sheppo 		}
32231ae08745Sheppo 
32241ae08745Sheppo 		vdc->state = VD_STATE_ATTR;
32251ae08745Sheppo 		status = vdc_init_dring_negotiate(vdc);
32261ae08745Sheppo 		break;
32271ae08745Sheppo 
32281ae08745Sheppo 	case VIO_SUBTYPE_NACK:
32291ae08745Sheppo 		/*
32301ae08745Sheppo 		 * vds could not handle the attributes we sent so we
32311ae08745Sheppo 		 * stop negotiating.
32321ae08745Sheppo 		 */
32331ae08745Sheppo 		status = EPROTO;
32341ae08745Sheppo 		break;
32351ae08745Sheppo 
32361ae08745Sheppo 	case VIO_SUBTYPE_INFO:
32371ae08745Sheppo 		/*
32381ae08745Sheppo 		 * Handle the case where vds starts the handshake
32391ae08745Sheppo 		 * (for now; vdc is the only supported instigatior)
32401ae08745Sheppo 		 */
32411ae08745Sheppo 		status = ENOTSUP;
32421ae08745Sheppo 		break;
32431ae08745Sheppo 
32441ae08745Sheppo 	default:
32451ae08745Sheppo 		status = ENOTSUP;
32461ae08745Sheppo 		break;
32471ae08745Sheppo 	}
32481ae08745Sheppo 
32490a55fbb7Slm66018 	return (status);
32501ae08745Sheppo }
32511ae08745Sheppo 
32520a55fbb7Slm66018 /*
32530a55fbb7Slm66018  * Function:
32540a55fbb7Slm66018  *	vdc_handle_dring_reg_msg()
32550a55fbb7Slm66018  *
32560a55fbb7Slm66018  * Description:
32570a55fbb7Slm66018  *
32580a55fbb7Slm66018  * Arguments:
32590a55fbb7Slm66018  *	vdc		- soft state pointer for this instance of the driver.
32600a55fbb7Slm66018  *	dring_msg	- LDC message sent by vDisk server
32610a55fbb7Slm66018  *
32620a55fbb7Slm66018  * Return Code:
32630a55fbb7Slm66018  *	0	- Success
32640a55fbb7Slm66018  */
32650a55fbb7Slm66018 static int
32660a55fbb7Slm66018 vdc_handle_dring_reg_msg(vdc_t *vdc, vio_dring_reg_msg_t *dring_msg)
32670a55fbb7Slm66018 {
32680a55fbb7Slm66018 	int		status = 0;
32690a55fbb7Slm66018 	vio_rdx_msg_t	msg = {0};
32700a55fbb7Slm66018 	size_t		msglen = sizeof (msg);
32711ae08745Sheppo 
32720a55fbb7Slm66018 	ASSERT(vdc != NULL);
32730a55fbb7Slm66018 	ASSERT(mutex_owned(&vdc->lock));
32740a55fbb7Slm66018 
32750a55fbb7Slm66018 	if (dring_msg->tag.vio_subtype_env != VIO_DRING_REG) {
32760a55fbb7Slm66018 		return (EPROTO);
32770a55fbb7Slm66018 	}
32780a55fbb7Slm66018 
32790a55fbb7Slm66018 	switch (dring_msg->tag.vio_subtype) {
32800a55fbb7Slm66018 	case VIO_SUBTYPE_ACK:
32811ae08745Sheppo 		/* save the received dring_ident */
32821ae08745Sheppo 		vdc->dring_ident = dring_msg->dring_ident;
32831ae08745Sheppo 		PR0("%s[%d] Received dring ident=0x%lx\n",
32841ae08745Sheppo 			__func__, vdc->instance, vdc->dring_ident);
32851ae08745Sheppo 
32861ae08745Sheppo 		/*
32871ae08745Sheppo 		 * Send an RDX message to vds to indicate we are ready
32881ae08745Sheppo 		 * to send data
32891ae08745Sheppo 		 */
32901ae08745Sheppo 		msg.tag.vio_msgtype = VIO_TYPE_CTRL;
32911ae08745Sheppo 		msg.tag.vio_subtype = VIO_SUBTYPE_INFO;
32921ae08745Sheppo 		msg.tag.vio_subtype_env = VIO_RDX;
32931ae08745Sheppo 		msg.tag.vio_sid = vdc->session_id;
32940a55fbb7Slm66018 		status = vdc_send(vdc, (caddr_t)&msg, &msglen);
32951ae08745Sheppo 		if (status != 0) {
32961ae08745Sheppo 			cmn_err(CE_NOTE, "[%d] Failed to send RDX"
32971ae08745Sheppo 				" message (%d)", vdc->instance, status);
32981ae08745Sheppo 			break;
32991ae08745Sheppo 		}
33001ae08745Sheppo 
33011ae08745Sheppo 		vdc->state = VD_STATE_RDX;
33021ae08745Sheppo 		break;
33031ae08745Sheppo 
33041ae08745Sheppo 	case VIO_SUBTYPE_NACK:
33051ae08745Sheppo 		/*
33061ae08745Sheppo 		 * vds could not handle the DRing info we sent so we
33071ae08745Sheppo 		 * stop negotiating.
33081ae08745Sheppo 		 */
33091ae08745Sheppo 		cmn_err(CE_CONT, "server could not register DRing\n");
33101ae08745Sheppo 		vdc_reset_connection(vdc, B_FALSE);
33111ae08745Sheppo 		vdc_destroy_descriptor_ring(vdc);
33121ae08745Sheppo 		status = EPROTO;
33131ae08745Sheppo 		break;
33141ae08745Sheppo 
33151ae08745Sheppo 	case VIO_SUBTYPE_INFO:
33161ae08745Sheppo 		/*
33171ae08745Sheppo 		 * Handle the case where vds starts handshake
33181ae08745Sheppo 		 * (for now only vdc is the instigatior)
33191ae08745Sheppo 		 */
33201ae08745Sheppo 		status = ENOTSUP;
33211ae08745Sheppo 		break;
33221ae08745Sheppo 	default:
33231ae08745Sheppo 		status = ENOTSUP;
33241ae08745Sheppo 	}
33251ae08745Sheppo 
33261ae08745Sheppo 	return (status);
33271ae08745Sheppo }
33281ae08745Sheppo 
33291ae08745Sheppo /*
33301ae08745Sheppo  * Function:
33311ae08745Sheppo  *	vdc_verify_seq_num()
33321ae08745Sheppo  *
33331ae08745Sheppo  * Description:
33341ae08745Sheppo  *	This functions verifies that the sequence number sent back by vds with
33351ae08745Sheppo  *	the latest message correctly follows the last request processed.
33361ae08745Sheppo  *
33371ae08745Sheppo  * Arguments:
33381ae08745Sheppo  *	vdc		- soft state pointer for this instance of the driver.
33391ae08745Sheppo  *	dring_msg	- pointer to the LDC message sent by vds
33401ae08745Sheppo  *	num_msgs	- the number of requests being acknowledged
33411ae08745Sheppo  *
33421ae08745Sheppo  * Return Code:
33431ae08745Sheppo  *	B_TRUE	- Success.
33441ae08745Sheppo  *	B_FALSE	- The seq numbers are so out of sync, vdc cannot deal with them
33451ae08745Sheppo  */
33461ae08745Sheppo static boolean_t
33471ae08745Sheppo vdc_verify_seq_num(vdc_t *vdc, vio_dring_msg_t *dring_msg, int num_msgs)
33481ae08745Sheppo {
33491ae08745Sheppo 	ASSERT(vdc != NULL);
33501ae08745Sheppo 	ASSERT(dring_msg != NULL);
33511ae08745Sheppo 
33521ae08745Sheppo 	/*
33531ae08745Sheppo 	 * Check to see if the messages were responded to in the correct
33541ae08745Sheppo 	 * order by vds. There are 3 possible scenarios:
33551ae08745Sheppo 	 *	- the seq_num we expected is returned (everything is OK)
33561ae08745Sheppo 	 *	- a seq_num earlier than the last one acknowledged is returned,
33571ae08745Sheppo 	 *	  if so something is seriously wrong so we reset the connection
33581ae08745Sheppo 	 *	- a seq_num greater than what we expected is returned.
33591ae08745Sheppo 	 */
33601ae08745Sheppo 	if (dring_msg->seq_num != (vdc->seq_num_reply + num_msgs)) {
33611ae08745Sheppo 		vdc_msg("%s[%d]: Bogus seq_num %d, expected %d\n",
33621ae08745Sheppo 			__func__, vdc->instance, dring_msg->seq_num,
33631ae08745Sheppo 			vdc->seq_num_reply + num_msgs);
33641ae08745Sheppo 		if (dring_msg->seq_num < (vdc->seq_num_reply + num_msgs)) {
33651ae08745Sheppo 			return (B_FALSE);
33661ae08745Sheppo 		} else {
33671ae08745Sheppo 			/*
33681ae08745Sheppo 			 * vds has responded with a seq_num greater than what we
33691ae08745Sheppo 			 * expected
33701ae08745Sheppo 			 */
33711ae08745Sheppo 			return (B_FALSE);
33721ae08745Sheppo 		}
33731ae08745Sheppo 	}
33741ae08745Sheppo 	vdc->seq_num_reply += num_msgs;
33751ae08745Sheppo 
33761ae08745Sheppo 	return (B_TRUE);
33771ae08745Sheppo }
33781ae08745Sheppo 
33790a55fbb7Slm66018 
33800a55fbb7Slm66018 /*
33810a55fbb7Slm66018  * Function:
33820a55fbb7Slm66018  *	vdc_is_supported_version()
33830a55fbb7Slm66018  *
33840a55fbb7Slm66018  * Description:
33850a55fbb7Slm66018  *	This routine checks if the major/minor version numbers specified in
33860a55fbb7Slm66018  *	'ver_msg' are supported. If not it finds the next version that is
33870a55fbb7Slm66018  *	in the supported version list 'vdc_version[]' and sets the fields in
33880a55fbb7Slm66018  *	'ver_msg' to those values
33890a55fbb7Slm66018  *
33900a55fbb7Slm66018  * Arguments:
33910a55fbb7Slm66018  *	ver_msg	- LDC message sent by vDisk server
33920a55fbb7Slm66018  *
33930a55fbb7Slm66018  * Return Code:
33940a55fbb7Slm66018  *	B_TRUE	- Success
33950a55fbb7Slm66018  *	B_FALSE	- Version not supported
33960a55fbb7Slm66018  */
33970a55fbb7Slm66018 static boolean_t
33980a55fbb7Slm66018 vdc_is_supported_version(vio_ver_msg_t *ver_msg)
33990a55fbb7Slm66018 {
34000a55fbb7Slm66018 	int vdc_num_versions = sizeof (vdc_version) / sizeof (vdc_version[0]);
34010a55fbb7Slm66018 
34020a55fbb7Slm66018 	for (int i = 0; i < vdc_num_versions; i++) {
34030a55fbb7Slm66018 		ASSERT(vdc_version[i].major > 0);
34040a55fbb7Slm66018 		ASSERT((i == 0) ||
34050a55fbb7Slm66018 		    (vdc_version[i].major < vdc_version[i-1].major));
34060a55fbb7Slm66018 
34070a55fbb7Slm66018 		/*
34080a55fbb7Slm66018 		 * If the major versions match, adjust the minor version, if
34090a55fbb7Slm66018 		 * necessary, down to the highest value supported by this
34100a55fbb7Slm66018 		 * client. The server should support all minor versions lower
34110a55fbb7Slm66018 		 * than the value it sent
34120a55fbb7Slm66018 		 */
34130a55fbb7Slm66018 		if (ver_msg->ver_major == vdc_version[i].major) {
34140a55fbb7Slm66018 			if (ver_msg->ver_minor > vdc_version[i].minor) {
34150a55fbb7Slm66018 				PR0("Adjusting minor version from %u to %u",
34160a55fbb7Slm66018 				    ver_msg->ver_minor, vdc_version[i].minor);
34170a55fbb7Slm66018 				ver_msg->ver_minor = vdc_version[i].minor;
34180a55fbb7Slm66018 			}
34190a55fbb7Slm66018 			return (B_TRUE);
34200a55fbb7Slm66018 		}
34210a55fbb7Slm66018 
34220a55fbb7Slm66018 		/*
34230a55fbb7Slm66018 		 * If the message contains a higher major version number, set
34240a55fbb7Slm66018 		 * the message's major/minor versions to the current values
34250a55fbb7Slm66018 		 * and return false, so this message will get resent with
34260a55fbb7Slm66018 		 * these values, and the server will potentially try again
34270a55fbb7Slm66018 		 * with the same or a lower version
34280a55fbb7Slm66018 		 */
34290a55fbb7Slm66018 		if (ver_msg->ver_major > vdc_version[i].major) {
34300a55fbb7Slm66018 			ver_msg->ver_major = vdc_version[i].major;
34310a55fbb7Slm66018 			ver_msg->ver_minor = vdc_version[i].minor;
34320a55fbb7Slm66018 			PR0("Suggesting major/minor (0x%x/0x%x)\n",
34330a55fbb7Slm66018 				ver_msg->ver_major, ver_msg->ver_minor);
34340a55fbb7Slm66018 
34350a55fbb7Slm66018 			return (B_FALSE);
34360a55fbb7Slm66018 		}
34370a55fbb7Slm66018 
34380a55fbb7Slm66018 		/*
34390a55fbb7Slm66018 		 * Otherwise, the message's major version is less than the
34400a55fbb7Slm66018 		 * current major version, so continue the loop to the next
34410a55fbb7Slm66018 		 * (lower) supported version
34420a55fbb7Slm66018 		 */
34430a55fbb7Slm66018 	}
34440a55fbb7Slm66018 
34450a55fbb7Slm66018 	/*
34460a55fbb7Slm66018 	 * No common version was found; "ground" the version pair in the
34470a55fbb7Slm66018 	 * message to terminate negotiation
34480a55fbb7Slm66018 	 */
34490a55fbb7Slm66018 	ver_msg->ver_major = 0;
34500a55fbb7Slm66018 	ver_msg->ver_minor = 0;
34510a55fbb7Slm66018 
34520a55fbb7Slm66018 	return (B_FALSE);
34530a55fbb7Slm66018 }
34541ae08745Sheppo /* -------------------------------------------------------------------------- */
34551ae08745Sheppo 
34561ae08745Sheppo /*
34571ae08745Sheppo  * DKIO(7) support
34581ae08745Sheppo  */
34591ae08745Sheppo 
34601ae08745Sheppo typedef struct vdc_dk_arg {
34611ae08745Sheppo 	struct dk_callback	dkc;
34621ae08745Sheppo 	int			mode;
34631ae08745Sheppo 	dev_t			dev;
34641ae08745Sheppo 	vdc_t			*vdc;
34651ae08745Sheppo } vdc_dk_arg_t;
34661ae08745Sheppo 
34671ae08745Sheppo /*
34681ae08745Sheppo  * Function:
34691ae08745Sheppo  * 	vdc_dkio_flush_cb()
34701ae08745Sheppo  *
34711ae08745Sheppo  * Description:
34721ae08745Sheppo  *	This routine is a callback for DKIOCFLUSHWRITECACHE which can be called
34731ae08745Sheppo  *	by kernel code.
34741ae08745Sheppo  *
34751ae08745Sheppo  * Arguments:
34761ae08745Sheppo  *	arg	- a pointer to a vdc_dk_arg_t structure.
34771ae08745Sheppo  */
34781ae08745Sheppo void
34791ae08745Sheppo vdc_dkio_flush_cb(void *arg)
34801ae08745Sheppo {
34811ae08745Sheppo 	struct vdc_dk_arg	*dk_arg = (struct vdc_dk_arg *)arg;
34821ae08745Sheppo 	struct dk_callback	*dkc = NULL;
34831ae08745Sheppo 	vdc_t			*vdc = NULL;
34841ae08745Sheppo 	int			rv;
34851ae08745Sheppo 
34861ae08745Sheppo 	if (dk_arg == NULL) {
34871ae08745Sheppo 		vdc_msg("%s[?] DKIOCFLUSHWRITECACHE arg is NULL\n", __func__);
34881ae08745Sheppo 		return;
34891ae08745Sheppo 	}
34901ae08745Sheppo 	dkc = &dk_arg->dkc;
34911ae08745Sheppo 	vdc = dk_arg->vdc;
34921ae08745Sheppo 	ASSERT(vdc != NULL);
34931ae08745Sheppo 
34941ae08745Sheppo 	rv = vdc_populate_descriptor(vdc, NULL, 0, VD_OP_FLUSH,
34951ae08745Sheppo 		dk_arg->mode, SDPART(getminor(dk_arg->dev)));
34961ae08745Sheppo 	if (rv != 0) {
3497*8e6a2a04Slm66018 		PR0("%s[%d] DKIOCFLUSHWRITECACHE failed %d : model %x\n",
3498*8e6a2a04Slm66018 			__func__, vdc->instance, rv,
34991ae08745Sheppo 			ddi_model_convert_from(dk_arg->mode & FMODELS));
35001ae08745Sheppo 	}
35011ae08745Sheppo 
35021ae08745Sheppo 	/*
35031ae08745Sheppo 	 * Trigger the call back to notify the caller the the ioctl call has
35041ae08745Sheppo 	 * been completed.
35051ae08745Sheppo 	 */
35061ae08745Sheppo 	if ((dk_arg->mode & FKIOCTL) &&
35071ae08745Sheppo 	    (dkc != NULL) &&
35081ae08745Sheppo 	    (dkc->dkc_callback != NULL)) {
35091ae08745Sheppo 		ASSERT(dkc->dkc_cookie != NULL);
3510*8e6a2a04Slm66018 		(*dkc->dkc_callback)(dkc->dkc_cookie, rv);
35111ae08745Sheppo 	}
35121ae08745Sheppo 
35131ae08745Sheppo 	/* Indicate that one less DKIO write flush is outstanding */
35141ae08745Sheppo 	mutex_enter(&vdc->lock);
35151ae08745Sheppo 	vdc->dkio_flush_pending--;
35161ae08745Sheppo 	ASSERT(vdc->dkio_flush_pending >= 0);
35171ae08745Sheppo 	mutex_exit(&vdc->lock);
3518*8e6a2a04Slm66018 
3519*8e6a2a04Slm66018 	/* free the mem that was allocated when the callback was dispatched */
3520*8e6a2a04Slm66018 	kmem_free(arg, sizeof (vdc_dk_arg_t));
35211ae08745Sheppo }
35221ae08745Sheppo 
35231ae08745Sheppo /*
35241ae08745Sheppo  * This structure is used in the DKIO(7I) array below.
35251ae08745Sheppo  */
35261ae08745Sheppo typedef struct vdc_dk_ioctl {
35271ae08745Sheppo 	uint8_t		op;		/* VD_OP_XXX value */
35281ae08745Sheppo 	int		cmd;		/* Solaris ioctl operation number */
35291ae08745Sheppo 	size_t		nbytes;		/* size of structure to be copied */
35300a55fbb7Slm66018 
35310a55fbb7Slm66018 	/* function to convert between vDisk and Solaris structure formats */
35320a55fbb7Slm66018 	int	(*convert)(void *vd_buf, void *ioctl_arg, int mode, int dir);
35331ae08745Sheppo } vdc_dk_ioctl_t;
35341ae08745Sheppo 
35351ae08745Sheppo /*
35361ae08745Sheppo  * Subset of DKIO(7I) operations currently supported
35371ae08745Sheppo  */
35381ae08745Sheppo static vdc_dk_ioctl_t	dk_ioctl[] = {
35390a55fbb7Slm66018 	{VD_OP_FLUSH,		DKIOCFLUSHWRITECACHE,	sizeof (int),
35400a55fbb7Slm66018 		vdc_null_copy_func},
35410a55fbb7Slm66018 	{VD_OP_GET_WCE,		DKIOCGETWCE,		sizeof (int),
35420a55fbb7Slm66018 		vdc_null_copy_func},
35430a55fbb7Slm66018 	{VD_OP_SET_WCE,		DKIOCSETWCE,		sizeof (int),
35440a55fbb7Slm66018 		vdc_null_copy_func},
35450a55fbb7Slm66018 	{VD_OP_GET_VTOC,	DKIOCGVTOC,		sizeof (vd_vtoc_t),
35460a55fbb7Slm66018 		vdc_get_vtoc_convert},
35470a55fbb7Slm66018 	{VD_OP_SET_VTOC,	DKIOCSVTOC,		sizeof (vd_vtoc_t),
35480a55fbb7Slm66018 		vdc_set_vtoc_convert},
35490a55fbb7Slm66018 	{VD_OP_SET_DISKGEOM,	DKIOCSGEOM,		sizeof (vd_geom_t),
35500a55fbb7Slm66018 		vdc_get_geom_convert},
35510a55fbb7Slm66018 	{VD_OP_GET_DISKGEOM,	DKIOCGGEOM,		sizeof (vd_geom_t),
35520a55fbb7Slm66018 		vdc_get_geom_convert},
35530a55fbb7Slm66018 	{VD_OP_GET_DISKGEOM,	DKIOCG_PHYGEOM,		sizeof (vd_geom_t),
35540a55fbb7Slm66018 		vdc_get_geom_convert},
35550a55fbb7Slm66018 	{VD_OP_GET_DISKGEOM, DKIOCG_VIRTGEOM,		sizeof (vd_geom_t),
35560a55fbb7Slm66018 		vdc_get_geom_convert},
35570a55fbb7Slm66018 	{VD_OP_SET_DISKGEOM, DKIOCSGEOM,		sizeof (vd_geom_t),
35580a55fbb7Slm66018 		vdc_set_geom_convert},
35590a55fbb7Slm66018 
35600a55fbb7Slm66018 	/*
35610a55fbb7Slm66018 	 * These particular ioctls are not sent to the server - vdc fakes up
35620a55fbb7Slm66018 	 * the necessary info.
35630a55fbb7Slm66018 	 */
35640a55fbb7Slm66018 	{0, DKIOCINFO, sizeof (struct dk_cinfo), vdc_null_copy_func},
35650a55fbb7Slm66018 	{0, DKIOCGMEDIAINFO, sizeof (struct dk_minfo), vdc_null_copy_func},
35660a55fbb7Slm66018 	{0, USCSICMD,	sizeof (struct uscsi_cmd), vdc_null_copy_func},
35670a55fbb7Slm66018 	{0, DKIOCREMOVABLE, 0, vdc_null_copy_func},
35680a55fbb7Slm66018 	{0, CDROMREADOFFSET, 0, vdc_null_copy_func}
35691ae08745Sheppo };
35701ae08745Sheppo 
35711ae08745Sheppo /*
35721ae08745Sheppo  * Function:
35731ae08745Sheppo  *	vd_process_ioctl()
35741ae08745Sheppo  *
35751ae08745Sheppo  * Description:
35760a55fbb7Slm66018  *	This routine processes disk specific ioctl calls
35771ae08745Sheppo  *
35781ae08745Sheppo  * Arguments:
35791ae08745Sheppo  *	dev	- the device number
35801ae08745Sheppo  *	cmd	- the operation [dkio(7I)] to be processed
35811ae08745Sheppo  *	arg	- pointer to user provided structure
35821ae08745Sheppo  *		  (contains data to be set or reference parameter for get)
35831ae08745Sheppo  *	mode	- bit flag, indicating open settings, 32/64 bit type, etc
35841ae08745Sheppo  *
35851ae08745Sheppo  * Return Code:
35861ae08745Sheppo  *	0
35871ae08745Sheppo  *	EFAULT
35881ae08745Sheppo  *	ENXIO
35891ae08745Sheppo  *	EIO
35901ae08745Sheppo  *	ENOTSUP
35911ae08745Sheppo  */
35921ae08745Sheppo static int
35931ae08745Sheppo vd_process_ioctl(dev_t dev, int cmd, caddr_t arg, int mode)
35941ae08745Sheppo {
35951ae08745Sheppo 	int		instance = SDUNIT(getminor(dev));
35961ae08745Sheppo 	vdc_t		*vdc = NULL;
35971ae08745Sheppo 	int		rv = -1;
35981ae08745Sheppo 	int		idx = 0;		/* index into dk_ioctl[] */
35991ae08745Sheppo 	size_t		len = 0;		/* #bytes to send to vds */
36001ae08745Sheppo 	size_t		alloc_len = 0;		/* #bytes to allocate mem for */
36011ae08745Sheppo 	caddr_t		mem_p = NULL;
36021ae08745Sheppo 	size_t		nioctls = (sizeof (dk_ioctl)) / (sizeof (dk_ioctl[0]));
36031ae08745Sheppo 
36041ae08745Sheppo 	PR0("%s: Processing ioctl(%x) for dev %x : model %x\n",
36051ae08745Sheppo 		__func__, cmd, dev, ddi_model_convert_from(mode & FMODELS));
36061ae08745Sheppo 
36071ae08745Sheppo 	vdc = ddi_get_soft_state(vdc_state, instance);
36081ae08745Sheppo 	if (vdc == NULL) {
36091ae08745Sheppo 		cmn_err(CE_NOTE, "![%d] Could not get soft state structure",
36101ae08745Sheppo 		    instance);
36111ae08745Sheppo 		return (ENXIO);
36121ae08745Sheppo 	}
36131ae08745Sheppo 
36141ae08745Sheppo 	/*
36151ae08745Sheppo 	 * Check to see if we can communicate with the vDisk server
36161ae08745Sheppo 	 */
36170a55fbb7Slm66018 	if (!vdc_is_able_to_tx_data(vdc, O_NONBLOCK)) {
36181ae08745Sheppo 		PR0("%s[%d] Not ready to transmit data\n", __func__, instance);
36191ae08745Sheppo 		return (ENOLINK);
36201ae08745Sheppo 	}
36211ae08745Sheppo 
36221ae08745Sheppo 	/*
36231ae08745Sheppo 	 * Validate the ioctl operation to be performed.
36241ae08745Sheppo 	 *
36251ae08745Sheppo 	 * If we have looped through the array without finding a match then we
36261ae08745Sheppo 	 * don't support this ioctl.
36271ae08745Sheppo 	 */
36281ae08745Sheppo 	for (idx = 0; idx < nioctls; idx++) {
36291ae08745Sheppo 		if (cmd == dk_ioctl[idx].cmd)
36301ae08745Sheppo 			break;
36311ae08745Sheppo 	}
36321ae08745Sheppo 
36331ae08745Sheppo 	if (idx >= nioctls) {
36341ae08745Sheppo 		PR0("%s[%d] Unsupported ioctl(%x)\n",
36351ae08745Sheppo 				__func__, vdc->instance, cmd);
36361ae08745Sheppo 		return (ENOTSUP);
36371ae08745Sheppo 	}
36381ae08745Sheppo 
36390a55fbb7Slm66018 	len = dk_ioctl[idx].nbytes;
36401ae08745Sheppo 
36411ae08745Sheppo 	/*
36420a55fbb7Slm66018 	 * Deal with the ioctls which the server does not provide. vdc can
36430a55fbb7Slm66018 	 * fake these up and return immediately
36441ae08745Sheppo 	 */
36451ae08745Sheppo 	switch (cmd) {
36461ae08745Sheppo 	case CDROMREADOFFSET:
36471ae08745Sheppo 	case DKIOCREMOVABLE:
36480a55fbb7Slm66018 	case USCSICMD:
36491ae08745Sheppo 		return (ENOTTY);
36501ae08745Sheppo 
36511ae08745Sheppo 	case DKIOCINFO:
36521ae08745Sheppo 		{
36531ae08745Sheppo 			struct dk_cinfo	cinfo;
36541ae08745Sheppo 			if (vdc->cinfo == NULL)
36551ae08745Sheppo 				return (ENXIO);
36561ae08745Sheppo 
36571ae08745Sheppo 			bcopy(vdc->cinfo, &cinfo, sizeof (struct dk_cinfo));
36581ae08745Sheppo 			cinfo.dki_partition = SDPART(getminor(dev));
36591ae08745Sheppo 
36601ae08745Sheppo 			rv = ddi_copyout(&cinfo, (void *)arg,
36611ae08745Sheppo 					sizeof (struct dk_cinfo), mode);
36621ae08745Sheppo 			if (rv != 0)
36631ae08745Sheppo 				return (EFAULT);
36641ae08745Sheppo 
36651ae08745Sheppo 			return (0);
36661ae08745Sheppo 		}
36671ae08745Sheppo 
36681ae08745Sheppo 	case DKIOCGMEDIAINFO:
3669*8e6a2a04Slm66018 		{
36701ae08745Sheppo 			if (vdc->minfo == NULL)
36711ae08745Sheppo 				return (ENXIO);
36721ae08745Sheppo 
36731ae08745Sheppo 			rv = ddi_copyout(vdc->minfo, (void *)arg,
36741ae08745Sheppo 					sizeof (struct dk_minfo), mode);
36751ae08745Sheppo 			if (rv != 0)
36761ae08745Sheppo 				return (EFAULT);
36771ae08745Sheppo 
36781ae08745Sheppo 			return (0);
36791ae08745Sheppo 		}
36801ae08745Sheppo 
3681*8e6a2a04Slm66018 	case DKIOCFLUSHWRITECACHE:
3682*8e6a2a04Slm66018 		{
3683*8e6a2a04Slm66018 			struct dk_callback *dkc = (struct dk_callback *)arg;
3684*8e6a2a04Slm66018 			vdc_dk_arg_t	*dkarg = NULL;
3685*8e6a2a04Slm66018 
3686*8e6a2a04Slm66018 			PR1("[%d] Flush W$: mode %x\n", instance, mode);
3687*8e6a2a04Slm66018 
3688*8e6a2a04Slm66018 			/*
3689*8e6a2a04Slm66018 			 * If the backing device is not a 'real' disk then the
3690*8e6a2a04Slm66018 			 * W$ operation request to the vDisk server will fail
3691*8e6a2a04Slm66018 			 * so we might as well save the cycles and return now.
3692*8e6a2a04Slm66018 			 */
3693*8e6a2a04Slm66018 			if (vdc->vdisk_type != VD_DISK_TYPE_DISK)
3694*8e6a2a04Slm66018 				return (ENOTTY);
3695*8e6a2a04Slm66018 
3696*8e6a2a04Slm66018 			/*
3697*8e6a2a04Slm66018 			 * If arg is NULL, then there is no callback function
3698*8e6a2a04Slm66018 			 * registered and the call operates synchronously; we
3699*8e6a2a04Slm66018 			 * break and continue with the rest of the function and
3700*8e6a2a04Slm66018 			 * wait for vds to return (i.e. after the request to
3701*8e6a2a04Slm66018 			 * vds returns successfully, all writes completed prior
3702*8e6a2a04Slm66018 			 * to the ioctl will have been flushed from the disk
3703*8e6a2a04Slm66018 			 * write cache to persistent media.
3704*8e6a2a04Slm66018 			 *
3705*8e6a2a04Slm66018 			 * If a callback function is registered, we dispatch
3706*8e6a2a04Slm66018 			 * the request on a task queue and return immediately.
3707*8e6a2a04Slm66018 			 * The callback will deal with informing the calling
3708*8e6a2a04Slm66018 			 * thread that the flush request is completed.
3709*8e6a2a04Slm66018 			 */
3710*8e6a2a04Slm66018 			if (dkc == NULL)
3711*8e6a2a04Slm66018 				break;
3712*8e6a2a04Slm66018 
3713*8e6a2a04Slm66018 			dkarg = kmem_zalloc(sizeof (vdc_dk_arg_t), KM_SLEEP);
3714*8e6a2a04Slm66018 
3715*8e6a2a04Slm66018 			dkarg->mode = mode;
3716*8e6a2a04Slm66018 			dkarg->dev = dev;
3717*8e6a2a04Slm66018 			bcopy(dkc, &dkarg->dkc, sizeof (*dkc));
3718*8e6a2a04Slm66018 
3719*8e6a2a04Slm66018 			mutex_enter(&vdc->lock);
3720*8e6a2a04Slm66018 			vdc->dkio_flush_pending++;
3721*8e6a2a04Slm66018 			dkarg->vdc = vdc;
3722*8e6a2a04Slm66018 			mutex_exit(&vdc->lock);
3723*8e6a2a04Slm66018 
3724*8e6a2a04Slm66018 			/* put the request on a task queue */
3725*8e6a2a04Slm66018 			rv = taskq_dispatch(system_taskq, vdc_dkio_flush_cb,
3726*8e6a2a04Slm66018 				(void *)dkarg, DDI_SLEEP);
3727*8e6a2a04Slm66018 
3728*8e6a2a04Slm66018 			return (rv == NULL ? ENOMEM : 0);
3729*8e6a2a04Slm66018 		}
3730*8e6a2a04Slm66018 	}
3731*8e6a2a04Slm66018 
37321ae08745Sheppo 	/* catch programming error in vdc - should be a VD_OP_XXX ioctl */
37330a55fbb7Slm66018 	ASSERT(dk_ioctl[idx].op != 0);
37341ae08745Sheppo 
37351ae08745Sheppo 	/* LDC requires that the memory being mapped is 8-byte aligned */
37361ae08745Sheppo 	alloc_len = P2ROUNDUP(len, sizeof (uint64_t));
37371ae08745Sheppo 	PR1("%s[%d]: struct size %d alloc %d\n",
37381ae08745Sheppo 			__func__, instance, len, alloc_len);
37391ae08745Sheppo 
37400a55fbb7Slm66018 	ASSERT(alloc_len != 0);	/* sanity check */
37411ae08745Sheppo 	mem_p = kmem_zalloc(alloc_len, KM_SLEEP);
37421ae08745Sheppo 
37430a55fbb7Slm66018 	/*
37440a55fbb7Slm66018 	 * Call the conversion function for this ioctl whhich if necessary
37450a55fbb7Slm66018 	 * converts from the Solaris format to the format ARC'ed
37460a55fbb7Slm66018 	 * as part of the vDisk protocol (FWARC 2006/195)
37470a55fbb7Slm66018 	 */
37480a55fbb7Slm66018 	ASSERT(dk_ioctl[idx].convert != NULL);
37490a55fbb7Slm66018 	rv = (dk_ioctl[idx].convert)(arg, mem_p, mode, VD_COPYIN);
37501ae08745Sheppo 	if (rv != 0) {
37510a55fbb7Slm66018 		PR0("%s[%d]: convert returned %d for ioctl 0x%x\n",
37520a55fbb7Slm66018 				__func__, instance, rv, cmd);
37531ae08745Sheppo 		if (mem_p != NULL)
37541ae08745Sheppo 			kmem_free(mem_p, alloc_len);
37550a55fbb7Slm66018 		return (rv);
37561ae08745Sheppo 	}
37571ae08745Sheppo 
37581ae08745Sheppo 	/*
37591ae08745Sheppo 	 * send request to vds to service the ioctl.
37601ae08745Sheppo 	 */
37610a55fbb7Slm66018 	rv = vdc_populate_descriptor(vdc, mem_p, alloc_len, dk_ioctl[idx].op,
37620a55fbb7Slm66018 			mode, SDPART((getminor(dev))));
37631ae08745Sheppo 	if (rv != 0) {
37641ae08745Sheppo 		/*
37651ae08745Sheppo 		 * This is not necessarily an error. The ioctl could
37661ae08745Sheppo 		 * be returning a value such as ENOTTY to indicate
37671ae08745Sheppo 		 * that the ioctl is not applicable.
37681ae08745Sheppo 		 */
37691ae08745Sheppo 		PR0("%s[%d]: vds returned %d for ioctl 0x%x\n",
37701ae08745Sheppo 			__func__, instance, rv, cmd);
37711ae08745Sheppo 		if (mem_p != NULL)
37721ae08745Sheppo 			kmem_free(mem_p, alloc_len);
37731ae08745Sheppo 		return (rv);
37741ae08745Sheppo 	}
37751ae08745Sheppo 
37761ae08745Sheppo 	/*
37771ae08745Sheppo 	 * If the VTOC has been changed, then vdc needs to update the copy
37781ae08745Sheppo 	 * it saved in the soft state structure and try and update the device
37791ae08745Sheppo 	 * node properties. Failing to set the properties should not cause
37801ae08745Sheppo 	 * an error to be return the caller though.
37811ae08745Sheppo 	 */
37821ae08745Sheppo 	if (cmd == DKIOCSVTOC) {
37831ae08745Sheppo 		bcopy(mem_p, vdc->vtoc, sizeof (struct vtoc));
37841ae08745Sheppo 		if (vdc_create_device_nodes_props(vdc)) {
37851ae08745Sheppo 			cmn_err(CE_NOTE, "![%d] Failed to update device nodes"
37861ae08745Sheppo 				" properties", instance);
37871ae08745Sheppo 		}
37881ae08745Sheppo 	}
37891ae08745Sheppo 
37901ae08745Sheppo 	/*
37910a55fbb7Slm66018 	 * Call the conversion function (if it exists) for this ioctl
37920a55fbb7Slm66018 	 * which converts from the format ARC'ed as part of the vDisk
37930a55fbb7Slm66018 	 * protocol (FWARC 2006/195) back to a format understood by
37940a55fbb7Slm66018 	 * the rest of Solaris.
37951ae08745Sheppo 	 */
37960a55fbb7Slm66018 	rv = (dk_ioctl[idx].convert)(mem_p, arg, mode, VD_COPYOUT);
37970a55fbb7Slm66018 	if (rv != 0) {
37980a55fbb7Slm66018 		PR0("%s[%d]: convert returned %d for ioctl 0x%x\n",
37990a55fbb7Slm66018 				__func__, instance, rv, cmd);
38001ae08745Sheppo 		if (mem_p != NULL)
38011ae08745Sheppo 			kmem_free(mem_p, alloc_len);
38020a55fbb7Slm66018 		return (rv);
38031ae08745Sheppo 	}
38041ae08745Sheppo 
38051ae08745Sheppo 	if (mem_p != NULL)
38061ae08745Sheppo 		kmem_free(mem_p, alloc_len);
38071ae08745Sheppo 
38081ae08745Sheppo 	return (rv);
38091ae08745Sheppo }
38101ae08745Sheppo 
38111ae08745Sheppo /*
38121ae08745Sheppo  * Function:
38130a55fbb7Slm66018  *
38140a55fbb7Slm66018  * Description:
38150a55fbb7Slm66018  *	This is an empty conversion function used by ioctl calls which
38160a55fbb7Slm66018  *	do not need to convert the data being passed in/out to userland
38170a55fbb7Slm66018  */
38180a55fbb7Slm66018 static int
38190a55fbb7Slm66018 vdc_null_copy_func(void *from, void *to, int mode, int dir)
38200a55fbb7Slm66018 {
38210a55fbb7Slm66018 	_NOTE(ARGUNUSED(from))
38220a55fbb7Slm66018 	_NOTE(ARGUNUSED(to))
38230a55fbb7Slm66018 	_NOTE(ARGUNUSED(mode))
38240a55fbb7Slm66018 	_NOTE(ARGUNUSED(dir))
38250a55fbb7Slm66018 
38260a55fbb7Slm66018 	return (0);
38270a55fbb7Slm66018 }
38280a55fbb7Slm66018 
38290a55fbb7Slm66018 /*
38300a55fbb7Slm66018  * Function:
38310a55fbb7Slm66018  *	vdc_get_vtoc_convert()
38320a55fbb7Slm66018  *
38330a55fbb7Slm66018  * Description:
38340a55fbb7Slm66018  *	This routine fakes up the disk info needed for some DKIO ioctls.
38350a55fbb7Slm66018  *
38360a55fbb7Slm66018  * Arguments:
38370a55fbb7Slm66018  *	from	- the buffer containing the data to be copied from
38380a55fbb7Slm66018  *	to	- the buffer to be copied to
38390a55fbb7Slm66018  *	mode	- flags passed to ioctl() call
38400a55fbb7Slm66018  *	dir	- the "direction" of the copy - VD_COPYIN or VD_COPYOUT
38410a55fbb7Slm66018  *
38420a55fbb7Slm66018  * Return Code:
38430a55fbb7Slm66018  *	0	- Success
38440a55fbb7Slm66018  *	ENXIO	- incorrect buffer passed in.
38450a55fbb7Slm66018  *	EFAULT	- ddi_copyxxx routine encountered an error.
38460a55fbb7Slm66018  */
38470a55fbb7Slm66018 static int
38480a55fbb7Slm66018 vdc_get_vtoc_convert(void *from, void *to, int mode, int dir)
38490a55fbb7Slm66018 {
38500a55fbb7Slm66018 	void		*tmp_mem = NULL;
38510a55fbb7Slm66018 	void		*tmp_memp;
38520a55fbb7Slm66018 	struct vtoc	vt;
38530a55fbb7Slm66018 	struct vtoc32	vt32;
38540a55fbb7Slm66018 	int		copy_len = 0;
38550a55fbb7Slm66018 	int		rv = 0;
38560a55fbb7Slm66018 
38570a55fbb7Slm66018 	if (dir != VD_COPYOUT)
38580a55fbb7Slm66018 		return (0);	/* nothing to do */
38590a55fbb7Slm66018 
38600a55fbb7Slm66018 	if ((from == NULL) || (to == NULL))
38610a55fbb7Slm66018 		return (ENXIO);
38620a55fbb7Slm66018 
38630a55fbb7Slm66018 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32)
38640a55fbb7Slm66018 		copy_len = sizeof (struct vtoc32);
38650a55fbb7Slm66018 	else
38660a55fbb7Slm66018 		copy_len = sizeof (struct vtoc);
38670a55fbb7Slm66018 
38680a55fbb7Slm66018 	tmp_mem = kmem_alloc(copy_len, KM_SLEEP);
38690a55fbb7Slm66018 
38700a55fbb7Slm66018 	VD_VTOC2VTOC((vd_vtoc_t *)from, &vt);
38710a55fbb7Slm66018 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
38720a55fbb7Slm66018 		vtoctovtoc32(vt, vt32);
38730a55fbb7Slm66018 		tmp_memp = &vt32;
38740a55fbb7Slm66018 	} else {
38750a55fbb7Slm66018 		tmp_memp = &vt;
38760a55fbb7Slm66018 	}
38770a55fbb7Slm66018 	rv = ddi_copyout(tmp_memp, to, copy_len, mode);
38780a55fbb7Slm66018 	if (rv != 0)
38790a55fbb7Slm66018 		rv = EFAULT;
38800a55fbb7Slm66018 
38810a55fbb7Slm66018 	kmem_free(tmp_mem, copy_len);
38820a55fbb7Slm66018 	return (rv);
38830a55fbb7Slm66018 }
38840a55fbb7Slm66018 
38850a55fbb7Slm66018 /*
38860a55fbb7Slm66018  * Function:
38870a55fbb7Slm66018  *	vdc_set_vtoc_convert()
38880a55fbb7Slm66018  *
38890a55fbb7Slm66018  * Description:
38900a55fbb7Slm66018  *
38910a55fbb7Slm66018  * Arguments:
38920a55fbb7Slm66018  *	from	- Buffer with data
38930a55fbb7Slm66018  *	to	- Buffer where data is to be copied to
38940a55fbb7Slm66018  *	mode	- flags passed to ioctl
38950a55fbb7Slm66018  *	dir	- direction of copy (in or out)
38960a55fbb7Slm66018  *
38970a55fbb7Slm66018  * Return Code:
38980a55fbb7Slm66018  *	0	- Success
38990a55fbb7Slm66018  *	ENXIO	- Invalid buffer passed in
39000a55fbb7Slm66018  *	EFAULT	- ddi_copyin of data failed
39010a55fbb7Slm66018  */
39020a55fbb7Slm66018 static int
39030a55fbb7Slm66018 vdc_set_vtoc_convert(void *from, void *to, int mode, int dir)
39040a55fbb7Slm66018 {
39050a55fbb7Slm66018 	void		*tmp_mem = NULL;
39060a55fbb7Slm66018 	struct vtoc	vt;
39070a55fbb7Slm66018 	struct vtoc	*vtp = &vt;
39080a55fbb7Slm66018 	vd_vtoc_t	vtvd;
39090a55fbb7Slm66018 	int		copy_len = 0;
39100a55fbb7Slm66018 	int		rv = 0;
39110a55fbb7Slm66018 
39120a55fbb7Slm66018 	if (dir != VD_COPYIN)
39130a55fbb7Slm66018 		return (0);	/* nothing to do */
39140a55fbb7Slm66018 
39150a55fbb7Slm66018 	if ((from == NULL) || (to == NULL))
39160a55fbb7Slm66018 		return (ENXIO);
39170a55fbb7Slm66018 
39180a55fbb7Slm66018 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32)
39190a55fbb7Slm66018 		copy_len = sizeof (struct vtoc32);
39200a55fbb7Slm66018 	else
39210a55fbb7Slm66018 		copy_len = sizeof (struct vtoc);
39220a55fbb7Slm66018 
39230a55fbb7Slm66018 	tmp_mem = kmem_alloc(copy_len, KM_SLEEP);
39240a55fbb7Slm66018 
39250a55fbb7Slm66018 	rv = ddi_copyin(from, tmp_mem, copy_len, mode);
39260a55fbb7Slm66018 	if (rv != 0) {
39270a55fbb7Slm66018 		kmem_free(tmp_mem, copy_len);
39280a55fbb7Slm66018 		return (EFAULT);
39290a55fbb7Slm66018 	}
39300a55fbb7Slm66018 
39310a55fbb7Slm66018 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
39320a55fbb7Slm66018 		vtoc32tovtoc((*(struct vtoc32 *)tmp_mem), vt);
39330a55fbb7Slm66018 	} else {
39340a55fbb7Slm66018 		vtp = tmp_mem;
39350a55fbb7Slm66018 	}
39360a55fbb7Slm66018 
39370a55fbb7Slm66018 	VTOC2VD_VTOC(vtp, &vtvd);
39380a55fbb7Slm66018 	bcopy(&vtvd, to, sizeof (vd_vtoc_t));
39390a55fbb7Slm66018 	kmem_free(tmp_mem, copy_len);
39400a55fbb7Slm66018 
39410a55fbb7Slm66018 	return (0);
39420a55fbb7Slm66018 }
39430a55fbb7Slm66018 
39440a55fbb7Slm66018 /*
39450a55fbb7Slm66018  * Function:
39460a55fbb7Slm66018  *	vdc_get_geom_convert()
39470a55fbb7Slm66018  *
39480a55fbb7Slm66018  * Description:
39490a55fbb7Slm66018  *
39500a55fbb7Slm66018  * Arguments:
39510a55fbb7Slm66018  *	from	- Buffer with data
39520a55fbb7Slm66018  *	to	- Buffer where data is to be copied to
39530a55fbb7Slm66018  *	mode	- flags passed to ioctl
39540a55fbb7Slm66018  *	dir	- direction of copy (in or out)
39550a55fbb7Slm66018  *
39560a55fbb7Slm66018  * Return Code:
39570a55fbb7Slm66018  *	0	- Success
39580a55fbb7Slm66018  *	ENXIO	- Invalid buffer passed in
39590a55fbb7Slm66018  *	EFAULT	- ddi_copyin of data failed
39600a55fbb7Slm66018  */
39610a55fbb7Slm66018 static int
39620a55fbb7Slm66018 vdc_get_geom_convert(void *from, void *to, int mode, int dir)
39630a55fbb7Slm66018 {
39640a55fbb7Slm66018 	struct dk_geom	geom;
39650a55fbb7Slm66018 	int	copy_len = sizeof (struct dk_geom);
39660a55fbb7Slm66018 	int	rv = 0;
39670a55fbb7Slm66018 
39680a55fbb7Slm66018 	if (dir != VD_COPYOUT)
39690a55fbb7Slm66018 		return (0);	/* nothing to do */
39700a55fbb7Slm66018 
39710a55fbb7Slm66018 	if ((from == NULL) || (to == NULL))
39720a55fbb7Slm66018 		return (ENXIO);
39730a55fbb7Slm66018 
39740a55fbb7Slm66018 	VD_GEOM2DK_GEOM((vd_geom_t *)from, &geom);
39750a55fbb7Slm66018 	rv = ddi_copyout(&geom, to, copy_len, mode);
39760a55fbb7Slm66018 	if (rv != 0)
39770a55fbb7Slm66018 		rv = EFAULT;
39780a55fbb7Slm66018 
39790a55fbb7Slm66018 	return (rv);
39800a55fbb7Slm66018 }
39810a55fbb7Slm66018 
39820a55fbb7Slm66018 /*
39830a55fbb7Slm66018  * Function:
39840a55fbb7Slm66018  *	vdc_set_geom_convert()
39850a55fbb7Slm66018  *
39860a55fbb7Slm66018  * Description:
39870a55fbb7Slm66018  *	This routine performs the necessary convertions from the DKIOCSVTOC
39880a55fbb7Slm66018  *	Solaris structure to the format defined in FWARC 2006/195
39890a55fbb7Slm66018  *
39900a55fbb7Slm66018  * Arguments:
39910a55fbb7Slm66018  *	from	- Buffer with data
39920a55fbb7Slm66018  *	to	- Buffer where data is to be copied to
39930a55fbb7Slm66018  *	mode	- flags passed to ioctl
39940a55fbb7Slm66018  *	dir	- direction of copy (in or out)
39950a55fbb7Slm66018  *
39960a55fbb7Slm66018  * Return Code:
39970a55fbb7Slm66018  *	0	- Success
39980a55fbb7Slm66018  *	ENXIO	- Invalid buffer passed in
39990a55fbb7Slm66018  *	EFAULT	- ddi_copyin of data failed
40000a55fbb7Slm66018  */
40010a55fbb7Slm66018 static int
40020a55fbb7Slm66018 vdc_set_geom_convert(void *from, void *to, int mode, int dir)
40030a55fbb7Slm66018 {
40040a55fbb7Slm66018 	vd_geom_t	vdgeom;
40050a55fbb7Slm66018 	void		*tmp_mem = NULL;
40060a55fbb7Slm66018 	int		copy_len = sizeof (struct dk_geom);
40070a55fbb7Slm66018 	int		rv = 0;
40080a55fbb7Slm66018 
40090a55fbb7Slm66018 	if (dir != VD_COPYIN)
40100a55fbb7Slm66018 		return (0);	/* nothing to do */
40110a55fbb7Slm66018 
40120a55fbb7Slm66018 	if ((from == NULL) || (to == NULL))
40130a55fbb7Slm66018 		return (ENXIO);
40140a55fbb7Slm66018 
40150a55fbb7Slm66018 	tmp_mem = kmem_alloc(copy_len, KM_SLEEP);
40160a55fbb7Slm66018 
40170a55fbb7Slm66018 	rv = ddi_copyin(from, tmp_mem, copy_len, mode);
40180a55fbb7Slm66018 	if (rv != 0) {
40190a55fbb7Slm66018 		kmem_free(tmp_mem, copy_len);
40200a55fbb7Slm66018 		return (EFAULT);
40210a55fbb7Slm66018 	}
40220a55fbb7Slm66018 	DK_GEOM2VD_GEOM((struct dk_geom *)tmp_mem, &vdgeom);
40230a55fbb7Slm66018 	bcopy(&vdgeom, to, sizeof (vdgeom));
40240a55fbb7Slm66018 	kmem_free(tmp_mem, copy_len);
40250a55fbb7Slm66018 
40260a55fbb7Slm66018 	return (0);
40270a55fbb7Slm66018 }
40280a55fbb7Slm66018 
40290a55fbb7Slm66018 /*
40300a55fbb7Slm66018  * Function:
40311ae08745Sheppo  *	vdc_create_fake_geometry()
40321ae08745Sheppo  *
40331ae08745Sheppo  * Description:
40341ae08745Sheppo  *	This routine fakes up the disk info needed for some DKIO ioctls.
40351ae08745Sheppo  *		- DKIOCINFO
40361ae08745Sheppo  *		- DKIOCGMEDIAINFO
40371ae08745Sheppo  *
40381ae08745Sheppo  *	[ just like lofi(7D) and ramdisk(7D) ]
40391ae08745Sheppo  *
40401ae08745Sheppo  * Arguments:
40411ae08745Sheppo  *	vdc	- soft state pointer for this instance of the device driver.
40421ae08745Sheppo  *
40431ae08745Sheppo  * Return Code:
40441ae08745Sheppo  *	0	- Success
40451ae08745Sheppo  */
40461ae08745Sheppo static int
40471ae08745Sheppo vdc_create_fake_geometry(vdc_t *vdc)
40481ae08745Sheppo {
40490a55fbb7Slm66018 	int	rv = 0;
40500a55fbb7Slm66018 
40511ae08745Sheppo 	ASSERT(vdc != NULL);
40521ae08745Sheppo 
40531ae08745Sheppo 	/*
40541ae08745Sheppo 	 * DKIOCINFO support
40551ae08745Sheppo 	 */
40561ae08745Sheppo 	vdc->cinfo = kmem_zalloc(sizeof (struct dk_cinfo), KM_SLEEP);
40571ae08745Sheppo 
40581ae08745Sheppo 	(void) strcpy(vdc->cinfo->dki_cname, VDC_DRIVER_NAME);
40591ae08745Sheppo 	(void) strcpy(vdc->cinfo->dki_dname, VDC_DRIVER_NAME);
4060*8e6a2a04Slm66018 	/* max_xfer_sz is #blocks so we don't need to divide by DEV_BSIZE */
4061*8e6a2a04Slm66018 	vdc->cinfo->dki_maxtransfer = vdc->max_xfer_sz;
40621ae08745Sheppo 	vdc->cinfo->dki_ctype = DKC_SCSI_CCS;
40631ae08745Sheppo 	vdc->cinfo->dki_flags = DKI_FMTVOL;
40641ae08745Sheppo 	vdc->cinfo->dki_cnum = 0;
40651ae08745Sheppo 	vdc->cinfo->dki_addr = 0;
40661ae08745Sheppo 	vdc->cinfo->dki_space = 0;
40671ae08745Sheppo 	vdc->cinfo->dki_prio = 0;
40681ae08745Sheppo 	vdc->cinfo->dki_vec = 0;
40691ae08745Sheppo 	vdc->cinfo->dki_unit = vdc->instance;
40701ae08745Sheppo 	vdc->cinfo->dki_slave = 0;
40711ae08745Sheppo 	/*
40721ae08745Sheppo 	 * The partition number will be created on the fly depending on the
40731ae08745Sheppo 	 * actual slice (i.e. minor node) that is used to request the data.
40741ae08745Sheppo 	 */
40751ae08745Sheppo 	vdc->cinfo->dki_partition = 0;
40761ae08745Sheppo 
40771ae08745Sheppo 	/*
40781ae08745Sheppo 	 * DKIOCGMEDIAINFO support
40791ae08745Sheppo 	 */
40800a55fbb7Slm66018 	if (vdc->minfo == NULL)
40811ae08745Sheppo 		vdc->minfo = kmem_zalloc(sizeof (struct dk_minfo), KM_SLEEP);
40821ae08745Sheppo 	vdc->minfo->dki_media_type = DK_FIXED_DISK;
40831ae08745Sheppo 	vdc->minfo->dki_capacity = 1;
40841ae08745Sheppo 	vdc->minfo->dki_lbsize = DEV_BSIZE;
40851ae08745Sheppo 
40860a55fbb7Slm66018 	return (rv);
40870a55fbb7Slm66018 }
40880a55fbb7Slm66018 
40890a55fbb7Slm66018 /*
40900a55fbb7Slm66018  * Function:
40910a55fbb7Slm66018  *	vdc_setup_disk_layout()
40920a55fbb7Slm66018  *
40930a55fbb7Slm66018  * Description:
40940a55fbb7Slm66018  *	This routine discovers all the necessary details about the "disk"
40950a55fbb7Slm66018  *	by requesting the data that is available from the vDisk server and by
40960a55fbb7Slm66018  *	faking up the rest of the data.
40970a55fbb7Slm66018  *
40980a55fbb7Slm66018  * Arguments:
40990a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
41000a55fbb7Slm66018  *
41010a55fbb7Slm66018  * Return Code:
41020a55fbb7Slm66018  *	0	- Success
41030a55fbb7Slm66018  */
41040a55fbb7Slm66018 static int
41050a55fbb7Slm66018 vdc_setup_disk_layout(vdc_t *vdc)
41060a55fbb7Slm66018 {
41070a55fbb7Slm66018 	dev_t	dev;
41080a55fbb7Slm66018 	int	slice = 0;
41090a55fbb7Slm66018 	int	rv;
41100a55fbb7Slm66018 
41110a55fbb7Slm66018 	ASSERT(vdc != NULL);
41120a55fbb7Slm66018 
41130a55fbb7Slm66018 	rv = vdc_create_fake_geometry(vdc);
41140a55fbb7Slm66018 	if (rv != 0) {
41150a55fbb7Slm66018 		cmn_err(CE_NOTE, "[%d] Failed to create disk geometry (err%d)",
41160a55fbb7Slm66018 				vdc->instance, rv);
41170a55fbb7Slm66018 	}
41180a55fbb7Slm66018 
41190a55fbb7Slm66018 	if (vdc->vtoc == NULL)
41200a55fbb7Slm66018 		vdc->vtoc = kmem_zalloc(sizeof (struct vtoc), KM_SLEEP);
41210a55fbb7Slm66018 
41220a55fbb7Slm66018 	dev = makedevice(ddi_driver_major(vdc->dip),
41230a55fbb7Slm66018 				VD_MAKE_DEV(vdc->instance, 0));
41240a55fbb7Slm66018 	rv = vd_process_ioctl(dev, DKIOCGVTOC, (caddr_t)vdc->vtoc, FKIOCTL);
41250a55fbb7Slm66018 	if (rv) {
41260a55fbb7Slm66018 		cmn_err(CE_NOTE, "[%d] Failed to get VTOC (err=%d)",
41270a55fbb7Slm66018 				vdc->instance, rv);
41280a55fbb7Slm66018 		return (rv);
41290a55fbb7Slm66018 	}
41300a55fbb7Slm66018 
41310a55fbb7Slm66018 	/*
41320a55fbb7Slm66018 	 * Read disk label from start of disk
41330a55fbb7Slm66018 	 */
41340a55fbb7Slm66018 	vdc->label = kmem_zalloc(DK_LABEL_SIZE, KM_SLEEP);
41350a55fbb7Slm66018 
41360a55fbb7Slm66018 	/*
41370a55fbb7Slm66018 	 * find the slice that represents the entire "disk" and use that to
41380a55fbb7Slm66018 	 * read the disk label. The convention in Solaris is that slice 2
41390a55fbb7Slm66018 	 * represents the whole disk so we check that it is otherwise we
41400a55fbb7Slm66018 	 * default to slice 0
41410a55fbb7Slm66018 	 */
41420a55fbb7Slm66018 	if ((vdc->vdisk_type == VD_DISK_TYPE_DISK) &&
41430a55fbb7Slm66018 	    (vdc->vtoc->v_part[2].p_tag == V_BACKUP)) {
41440a55fbb7Slm66018 		slice = 2;
41450a55fbb7Slm66018 	} else {
41460a55fbb7Slm66018 		slice = 0;
41470a55fbb7Slm66018 	}
41480a55fbb7Slm66018 	rv = vdc_populate_descriptor(vdc, (caddr_t)vdc->label, DK_LABEL_SIZE,
41490a55fbb7Slm66018 			VD_OP_BREAD, 0, slice);
41500a55fbb7Slm66018 
41510a55fbb7Slm66018 	return (rv);
41521ae08745Sheppo }
4153