xref: /titanic_53/usr/src/uts/sun4v/io/vdc.c (revision 0a55fbb79ee31ed09f84a9ae28e9747bc23f4a08)
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 */
118*0a55fbb7Slm66018 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);
124*0a55fbb7Slm66018 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);
131*0a55fbb7Slm66018 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);
136*0a55fbb7Slm66018 static boolean_t	vdc_is_supported_version(vio_ver_msg_t *ver_msg);
1371ae08745Sheppo 
138*0a55fbb7Slm66018 /* processing incoming messages from vDisk server */
1391ae08745Sheppo static void	vdc_process_msg_thread(vdc_t *vdc);
1401ae08745Sheppo static void	vdc_process_msg(void *arg);
141*0a55fbb7Slm66018 static void	vdc_do_process_msg(vdc_t *vdc);
142*0a55fbb7Slm66018 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);
146*0a55fbb7Slm66018 static int	vdc_handle_ver_msg(vdc_t *vdc, vio_ver_msg_t *ver_msg);
147*0a55fbb7Slm66018 static int	vdc_handle_attr_msg(vdc_t *vdc, vd_attr_msg_t *attr_msg);
148*0a55fbb7Slm66018 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);
164*0a55fbb7Slm66018 static int	vdc_setup_disk_layout(vdc_t *vdc);
165*0a55fbb7Slm66018 static int	vdc_null_copy_func(void *from, void *to, int mode, int dir);
166*0a55fbb7Slm66018 static int	vdc_get_vtoc_convert(void *from, void *to, int mode, int dir);
167*0a55fbb7Slm66018 static int	vdc_set_vtoc_convert(void *from, void *to, int mode, int dir);
168*0a55fbb7Slm66018 static int	vdc_get_geom_convert(void *from, void *to, int mode, int dir);
169*0a55fbb7Slm66018 static int	vdc_set_geom_convert(void *from, void *to, int mode, int dir);
170*0a55fbb7Slm66018 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 
187*0a55fbb7Slm66018 /*
188*0a55fbb7Slm66018  * Supported vDisk protocol version pairs.
189*0a55fbb7Slm66018  *
190*0a55fbb7Slm66018  * The first array entry is the latest and preferred version.
191*0a55fbb7Slm66018  */
192*0a55fbb7Slm66018 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 
414*0a55fbb7Slm66018 	if (vdc->label)
415*0a55fbb7Slm66018 		kmem_free(vdc->label, DK_LABEL_SIZE);
416*0a55fbb7Slm66018 
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;
4651ae08745Sheppo 	vdc->max_xfer_sz = VD_MAX_BLOCK_SIZE / 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);
526*0a55fbb7Slm66018 				vdc_init_handshake_negotiation(vdc);
5271ae08745Sheppo 				retries++;
5281ae08745Sheppo 			}
5291ae08745Sheppo 		}
5301ae08745Sheppo 	}
5311ae08745Sheppo 	mutex_exit(&vdc->attach_lock);
5321ae08745Sheppo 
533*0a55fbb7Slm66018 	/*
534*0a55fbb7Slm66018 	 * Once the handshake is complete, we can use the DRing to send
535*0a55fbb7Slm66018 	 * requests to the vDisk server to calculate the geometry and
536*0a55fbb7Slm66018 	 * VTOC of the "disk"
537*0a55fbb7Slm66018 	 */
538*0a55fbb7Slm66018 	status = vdc_setup_disk_layout(vdc);
539*0a55fbb7Slm66018 	if (status != 0) {
540*0a55fbb7Slm66018 		cmn_err(CE_NOTE, "[%d] Failed to discover disk layout (err%d)",
541*0a55fbb7Slm66018 				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"
557*0a55fbb7Slm66018 				" 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 	PR0("%s[%d]  Entered.  Built %s %s\n", __func__, ddi_get_instance(dip),
5731ae08745Sheppo 		__DATE__, __TIME__);
5741ae08745Sheppo 
5751ae08745Sheppo 	switch (cmd) {
5761ae08745Sheppo 	case DDI_ATTACH:
5771ae08745Sheppo 		if ((status = vdc_do_attach(dip)) != 0)
5781ae08745Sheppo 			(void) vdc_detach(dip, DDI_DETACH);
5791ae08745Sheppo 		return (status);
5801ae08745Sheppo 	case DDI_RESUME:
5811ae08745Sheppo 		/* nothing to do for this non-device */
5821ae08745Sheppo 		return (DDI_SUCCESS);
5831ae08745Sheppo 	default:
5841ae08745Sheppo 		return (DDI_FAILURE);
5851ae08745Sheppo 	}
5861ae08745Sheppo }
5871ae08745Sheppo 
5881ae08745Sheppo static int
5891ae08745Sheppo vdc_do_ldc_init(vdc_t *vdc)
5901ae08745Sheppo {
5911ae08745Sheppo 	int			status = 0;
5921ae08745Sheppo 	ldc_status_t		ldc_state;
5931ae08745Sheppo 	ldc_attr_t		ldc_attr;
5941ae08745Sheppo 	uint64_t		ldc_id = 0;
5951ae08745Sheppo 	dev_info_t		*dip = NULL;
5961ae08745Sheppo 
5971ae08745Sheppo 	ASSERT(vdc != NULL);
5981ae08745Sheppo 
5991ae08745Sheppo 	dip = vdc->dip;
6001ae08745Sheppo 	vdc->initialized |= VDC_LDC;
6011ae08745Sheppo 
6021ae08745Sheppo 	if ((status = vdc_get_ldc_id(dip, &ldc_id)) != 0) {
6031ae08745Sheppo 		vdc_msg("%s:  Failed to get <ldc_id> property\n", __func__);
6041ae08745Sheppo 		return (EIO);
6051ae08745Sheppo 	}
6061ae08745Sheppo 	vdc->ldc_id = ldc_id;
6071ae08745Sheppo 
6081ae08745Sheppo 	ldc_attr.devclass = LDC_DEV_BLK;
6091ae08745Sheppo 	ldc_attr.instance = vdc->instance;
6101ae08745Sheppo 	ldc_attr.mode = LDC_MODE_UNRELIABLE;	/* unreliable transport */
6111ae08745Sheppo 	ldc_attr.qlen = VD_LDC_QLEN;
6121ae08745Sheppo 
6131ae08745Sheppo 	if ((vdc->initialized & VDC_LDC_INIT) == 0) {
6141ae08745Sheppo 		status = ldc_init(ldc_id, &ldc_attr, &vdc->ldc_handle);
6151ae08745Sheppo 		if (status != 0) {
6161ae08745Sheppo 			cmn_err(CE_NOTE, "[%d] ldc_init(chan %ld) returned %d",
6171ae08745Sheppo 					vdc->instance, ldc_id, status);
6181ae08745Sheppo 			return (status);
6191ae08745Sheppo 		}
6201ae08745Sheppo 		vdc->initialized |= VDC_LDC_INIT;
6211ae08745Sheppo 	}
6221ae08745Sheppo 	status = ldc_status(vdc->ldc_handle, &ldc_state);
6231ae08745Sheppo 	if (status != 0) {
6241ae08745Sheppo 		vdc_msg("Cannot discover LDC status [err=%d].", status);
6251ae08745Sheppo 		return (status);
6261ae08745Sheppo 	}
6271ae08745Sheppo 	vdc->ldc_state = ldc_state;
6281ae08745Sheppo 
6291ae08745Sheppo 	if ((vdc->initialized & VDC_LDC_CB) == 0) {
6301ae08745Sheppo 		status = ldc_reg_callback(vdc->ldc_handle, vdc_handle_cb,
6311ae08745Sheppo 		    (caddr_t)vdc);
6321ae08745Sheppo 		if (status != 0) {
6331ae08745Sheppo 			vdc_msg("%s: ldc_reg_callback()=%d", __func__, status);
6341ae08745Sheppo 			return (status);
6351ae08745Sheppo 		}
6361ae08745Sheppo 		vdc->initialized |= VDC_LDC_CB;
6371ae08745Sheppo 	}
6381ae08745Sheppo 
6391ae08745Sheppo 	vdc->initialized |= VDC_LDC;
6401ae08745Sheppo 
6411ae08745Sheppo 	/*
6421ae08745Sheppo 	 * At this stage we have initialised LDC, we will now try and open
6431ae08745Sheppo 	 * the connection.
6441ae08745Sheppo 	 */
6451ae08745Sheppo 	if (vdc->ldc_state == LDC_INIT) {
6461ae08745Sheppo 		status = ldc_open(vdc->ldc_handle);
6471ae08745Sheppo 		if (status != 0) {
6481ae08745Sheppo 			cmn_err(CE_NOTE, "[%d] ldc_open(chan %ld) returned %d",
6491ae08745Sheppo 					vdc->instance, vdc->ldc_id, status);
6501ae08745Sheppo 			return (status);
6511ae08745Sheppo 		}
6521ae08745Sheppo 		vdc->initialized |= VDC_LDC_OPEN;
6531ae08745Sheppo 	}
6541ae08745Sheppo 
6551ae08745Sheppo 	return (status);
6561ae08745Sheppo }
6571ae08745Sheppo 
6581ae08745Sheppo static int
6591ae08745Sheppo vdc_start_ldc_connection(vdc_t *vdc)
6601ae08745Sheppo {
6611ae08745Sheppo 	int		status = 0;
6621ae08745Sheppo 
6631ae08745Sheppo 	ASSERT(vdc != NULL);
6641ae08745Sheppo 
6651ae08745Sheppo 	mutex_enter(&vdc->lock);
6661ae08745Sheppo 
6671ae08745Sheppo 	if (vdc->ldc_state == LDC_UP) {
6681ae08745Sheppo 		PR0("%s:  LDC is already UP ..\n", __func__);
6691ae08745Sheppo 		mutex_exit(&vdc->lock);
6701ae08745Sheppo 		return (0);
6711ae08745Sheppo 	}
6721ae08745Sheppo 
673*0a55fbb7Slm66018 	status = vdc_do_ldc_up(vdc);
6741ae08745Sheppo 
6751ae08745Sheppo 	PR0("%s[%d] Finished bringing up LDC\n", __func__, vdc->instance);
6761ae08745Sheppo 
6771ae08745Sheppo 	mutex_exit(&vdc->lock);
6781ae08745Sheppo 
6791ae08745Sheppo 	return (status);
6801ae08745Sheppo }
6811ae08745Sheppo 
6821ae08745Sheppo 
6831ae08745Sheppo /*
6841ae08745Sheppo  * Function:
6851ae08745Sheppo  *	vdc_create_device_nodes
6861ae08745Sheppo  *
6871ae08745Sheppo  * Description:
6881ae08745Sheppo  *	This function creates the block and character device nodes under
6891ae08745Sheppo  *	/devices along with the node properties. It is called as part of
6901ae08745Sheppo  *	the attach(9E) of the instance during the handshake with vds after
6911ae08745Sheppo  *	vds has sent the attributes to vdc.
6921ae08745Sheppo  *
6931ae08745Sheppo  *	If the device is of type VD_DISK_TYPE_SLICE then the minor node
6941ae08745Sheppo  *	of 2 is used in keeping with the Solaris convention that slice 2
6951ae08745Sheppo  *	refers to a whole disk. Slices start at 'a'
6961ae08745Sheppo  *
6971ae08745Sheppo  * Parameters:
6981ae08745Sheppo  *	vdc 		- soft state pointer
6991ae08745Sheppo  *
7001ae08745Sheppo  * Return Values
7011ae08745Sheppo  *	0		- Success
7021ae08745Sheppo  *	EIO		- Failed to create node
7031ae08745Sheppo  *	EINVAL		- Unknown type of disk exported
7041ae08745Sheppo  */
7051ae08745Sheppo static int
7061ae08745Sheppo vdc_create_device_nodes(vdc_t *vdc)
7071ae08745Sheppo {
7081ae08745Sheppo 	/* uses NNNN which is OK as long as # of disks <= 10000 */
7091ae08745Sheppo 	char		name[sizeof ("disk@NNNN:s,raw")];
7101ae08745Sheppo 	dev_info_t	*dip = NULL;
7111ae08745Sheppo 	int		instance;
7121ae08745Sheppo 	int		num_slices = 1;
7131ae08745Sheppo 	int		i;
7141ae08745Sheppo 
7151ae08745Sheppo 	ASSERT(vdc != NULL);
7161ae08745Sheppo 
7171ae08745Sheppo 	instance = vdc->instance;
7181ae08745Sheppo 	dip = vdc->dip;
7191ae08745Sheppo 
7201ae08745Sheppo 	switch (vdc->vdisk_type) {
7211ae08745Sheppo 	case VD_DISK_TYPE_DISK:
7221ae08745Sheppo 		num_slices = V_NUMPAR;
7231ae08745Sheppo 		break;
7241ae08745Sheppo 	case VD_DISK_TYPE_SLICE:
7251ae08745Sheppo 		num_slices = 1;
7261ae08745Sheppo 		break;
7271ae08745Sheppo 	case VD_DISK_TYPE_UNK:
7281ae08745Sheppo 	default:
7291ae08745Sheppo 		return (EINVAL);
7301ae08745Sheppo 	}
7311ae08745Sheppo 
7321ae08745Sheppo 	for (i = 0; i < num_slices; i++) {
7331ae08745Sheppo 		(void) snprintf(name, sizeof (name), "%c", 'a' + i);
7341ae08745Sheppo 		if (ddi_create_minor_node(dip, name, S_IFBLK,
7351ae08745Sheppo 		    VD_MAKE_DEV(instance, i), DDI_NT_BLOCK, 0) != DDI_SUCCESS) {
7361ae08745Sheppo 			vdc_msg("%s[%d]: Couldn't add block node %s.",
7371ae08745Sheppo 				__func__, instance, name);
7381ae08745Sheppo 			return (EIO);
7391ae08745Sheppo 		}
7401ae08745Sheppo 
7411ae08745Sheppo 		/* if any device node is created we set this flag */
7421ae08745Sheppo 		vdc->initialized |= VDC_MINOR;
7431ae08745Sheppo 
7441ae08745Sheppo 		(void) snprintf(name, sizeof (name), "%c%s",
7451ae08745Sheppo 			'a' + i, ",raw");
7461ae08745Sheppo 		if (ddi_create_minor_node(dip, name, S_IFCHR,
7471ae08745Sheppo 		    VD_MAKE_DEV(instance, i), DDI_NT_BLOCK, 0) != DDI_SUCCESS) {
7481ae08745Sheppo 			vdc_msg("%s[%d]:  Could not add raw node %s.",
7491ae08745Sheppo 				__func__, instance, name);
7501ae08745Sheppo 			return (EIO);
7511ae08745Sheppo 		}
7521ae08745Sheppo 	}
7531ae08745Sheppo 
7541ae08745Sheppo 	return (0);
7551ae08745Sheppo }
7561ae08745Sheppo 
7571ae08745Sheppo /*
7581ae08745Sheppo  * Function:
7591ae08745Sheppo  *	vdc_create_device_nodes_props
7601ae08745Sheppo  *
7611ae08745Sheppo  * Description:
7621ae08745Sheppo  *	This function creates the block and character device nodes under
7631ae08745Sheppo  *	/devices along with the node properties. It is called as part of
7641ae08745Sheppo  *	the attach(9E) of the instance during the handshake with vds after
7651ae08745Sheppo  *	vds has sent the attributes to vdc.
7661ae08745Sheppo  *
7671ae08745Sheppo  * Parameters:
7681ae08745Sheppo  *	vdc 		- soft state pointer
7691ae08745Sheppo  *
7701ae08745Sheppo  * Return Values
7711ae08745Sheppo  *	0		- Success
7721ae08745Sheppo  *	EIO		- Failed to create device node property
7731ae08745Sheppo  *	EINVAL		- Unknown type of disk exported
7741ae08745Sheppo  */
7751ae08745Sheppo static int
7761ae08745Sheppo vdc_create_device_nodes_props(vdc_t *vdc)
7771ae08745Sheppo {
7781ae08745Sheppo 	dev_info_t	*dip = NULL;
7791ae08745Sheppo 	int		instance;
7801ae08745Sheppo 	int		num_slices = 1;
7811ae08745Sheppo 	int64_t		size = 0;
7821ae08745Sheppo 	dev_t		dev;
7831ae08745Sheppo 	int		rv;
7841ae08745Sheppo 	int		i;
7851ae08745Sheppo 
7861ae08745Sheppo 	ASSERT(vdc != NULL);
7871ae08745Sheppo 
7881ae08745Sheppo 	instance = vdc->instance;
7891ae08745Sheppo 	dip = vdc->dip;
7901ae08745Sheppo 
7911ae08745Sheppo 	if ((vdc->vtoc == NULL) || (vdc->vtoc->v_sanity != VTOC_SANE)) {
7921ae08745Sheppo 		cmn_err(CE_NOTE, "![%d] Could not create device node property."
7931ae08745Sheppo 				" No VTOC available", instance);
7941ae08745Sheppo 		return (ENXIO);
7951ae08745Sheppo 	}
7961ae08745Sheppo 
7971ae08745Sheppo 	switch (vdc->vdisk_type) {
7981ae08745Sheppo 	case VD_DISK_TYPE_DISK:
7991ae08745Sheppo 		num_slices = V_NUMPAR;
8001ae08745Sheppo 		break;
8011ae08745Sheppo 	case VD_DISK_TYPE_SLICE:
8021ae08745Sheppo 		num_slices = 1;
8031ae08745Sheppo 		break;
8041ae08745Sheppo 	case VD_DISK_TYPE_UNK:
8051ae08745Sheppo 	default:
8061ae08745Sheppo 		return (EINVAL);
8071ae08745Sheppo 	}
8081ae08745Sheppo 
8091ae08745Sheppo 	for (i = 0; i < num_slices; i++) {
8101ae08745Sheppo 		dev = makedevice(ddi_driver_major(dip),
8111ae08745Sheppo 			VD_MAKE_DEV(instance, i));
8121ae08745Sheppo 
8131ae08745Sheppo 		size = vdc->vtoc->v_part[i].p_size * vdc->vtoc->v_sectorsz;
8141ae08745Sheppo 		PR0("%s[%d] sz %ld (%ld Mb)  p_size %lx\n",
8151ae08745Sheppo 				__func__, instance, size, size / (1024 * 1024),
8161ae08745Sheppo 				vdc->vtoc->v_part[i].p_size);
8171ae08745Sheppo 
8181ae08745Sheppo 		rv = ddi_prop_update_int64(dev, dip, VDC_SIZE_PROP_NAME, size);
8191ae08745Sheppo 		if (rv != DDI_PROP_SUCCESS) {
8201ae08745Sheppo 			vdc_msg("%s:(%d): Couldn't add \"%s\" [%d]\n",
8211ae08745Sheppo 				__func__, instance, VDC_SIZE_PROP_NAME, size);
8221ae08745Sheppo 			return (EIO);
8231ae08745Sheppo 		}
8241ae08745Sheppo 
8251ae08745Sheppo 		rv = ddi_prop_update_int64(dev, dip, VDC_NBLOCKS_PROP_NAME,
8261ae08745Sheppo 			lbtodb(size));
8271ae08745Sheppo 		if (rv != DDI_PROP_SUCCESS) {
8281ae08745Sheppo 			vdc_msg("%s:(%d): Couldn't add \"%s\" [%d]\n", __func__,
8291ae08745Sheppo 				instance, VDC_NBLOCKS_PROP_NAME, lbtodb(size));
8301ae08745Sheppo 			return (EIO);
8311ae08745Sheppo 		}
8321ae08745Sheppo 	}
8331ae08745Sheppo 
8341ae08745Sheppo 	return (0);
8351ae08745Sheppo }
8361ae08745Sheppo 
8371ae08745Sheppo static int
8381ae08745Sheppo vdc_open(dev_t *dev, int flag, int otyp, cred_t *cred)
8391ae08745Sheppo {
8401ae08745Sheppo 	_NOTE(ARGUNUSED(cred))
8411ae08745Sheppo 
8421ae08745Sheppo 	int		instance;
8431ae08745Sheppo 	vdc_t		*vdc;
8441ae08745Sheppo 
8451ae08745Sheppo 	ASSERT(dev != NULL);
8461ae08745Sheppo 	instance = SDUNIT(getminor(*dev));
8471ae08745Sheppo 
8481ae08745Sheppo 	PR0("%s[%d] minor = %d flag = %x, otyp = %x\n", __func__, instance,
8491ae08745Sheppo 			getminor(*dev), flag, otyp);
8501ae08745Sheppo 
8511ae08745Sheppo 	if ((otyp != OTYP_CHR) && (otyp != OTYP_BLK))
8521ae08745Sheppo 		return (EINVAL);
8531ae08745Sheppo 
8541ae08745Sheppo 	if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) {
8551ae08745Sheppo 		vdc_msg("%s[%d] Could not get state.", __func__, instance);
8561ae08745Sheppo 		return (ENXIO);
8571ae08745Sheppo 	}
8581ae08745Sheppo 
8591ae08745Sheppo 	/*
8601ae08745Sheppo 	 * Check to see if we can communicate with vds
8611ae08745Sheppo 	 */
862*0a55fbb7Slm66018 	if (!vdc_is_able_to_tx_data(vdc, flag)) {
8631ae08745Sheppo 		PR0("%s[%d] Not ready to transmit data\n", __func__, instance);
8641ae08745Sheppo 		return (ENOLINK);
8651ae08745Sheppo 	}
8661ae08745Sheppo 
8671ae08745Sheppo 	mutex_enter(&vdc->lock);
8681ae08745Sheppo 	vdc->open++;
8691ae08745Sheppo 	mutex_exit(&vdc->lock);
8701ae08745Sheppo 
8711ae08745Sheppo 	return (0);
8721ae08745Sheppo }
8731ae08745Sheppo 
8741ae08745Sheppo static int
8751ae08745Sheppo vdc_close(dev_t dev, int flag, int otyp, cred_t *cred)
8761ae08745Sheppo {
8771ae08745Sheppo 	_NOTE(ARGUNUSED(cred))
8781ae08745Sheppo 
8791ae08745Sheppo 	int	instance;
8801ae08745Sheppo 	vdc_t	*vdc;
8811ae08745Sheppo 
8821ae08745Sheppo 	instance = SDUNIT(getminor(dev));
8831ae08745Sheppo 
8841ae08745Sheppo 	PR0("%s[%d] flag = %x, otyp = %x\n", __func__, instance, flag, otyp);
8851ae08745Sheppo 
8861ae08745Sheppo 	if ((otyp != OTYP_CHR) && (otyp != OTYP_BLK))
8871ae08745Sheppo 		return (EINVAL);
8881ae08745Sheppo 
8891ae08745Sheppo 	if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) {
8901ae08745Sheppo 		vdc_msg("%s[%d] Could not get state.", __func__, instance);
8911ae08745Sheppo 		return (ENXIO);
8921ae08745Sheppo 	}
8931ae08745Sheppo 
8941ae08745Sheppo 	/*
8951ae08745Sheppo 	 * Check to see if we can communicate with vds
8961ae08745Sheppo 	 */
897*0a55fbb7Slm66018 	if (!vdc_is_able_to_tx_data(vdc, 0)) {
8981ae08745Sheppo 		PR0("%s[%d] Not ready to transmit data\n", __func__, instance);
8991ae08745Sheppo 		return (ETIMEDOUT);
9001ae08745Sheppo 	}
9011ae08745Sheppo 
9021ae08745Sheppo 	if (vdc->dkio_flush_pending) {
9031ae08745Sheppo 		PR0("%s[%d]: Cannot detach: %d outstanding DKIO flushes",
9041ae08745Sheppo 			__func__, instance, vdc->dkio_flush_pending);
9051ae08745Sheppo 		return (EBUSY);
9061ae08745Sheppo 	}
9071ae08745Sheppo 
9081ae08745Sheppo 	/*
9091ae08745Sheppo 	 * Should not need the mutex here, since the framework should protect
9101ae08745Sheppo 	 * against more opens on this device, but just in case.
9111ae08745Sheppo 	 */
9121ae08745Sheppo 	mutex_enter(&vdc->lock);
9131ae08745Sheppo 	vdc->open--;
9141ae08745Sheppo 	mutex_exit(&vdc->lock);
9151ae08745Sheppo 
9161ae08745Sheppo 	return (0);
9171ae08745Sheppo }
9181ae08745Sheppo 
9191ae08745Sheppo static int
9201ae08745Sheppo vdc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
9211ae08745Sheppo {
9221ae08745Sheppo 	_NOTE(ARGUNUSED(credp))
9231ae08745Sheppo 	_NOTE(ARGUNUSED(rvalp))
9241ae08745Sheppo 
9251ae08745Sheppo 	return (vd_process_ioctl(dev, cmd, (caddr_t)arg, mode));
9261ae08745Sheppo }
9271ae08745Sheppo 
9281ae08745Sheppo static int
9291ae08745Sheppo vdc_print(dev_t dev, char *str)
9301ae08745Sheppo {
9311ae08745Sheppo 	cmn_err(CE_NOTE, "vdc%d:  %s", SDUNIT(getminor(dev)), str);
9321ae08745Sheppo 	return (0);
9331ae08745Sheppo }
9341ae08745Sheppo 
9351ae08745Sheppo static int
9361ae08745Sheppo vdc_dump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk)
9371ae08745Sheppo {
9381ae08745Sheppo 	int			rv = 0;
9391ae08745Sheppo 	size_t			nbytes = (nblk * DEV_BSIZE);
9401ae08745Sheppo 	int			instance = SDUNIT(getminor(dev));
9411ae08745Sheppo 	vdc_t			*vdc;
9421ae08745Sheppo 
9431ae08745Sheppo 	if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) {
9441ae08745Sheppo 		vdc_msg("%s (%d):  Could not get state.", __func__, instance);
9451ae08745Sheppo 		return (ENXIO);
9461ae08745Sheppo 	}
9471ae08745Sheppo 
9481ae08745Sheppo 	rv = vdc_populate_descriptor(vdc, addr, nbytes, VD_OP_BWRITE,
9491ae08745Sheppo 					blkno, SDPART(getminor(dev)));
9501ae08745Sheppo 
9511ae08745Sheppo 	PR1("%s: status=%d\n", __func__, rv);
9521ae08745Sheppo 
9531ae08745Sheppo 	return (rv);
9541ae08745Sheppo }
9551ae08745Sheppo 
9561ae08745Sheppo /* -------------------------------------------------------------------------- */
9571ae08745Sheppo 
9581ae08745Sheppo /*
9591ae08745Sheppo  * Disk access routines
9601ae08745Sheppo  *
9611ae08745Sheppo  */
9621ae08745Sheppo 
9631ae08745Sheppo /*
9641ae08745Sheppo  * vdc_strategy()
9651ae08745Sheppo  *
9661ae08745Sheppo  * Return Value:
9671ae08745Sheppo  *	0:	As per strategy(9E), the strategy() function must return 0
9681ae08745Sheppo  *		[ bioerror(9f) sets b_flags to the proper error code ]
9691ae08745Sheppo  */
9701ae08745Sheppo static int
9711ae08745Sheppo vdc_strategy(struct buf *buf)
9721ae08745Sheppo {
9731ae08745Sheppo 	int		rv = -1;
9741ae08745Sheppo 	vdc_t		*vdc = NULL;
9751ae08745Sheppo 	int		instance = SDUNIT(getminor(buf->b_edev));
9761ae08745Sheppo 	int	op = (buf->b_flags & B_READ) ? VD_OP_BREAD : VD_OP_BWRITE;
9771ae08745Sheppo 
9781ae08745Sheppo 	PR1("%s: %s %ld bytes at block %ld : b_addr=0x%p",
9791ae08745Sheppo 	    __func__, (buf->b_flags & B_READ) ? "Read" : "Write",
9801ae08745Sheppo 	    buf->b_bcount, buf->b_lblkno, buf->b_un.b_addr);
9811ae08745Sheppo 
9821ae08745Sheppo 	if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) {
9831ae08745Sheppo 		vdc_msg("%s[%d]:  Could not get state.", __func__, instance);
9841ae08745Sheppo 		bioerror(buf, ENXIO);
9851ae08745Sheppo 		biodone(buf);
9861ae08745Sheppo 		return (0);
9871ae08745Sheppo 	}
9881ae08745Sheppo 
9891ae08745Sheppo 	ASSERT(buf->b_bcount <= (vdc->max_xfer_sz * vdc->block_size));
9901ae08745Sheppo 
991*0a55fbb7Slm66018 	if (!vdc_is_able_to_tx_data(vdc, O_NONBLOCK)) {
9921ae08745Sheppo 		vdc_msg("%s: Not ready to transmit data", __func__);
9931ae08745Sheppo 		bioerror(buf, ENXIO);
9941ae08745Sheppo 		biodone(buf);
9951ae08745Sheppo 		return (0);
9961ae08745Sheppo 	}
9971ae08745Sheppo 	bp_mapin(buf);
9981ae08745Sheppo 
9991ae08745Sheppo 	rv = vdc_populate_descriptor(vdc, buf->b_un.b_addr, buf->b_bcount, op,
10001ae08745Sheppo 			buf->b_lblkno, SDPART(getminor(buf->b_edev)));
10011ae08745Sheppo 
10021ae08745Sheppo 	PR1("%s: status=%d", __func__, rv);
10031ae08745Sheppo 	bioerror(buf, rv);
10041ae08745Sheppo 	biodone(buf);
10051ae08745Sheppo 	return (0);
10061ae08745Sheppo }
10071ae08745Sheppo 
10081ae08745Sheppo 
10091ae08745Sheppo static int
10101ae08745Sheppo vdc_read(dev_t dev, struct uio *uio, cred_t *cred)
10111ae08745Sheppo {
10121ae08745Sheppo 	_NOTE(ARGUNUSED(cred))
10131ae08745Sheppo 
10141ae08745Sheppo 	PR1("vdc_read():  Entered");
10151ae08745Sheppo 	return (physio(vdc_strategy, NULL, dev, B_READ, minphys, uio));
10161ae08745Sheppo }
10171ae08745Sheppo 
10181ae08745Sheppo static int
10191ae08745Sheppo vdc_write(dev_t dev, struct uio *uio, cred_t *cred)
10201ae08745Sheppo {
10211ae08745Sheppo 	_NOTE(ARGUNUSED(cred))
10221ae08745Sheppo 
10231ae08745Sheppo 	PR1("vdc_write():  Entered");
10241ae08745Sheppo 	return (physio(vdc_strategy, NULL, dev, B_WRITE, minphys, uio));
10251ae08745Sheppo }
10261ae08745Sheppo 
10271ae08745Sheppo static int
10281ae08745Sheppo vdc_aread(dev_t dev, struct aio_req *aio, cred_t *cred)
10291ae08745Sheppo {
10301ae08745Sheppo 	_NOTE(ARGUNUSED(cred))
10311ae08745Sheppo 
10321ae08745Sheppo 	PR1("vdc_aread():  Entered");
10331ae08745Sheppo 	return (aphysio(vdc_strategy, anocancel, dev, B_READ, minphys, aio));
10341ae08745Sheppo }
10351ae08745Sheppo 
10361ae08745Sheppo static int
10371ae08745Sheppo vdc_awrite(dev_t dev, struct aio_req *aio, cred_t *cred)
10381ae08745Sheppo {
10391ae08745Sheppo 	_NOTE(ARGUNUSED(cred))
10401ae08745Sheppo 
10411ae08745Sheppo 	PR1("vdc_awrite():  Entered");
10421ae08745Sheppo 	return (aphysio(vdc_strategy, anocancel, dev, B_WRITE, minphys, aio));
10431ae08745Sheppo }
10441ae08745Sheppo 
10451ae08745Sheppo 
10461ae08745Sheppo /* -------------------------------------------------------------------------- */
10471ae08745Sheppo 
10481ae08745Sheppo /*
10491ae08745Sheppo  * Handshake support
10501ae08745Sheppo  */
10511ae08745Sheppo 
10521ae08745Sheppo /*
10531ae08745Sheppo  * vdc_init_handshake_negotiation
10541ae08745Sheppo  *
10551ae08745Sheppo  * Description:
10561ae08745Sheppo  *	This function is called to trigger the handshake negotiations between
10571ae08745Sheppo  *	the client (vdc) and the server (vds). It may be called multiple times.
10581ae08745Sheppo  *
10591ae08745Sheppo  * Parameters:
10601ae08745Sheppo  *	vdc - soft state pointer
10611ae08745Sheppo  */
10621ae08745Sheppo static void
10631ae08745Sheppo vdc_init_handshake_negotiation(void *arg)
10641ae08745Sheppo {
10651ae08745Sheppo 	vdc_t		*vdc = (vdc_t *)(void *)arg;
1066*0a55fbb7Slm66018 	ldc_status_t	ldc_state;
10671ae08745Sheppo 	vd_state_t	state;
1068*0a55fbb7Slm66018 	int		status;
10691ae08745Sheppo 
10701ae08745Sheppo 	ASSERT(vdc != NULL);
10711ae08745Sheppo 
1072*0a55fbb7Slm66018 	PR0("[%d] Initializing vdc<->vds handshake\n", vdc->instance);
1073*0a55fbb7Slm66018 
1074*0a55fbb7Slm66018 	/* get LDC state */
1075*0a55fbb7Slm66018 	status = ldc_status(vdc->ldc_handle, &ldc_state);
1076*0a55fbb7Slm66018 	if (status != 0) {
1077*0a55fbb7Slm66018 		cmn_err(CE_NOTE, "[%d] Couldn't get LDC status: err=%d",
1078*0a55fbb7Slm66018 				vdc->instance, status);
1079*0a55fbb7Slm66018 		return;
1080*0a55fbb7Slm66018 	}
10811ae08745Sheppo 
10821ae08745Sheppo 	/*
1083*0a55fbb7Slm66018 	 * If the LDC connection is not UP we bring it up now and return.
1084*0a55fbb7Slm66018 	 * The handshake will be started again when the callback is
1085*0a55fbb7Slm66018 	 * triggered due to the UP event.
1086*0a55fbb7Slm66018 	 */
1087*0a55fbb7Slm66018 	if (ldc_state != LDC_UP) {
1088*0a55fbb7Slm66018 		PR0("[%d] Triggering an LDC_UP and returning\n", vdc->instance);
1089*0a55fbb7Slm66018 		(void) vdc_do_ldc_up(vdc);
1090*0a55fbb7Slm66018 		return;
1091*0a55fbb7Slm66018 	}
1092*0a55fbb7Slm66018 
1093*0a55fbb7Slm66018 	mutex_enter(&vdc->lock);
1094*0a55fbb7Slm66018 	/*
10951ae08745Sheppo 	 * Do not continue if another thread has triggered a handshake which
1096*0a55fbb7Slm66018 	 * has not been reset or detach() has stopped further handshakes.
10971ae08745Sheppo 	 */
10981ae08745Sheppo 	if (vdc->initialized & (VDC_HANDSHAKE | VDC_HANDSHAKE_STOP)) {
10991ae08745Sheppo 		PR0("%s[%d] Negotiation not triggered. [init=%x]\n",
11001ae08745Sheppo 			__func__, vdc->instance, vdc->initialized);
11011ae08745Sheppo 		mutex_exit(&vdc->lock);
11021ae08745Sheppo 		return;
11031ae08745Sheppo 	}
11041ae08745Sheppo 
1105*0a55fbb7Slm66018 	if (vdc->hshake_cnt++ > vdc_retries) {
1106*0a55fbb7Slm66018 		cmn_err(CE_NOTE, "[%d] Failed repeatedly to complete handshake"
1107*0a55fbb7Slm66018 				"with vDisk server", vdc->instance);
1108*0a55fbb7Slm66018 		mutex_exit(&vdc->lock);
1109*0a55fbb7Slm66018 		return;
1110*0a55fbb7Slm66018 	}
11111ae08745Sheppo 
11121ae08745Sheppo 	vdc->initialized |= VDC_HANDSHAKE;
1113*0a55fbb7Slm66018 	vdc->ldc_state = ldc_state;
11141ae08745Sheppo 
11151ae08745Sheppo 	state = vdc->state;
11161ae08745Sheppo 
11171ae08745Sheppo 	if (state == VD_STATE_INIT) {
1118*0a55fbb7Slm66018 		/*
1119*0a55fbb7Slm66018 		 * Set the desired version parameter to the first entry in the
1120*0a55fbb7Slm66018 		 * version array. If this specific version is not supported,
1121*0a55fbb7Slm66018 		 * the response handling code will step down the version number
1122*0a55fbb7Slm66018 		 * to the next array entry and deal with it accordingly.
1123*0a55fbb7Slm66018 		 */
1124*0a55fbb7Slm66018 		(void) vdc_init_ver_negotiation(vdc, vdc_version[0]);
11251ae08745Sheppo 	} else if (state == VD_STATE_VER) {
11261ae08745Sheppo 		(void) vdc_init_attr_negotiation(vdc);
11271ae08745Sheppo 	} else if (state == VD_STATE_ATTR) {
11281ae08745Sheppo 		(void) vdc_init_dring_negotiate(vdc);
11291ae08745Sheppo 	} else if (state == VD_STATE_DATA) {
11301ae08745Sheppo 		/*
11311ae08745Sheppo 		 * nothing to do - we have already completed the negotiation
11321ae08745Sheppo 		 * and we can transmit data when ready.
11331ae08745Sheppo 		 */
11341ae08745Sheppo 		PR0("%s[%d] Negotiation triggered after handshake completed",
11351ae08745Sheppo 			__func__, vdc->instance);
11361ae08745Sheppo 	}
11371ae08745Sheppo 
11381ae08745Sheppo 	mutex_exit(&vdc->lock);
11391ae08745Sheppo }
11401ae08745Sheppo 
1141*0a55fbb7Slm66018 /*
1142*0a55fbb7Slm66018  * Function:
1143*0a55fbb7Slm66018  *	vdc_init_ver_negotiation()
1144*0a55fbb7Slm66018  *
1145*0a55fbb7Slm66018  * Description:
1146*0a55fbb7Slm66018  *
1147*0a55fbb7Slm66018  * Arguments:
1148*0a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
1149*0a55fbb7Slm66018  *
1150*0a55fbb7Slm66018  * Return Code:
1151*0a55fbb7Slm66018  *	0	- Success
1152*0a55fbb7Slm66018  */
11531ae08745Sheppo static int
1154*0a55fbb7Slm66018 vdc_init_ver_negotiation(vdc_t *vdc, vio_ver_t ver)
11551ae08745Sheppo {
11561ae08745Sheppo 	vio_ver_msg_t	pkt;
11571ae08745Sheppo 	size_t		msglen = sizeof (pkt);
11581ae08745Sheppo 	int		status = -1;
11591ae08745Sheppo 
11601ae08745Sheppo 	PR0("%s: Entered.\n", __func__);
11611ae08745Sheppo 
11621ae08745Sheppo 	ASSERT(vdc != NULL);
11631ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
11641ae08745Sheppo 
11651ae08745Sheppo 	/*
11661ae08745Sheppo 	 * set the Session ID to a unique value
11671ae08745Sheppo 	 * (the lower 32 bits of the clock tick)
11681ae08745Sheppo 	 */
11691ae08745Sheppo 	vdc->session_id = ((uint32_t)gettick() & 0xffffffff);
11701ae08745Sheppo 
11711ae08745Sheppo 	pkt.tag.vio_msgtype = VIO_TYPE_CTRL;
11721ae08745Sheppo 	pkt.tag.vio_subtype = VIO_SUBTYPE_INFO;
11731ae08745Sheppo 	pkt.tag.vio_subtype_env = VIO_VER_INFO;
11741ae08745Sheppo 	pkt.tag.vio_sid = vdc->session_id;
11751ae08745Sheppo 	pkt.dev_class = VDEV_DISK;
1176*0a55fbb7Slm66018 	pkt.ver_major = ver.major;
1177*0a55fbb7Slm66018 	pkt.ver_minor = ver.minor;
11781ae08745Sheppo 
1179*0a55fbb7Slm66018 	status = vdc_send(vdc, (caddr_t)&pkt, &msglen);
11801ae08745Sheppo 	PR0("%s: vdc_send(status = %d)\n", __func__, status);
11811ae08745Sheppo 
11821ae08745Sheppo 	if ((status != 0) || (msglen != sizeof (vio_ver_msg_t))) {
11831ae08745Sheppo 		PR0("%s[%d] vdc_send failed: id(%lx) rv(%d) size(%d)\n",
11841ae08745Sheppo 				__func__, vdc->instance, vdc->ldc_handle,
11851ae08745Sheppo 				status, msglen);
11861ae08745Sheppo 		if (msglen != sizeof (vio_ver_msg_t))
11871ae08745Sheppo 			status = ENOMSG;
11881ae08745Sheppo 	}
11891ae08745Sheppo 
11901ae08745Sheppo 	return (status);
11911ae08745Sheppo }
11921ae08745Sheppo 
1193*0a55fbb7Slm66018 /*
1194*0a55fbb7Slm66018  * Function:
1195*0a55fbb7Slm66018  *	vdc_init_attr_negotiation()
1196*0a55fbb7Slm66018  *
1197*0a55fbb7Slm66018  * Description:
1198*0a55fbb7Slm66018  *
1199*0a55fbb7Slm66018  * Arguments:
1200*0a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
1201*0a55fbb7Slm66018  *
1202*0a55fbb7Slm66018  * Return Code:
1203*0a55fbb7Slm66018  *	0	- Success
1204*0a55fbb7Slm66018  */
12051ae08745Sheppo static int
12061ae08745Sheppo vdc_init_attr_negotiation(vdc_t *vdc)
12071ae08745Sheppo {
12081ae08745Sheppo 	vd_attr_msg_t	pkt;
12091ae08745Sheppo 	size_t		msglen = sizeof (pkt);
12101ae08745Sheppo 	int		status;
12111ae08745Sheppo 
12121ae08745Sheppo 	ASSERT(vdc != NULL);
12131ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
12141ae08745Sheppo 
12151ae08745Sheppo 	PR0("%s[%d] entered\n", __func__, vdc->instance);
12161ae08745Sheppo 
12171ae08745Sheppo 	/* fill in tag */
12181ae08745Sheppo 	pkt.tag.vio_msgtype = VIO_TYPE_CTRL;
12191ae08745Sheppo 	pkt.tag.vio_subtype = VIO_SUBTYPE_INFO;
12201ae08745Sheppo 	pkt.tag.vio_subtype_env = VIO_ATTR_INFO;
12211ae08745Sheppo 	pkt.tag.vio_sid = vdc->session_id;
12221ae08745Sheppo 	/* fill in payload */
12231ae08745Sheppo 	pkt.max_xfer_sz = vdc->max_xfer_sz;
12241ae08745Sheppo 	pkt.vdisk_block_size = vdc->block_size;
12251ae08745Sheppo 	pkt.xfer_mode = VIO_DRING_MODE;
12261ae08745Sheppo 	pkt.operations = 0;	/* server will set bits of valid operations */
12271ae08745Sheppo 	pkt.vdisk_type = 0;	/* server will set to valid device type */
12281ae08745Sheppo 	pkt.vdisk_size = 0;	/* server will set to valid size */
12291ae08745Sheppo 
1230*0a55fbb7Slm66018 	status = vdc_send(vdc, (caddr_t)&pkt, &msglen);
12311ae08745Sheppo 	PR0("%s: vdc_send(status = %d)\n", __func__, status);
12321ae08745Sheppo 
12331ae08745Sheppo 	if ((status != 0) || (msglen != sizeof (vio_ver_msg_t))) {
12341ae08745Sheppo 		PR0("%s[%d] ldc_write failed: id(%lx) rv(%d) size (%d)\n",
12351ae08745Sheppo 			__func__, vdc->instance, vdc->ldc_handle,
12361ae08745Sheppo 			status, msglen);
12371ae08745Sheppo 		if (msglen != sizeof (vio_ver_msg_t))
12381ae08745Sheppo 			status = ENOMSG;
12391ae08745Sheppo 	}
12401ae08745Sheppo 
12411ae08745Sheppo 	return (status);
12421ae08745Sheppo }
12431ae08745Sheppo 
1244*0a55fbb7Slm66018 /*
1245*0a55fbb7Slm66018  * Function:
1246*0a55fbb7Slm66018  *	vdc_init_dring_negotiate()
1247*0a55fbb7Slm66018  *
1248*0a55fbb7Slm66018  * Description:
1249*0a55fbb7Slm66018  *
1250*0a55fbb7Slm66018  * Arguments:
1251*0a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
1252*0a55fbb7Slm66018  *
1253*0a55fbb7Slm66018  * Return Code:
1254*0a55fbb7Slm66018  *	0	- Success
1255*0a55fbb7Slm66018  */
12561ae08745Sheppo static int
12571ae08745Sheppo vdc_init_dring_negotiate(vdc_t *vdc)
12581ae08745Sheppo {
12591ae08745Sheppo 	vio_dring_reg_msg_t	pkt;
12601ae08745Sheppo 	size_t			msglen = sizeof (pkt);
12611ae08745Sheppo 	int			status = -1;
12621ae08745Sheppo 
12631ae08745Sheppo 	ASSERT(vdc != NULL);
12641ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
12651ae08745Sheppo 
12661ae08745Sheppo 	status = vdc_init_descriptor_ring(vdc);
12671ae08745Sheppo 	if (status != 0) {
12681ae08745Sheppo 		cmn_err(CE_CONT, "[%d] Failed to init DRing (status = %d)\n",
12691ae08745Sheppo 				vdc->instance, status);
1270*0a55fbb7Slm66018 		vdc_destroy_descriptor_ring(vdc);
12711ae08745Sheppo 		vdc_reset_connection(vdc, B_FALSE);
12721ae08745Sheppo 		return (status);
12731ae08745Sheppo 	}
1274*0a55fbb7Slm66018 	PR0("%s[%d] Init of descriptor ring completed (status = %d)\n",
1275*0a55fbb7Slm66018 			__func__, vdc->instance, status);
12761ae08745Sheppo 
12771ae08745Sheppo 	/* fill in tag */
12781ae08745Sheppo 	pkt.tag.vio_msgtype = VIO_TYPE_CTRL;
12791ae08745Sheppo 	pkt.tag.vio_subtype = VIO_SUBTYPE_INFO;
12801ae08745Sheppo 	pkt.tag.vio_subtype_env = VIO_DRING_REG;
12811ae08745Sheppo 	pkt.tag.vio_sid = vdc->session_id;
12821ae08745Sheppo 	/* fill in payload */
12831ae08745Sheppo 	pkt.dring_ident = 0;
12841ae08745Sheppo 	pkt.num_descriptors = VD_DRING_LEN;
12851ae08745Sheppo 	pkt.descriptor_size = VD_DRING_ENTRY_SZ;
12861ae08745Sheppo 	pkt.options = (VIO_TX_DRING | VIO_RX_DRING);
12871ae08745Sheppo 	pkt.ncookies = vdc->dring_cookie_count;
12881ae08745Sheppo 	pkt.cookie[0] = vdc->dring_cookie[0];	/* for now just one cookie */
12891ae08745Sheppo 
1290*0a55fbb7Slm66018 	status = vdc_send(vdc, (caddr_t)&pkt, &msglen);
12911ae08745Sheppo 	if (status != 0) {
12921ae08745Sheppo 		PR0("%s[%d] Failed to register DRing (status = %d)\n",
12931ae08745Sheppo 				__func__, vdc->instance, status);
12941ae08745Sheppo 		vdc_reset_connection(vdc, B_FALSE);
12951ae08745Sheppo 	}
12961ae08745Sheppo 
12971ae08745Sheppo 	return (status);
12981ae08745Sheppo }
12991ae08745Sheppo 
13001ae08745Sheppo 
13011ae08745Sheppo /* -------------------------------------------------------------------------- */
13021ae08745Sheppo 
13031ae08745Sheppo /*
13041ae08745Sheppo  * LDC helper routines
13051ae08745Sheppo  */
13061ae08745Sheppo 
13071ae08745Sheppo /*
13081ae08745Sheppo  * Function:
13091ae08745Sheppo  *	vdc_send()
13101ae08745Sheppo  *
13111ae08745Sheppo  * Description:
13121ae08745Sheppo  *	The function encapsulates the call to write a message using LDC.
13131ae08745Sheppo  *	If LDC indicates that the call failed due to the queue being full,
13141ae08745Sheppo  *	we retry the ldc_write() [ up to 'vdc_retries' time ], otherwise
13151ae08745Sheppo  *	we return the error returned by LDC.
13161ae08745Sheppo  *
13171ae08745Sheppo  * Arguments:
13181ae08745Sheppo  *	ldc_handle	- LDC handle for the channel this instance of vdc uses
13191ae08745Sheppo  *	pkt		- address of LDC message to be sent
13201ae08745Sheppo  *	msglen		- the size of the message being sent. When the function
13211ae08745Sheppo  *			  returns, this contains the number of bytes written.
13221ae08745Sheppo  *
13231ae08745Sheppo  * Return Code:
13241ae08745Sheppo  *	0		- Success.
13251ae08745Sheppo  *	EINVAL		- pkt or msglen were NULL
13261ae08745Sheppo  *	ECONNRESET	- The connection was not up.
13271ae08745Sheppo  *	EWOULDBLOCK	- LDC queue is full
13281ae08745Sheppo  *	xxx		- other error codes returned by ldc_write
13291ae08745Sheppo  */
13301ae08745Sheppo static int
1331*0a55fbb7Slm66018 vdc_send(vdc_t *vdc, caddr_t pkt, size_t *msglen)
13321ae08745Sheppo {
13331ae08745Sheppo 	size_t	size = 0;
13341ae08745Sheppo 	int	retries = 0;
13351ae08745Sheppo 	int	status = 0;
13361ae08745Sheppo 
1337*0a55fbb7Slm66018 	ASSERT(vdc != NULL);
1338*0a55fbb7Slm66018 	ASSERT(mutex_owned(&vdc->lock));
13391ae08745Sheppo 	ASSERT(msglen != NULL);
13401ae08745Sheppo 	ASSERT(*msglen != 0);
13411ae08745Sheppo 
13421ae08745Sheppo 	do {
13431ae08745Sheppo 		size = *msglen;
1344*0a55fbb7Slm66018 		status = ldc_write(vdc->ldc_handle, pkt, &size);
13451ae08745Sheppo 	} while (status == EWOULDBLOCK && retries++ < vdc_retries);
13461ae08745Sheppo 
1347*0a55fbb7Slm66018 	/* if LDC had serious issues --- reset vdc state */
1348*0a55fbb7Slm66018 	if (status == EIO || status == ECONNRESET) {
1349*0a55fbb7Slm66018 		vdc_reset_connection(vdc, B_TRUE);
1350*0a55fbb7Slm66018 	}
1351*0a55fbb7Slm66018 
13521ae08745Sheppo 	/* return the last size written */
13531ae08745Sheppo 	*msglen = size;
13541ae08745Sheppo 
13551ae08745Sheppo 	return (status);
13561ae08745Sheppo }
13571ae08745Sheppo 
13581ae08745Sheppo /*
13591ae08745Sheppo  * Function:
13601ae08745Sheppo  *	vdc_get_ldc_id()
13611ae08745Sheppo  *
13621ae08745Sheppo  * Description:
13631ae08745Sheppo  *	This function gets the 'ldc-id' for this particular instance of vdc.
13641ae08745Sheppo  *	The id returned is the guest domain channel endpoint LDC uses for
13651ae08745Sheppo  *	communication with vds.
13661ae08745Sheppo  *
13671ae08745Sheppo  * Arguments:
13681ae08745Sheppo  *	dip	- dev info pointer for this instance of the device driver.
13691ae08745Sheppo  *	ldc_id	- pointer to variable used to return the 'ldc-id' found.
13701ae08745Sheppo  *
13711ae08745Sheppo  * Return Code:
13721ae08745Sheppo  *	0	- Success.
13731ae08745Sheppo  *	ENOENT	- Expected node or property did not exist.
13741ae08745Sheppo  *	ENXIO	- Unexpected error communicating with MD framework
13751ae08745Sheppo  */
13761ae08745Sheppo static int
13771ae08745Sheppo vdc_get_ldc_id(dev_info_t *dip, uint64_t *ldc_id)
13781ae08745Sheppo {
13791ae08745Sheppo 	int		status = ENOENT;
13801ae08745Sheppo 	char		*node_name = NULL;
13811ae08745Sheppo 	md_t		*mdp = NULL;
13821ae08745Sheppo 	int		num_nodes;
13831ae08745Sheppo 	int		num_vdevs;
13841ae08745Sheppo 	int		num_chans;
13851ae08745Sheppo 	mde_cookie_t	rootnode;
13861ae08745Sheppo 	mde_cookie_t	*listp = NULL;
13871ae08745Sheppo 	mde_cookie_t	*chanp = NULL;
13881ae08745Sheppo 	boolean_t	found_inst = B_FALSE;
13891ae08745Sheppo 	int		listsz;
13901ae08745Sheppo 	int		idx;
13911ae08745Sheppo 	uint64_t	md_inst;
13921ae08745Sheppo 	int		obp_inst;
13931ae08745Sheppo 	int		instance = ddi_get_instance(dip);
13941ae08745Sheppo 
13951ae08745Sheppo 	ASSERT(ldc_id != NULL);
13961ae08745Sheppo 	*ldc_id = 0;
13971ae08745Sheppo 
13981ae08745Sheppo 	/*
13991ae08745Sheppo 	 * Get the OBP instance number for comparison with the MD instance
14001ae08745Sheppo 	 *
14011ae08745Sheppo 	 * The "cfg-handle" property of a vdc node in an MD contains the MD's
14021ae08745Sheppo 	 * notion of "instance", or unique identifier, for that node; OBP
14031ae08745Sheppo 	 * stores the value of the "cfg-handle" MD property as the value of
14041ae08745Sheppo 	 * the "reg" property on the node in the device tree it builds from
14051ae08745Sheppo 	 * the MD and passes to Solaris.  Thus, we look up the devinfo node's
14061ae08745Sheppo 	 * "reg" property value to uniquely identify this device instance.
14071ae08745Sheppo 	 * If the "reg" property cannot be found, the device tree state is
14081ae08745Sheppo 	 * presumably so broken that there is no point in continuing.
14091ae08745Sheppo 	 */
14101ae08745Sheppo 	if (!ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, OBP_REG)) {
14111ae08745Sheppo 		cmn_err(CE_WARN, "'%s' property does not exist", OBP_REG);
14121ae08745Sheppo 		return (ENOENT);
14131ae08745Sheppo 	}
14141ae08745Sheppo 	obp_inst = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
14151ae08745Sheppo 			OBP_REG, -1);
14161ae08745Sheppo 	PR1("%s[%d]: OBP inst=%d\n", __func__, instance, obp_inst);
14171ae08745Sheppo 
14181ae08745Sheppo 	/*
14191ae08745Sheppo 	 * We now walk the MD nodes and if an instance of a vdc node matches
14201ae08745Sheppo 	 * the instance got from OBP we get the ldc-id property.
14211ae08745Sheppo 	 */
14221ae08745Sheppo 	if ((mdp = md_get_handle()) == NULL) {
14231ae08745Sheppo 		cmn_err(CE_WARN, "unable to init machine description");
14241ae08745Sheppo 		return (ENXIO);
14251ae08745Sheppo 	}
14261ae08745Sheppo 
14271ae08745Sheppo 	num_nodes = md_node_count(mdp);
14281ae08745Sheppo 	ASSERT(num_nodes > 0);
14291ae08745Sheppo 
14301ae08745Sheppo 	listsz = num_nodes * sizeof (mde_cookie_t);
14311ae08745Sheppo 
14321ae08745Sheppo 	/* allocate memory for nodes */
14331ae08745Sheppo 	listp = kmem_zalloc(listsz, KM_SLEEP);
14341ae08745Sheppo 	chanp = kmem_zalloc(listsz, KM_SLEEP);
14351ae08745Sheppo 
14361ae08745Sheppo 	rootnode = md_root_node(mdp);
14371ae08745Sheppo 	ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE);
14381ae08745Sheppo 
14391ae08745Sheppo 	/*
14401ae08745Sheppo 	 * Search for all the virtual devices, we will then check to see which
14411ae08745Sheppo 	 * ones are disk nodes.
14421ae08745Sheppo 	 */
14431ae08745Sheppo 	num_vdevs = md_scan_dag(mdp, rootnode,
14441ae08745Sheppo 			md_find_name(mdp, VDC_MD_VDEV_NAME),
14451ae08745Sheppo 			md_find_name(mdp, "fwd"), listp);
14461ae08745Sheppo 
14471ae08745Sheppo 	if (num_vdevs <= 0) {
14481ae08745Sheppo 		cmn_err(CE_NOTE, "No '%s' node found", VDC_MD_VDEV_NAME);
14491ae08745Sheppo 		status = ENOENT;
14501ae08745Sheppo 		goto done;
14511ae08745Sheppo 	}
14521ae08745Sheppo 
14531ae08745Sheppo 	PR1("%s[%d] num_vdevs=%d\n", __func__, instance, num_vdevs);
14541ae08745Sheppo 	for (idx = 0; idx < num_vdevs; idx++) {
14551ae08745Sheppo 		status = md_get_prop_str(mdp, listp[idx], "name", &node_name);
14561ae08745Sheppo 		if ((status != 0) || (node_name == NULL)) {
14571ae08745Sheppo 			cmn_err(CE_NOTE, "Unable to get name of node type '%s'"
14581ae08745Sheppo 					": err %d", VDC_MD_VDEV_NAME, status);
14591ae08745Sheppo 			continue;
14601ae08745Sheppo 		}
14611ae08745Sheppo 
14621ae08745Sheppo 		PR1("%s[%d] Found node %s\n", __func__, instance, node_name);
14631ae08745Sheppo 		if (strcmp(VDC_MD_DISK_NAME, node_name) == 0) {
14641ae08745Sheppo 			status = md_get_prop_val(mdp, listp[idx],
14651ae08745Sheppo 					VDC_MD_CFG_HDL, &md_inst);
14661ae08745Sheppo 			PR1("%s[%d] vdc inst# in MD=%d\n",
14671ae08745Sheppo 					__func__, instance, md_inst);
14681ae08745Sheppo 			if ((status == 0) && (md_inst == obp_inst)) {
14691ae08745Sheppo 				found_inst = B_TRUE;
14701ae08745Sheppo 				break;
14711ae08745Sheppo 			}
14721ae08745Sheppo 		}
14731ae08745Sheppo 	}
14741ae08745Sheppo 
1475*0a55fbb7Slm66018 	if (!found_inst) {
14761ae08745Sheppo 		cmn_err(CE_NOTE, "Unable to find correct '%s' node",
14771ae08745Sheppo 				VDC_MD_DISK_NAME);
14781ae08745Sheppo 		status = ENOENT;
14791ae08745Sheppo 		goto done;
14801ae08745Sheppo 	}
14811ae08745Sheppo 	PR0("%s[%d] MD inst=%d\n", __func__, instance, md_inst);
14821ae08745Sheppo 
14831ae08745Sheppo 	/* get the channels for this node */
14841ae08745Sheppo 	num_chans = md_scan_dag(mdp, listp[idx],
14851ae08745Sheppo 			md_find_name(mdp, VDC_MD_CHAN_NAME),
14861ae08745Sheppo 			md_find_name(mdp, "fwd"), chanp);
14871ae08745Sheppo 
14881ae08745Sheppo 	/* expecting at least one channel */
14891ae08745Sheppo 	if (num_chans <= 0) {
14901ae08745Sheppo 		cmn_err(CE_NOTE, "No '%s' node for '%s' port",
14911ae08745Sheppo 				VDC_MD_CHAN_NAME, VDC_MD_VDEV_NAME);
14921ae08745Sheppo 		status = ENOENT;
14931ae08745Sheppo 		goto done;
14941ae08745Sheppo 
14951ae08745Sheppo 	} else if (num_chans != 1) {
14961ae08745Sheppo 		PR0("%s[%d] Expected 1 '%s' node for '%s' port, found %d\n",
14971ae08745Sheppo 			__func__, instance, VDC_MD_CHAN_NAME, VDC_MD_VDEV_NAME,
14981ae08745Sheppo 			num_chans);
14991ae08745Sheppo 	}
15001ae08745Sheppo 
15011ae08745Sheppo 	/*
15021ae08745Sheppo 	 * We use the first channel found (index 0), irrespective of how
15031ae08745Sheppo 	 * many are there in total.
15041ae08745Sheppo 	 */
15051ae08745Sheppo 	if (md_get_prop_val(mdp, chanp[0], VDC_ID_PROP, ldc_id) != 0) {
15061ae08745Sheppo 		cmn_err(CE_NOTE, "Channel '%s' property not found",
15071ae08745Sheppo 				VDC_ID_PROP);
15081ae08745Sheppo 		status = ENOENT;
15091ae08745Sheppo 	}
15101ae08745Sheppo 
15111ae08745Sheppo 	PR0("%s[%d] LDC id is 0x%lx\n", __func__, instance, *ldc_id);
15121ae08745Sheppo 
15131ae08745Sheppo done:
15141ae08745Sheppo 	if (chanp)
15151ae08745Sheppo 		kmem_free(chanp, listsz);
15161ae08745Sheppo 	if (listp)
15171ae08745Sheppo 		kmem_free(listp, listsz);
15181ae08745Sheppo 
15191ae08745Sheppo 	(void) md_fini_handle(mdp);
15201ae08745Sheppo 
15211ae08745Sheppo 	return (status);
15221ae08745Sheppo }
15231ae08745Sheppo 
1524*0a55fbb7Slm66018 static int
1525*0a55fbb7Slm66018 vdc_do_ldc_up(vdc_t *vdc)
1526*0a55fbb7Slm66018 {
1527*0a55fbb7Slm66018 	int	status;
1528*0a55fbb7Slm66018 
1529*0a55fbb7Slm66018 	PR0("[%d] Bringing up channel %x\n", vdc->instance, vdc->ldc_id);
1530*0a55fbb7Slm66018 
1531*0a55fbb7Slm66018 	if ((status = ldc_up(vdc->ldc_handle)) != 0) {
1532*0a55fbb7Slm66018 		switch (status) {
1533*0a55fbb7Slm66018 		case ECONNREFUSED:	/* listener not ready at other end */
1534*0a55fbb7Slm66018 			PR0("%s: ldc_up(%d,...) return %d\n",
1535*0a55fbb7Slm66018 					__func__, vdc->ldc_id, status);
1536*0a55fbb7Slm66018 			status = 0;
1537*0a55fbb7Slm66018 			break;
1538*0a55fbb7Slm66018 		default:
1539*0a55fbb7Slm66018 			cmn_err(CE_NOTE, "[%d] Failed to bring up LDC: "
1540*0a55fbb7Slm66018 					"channel=%ld, err=%d",
1541*0a55fbb7Slm66018 					vdc->instance, vdc->ldc_id, status);
1542*0a55fbb7Slm66018 		}
1543*0a55fbb7Slm66018 	}
1544*0a55fbb7Slm66018 
1545*0a55fbb7Slm66018 	return (status);
1546*0a55fbb7Slm66018 }
1547*0a55fbb7Slm66018 
15481ae08745Sheppo 
15491ae08745Sheppo /*
15501ae08745Sheppo  * vdc_is_able_to_tx_data()
15511ae08745Sheppo  *
15521ae08745Sheppo  * Description:
15531ae08745Sheppo  *	This function checks if we are able to send data to the
15541ae08745Sheppo  *	vDisk server (vds). The LDC connection needs to be up and
15551ae08745Sheppo  *	vdc & vds need to have completed the handshake negotiation.
15561ae08745Sheppo  *
15571ae08745Sheppo  * Parameters:
15581ae08745Sheppo  *	vdc 		- soft state pointer
15591ae08745Sheppo  *	flag		- flag to indicate if we can block or not
15601ae08745Sheppo  *			  [ If O_NONBLOCK or O_NDELAY (which are defined in
15611ae08745Sheppo  *			    open(2)) are set then do not block)
15621ae08745Sheppo  *
15631ae08745Sheppo  * Return Values
15641ae08745Sheppo  *	B_TRUE		- can talk to vds
15651ae08745Sheppo  *	B_FALSE		- unable to talk to vds
15661ae08745Sheppo  */
15671ae08745Sheppo static boolean_t
15681ae08745Sheppo vdc_is_able_to_tx_data(vdc_t *vdc, int flag)
15691ae08745Sheppo {
15701ae08745Sheppo 	vd_state_t	state;
15711ae08745Sheppo 	uint32_t	ldc_state;
15721ae08745Sheppo 	uint_t		retries = 0;
15731ae08745Sheppo 	int		rv = -1;
15741ae08745Sheppo 
15751ae08745Sheppo 	ASSERT(vdc != NULL);
15761ae08745Sheppo 
15771ae08745Sheppo 	mutex_enter(&vdc->lock);
15781ae08745Sheppo 	state = vdc->state;
15791ae08745Sheppo 	ldc_state = vdc->ldc_state;
15801ae08745Sheppo 	mutex_exit(&vdc->lock);
15811ae08745Sheppo 
15821ae08745Sheppo 	if ((state == VD_STATE_DATA) && (ldc_state == LDC_UP))
15831ae08745Sheppo 		return (B_TRUE);
15841ae08745Sheppo 
15851ae08745Sheppo 	if ((flag & O_NONBLOCK) || (flag & O_NDELAY)) {
15861ae08745Sheppo 		PR0("%s[%d] Not ready to tx - state %d LDC state %d\n",
15871ae08745Sheppo 			__func__, vdc->instance, state, ldc_state);
15881ae08745Sheppo 		return (B_FALSE);
15891ae08745Sheppo 	}
15901ae08745Sheppo 
15911ae08745Sheppo 	/*
15921ae08745Sheppo 	 * We want to check and see if any negotiations triggered earlier
15931ae08745Sheppo 	 * have succeeded. We are prepared to wait a little while in case
15941ae08745Sheppo 	 * they are still in progress.
15951ae08745Sheppo 	 */
15961ae08745Sheppo 	mutex_enter(&vdc->lock);
15971ae08745Sheppo 	while ((vdc->ldc_state != LDC_UP) || (vdc->state != VD_STATE_DATA)) {
15981ae08745Sheppo 		PR0("%s: Waiting for connection at state %d (LDC state %d)\n",
15991ae08745Sheppo 			__func__, vdc->state, vdc->ldc_state);
16001ae08745Sheppo 
16011ae08745Sheppo 		rv = cv_timedwait(&vdc->cv, &vdc->lock,
16021ae08745Sheppo 			VD_GET_TIMEOUT_HZ(retries));
16031ae08745Sheppo 
16041ae08745Sheppo 		/*
16051ae08745Sheppo 		 * An rv of -1 indicates that we timed out without the LDC
16061ae08745Sheppo 		 * state changing so it looks like the other side (vdc) is
16071ae08745Sheppo 		 * not yet ready/responding.
16081ae08745Sheppo 		 *
16091ae08745Sheppo 		 * Any other value of rv indicates that the LDC triggered an
16101ae08745Sheppo 		 * interrupt so we just loop again, check the handshake state
16111ae08745Sheppo 		 * and keep waiting if necessary.
16121ae08745Sheppo 		 */
16131ae08745Sheppo 		if (rv == -1) {
16141ae08745Sheppo 			if (retries >= vdc_retries) {
16151ae08745Sheppo 				PR0("%s[%d] handshake wait timed out.\n",
16161ae08745Sheppo 						__func__, vdc->instance);
16171ae08745Sheppo 				mutex_exit(&vdc->lock);
16181ae08745Sheppo 				return (B_FALSE);
16191ae08745Sheppo 			} else {
16201ae08745Sheppo 				PR1("%s[%d] Retry #%d for handshake timedout\n",
16211ae08745Sheppo 					__func__, vdc->instance, retries);
16221ae08745Sheppo 				retries++;
16231ae08745Sheppo 			}
16241ae08745Sheppo 		}
16251ae08745Sheppo 	}
16261ae08745Sheppo 
16271ae08745Sheppo 	ASSERT(vdc->ldc_state == LDC_UP);
16281ae08745Sheppo 	ASSERT(vdc->state == VD_STATE_DATA);
16291ae08745Sheppo 
16301ae08745Sheppo 	mutex_exit(&vdc->lock);
16311ae08745Sheppo 
16321ae08745Sheppo 	return (B_TRUE);
16331ae08745Sheppo }
16341ae08745Sheppo 
16351ae08745Sheppo 
1636*0a55fbb7Slm66018 /*
1637*0a55fbb7Slm66018  * Function:
1638*0a55fbb7Slm66018  *	vdc_terminate_ldc()
1639*0a55fbb7Slm66018  *
1640*0a55fbb7Slm66018  * Description:
1641*0a55fbb7Slm66018  *
1642*0a55fbb7Slm66018  * Arguments:
1643*0a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
1644*0a55fbb7Slm66018  *
1645*0a55fbb7Slm66018  * Return Code:
1646*0a55fbb7Slm66018  *	None
1647*0a55fbb7Slm66018  */
16481ae08745Sheppo static void
16491ae08745Sheppo vdc_terminate_ldc(vdc_t *vdc)
16501ae08745Sheppo {
16511ae08745Sheppo 	int	instance = ddi_get_instance(vdc->dip);
16521ae08745Sheppo 
16531ae08745Sheppo 	ASSERT(vdc != NULL);
16541ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
16551ae08745Sheppo 
16561ae08745Sheppo 	PR0("%s[%d] initialized=%x\n", __func__, instance, vdc->initialized);
16571ae08745Sheppo 
16581ae08745Sheppo 	if (vdc->initialized & VDC_LDC_OPEN) {
16591ae08745Sheppo 		PR0("%s[%d]: ldc_close()\n", __func__, instance);
16601ae08745Sheppo 		(void) ldc_close(vdc->ldc_handle);
16611ae08745Sheppo 	}
16621ae08745Sheppo 	if (vdc->initialized & VDC_LDC_CB) {
16631ae08745Sheppo 		PR0("%s[%d]: ldc_unreg_callback()\n", __func__, instance);
16641ae08745Sheppo 		(void) ldc_unreg_callback(vdc->ldc_handle);
16651ae08745Sheppo 	}
16661ae08745Sheppo 	if (vdc->initialized & VDC_LDC) {
16671ae08745Sheppo 		PR0("%s[%d]: ldc_fini()\n", __func__, instance);
16681ae08745Sheppo 		(void) ldc_fini(vdc->ldc_handle);
16691ae08745Sheppo 		vdc->ldc_handle = NULL;
16701ae08745Sheppo 	}
16711ae08745Sheppo 
16721ae08745Sheppo 	vdc->initialized &= ~(VDC_LDC | VDC_LDC_CB | VDC_LDC_OPEN);
16731ae08745Sheppo }
16741ae08745Sheppo 
1675*0a55fbb7Slm66018 /*
1676*0a55fbb7Slm66018  * Function:
1677*0a55fbb7Slm66018  *	vdc_reset_connection()
1678*0a55fbb7Slm66018  *
1679*0a55fbb7Slm66018  * Description:
1680*0a55fbb7Slm66018  *
1681*0a55fbb7Slm66018  * Arguments:
1682*0a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
1683*0a55fbb7Slm66018  *	reset_ldc - Flag whether or not to reset the LDC connection also.
1684*0a55fbb7Slm66018  *
1685*0a55fbb7Slm66018  * Return Code:
1686*0a55fbb7Slm66018  *	None
1687*0a55fbb7Slm66018  */
16881ae08745Sheppo static void
16891ae08745Sheppo vdc_reset_connection(vdc_t *vdc, boolean_t reset_ldc)
16901ae08745Sheppo {
16911ae08745Sheppo 	int	status;
16921ae08745Sheppo 
16931ae08745Sheppo 	ASSERT(vdc != NULL);
16941ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
16951ae08745Sheppo 
16961ae08745Sheppo 	PR0("%s[%d] Entered\n", __func__, vdc->instance);
16971ae08745Sheppo 
16981ae08745Sheppo 	vdc->state = VD_STATE_INIT;
16991ae08745Sheppo 
1700*0a55fbb7Slm66018 	if (reset_ldc) {
17011ae08745Sheppo 		status = ldc_reset(vdc->ldc_handle);
17021ae08745Sheppo 		PR0("%s[%d]  ldc_reset() = %d\n",
17031ae08745Sheppo 				__func__, vdc->instance, status);
17041ae08745Sheppo 	}
17051ae08745Sheppo 
17061ae08745Sheppo 	vdc->initialized &= ~VDC_HANDSHAKE;
17071ae08745Sheppo 	PR0("%s[%d] init=%x\n", __func__, vdc->instance, vdc->initialized);
17081ae08745Sheppo }
17091ae08745Sheppo 
17101ae08745Sheppo /* -------------------------------------------------------------------------- */
17111ae08745Sheppo 
17121ae08745Sheppo /*
17131ae08745Sheppo  * Descriptor Ring helper routines
17141ae08745Sheppo  */
17151ae08745Sheppo 
1716*0a55fbb7Slm66018 /*
1717*0a55fbb7Slm66018  * Function:
1718*0a55fbb7Slm66018  *	vdc_init_descriptor_ring()
1719*0a55fbb7Slm66018  *
1720*0a55fbb7Slm66018  * Description:
1721*0a55fbb7Slm66018  *
1722*0a55fbb7Slm66018  * Arguments:
1723*0a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
1724*0a55fbb7Slm66018  *
1725*0a55fbb7Slm66018  * Return Code:
1726*0a55fbb7Slm66018  *	0	- Success
1727*0a55fbb7Slm66018  */
17281ae08745Sheppo static int
17291ae08745Sheppo vdc_init_descriptor_ring(vdc_t *vdc)
17301ae08745Sheppo {
17311ae08745Sheppo 	vd_dring_entry_t	*dep = NULL;	/* DRing Entry pointer */
1732*0a55fbb7Slm66018 	int	status = 0;
17331ae08745Sheppo 	int	i;
17341ae08745Sheppo 
1735*0a55fbb7Slm66018 	PR0("%s[%d] initialized=%x\n",
1736*0a55fbb7Slm66018 			__func__, vdc->instance, vdc->initialized);
17371ae08745Sheppo 
17381ae08745Sheppo 	ASSERT(vdc != NULL);
17391ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
17401ae08745Sheppo 	ASSERT(vdc->ldc_handle != NULL);
17411ae08745Sheppo 
1742*0a55fbb7Slm66018 	if ((vdc->initialized & VDC_DRING_INIT) == 0) {
1743*0a55fbb7Slm66018 		PR0("%s[%d] ldc_mem_dring_create\n", __func__, vdc->instance);
17441ae08745Sheppo 		status = ldc_mem_dring_create(VD_DRING_LEN, VD_DRING_ENTRY_SZ,
17451ae08745Sheppo 				&vdc->ldc_dring_hdl);
17461ae08745Sheppo 		if ((vdc->ldc_dring_hdl == NULL) || (status != 0)) {
17471ae08745Sheppo 			PR0("%s: Failed to create a descriptor ring", __func__);
17481ae08745Sheppo 			return (status);
17491ae08745Sheppo 		}
17501ae08745Sheppo 		vdc->dring_entry_size = VD_DRING_ENTRY_SZ;
17511ae08745Sheppo 		vdc->dring_len = VD_DRING_LEN;
1752*0a55fbb7Slm66018 		vdc->initialized |= VDC_DRING_INIT;
1753*0a55fbb7Slm66018 	}
17541ae08745Sheppo 
1755*0a55fbb7Slm66018 	if ((vdc->initialized & VDC_DRING_BOUND) == 0) {
1756*0a55fbb7Slm66018 		PR0("%s[%d] ldc_mem_dring_bind\n", __func__, vdc->instance);
1757*0a55fbb7Slm66018 		vdc->dring_cookie =
1758*0a55fbb7Slm66018 			kmem_zalloc(sizeof (ldc_mem_cookie_t), KM_SLEEP);
17591ae08745Sheppo 
17601ae08745Sheppo 		status = ldc_mem_dring_bind(vdc->ldc_handle, vdc->ldc_dring_hdl,
1761*0a55fbb7Slm66018 				LDC_SHADOW_MAP, LDC_MEM_RW,
1762*0a55fbb7Slm66018 				&vdc->dring_cookie[0],
17631ae08745Sheppo 				&vdc->dring_cookie_count);
17641ae08745Sheppo 		if (status != 0) {
1765*0a55fbb7Slm66018 			PR0("%s: Failed to bind descriptor ring (%p) "
1766*0a55fbb7Slm66018 				"to channel (%p)\n",
17671ae08745Sheppo 				__func__, vdc->ldc_dring_hdl, vdc->ldc_handle);
17681ae08745Sheppo 			return (status);
17691ae08745Sheppo 		}
17701ae08745Sheppo 		ASSERT(vdc->dring_cookie_count == 1);
17711ae08745Sheppo 		vdc->initialized |= VDC_DRING_BOUND;
1772*0a55fbb7Slm66018 	}
17731ae08745Sheppo 
17741ae08745Sheppo 	status = ldc_mem_dring_info(vdc->ldc_dring_hdl, &vdc->dring_mem_info);
17751ae08745Sheppo 	if (status != 0) {
17761ae08745Sheppo 		PR0("%s: Failed to get info for descriptor ring (%p)\n",
17771ae08745Sheppo 			__func__, vdc->ldc_dring_hdl);
17781ae08745Sheppo 		return (status);
17791ae08745Sheppo 	}
17801ae08745Sheppo 
1781*0a55fbb7Slm66018 	if ((vdc->initialized & VDC_DRING_LOCAL) == 0) {
1782*0a55fbb7Slm66018 		PR0("%s[%d] local dring\n", __func__, vdc->instance);
1783*0a55fbb7Slm66018 
17841ae08745Sheppo 		/* Allocate the local copy of this dring */
1785*0a55fbb7Slm66018 		vdc->local_dring =
1786*0a55fbb7Slm66018 			kmem_zalloc(VD_DRING_LEN * sizeof (vdc_local_desc_t),
17871ae08745Sheppo 						KM_SLEEP);
17881ae08745Sheppo 		vdc->initialized |= VDC_DRING_LOCAL;
1789*0a55fbb7Slm66018 	}
17901ae08745Sheppo 
17911ae08745Sheppo 	/*
1792*0a55fbb7Slm66018 	 * Mark all DRing entries as free and initialize the private
1793*0a55fbb7Slm66018 	 * descriptor's memory handles. If any entry is initialized,
1794*0a55fbb7Slm66018 	 * we need to free it later so we set the bit in 'initialized'
1795*0a55fbb7Slm66018 	 * at the start.
17961ae08745Sheppo 	 */
17971ae08745Sheppo 	vdc->initialized |= VDC_DRING_ENTRY;
17981ae08745Sheppo 	for (i = 0; i < VD_DRING_LEN; i++) {
17991ae08745Sheppo 		dep = VDC_GET_DRING_ENTRY_PTR(vdc, i);
18001ae08745Sheppo 		dep->hdr.dstate = VIO_DESC_FREE;
18011ae08745Sheppo 
18021ae08745Sheppo 		status = ldc_mem_alloc_handle(vdc->ldc_handle,
18031ae08745Sheppo 				&vdc->local_dring[i].desc_mhdl);
18041ae08745Sheppo 		if (status != 0) {
18051ae08745Sheppo 			cmn_err(CE_NOTE, "![%d] Failed to alloc mem handle for"
18061ae08745Sheppo 					" descriptor %d", vdc->instance, i);
18071ae08745Sheppo 			return (status);
18081ae08745Sheppo 		}
18091ae08745Sheppo 		vdc->local_dring[i].flags = VIO_DESC_FREE;
18101ae08745Sheppo 		vdc->local_dring[i].dep = dep;
18111ae08745Sheppo 
18121ae08745Sheppo 		mutex_init(&vdc->local_dring[i].lock, NULL, MUTEX_DRIVER, NULL);
18131ae08745Sheppo 		cv_init(&vdc->local_dring[i].cv, NULL, CV_DRIVER, NULL);
18141ae08745Sheppo 	}
18151ae08745Sheppo 
18161ae08745Sheppo 	/*
18171ae08745Sheppo 	 * We init the index of the last DRing entry used. Since the code to
18181ae08745Sheppo 	 * get the next available entry increments it before selecting one,
18191ae08745Sheppo 	 * we set it to the last DRing entry so that it wraps around to zero
18201ae08745Sheppo 	 * for the 1st entry to be used.
18211ae08745Sheppo 	 */
18221ae08745Sheppo 	vdc->dring_curr_idx = VD_DRING_LEN - 1;
18231ae08745Sheppo 
18241ae08745Sheppo 	return (status);
18251ae08745Sheppo }
18261ae08745Sheppo 
1827*0a55fbb7Slm66018 /*
1828*0a55fbb7Slm66018  * Function:
1829*0a55fbb7Slm66018  *	vdc_destroy_descriptor_ring()
1830*0a55fbb7Slm66018  *
1831*0a55fbb7Slm66018  * Description:
1832*0a55fbb7Slm66018  *
1833*0a55fbb7Slm66018  * Arguments:
1834*0a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
1835*0a55fbb7Slm66018  *
1836*0a55fbb7Slm66018  * Return Code:
1837*0a55fbb7Slm66018  *	None
1838*0a55fbb7Slm66018  */
18391ae08745Sheppo static void
18401ae08745Sheppo vdc_destroy_descriptor_ring(vdc_t *vdc)
18411ae08745Sheppo {
1842*0a55fbb7Slm66018 	vdc_local_desc_t	*ldep = NULL;	/* Local Dring Entry Pointer */
18431ae08745Sheppo 	ldc_mem_handle_t	mhdl = NULL;
18441ae08745Sheppo 	int			status = -1;
18451ae08745Sheppo 	int			i;	/* loop */
18461ae08745Sheppo 
18471ae08745Sheppo 	ASSERT(vdc != NULL);
18481ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
18491ae08745Sheppo 	ASSERT(vdc->state == VD_STATE_INIT);
18501ae08745Sheppo 
18511ae08745Sheppo 	PR0("%s: Entered\n", __func__);
18521ae08745Sheppo 
18531ae08745Sheppo 	if (vdc->initialized & VDC_DRING_ENTRY) {
1854*0a55fbb7Slm66018 		PR0("[%d] Removing Local DRing entries\n", vdc->instance);
18551ae08745Sheppo 		for (i = 0; i < VD_DRING_LEN; i++) {
1856*0a55fbb7Slm66018 			ldep = &vdc->local_dring[i];
1857*0a55fbb7Slm66018 			mhdl = ldep->desc_mhdl;
18581ae08745Sheppo 
1859*0a55fbb7Slm66018 			if (mhdl == NULL)
1860*0a55fbb7Slm66018 				continue;
1861*0a55fbb7Slm66018 
18621ae08745Sheppo 			(void) ldc_mem_free_handle(mhdl);
1863*0a55fbb7Slm66018 			mutex_destroy(&ldep->lock);
1864*0a55fbb7Slm66018 			cv_destroy(&ldep->cv);
18651ae08745Sheppo 		}
18661ae08745Sheppo 		vdc->initialized &= ~VDC_DRING_ENTRY;
18671ae08745Sheppo 	}
18681ae08745Sheppo 
18691ae08745Sheppo 	if (vdc->initialized & VDC_DRING_LOCAL) {
1870*0a55fbb7Slm66018 		PR0("[%d] Freeing Local DRing\n", vdc->instance);
18711ae08745Sheppo 		kmem_free(vdc->local_dring,
18721ae08745Sheppo 				VD_DRING_LEN * sizeof (vdc_local_desc_t));
18731ae08745Sheppo 		vdc->initialized &= ~VDC_DRING_LOCAL;
18741ae08745Sheppo 	}
18751ae08745Sheppo 
18761ae08745Sheppo 	if (vdc->initialized & VDC_DRING_BOUND) {
1877*0a55fbb7Slm66018 		PR0("[%d] Unbinding DRing\n", vdc->instance);
18781ae08745Sheppo 		status = ldc_mem_dring_unbind(vdc->ldc_dring_hdl);
18791ae08745Sheppo 		if (status == 0) {
18801ae08745Sheppo 			vdc->initialized &= ~VDC_DRING_BOUND;
18811ae08745Sheppo 		} else {
18821ae08745Sheppo 			vdc_msg("%s: Failed to unbind Descriptor Ring (%lx)\n",
18831ae08745Sheppo 				vdc->ldc_dring_hdl);
18841ae08745Sheppo 		}
18851ae08745Sheppo 	}
18861ae08745Sheppo 
18871ae08745Sheppo 	if (vdc->initialized & VDC_DRING_INIT) {
1888*0a55fbb7Slm66018 		PR0("[%d] Destroying DRing\n", vdc->instance);
18891ae08745Sheppo 		status = ldc_mem_dring_destroy(vdc->ldc_dring_hdl);
18901ae08745Sheppo 		if (status == 0) {
18911ae08745Sheppo 			vdc->ldc_dring_hdl = NULL;
18921ae08745Sheppo 			bzero(&vdc->dring_mem_info, sizeof (ldc_mem_info_t));
18931ae08745Sheppo 			vdc->initialized &= ~VDC_DRING_INIT;
18941ae08745Sheppo 		} else {
18951ae08745Sheppo 			vdc_msg("%s: Failed to destroy Descriptor Ring (%lx)\n",
18961ae08745Sheppo 					vdc->ldc_dring_hdl);
18971ae08745Sheppo 		}
18981ae08745Sheppo 	}
18991ae08745Sheppo }
19001ae08745Sheppo 
19011ae08745Sheppo /*
19021ae08745Sheppo  * vdc_get_next_dring_entry_idx()
19031ae08745Sheppo  *
19041ae08745Sheppo  * Description:
19051ae08745Sheppo  *	This function gets the index of the next Descriptor Ring entry available
19061ae08745Sheppo  *
19071ae08745Sheppo  * Return Value:
19081ae08745Sheppo  *	0 <= rv < VD_DRING_LEN		Next available slot
19091ae08745Sheppo  *	-1 				DRing is full
19101ae08745Sheppo  */
19111ae08745Sheppo static int
19121ae08745Sheppo vdc_get_next_dring_entry_idx(vdc_t *vdc, uint_t num_slots_needed)
19131ae08745Sheppo {
19141ae08745Sheppo 	_NOTE(ARGUNUSED(num_slots_needed))
19151ae08745Sheppo 
19161ae08745Sheppo 	vd_dring_entry_t	*dep = NULL;	/* Dring Entry Pointer */
19171ae08745Sheppo 	int			idx = -1;
19181ae08745Sheppo 	int			start_idx = 0;
19191ae08745Sheppo 
19201ae08745Sheppo 	ASSERT(vdc != NULL);
19211ae08745Sheppo 	ASSERT(vdc->dring_len == VD_DRING_LEN);
19221ae08745Sheppo 	ASSERT(vdc->dring_curr_idx >= 0);
19231ae08745Sheppo 	ASSERT(vdc->dring_curr_idx < VD_DRING_LEN);
19241ae08745Sheppo 	ASSERT(mutex_owned(&vdc->dring_lock));
19251ae08745Sheppo 
19261ae08745Sheppo 	/* Start at the last entry used */
19271ae08745Sheppo 	idx = start_idx = vdc->dring_curr_idx;
19281ae08745Sheppo 
19291ae08745Sheppo 	/*
19301ae08745Sheppo 	 * Loop through Descriptor Ring checking for a free entry until we reach
19311ae08745Sheppo 	 * the entry we started at. We should never come close to filling the
19321ae08745Sheppo 	 * Ring at any stage, instead this is just to prevent an entry which
19331ae08745Sheppo 	 * gets into an inconsistent state (e.g. due to a request timing out)
19341ae08745Sheppo 	 * from blocking progress.
19351ae08745Sheppo 	 */
19361ae08745Sheppo 	do {
19371ae08745Sheppo 		/* Get the next entry after the last known index tried */
19381ae08745Sheppo 		idx = (idx + 1) % VD_DRING_LEN;
19391ae08745Sheppo 
19401ae08745Sheppo 		dep = VDC_GET_DRING_ENTRY_PTR(vdc, idx);
19411ae08745Sheppo 		ASSERT(dep != NULL);
19421ae08745Sheppo 
19431ae08745Sheppo 		if (dep->hdr.dstate == VIO_DESC_FREE) {
19441ae08745Sheppo 			ASSERT(idx >= 0);
19451ae08745Sheppo 			ASSERT(idx < VD_DRING_LEN);
19461ae08745Sheppo 			vdc->dring_curr_idx = idx;
19471ae08745Sheppo 			return (idx);
19481ae08745Sheppo 
19491ae08745Sheppo 		} else if (dep->hdr.dstate == VIO_DESC_READY) {
19501ae08745Sheppo 			PR0("%s: Entry %d waiting to be accepted\n",
19511ae08745Sheppo 					__func__, idx);
19521ae08745Sheppo 			continue;
19531ae08745Sheppo 
19541ae08745Sheppo 		} else if (dep->hdr.dstate == VIO_DESC_ACCEPTED) {
19551ae08745Sheppo 			PR0("%s: Entry %d waiting to be processed\n",
19561ae08745Sheppo 					__func__, idx);
19571ae08745Sheppo 			continue;
19581ae08745Sheppo 
19591ae08745Sheppo 		} else if (dep->hdr.dstate == VIO_DESC_DONE) {
19601ae08745Sheppo 			PR0("%s: Entry %d done but not marked free\n",
19611ae08745Sheppo 					__func__, idx);
19621ae08745Sheppo 
19631ae08745Sheppo 			/*
19641ae08745Sheppo 			 * If we are currently panicking, interrupts are
19651ae08745Sheppo 			 * disabled and we will not be getting ACKs from the
19661ae08745Sheppo 			 * vDisk server so we mark the descriptor ring entries
19671ae08745Sheppo 			 * as FREE here instead of in the ACK handler.
19681ae08745Sheppo 			 */
19691ae08745Sheppo 			if (panicstr) {
19701ae08745Sheppo 				(void) vdc_depopulate_descriptor(vdc, idx);
19711ae08745Sheppo 				dep->hdr.dstate = VIO_DESC_FREE;
19721ae08745Sheppo 				vdc->local_dring[idx].flags = VIO_DESC_FREE;
19731ae08745Sheppo 			}
19741ae08745Sheppo 			continue;
19751ae08745Sheppo 
19761ae08745Sheppo 		} else {
19771ae08745Sheppo 			vdc_msg("Public Descriptor Ring entry corrupted");
19781ae08745Sheppo 			mutex_enter(&vdc->lock);
1979*0a55fbb7Slm66018 			vdc_reset_connection(vdc, B_FALSE);
19801ae08745Sheppo 			mutex_exit(&vdc->lock);
19811ae08745Sheppo 			return (-1);
19821ae08745Sheppo 		}
19831ae08745Sheppo 
19841ae08745Sheppo 	} while (idx != start_idx);
19851ae08745Sheppo 
19861ae08745Sheppo 	return (-1);
19871ae08745Sheppo }
19881ae08745Sheppo 
19891ae08745Sheppo /*
19901ae08745Sheppo  * Function:
19911ae08745Sheppo  *	vdc_populate_descriptor
19921ae08745Sheppo  *
19931ae08745Sheppo  * Description:
19941ae08745Sheppo  *	This routine writes the data to be transmitted to vds into the
19951ae08745Sheppo  *	descriptor, notifies vds that the ring has been updated and
19961ae08745Sheppo  *	then waits for the request to be processed.
19971ae08745Sheppo  *
19981ae08745Sheppo  * Arguments:
19991ae08745Sheppo  *	vdc	- the soft state pointer
20001ae08745Sheppo  *	addr	- start address of memory region.
20011ae08745Sheppo  *	nbytes	- number of bytes to read/write
20021ae08745Sheppo  *	operation - operation we want vds to perform (VD_OP_XXX)
20031ae08745Sheppo  *	arg	- parameter to be sent to server (depends on VD_OP_XXX type)
20041ae08745Sheppo  *			. mode for ioctl(9e)
20051ae08745Sheppo  *			. LP64 diskaddr_t (block I/O)
20061ae08745Sheppo  *	slice	- the disk slice this request is for
20071ae08745Sheppo  *
20081ae08745Sheppo  * Return Codes:
20091ae08745Sheppo  *	0
20101ae08745Sheppo  *	EAGAIN
20111ae08745Sheppo  *		EFAULT
20121ae08745Sheppo  *		ENXIO
20131ae08745Sheppo  *		EIO
20141ae08745Sheppo  */
20151ae08745Sheppo static int
20161ae08745Sheppo vdc_populate_descriptor(vdc_t *vdc, caddr_t addr, size_t nbytes, int operation,
20171ae08745Sheppo 				uint64_t arg, uint64_t slice)
20181ae08745Sheppo {
20191ae08745Sheppo 	vdc_local_desc_t *local_dep = NULL;	/* Local Dring Entry Pointer */
20201ae08745Sheppo 	vd_dring_entry_t *dep = NULL;		/* Dring Entry Pointer */
20211ae08745Sheppo 	int			idx = 0;	/* Index of DRing entry used */
20221ae08745Sheppo 	vio_dring_msg_t		dmsg;
20231ae08745Sheppo 	size_t			msglen = sizeof (dmsg);
20241ae08745Sheppo 	int			status = 0;
20251ae08745Sheppo 	int			rv;
20261ae08745Sheppo 	int			retries = 0;
20271ae08745Sheppo 
20281ae08745Sheppo 	ASSERT(vdc != NULL);
20291ae08745Sheppo 	ASSERT(slice < V_NUMPAR);
20301ae08745Sheppo 
20311ae08745Sheppo 	/*
20321ae08745Sheppo 	 * Get next available DRing entry.
20331ae08745Sheppo 	 */
20341ae08745Sheppo 	mutex_enter(&vdc->dring_lock);
20351ae08745Sheppo 	idx = vdc_get_next_dring_entry_idx(vdc, 1);
20361ae08745Sheppo 	if (idx == -1) {
20371ae08745Sheppo 		mutex_exit(&vdc->dring_lock);
20381ae08745Sheppo 		vdc_msg("%s[%d]: no descriptor ring entry avail, seq=%d\n",
20391ae08745Sheppo 				__func__, vdc->instance, vdc->seq_num);
20401ae08745Sheppo 
20411ae08745Sheppo 		/*
20421ae08745Sheppo 		 * Since strategy should not block we don't wait for the DRing
20431ae08745Sheppo 		 * to empty and instead return
20441ae08745Sheppo 		 */
20451ae08745Sheppo 		return (EAGAIN);
20461ae08745Sheppo 	}
20471ae08745Sheppo 
20481ae08745Sheppo 	ASSERT(idx < VD_DRING_LEN);
20491ae08745Sheppo 	local_dep = &vdc->local_dring[idx];
20501ae08745Sheppo 	dep = local_dep->dep;
20511ae08745Sheppo 	ASSERT(dep != NULL);
20521ae08745Sheppo 
20531ae08745Sheppo 	/*
20541ae08745Sheppo 	 * Wait for anybody still using the DRing entry to finish.
20551ae08745Sheppo 	 * (e.g. still waiting for vds to respond to a request)
20561ae08745Sheppo 	 */
20571ae08745Sheppo 	mutex_enter(&local_dep->lock);
20581ae08745Sheppo 
20591ae08745Sheppo 	switch (operation) {
20601ae08745Sheppo 	case VD_OP_BREAD:
20611ae08745Sheppo 	case VD_OP_BWRITE:
20621ae08745Sheppo 		PR1("buf=%p, block=%lx, nbytes=%lx\n", addr, arg, nbytes);
20631ae08745Sheppo 		dep->payload.addr = (diskaddr_t)arg;
20641ae08745Sheppo 		rv = vdc_populate_mem_hdl(vdc, idx, addr, nbytes, operation);
20651ae08745Sheppo 		break;
20661ae08745Sheppo 
20671ae08745Sheppo 	case VD_OP_FLUSH:
20681ae08745Sheppo 	case VD_OP_GET_VTOC:
20691ae08745Sheppo 	case VD_OP_SET_VTOC:
20701ae08745Sheppo 	case VD_OP_GET_DISKGEOM:
20711ae08745Sheppo 	case VD_OP_SET_DISKGEOM:
20721ae08745Sheppo 	case VD_OP_SCSICMD:
20731ae08745Sheppo 		if (nbytes > 0) {
20741ae08745Sheppo 			rv = vdc_populate_mem_hdl(vdc, idx, addr, nbytes,
20751ae08745Sheppo 							operation);
20761ae08745Sheppo 		}
20771ae08745Sheppo 		break;
20781ae08745Sheppo 	default:
20791ae08745Sheppo 		cmn_err(CE_NOTE, "[%d] Unsupported vDisk operation [%d]\n",
20801ae08745Sheppo 				vdc->instance, operation);
20811ae08745Sheppo 		rv = EINVAL;
20821ae08745Sheppo 	}
20831ae08745Sheppo 
20841ae08745Sheppo 	if (rv != 0) {
20851ae08745Sheppo 		mutex_exit(&local_dep->lock);
20861ae08745Sheppo 		mutex_exit(&vdc->dring_lock);
20871ae08745Sheppo 		return (rv);
20881ae08745Sheppo 	}
20891ae08745Sheppo 
20901ae08745Sheppo 	/*
20911ae08745Sheppo 	 * fill in the data details into the DRing
20921ae08745Sheppo 	 */
20931ae08745Sheppo 	dep->payload.req_id = VDC_GET_NEXT_REQ_ID(vdc);
20941ae08745Sheppo 	dep->payload.operation = operation;
20951ae08745Sheppo 	dep->payload.nbytes = nbytes;
20961ae08745Sheppo 	dep->payload.status = EINPROGRESS;	/* vds will set valid value */
20971ae08745Sheppo 	dep->payload.slice = slice;
20981ae08745Sheppo 	dep->hdr.dstate = VIO_DESC_READY;
20991ae08745Sheppo 	dep->hdr.ack = 1;		/* request an ACK for every message */
21001ae08745Sheppo 
21011ae08745Sheppo 	local_dep->flags = VIO_DESC_READY;
21021ae08745Sheppo 	local_dep->addr = addr;
21031ae08745Sheppo 
21041ae08745Sheppo 	/*
21051ae08745Sheppo 	 * Send a msg with the DRing details to vds
21061ae08745Sheppo 	 */
21071ae08745Sheppo 	VIO_INIT_DRING_DATA_TAG(dmsg);
21081ae08745Sheppo 	VDC_INIT_DRING_DATA_MSG_IDS(dmsg, vdc);
21091ae08745Sheppo 	dmsg.dring_ident = vdc->dring_ident;
21101ae08745Sheppo 	dmsg.start_idx = idx;
21111ae08745Sheppo 	dmsg.end_idx = idx;
21121ae08745Sheppo 
21131ae08745Sheppo 	PR1("ident=0x%llx, st=%d, end=%d, seq=%d req=%d dep=%p\n",
21141ae08745Sheppo 			vdc->dring_ident, dmsg.start_idx, dmsg.end_idx,
21151ae08745Sheppo 			dmsg.seq_num, dep->payload.req_id, dep);
21161ae08745Sheppo 
2117*0a55fbb7Slm66018 	mutex_enter(&vdc->lock);
2118*0a55fbb7Slm66018 	status = vdc_send(vdc, (caddr_t)&dmsg, &msglen);
2119*0a55fbb7Slm66018 	mutex_exit(&vdc->lock);
21201ae08745Sheppo 	PR1("%s[%d]: ldc_write() status=%d\n", __func__, vdc->instance, status);
21211ae08745Sheppo 	if (status != 0) {
21221ae08745Sheppo 		mutex_exit(&local_dep->lock);
21231ae08745Sheppo 		mutex_exit(&vdc->dring_lock);
21241ae08745Sheppo 		vdc_msg("%s: ldc_write(%d)\n", __func__, status);
21251ae08745Sheppo 		return (EAGAIN);
21261ae08745Sheppo 	}
21271ae08745Sheppo 
21281ae08745Sheppo 	/*
2129*0a55fbb7Slm66018 	 * If the message was successfully sent, we increment the sequence
2130*0a55fbb7Slm66018 	 * number to be used by the next message
2131*0a55fbb7Slm66018 	 */
2132*0a55fbb7Slm66018 	vdc->seq_num++;
2133*0a55fbb7Slm66018 
2134*0a55fbb7Slm66018 	/*
21351ae08745Sheppo 	 * XXX - potential performance enhancement (Investigate at a later date)
21361ae08745Sheppo 	 *
21371ae08745Sheppo 	 * for calls from strategy(9E), instead of waiting for a response from
21381ae08745Sheppo 	 * vds, we could return at this stage and let the ACK handling code
21391ae08745Sheppo 	 * trigger the biodone(9F)
21401ae08745Sheppo 	 */
21411ae08745Sheppo 
21421ae08745Sheppo 	/*
21431ae08745Sheppo 	 * When a guest is panicking, the completion of requests needs to be
21441ae08745Sheppo 	 * handled differently because interrupts are disabled and vdc
21451ae08745Sheppo 	 * will not get messages. We have to poll for the messages instead.
21461ae08745Sheppo 	 */
21471ae08745Sheppo 	if (ddi_in_panic()) {
21481ae08745Sheppo 		int start = 0;
21491ae08745Sheppo 		retries = 0;
21501ae08745Sheppo 		for (;;) {
21511ae08745Sheppo 			msglen = sizeof (dmsg);
21521ae08745Sheppo 			status = ldc_read(vdc->ldc_handle, (caddr_t)&dmsg,
21531ae08745Sheppo 					&msglen);
21541ae08745Sheppo 			if (status) {
21551ae08745Sheppo 				status = EINVAL;
21561ae08745Sheppo 				break;
21571ae08745Sheppo 			}
21581ae08745Sheppo 
21591ae08745Sheppo 			/*
21601ae08745Sheppo 			 * if there are no packets wait and check again
21611ae08745Sheppo 			 */
21621ae08745Sheppo 			if ((status == 0) && (msglen == 0)) {
21631ae08745Sheppo 				if (retries++ > vdc_dump_retries) {
21641ae08745Sheppo 					PR0("[%d] Giving up waiting, idx %d\n",
21651ae08745Sheppo 							vdc->instance, idx);
21661ae08745Sheppo 					status = EAGAIN;
21671ae08745Sheppo 					break;
21681ae08745Sheppo 				}
21691ae08745Sheppo 
21701ae08745Sheppo 				PR1("Waiting for next packet @ %d\n", idx);
21711ae08745Sheppo 				delay(drv_usectohz(vdc_dump_usec_timeout));
21721ae08745Sheppo 				continue;
21731ae08745Sheppo 			}
21741ae08745Sheppo 
21751ae08745Sheppo 			/*
21761ae08745Sheppo 			 * Ignore all messages that are not ACKs/NACKs to
21771ae08745Sheppo 			 * DRing requests.
21781ae08745Sheppo 			 */
21791ae08745Sheppo 			if ((dmsg.tag.vio_msgtype != VIO_TYPE_DATA) ||
21801ae08745Sheppo 			    (dmsg.tag.vio_subtype_env != VIO_DRING_DATA)) {
21811ae08745Sheppo 				PR0("discarding pkt: type=%d sub=%d env=%d\n",
21821ae08745Sheppo 					dmsg.tag.vio_msgtype,
21831ae08745Sheppo 					dmsg.tag.vio_subtype,
21841ae08745Sheppo 					dmsg.tag.vio_subtype_env);
21851ae08745Sheppo 				continue;
21861ae08745Sheppo 			}
21871ae08745Sheppo 
21881ae08745Sheppo 			/*
21891ae08745Sheppo 			 * set the appropriate return value for the
21901ae08745Sheppo 			 * current request.
21911ae08745Sheppo 			 */
21921ae08745Sheppo 			switch (dmsg.tag.vio_subtype) {
21931ae08745Sheppo 			case VIO_SUBTYPE_ACK:
21941ae08745Sheppo 				status = 0;
21951ae08745Sheppo 				break;
21961ae08745Sheppo 			case VIO_SUBTYPE_NACK:
21971ae08745Sheppo 				status = EAGAIN;
21981ae08745Sheppo 				break;
21991ae08745Sheppo 			default:
22001ae08745Sheppo 				continue;
22011ae08745Sheppo 			}
22021ae08745Sheppo 
22031ae08745Sheppo 			start = dmsg.start_idx;
22041ae08745Sheppo 			if (start >= VD_DRING_LEN) {
22051ae08745Sheppo 				PR0("[%d] Bogus ack data : start %d\n",
22061ae08745Sheppo 					vdc->instance, start);
22071ae08745Sheppo 				continue;
22081ae08745Sheppo 			}
22091ae08745Sheppo 
22101ae08745Sheppo 			dep = VDC_GET_DRING_ENTRY_PTR(vdc, start);
22111ae08745Sheppo 
22121ae08745Sheppo 			PR1("[%d] Dumping start=%d idx=%d state=%d\n",
22131ae08745Sheppo 				vdc->instance, start, idx, dep->hdr.dstate);
22141ae08745Sheppo 
22151ae08745Sheppo 			if (dep->hdr.dstate != VIO_DESC_DONE) {
22161ae08745Sheppo 				PR0("[%d] Entry @ %d - state !DONE %d\n",
22171ae08745Sheppo 					vdc->instance, start, dep->hdr.dstate);
22181ae08745Sheppo 				continue;
22191ae08745Sheppo 			}
22201ae08745Sheppo 
22211ae08745Sheppo 			(void) vdc_depopulate_descriptor(vdc, start);
22221ae08745Sheppo 
22231ae08745Sheppo 			/*
22241ae08745Sheppo 			 * We want to process all Dring entries up to
22251ae08745Sheppo 			 * the current one so that we can return an
22261ae08745Sheppo 			 * error with the correct request.
22271ae08745Sheppo 			 */
22281ae08745Sheppo 			if (idx > start) {
22291ae08745Sheppo 				PR0("[%d] Looping: start %d, idx %d\n",
22301ae08745Sheppo 						vdc->instance, idx, start);
22311ae08745Sheppo 				continue;
22321ae08745Sheppo 			}
22331ae08745Sheppo 
22341ae08745Sheppo 			/* exit - all outstanding requests are completed */
22351ae08745Sheppo 			break;
22361ae08745Sheppo 		}
22371ae08745Sheppo 
22381ae08745Sheppo 		mutex_exit(&local_dep->lock);
22391ae08745Sheppo 		mutex_exit(&vdc->dring_lock);
22401ae08745Sheppo 
22411ae08745Sheppo 		return (status);
22421ae08745Sheppo 	}
22431ae08745Sheppo 
22441ae08745Sheppo 	/*
22451ae08745Sheppo 	 * Now watch the DRing entries we modified to get the response
22461ae08745Sheppo 	 * from vds.
22471ae08745Sheppo 	 */
22481ae08745Sheppo 	status = vdc_wait_for_descriptor_update(vdc, idx, dmsg);
22491ae08745Sheppo 	if (status == ETIMEDOUT) {
22501ae08745Sheppo 		/* debug info when dumping state on vds side */
22511ae08745Sheppo 		dep->payload.status = ECANCELED;
22521ae08745Sheppo 	}
22531ae08745Sheppo 
22541ae08745Sheppo 	status = vdc_depopulate_descriptor(vdc, idx);
22551ae08745Sheppo 	PR1("%s[%d] Status=%d\n", __func__, vdc->instance, status);
22561ae08745Sheppo 
22571ae08745Sheppo 	mutex_exit(&local_dep->lock);
22581ae08745Sheppo 	mutex_exit(&vdc->dring_lock);
22591ae08745Sheppo 
22601ae08745Sheppo 	return (status);
22611ae08745Sheppo }
22621ae08745Sheppo 
2263*0a55fbb7Slm66018 /*
2264*0a55fbb7Slm66018  * Function:
2265*0a55fbb7Slm66018  *	vdc_wait_for_descriptor_update()
2266*0a55fbb7Slm66018  *
2267*0a55fbb7Slm66018  * Description:
2268*0a55fbb7Slm66018  *
2269*0a55fbb7Slm66018  * Arguments:
2270*0a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
2271*0a55fbb7Slm66018  *	idx	- Index of the Descriptor Ring entry being modified
2272*0a55fbb7Slm66018  *	dmsg	- LDC message sent by vDisk server
2273*0a55fbb7Slm66018  *
2274*0a55fbb7Slm66018  * Return Code:
2275*0a55fbb7Slm66018  *	0	- Success
2276*0a55fbb7Slm66018  */
22771ae08745Sheppo static int
22781ae08745Sheppo vdc_wait_for_descriptor_update(vdc_t *vdc, uint_t idx, vio_dring_msg_t dmsg)
22791ae08745Sheppo {
22801ae08745Sheppo 	vd_dring_entry_t *dep = NULL;		/* Dring Entry Pointer */
22811ae08745Sheppo 	vdc_local_desc_t *local_dep = NULL;	/* Local Dring Entry Pointer */
22821ae08745Sheppo 	size_t	msglen = sizeof (dmsg);
22831ae08745Sheppo 	int	retries = 0;
2284*0a55fbb7Slm66018 	int	status = 0;
22851ae08745Sheppo 	int	rv = 0;
22861ae08745Sheppo 
22871ae08745Sheppo 	ASSERT(vdc != NULL);
2288*0a55fbb7Slm66018 	ASSERT(mutex_owned(&vdc->dring_lock));
22891ae08745Sheppo 	ASSERT(idx < VD_DRING_LEN);
22901ae08745Sheppo 	local_dep = &vdc->local_dring[idx];
22911ae08745Sheppo 	ASSERT(local_dep != NULL);
22921ae08745Sheppo 	dep = local_dep->dep;
22931ae08745Sheppo 	ASSERT(dep != NULL);
22941ae08745Sheppo 
22951ae08745Sheppo 	while (dep->hdr.dstate != VIO_DESC_DONE) {
22961ae08745Sheppo 		rv = cv_timedwait(&local_dep->cv, &local_dep->lock,
22971ae08745Sheppo 			VD_GET_TIMEOUT_HZ(retries));
22981ae08745Sheppo 		if (rv == -1) {
22991ae08745Sheppo 			/*
23001ae08745Sheppo 			 * If they persist in ignoring us we'll storm off in a
23011ae08745Sheppo 			 * huff and return ETIMEDOUT to the upper layers.
23021ae08745Sheppo 			 */
23031ae08745Sheppo 			if (retries >= vdc_retries) {
23041ae08745Sheppo 				PR0("%s: Finished waiting on entry %d\n",
23051ae08745Sheppo 					__func__, idx);
23061ae08745Sheppo 				status = ETIMEDOUT;
23071ae08745Sheppo 				break;
23081ae08745Sheppo 			} else {
23091ae08745Sheppo 				retries++;
23101ae08745Sheppo 				PR0("%s[%d]: Timeout #%d on entry %d "
23111ae08745Sheppo 				    "[seq %d][req %d]\n", __func__,
23121ae08745Sheppo 				    vdc->instance,
23131ae08745Sheppo 				    retries, idx, dmsg.seq_num,
23141ae08745Sheppo 				    dep->payload.req_id);
23151ae08745Sheppo 			}
23161ae08745Sheppo 
23171ae08745Sheppo 			if (dep->hdr.dstate & VIO_DESC_ACCEPTED) {
23181ae08745Sheppo 				PR0("%s[%d]: vds has accessed entry %d [seq %d]"
23191ae08745Sheppo 				    "[req %d] but not ack'ed it yet\n",
23201ae08745Sheppo 				    __func__, vdc->instance, idx, dmsg.seq_num,
23211ae08745Sheppo 				    dep->payload.req_id);
23221ae08745Sheppo 				continue;
23231ae08745Sheppo 			}
23241ae08745Sheppo 
23251ae08745Sheppo 			/*
23261ae08745Sheppo 			 * we resend the message as it may have been dropped
23271ae08745Sheppo 			 * and have never made it to the other side (vds).
23281ae08745Sheppo 			 * (We reuse the original message but update seq ID)
23291ae08745Sheppo 			 */
23301ae08745Sheppo 			VDC_INIT_DRING_DATA_MSG_IDS(dmsg, vdc);
23311ae08745Sheppo 			retries = 0;
2332*0a55fbb7Slm66018 			mutex_enter(&vdc->lock);
2333*0a55fbb7Slm66018 			status = vdc_send(vdc, (caddr_t)&dmsg, &msglen);
2334*0a55fbb7Slm66018 			mutex_exit(&vdc->lock);
23351ae08745Sheppo 			if (status != 0) {
23361ae08745Sheppo 				vdc_msg("%s: Error (%d) while resending after "
23371ae08745Sheppo 					"timeout\n", __func__, status);
23381ae08745Sheppo 				status = ETIMEDOUT;
23391ae08745Sheppo 				break;
23401ae08745Sheppo 			}
2341*0a55fbb7Slm66018 			/*
2342*0a55fbb7Slm66018 			 * If the message was successfully sent, we increment
2343*0a55fbb7Slm66018 			 * the sequence number to be used by the next message.
2344*0a55fbb7Slm66018 			 */
2345*0a55fbb7Slm66018 			vdc->seq_num++;
23461ae08745Sheppo 		}
23471ae08745Sheppo 	}
23481ae08745Sheppo 
23491ae08745Sheppo 	return (status);
23501ae08745Sheppo }
23511ae08745Sheppo 
23521ae08745Sheppo static int
23531ae08745Sheppo vdc_get_response(vdc_t *vdc, int start, int end)
23541ae08745Sheppo {
23551ae08745Sheppo 	vdc_local_desc_t	*ldep = NULL;	/* Local Dring Entry Pointer */
23561ae08745Sheppo 	vd_dring_entry_t	*dep = NULL;	/* Dring Entry Pointer */
23571ae08745Sheppo 	int			status = ENXIO;
23581ae08745Sheppo 	int			idx = -1;
23591ae08745Sheppo 
23601ae08745Sheppo 	ASSERT(vdc != NULL);
23611ae08745Sheppo 	ASSERT(start >= 0);
23621ae08745Sheppo 	ASSERT(start <= VD_DRING_LEN);
23631ae08745Sheppo 	ASSERT(start >= -1);
23641ae08745Sheppo 	ASSERT(start <= VD_DRING_LEN);
23651ae08745Sheppo 
23661ae08745Sheppo 	idx = start;
23671ae08745Sheppo 	ldep = &vdc->local_dring[idx];
23681ae08745Sheppo 	ASSERT(ldep != NULL);
23691ae08745Sheppo 	dep = ldep->dep;
23701ae08745Sheppo 	ASSERT(dep != NULL);
23711ae08745Sheppo 
23721ae08745Sheppo 	PR0("%s[%d] DRING entry=%d status=%d\n", __func__, vdc->instance,
23731ae08745Sheppo 			idx, VIO_GET_DESC_STATE(dep->hdr.dstate));
23741ae08745Sheppo 	while (VIO_GET_DESC_STATE(dep->hdr.dstate) == VIO_DESC_DONE) {
23751ae08745Sheppo 		if ((end != -1) && (idx > end))
23761ae08745Sheppo 			return (0);
23771ae08745Sheppo 
23781ae08745Sheppo 		switch (ldep->operation) {
23791ae08745Sheppo 		case VD_OP_BREAD:
23801ae08745Sheppo 		case VD_OP_BWRITE:
23811ae08745Sheppo 			/* call bioxxx */
23821ae08745Sheppo 			break;
23831ae08745Sheppo 		default:
23841ae08745Sheppo 			/* signal waiter */
23851ae08745Sheppo 			break;
23861ae08745Sheppo 		}
23871ae08745Sheppo 
23881ae08745Sheppo 		/* Clear the DRing entry */
23891ae08745Sheppo 		status = vdc_depopulate_descriptor(vdc, idx);
23901ae08745Sheppo 		PR0("%s[%d] Status=%d\n", __func__, vdc->instance, status);
23911ae08745Sheppo 
23921ae08745Sheppo 		/* loop accounting to get next DRing entry */
23931ae08745Sheppo 		idx++;
23941ae08745Sheppo 		ldep = &vdc->local_dring[idx];
23951ae08745Sheppo 		dep = ldep->dep;
23961ae08745Sheppo 	}
23971ae08745Sheppo 
23981ae08745Sheppo 	return (status);
23991ae08745Sheppo }
24001ae08745Sheppo 
2401*0a55fbb7Slm66018 /*
2402*0a55fbb7Slm66018  * Function:
2403*0a55fbb7Slm66018  *	vdc_depopulate_descriptor()
2404*0a55fbb7Slm66018  *
2405*0a55fbb7Slm66018  * Description:
2406*0a55fbb7Slm66018  *
2407*0a55fbb7Slm66018  * Arguments:
2408*0a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
2409*0a55fbb7Slm66018  *	idx	- Index of the Descriptor Ring entry being modified
2410*0a55fbb7Slm66018  *
2411*0a55fbb7Slm66018  * Return Code:
2412*0a55fbb7Slm66018  *	0	- Success
2413*0a55fbb7Slm66018  */
24141ae08745Sheppo static int
24151ae08745Sheppo vdc_depopulate_descriptor(vdc_t *vdc, uint_t idx)
24161ae08745Sheppo {
24171ae08745Sheppo 	vd_dring_entry_t *dep = NULL;		/* Dring Entry Pointer */
24181ae08745Sheppo 	vdc_local_desc_t *ldep = NULL;	/* Local Dring Entry Pointer */
24191ae08745Sheppo 	int	status = ENXIO;
24201ae08745Sheppo 
24211ae08745Sheppo 	ASSERT(vdc != NULL);
24221ae08745Sheppo 	ASSERT(idx < VD_DRING_LEN);
24231ae08745Sheppo 	ldep = &vdc->local_dring[idx];
24241ae08745Sheppo 	ASSERT(ldep != NULL);
24251ae08745Sheppo 	dep = ldep->dep;
24261ae08745Sheppo 	ASSERT(dep != NULL);
24271ae08745Sheppo 
24281ae08745Sheppo 	status = dep->payload.status;
24291ae08745Sheppo 	VDC_MARK_DRING_ENTRY_FREE(vdc, idx);
24301ae08745Sheppo 	ldep = &vdc->local_dring[idx];
24311ae08745Sheppo 	VIO_SET_DESC_STATE(ldep->flags, VIO_DESC_FREE);
24321ae08745Sheppo 
24331ae08745Sheppo 	/*
24341ae08745Sheppo 	 * If the upper layer passed in a misaligned address we copied the
24351ae08745Sheppo 	 * data into an aligned buffer before sending it to LDC - we now
24361ae08745Sheppo 	 * copy it back to the original buffer.
24371ae08745Sheppo 	 */
24381ae08745Sheppo 	if (ldep->align_addr) {
24391ae08745Sheppo 		ASSERT(ldep->addr != NULL);
24401ae08745Sheppo 		ASSERT(dep->payload.nbytes > 0);
24411ae08745Sheppo 
24421ae08745Sheppo 		bcopy(ldep->align_addr, ldep->addr, dep->payload.nbytes);
24431ae08745Sheppo 		kmem_free(ldep->align_addr,
24441ae08745Sheppo 				sizeof (caddr_t) * dep->payload.nbytes);
24451ae08745Sheppo 		ldep->align_addr = NULL;
24461ae08745Sheppo 	}
24471ae08745Sheppo 
24481ae08745Sheppo 	status = ldc_mem_unbind_handle(ldep->desc_mhdl);
24491ae08745Sheppo 	if (status != 0) {
24501ae08745Sheppo 		cmn_err(CE_NOTE, "[%d] unbind mem hdl 0x%lx @ idx %d failed:%d",
24511ae08745Sheppo 				vdc->instance, ldep->desc_mhdl, idx, status);
24521ae08745Sheppo 	}
24531ae08745Sheppo 
24541ae08745Sheppo 	return (status);
24551ae08745Sheppo }
24561ae08745Sheppo 
2457*0a55fbb7Slm66018 /*
2458*0a55fbb7Slm66018  * Function:
2459*0a55fbb7Slm66018  *	vdc_populate_mem_hdl()
2460*0a55fbb7Slm66018  *
2461*0a55fbb7Slm66018  * Description:
2462*0a55fbb7Slm66018  *
2463*0a55fbb7Slm66018  * Arguments:
2464*0a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
2465*0a55fbb7Slm66018  *	idx	- Index of the Descriptor Ring entry being modified
2466*0a55fbb7Slm66018  *	addr	- virtual address being mapped in
2467*0a55fbb7Slm66018  *	nybtes	- number of bytes in 'addr'
2468*0a55fbb7Slm66018  *	operation - the vDisk operation being performed (VD_OP_xxx)
2469*0a55fbb7Slm66018  *
2470*0a55fbb7Slm66018  * Return Code:
2471*0a55fbb7Slm66018  *	0	- Success
2472*0a55fbb7Slm66018  */
24731ae08745Sheppo static int
24741ae08745Sheppo vdc_populate_mem_hdl(vdc_t *vdc, uint_t idx, caddr_t addr, size_t nbytes,
24751ae08745Sheppo 			int operation)
24761ae08745Sheppo {
24771ae08745Sheppo 	vd_dring_entry_t	*dep = NULL;
24781ae08745Sheppo 	vdc_local_desc_t	*ldep = NULL;
24791ae08745Sheppo 	ldc_mem_handle_t	mhdl;
24801ae08745Sheppo 	caddr_t			vaddr;
24811ae08745Sheppo 	int			perm = LDC_MEM_RW;
24821ae08745Sheppo 	int			rv = 0;
24831ae08745Sheppo 	int			i;
24841ae08745Sheppo 
24851ae08745Sheppo 	ASSERT(vdc != NULL);
24861ae08745Sheppo 	ASSERT(idx < VD_DRING_LEN);
24871ae08745Sheppo 
24881ae08745Sheppo 	dep = VDC_GET_DRING_ENTRY_PTR(vdc, idx);
24891ae08745Sheppo 	ldep = &vdc->local_dring[idx];
24901ae08745Sheppo 	mhdl = ldep->desc_mhdl;
24911ae08745Sheppo 
24921ae08745Sheppo 	switch (operation) {
24931ae08745Sheppo 	case VD_OP_BREAD:
24941ae08745Sheppo 		perm = LDC_MEM_W;
24951ae08745Sheppo 		break;
24961ae08745Sheppo 
24971ae08745Sheppo 	case VD_OP_BWRITE:
24981ae08745Sheppo 		perm = LDC_MEM_R;
24991ae08745Sheppo 		break;
25001ae08745Sheppo 
25011ae08745Sheppo 	case VD_OP_FLUSH:
25021ae08745Sheppo 	case VD_OP_GET_VTOC:
25031ae08745Sheppo 	case VD_OP_SET_VTOC:
25041ae08745Sheppo 	case VD_OP_GET_DISKGEOM:
25051ae08745Sheppo 	case VD_OP_SET_DISKGEOM:
25061ae08745Sheppo 	case VD_OP_SCSICMD:
25071ae08745Sheppo 		perm = LDC_MEM_RW;
25081ae08745Sheppo 		break;
25091ae08745Sheppo 
25101ae08745Sheppo 	default:
25111ae08745Sheppo 		ASSERT(0);	/* catch bad programming in vdc */
25121ae08745Sheppo 	}
25131ae08745Sheppo 
25141ae08745Sheppo 	/*
25151ae08745Sheppo 	 * LDC expects any addresses passed in to be 8-byte aligned. We need
25161ae08745Sheppo 	 * to copy the contents of any misaligned buffers to a newly allocated
25171ae08745Sheppo 	 * buffer and bind it instead (and copy the the contents back to the
25181ae08745Sheppo 	 * original buffer passed in when depopulating the descriptor)
25191ae08745Sheppo 	 */
25201ae08745Sheppo 	vaddr = addr;
25211ae08745Sheppo 	if (((uint64_t)addr & 0x7) != 0) {
25221ae08745Sheppo 		ldep->align_addr =
25231ae08745Sheppo 			kmem_zalloc(sizeof (caddr_t) * nbytes, KM_SLEEP);
25241ae08745Sheppo 		PR0("%s[%d] Misaligned address %lx reallocating "
25251ae08745Sheppo 		    "(buf=%lx entry=%d)\n",
25261ae08745Sheppo 		    __func__, vdc->instance, addr, ldep->align_addr, idx);
25271ae08745Sheppo 		bcopy(addr, ldep->align_addr, nbytes);
25281ae08745Sheppo 		vaddr = ldep->align_addr;
25291ae08745Sheppo 	}
25301ae08745Sheppo 
25311ae08745Sheppo 	rv = ldc_mem_bind_handle(mhdl, vaddr, P2ROUNDUP(nbytes, 8),
25321ae08745Sheppo 		vdc->dring_mem_info.mtype, perm, &dep->payload.cookie[0],
25331ae08745Sheppo 		&dep->payload.ncookies);
25341ae08745Sheppo 	PR1("%s[%d] bound mem handle; ncookies=%d\n",
25351ae08745Sheppo 			__func__, vdc->instance, dep->payload.ncookies);
25361ae08745Sheppo 	if (rv != 0) {
25371ae08745Sheppo 		vdc_msg("%s[%d] failed to ldc_mem_bind_handle "
25381ae08745Sheppo 		    "(mhdl=%lx, buf=%lx entry=%d err=%d)\n",
25391ae08745Sheppo 		    __func__, vdc->instance, mhdl, addr, idx, rv);
25401ae08745Sheppo 		if (ldep->align_addr) {
25411ae08745Sheppo 			kmem_free(ldep->align_addr,
25421ae08745Sheppo 					sizeof (caddr_t) * dep->payload.nbytes);
25431ae08745Sheppo 			ldep->align_addr = NULL;
25441ae08745Sheppo 		}
25451ae08745Sheppo 		return (EAGAIN);
25461ae08745Sheppo 	}
25471ae08745Sheppo 
25481ae08745Sheppo 	/*
25491ae08745Sheppo 	 * Get the other cookies (if any).
25501ae08745Sheppo 	 */
25511ae08745Sheppo 	for (i = 1; i < dep->payload.ncookies; i++) {
25521ae08745Sheppo 		rv = ldc_mem_nextcookie(mhdl, &dep->payload.cookie[i]);
25531ae08745Sheppo 		if (rv != 0) {
25541ae08745Sheppo 			(void) ldc_mem_unbind_handle(mhdl);
25551ae08745Sheppo 			vdc_msg("%s: failed to get next cookie(mhdl=%lx "
25561ae08745Sheppo 				"cnum=%d), err=%d", __func__, mhdl, i, 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 	return (rv);
25671ae08745Sheppo }
25681ae08745Sheppo 
25691ae08745Sheppo /*
25701ae08745Sheppo  * Interrupt handlers for messages from LDC
25711ae08745Sheppo  */
25721ae08745Sheppo 
2573*0a55fbb7Slm66018 /*
2574*0a55fbb7Slm66018  * Function:
2575*0a55fbb7Slm66018  *	vdc_handle_cb()
2576*0a55fbb7Slm66018  *
2577*0a55fbb7Slm66018  * Description:
2578*0a55fbb7Slm66018  *
2579*0a55fbb7Slm66018  * Arguments:
2580*0a55fbb7Slm66018  *	event	- Type of event (LDC_EVT_xxx) that triggered the callback
2581*0a55fbb7Slm66018  *	arg	- soft state pointer for this instance of the device driver.
2582*0a55fbb7Slm66018  *
2583*0a55fbb7Slm66018  * Return Code:
2584*0a55fbb7Slm66018  *	0	- Success
2585*0a55fbb7Slm66018  */
25861ae08745Sheppo static uint_t
25871ae08745Sheppo vdc_handle_cb(uint64_t event, caddr_t arg)
25881ae08745Sheppo {
25891ae08745Sheppo 	ldc_status_t	ldc_state;
25901ae08745Sheppo 	int		rv = 0;
25911ae08745Sheppo 
25921ae08745Sheppo 	vdc_t	*vdc = (vdc_t *)(void *)arg;
25931ae08745Sheppo 
25941ae08745Sheppo 	ASSERT(vdc != NULL);
25951ae08745Sheppo 
25961ae08745Sheppo 	PR1("%s[%d] event=%x seqID=%d\n",
25971ae08745Sheppo 			__func__, vdc->instance, event, vdc->seq_num);
25981ae08745Sheppo 
25991ae08745Sheppo 	/*
26001ae08745Sheppo 	 * Depending on the type of event that triggered this callback,
26011ae08745Sheppo 	 * we modify the handhske state or read the data.
26021ae08745Sheppo 	 *
26031ae08745Sheppo 	 * NOTE: not done as a switch() as event could be triggered by
26041ae08745Sheppo 	 * a state change and a read request. Also the ordering	of the
26051ae08745Sheppo 	 * check for the event types is deliberate.
26061ae08745Sheppo 	 */
26071ae08745Sheppo 	if (event & LDC_EVT_UP) {
26081ae08745Sheppo 		PR0("%s[%d] Received LDC_EVT_UP\n", __func__, vdc->instance);
26091ae08745Sheppo 
26101ae08745Sheppo 		/* get LDC state */
26111ae08745Sheppo 		rv = ldc_status(vdc->ldc_handle, &ldc_state);
26121ae08745Sheppo 		if (rv != 0) {
26131ae08745Sheppo 			cmn_err(CE_NOTE, "[%d] Couldn't get LDC status %d",
26141ae08745Sheppo 					vdc->instance, rv);
2615*0a55fbb7Slm66018 			mutex_enter(&vdc->lock);
26161ae08745Sheppo 			vdc_reset_connection(vdc, B_TRUE);
2617*0a55fbb7Slm66018 			mutex_exit(&vdc->lock);
26181ae08745Sheppo 			return (LDC_SUCCESS);
26191ae08745Sheppo 		}
26201ae08745Sheppo 
26211ae08745Sheppo 		/*
26221ae08745Sheppo 		 * Reset the transaction sequence numbers when LDC comes up.
26231ae08745Sheppo 		 * We then kick off the handshake negotiation with the vDisk
26241ae08745Sheppo 		 * server.
26251ae08745Sheppo 		 */
26261ae08745Sheppo 		mutex_enter(&vdc->lock);
2627*0a55fbb7Slm66018 		vdc->seq_num = 1;
26281ae08745Sheppo 		vdc->seq_num_reply = 0;
26291ae08745Sheppo 		vdc->ldc_state = ldc_state;
26301ae08745Sheppo 		ASSERT(ldc_state == LDC_UP);
26311ae08745Sheppo 		mutex_exit(&vdc->lock);
26321ae08745Sheppo 
26331ae08745Sheppo 		vdc_init_handshake_negotiation(vdc);
26341ae08745Sheppo 
26351ae08745Sheppo 		ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0);
26361ae08745Sheppo 	}
26371ae08745Sheppo 
26381ae08745Sheppo 	if (event & LDC_EVT_READ) {
26391ae08745Sheppo 		/*
26401ae08745Sheppo 		 * Wake up the worker thread to process the message
26411ae08745Sheppo 		 */
26421ae08745Sheppo 		mutex_enter(&vdc->msg_proc_lock);
26431ae08745Sheppo 		vdc->msg_pending = B_TRUE;
26441ae08745Sheppo 		cv_signal(&vdc->msg_proc_cv);
26451ae08745Sheppo 		mutex_exit(&vdc->msg_proc_lock);
26461ae08745Sheppo 
26471ae08745Sheppo 		ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0);
26481ae08745Sheppo 
26491ae08745Sheppo 		/* that's all we have to do - no need to handle DOWN/RESET */
26501ae08745Sheppo 		return (LDC_SUCCESS);
26511ae08745Sheppo 	}
26521ae08745Sheppo 
26531ae08745Sheppo 	if (event & LDC_EVT_RESET) {
26541ae08745Sheppo 		PR0("%s[%d] Recvd LDC RESET event\n", __func__, vdc->instance);
2655*0a55fbb7Slm66018 
2656*0a55fbb7Slm66018 		/* get LDC state */
2657*0a55fbb7Slm66018 		rv = ldc_status(vdc->ldc_handle, &ldc_state);
2658*0a55fbb7Slm66018 		if (rv != 0) {
2659*0a55fbb7Slm66018 			cmn_err(CE_NOTE, "[%d] Couldn't get LDC status %d",
2660*0a55fbb7Slm66018 					vdc->instance, rv);
2661*0a55fbb7Slm66018 			ldc_state = LDC_OPEN;
2662*0a55fbb7Slm66018 		}
2663*0a55fbb7Slm66018 		mutex_enter(&vdc->lock);
2664*0a55fbb7Slm66018 		vdc->ldc_state = ldc_state;
2665*0a55fbb7Slm66018 		vdc_reset_connection(vdc, B_FALSE);
2666*0a55fbb7Slm66018 		mutex_exit(&vdc->lock);
2667*0a55fbb7Slm66018 
2668*0a55fbb7Slm66018 		vdc_init_handshake_negotiation(vdc);
26691ae08745Sheppo 	}
26701ae08745Sheppo 
26711ae08745Sheppo 	if (event & LDC_EVT_DOWN) {
26721ae08745Sheppo 		PR0("%s[%d] Recvd LDC DOWN event\n", __func__, vdc->instance);
26731ae08745Sheppo 
26741ae08745Sheppo 		/* get LDC state */
26751ae08745Sheppo 		rv = ldc_status(vdc->ldc_handle, &ldc_state);
26761ae08745Sheppo 		if (rv != 0) {
26771ae08745Sheppo 			cmn_err(CE_NOTE, "[%d] Couldn't get LDC status %d",
26781ae08745Sheppo 					vdc->instance, rv);
26791ae08745Sheppo 			ldc_state = LDC_OPEN;
26801ae08745Sheppo 		}
26811ae08745Sheppo 		mutex_enter(&vdc->lock);
26821ae08745Sheppo 		vdc->ldc_state = ldc_state;
26831ae08745Sheppo 		vdc_reset_connection(vdc, B_TRUE);
2684*0a55fbb7Slm66018 		mutex_exit(&vdc->lock);
26851ae08745Sheppo 	}
26861ae08745Sheppo 
26871ae08745Sheppo 	if (event & ~(LDC_EVT_UP | LDC_EVT_RESET | LDC_EVT_DOWN | LDC_EVT_READ))
26881ae08745Sheppo 		cmn_err(CE_NOTE, "![%d] Unexpected LDC event (%lx) received",
26891ae08745Sheppo 				vdc->instance, event);
26901ae08745Sheppo 
26911ae08745Sheppo 	return (LDC_SUCCESS);
26921ae08745Sheppo }
26931ae08745Sheppo 
26941ae08745Sheppo /* -------------------------------------------------------------------------- */
26951ae08745Sheppo 
26961ae08745Sheppo /*
26971ae08745Sheppo  * The following functions process the incoming messages from vds
26981ae08745Sheppo  */
26991ae08745Sheppo 
27001ae08745Sheppo 
2701*0a55fbb7Slm66018 /*
2702*0a55fbb7Slm66018  * Function:
2703*0a55fbb7Slm66018  *	vdc_process_msg_thread()
2704*0a55fbb7Slm66018  *
2705*0a55fbb7Slm66018  * Description:
2706*0a55fbb7Slm66018  *
2707*0a55fbb7Slm66018  * Arguments:
2708*0a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
2709*0a55fbb7Slm66018  *
2710*0a55fbb7Slm66018  * Return Code:
2711*0a55fbb7Slm66018  *	None
2712*0a55fbb7Slm66018  */
27131ae08745Sheppo static void
27141ae08745Sheppo vdc_process_msg_thread(vdc_t *vdc)
27151ae08745Sheppo {
27161ae08745Sheppo 	int		status = 0;
27171ae08745Sheppo 	boolean_t	q_is_empty = B_TRUE;
27181ae08745Sheppo 
27191ae08745Sheppo 	ASSERT(vdc != NULL);
27201ae08745Sheppo 
27211ae08745Sheppo 	mutex_enter(&vdc->msg_proc_lock);
27221ae08745Sheppo 	PR0("%s[%d]: Starting\n", __func__, vdc->instance);
27231ae08745Sheppo 
27241ae08745Sheppo 	vdc->msg_proc_thr_state = VDC_THR_RUNNING;
27251ae08745Sheppo 
27261ae08745Sheppo 	while (vdc->msg_proc_thr_state == VDC_THR_RUNNING) {
27271ae08745Sheppo 
27281ae08745Sheppo 		PR1("%s[%d] Waiting\n", __func__, vdc->instance);
2729*0a55fbb7Slm66018 		while (!vdc->msg_pending)
27301ae08745Sheppo 			cv_wait(&vdc->msg_proc_cv, &vdc->msg_proc_lock);
27311ae08745Sheppo 
27321ae08745Sheppo 		PR1("%s[%d] Message Received\n", __func__, vdc->instance);
27331ae08745Sheppo 
27341ae08745Sheppo 		/* check if there is data */
27351ae08745Sheppo 		status = ldc_chkq(vdc->ldc_handle, &q_is_empty);
27361ae08745Sheppo 		if ((status != 0) &&
27371ae08745Sheppo 		    (vdc->msg_proc_thr_state == VDC_THR_RUNNING)) {
27381ae08745Sheppo 			cmn_err(CE_NOTE, "[%d] Unable to communicate with vDisk"
27391ae08745Sheppo 					" server. Cannot check LDC queue: %d",
27401ae08745Sheppo 					vdc->instance, status);
27411ae08745Sheppo 			mutex_enter(&vdc->lock);
2742*0a55fbb7Slm66018 			vdc_reset_connection(vdc, B_FALSE);
27431ae08745Sheppo 			mutex_exit(&vdc->lock);
27441ae08745Sheppo 			vdc->msg_proc_thr_state = VDC_THR_STOP;
27451ae08745Sheppo 			continue;
27461ae08745Sheppo 		}
27471ae08745Sheppo 
2748*0a55fbb7Slm66018 		if (!q_is_empty) {
27491ae08745Sheppo 			PR1("%s: new pkt(s) available\n", __func__);
27501ae08745Sheppo 			vdc_process_msg(vdc);
27511ae08745Sheppo 		}
27521ae08745Sheppo 
27531ae08745Sheppo 		vdc->msg_pending = B_FALSE;
27541ae08745Sheppo 	}
27551ae08745Sheppo 
27561ae08745Sheppo 	PR0("Message processing thread stopped\n");
27571ae08745Sheppo 	vdc->msg_pending = B_FALSE;
27581ae08745Sheppo 	vdc->msg_proc_thr_state = VDC_THR_DONE;
27591ae08745Sheppo 	cv_signal(&vdc->msg_proc_cv);
27601ae08745Sheppo 	mutex_exit(&vdc->msg_proc_lock);
27611ae08745Sheppo 	thread_exit();
27621ae08745Sheppo }
27631ae08745Sheppo 
27641ae08745Sheppo 
27651ae08745Sheppo /*
27661ae08745Sheppo  * Function:
27671ae08745Sheppo  *	vdc_process_msg()
27681ae08745Sheppo  *
27691ae08745Sheppo  * Description:
27701ae08745Sheppo  *	This function is called by the message processing thread each time it
27711ae08745Sheppo  *	is triggered when LDC sends an interrupt to indicate that there are
27721ae08745Sheppo  *	more packets on the queue. When it is called it will continue to loop
27731ae08745Sheppo  *	and read the messages until there are no more left of the queue. If it
27741ae08745Sheppo  *	encounters an invalid sized message it will drop it and check the next
27751ae08745Sheppo  *	message.
27761ae08745Sheppo  *
27771ae08745Sheppo  * Arguments:
27781ae08745Sheppo  *	arg	- soft state pointer for this instance of the device driver.
27791ae08745Sheppo  *
27801ae08745Sheppo  * Return Code:
27811ae08745Sheppo  *	None.
27821ae08745Sheppo  */
27831ae08745Sheppo static void
27841ae08745Sheppo vdc_process_msg(void *arg)
27851ae08745Sheppo {
27861ae08745Sheppo 	vdc_t		*vdc = (vdc_t *)(void *)arg;
27871ae08745Sheppo 	vio_msg_t	vio_msg;
27881ae08745Sheppo 	size_t		nbytes = sizeof (vio_msg);
27891ae08745Sheppo 	int		status;
27901ae08745Sheppo 
27911ae08745Sheppo 	ASSERT(vdc != NULL);
27921ae08745Sheppo 
27931ae08745Sheppo 	mutex_enter(&vdc->lock);
27941ae08745Sheppo 
27951ae08745Sheppo 	PR1("%s\n", __func__);
27961ae08745Sheppo 
27971ae08745Sheppo 	for (;;) {
27981ae08745Sheppo 
27991ae08745Sheppo 		/* read all messages - until no more left */
28001ae08745Sheppo 		status = ldc_read(vdc->ldc_handle, (caddr_t)&vio_msg, &nbytes);
28011ae08745Sheppo 
28021ae08745Sheppo 		if (status) {
28031ae08745Sheppo 			vdc_msg("%s: ldc_read() failed = %d", __func__, status);
28041ae08745Sheppo 
28051ae08745Sheppo 			/* if status is ECONNRESET --- reset vdc state */
28061ae08745Sheppo 			if (status == EIO || status == ECONNRESET) {
2807*0a55fbb7Slm66018 				vdc_reset_connection(vdc, B_TRUE);
28081ae08745Sheppo 			}
28091ae08745Sheppo 
28101ae08745Sheppo 			mutex_exit(&vdc->lock);
28111ae08745Sheppo 			return;
28121ae08745Sheppo 		}
28131ae08745Sheppo 
28141ae08745Sheppo 		if ((nbytes > 0) && (nbytes < sizeof (vio_msg_tag_t))) {
28151ae08745Sheppo 			cmn_err(CE_CONT, "![%d] Expect %lu bytes; recv'd %lu\n",
28161ae08745Sheppo 				vdc->instance, sizeof (vio_msg_tag_t), nbytes);
28171ae08745Sheppo 			mutex_exit(&vdc->lock);
28181ae08745Sheppo 			return;
28191ae08745Sheppo 		}
28201ae08745Sheppo 
28211ae08745Sheppo 		if (nbytes == 0) {
28221ae08745Sheppo 			PR2("%s[%d]: ldc_read() done..\n",
28231ae08745Sheppo 					__func__, vdc->instance);
28241ae08745Sheppo 			mutex_exit(&vdc->lock);
28251ae08745Sheppo 			return;
28261ae08745Sheppo 		}
28271ae08745Sheppo 
28281ae08745Sheppo 		PR1("%s[%d] (%x/%x/%x)\n", __func__, vdc->instance,
28291ae08745Sheppo 		    vio_msg.tag.vio_msgtype,
28301ae08745Sheppo 		    vio_msg.tag.vio_subtype,
28311ae08745Sheppo 		    vio_msg.tag.vio_subtype_env);
28321ae08745Sheppo 
28331ae08745Sheppo 		/*
28341ae08745Sheppo 		 * Verify the Session ID of the message
28351ae08745Sheppo 		 *
28361ae08745Sheppo 		 * Every message after the Version has been negotiated should
28371ae08745Sheppo 		 * have the correct session ID set.
28381ae08745Sheppo 		 */
28391ae08745Sheppo 		if ((vio_msg.tag.vio_sid != vdc->session_id) &&
28401ae08745Sheppo 		    (vio_msg.tag.vio_subtype_env != VIO_VER_INFO)) {
2841*0a55fbb7Slm66018 			cmn_err(CE_NOTE, "[%d] Invalid SID 0x%x, expect 0x%lx",
2842*0a55fbb7Slm66018 				vdc->instance, vio_msg.tag.vio_sid,
28431ae08745Sheppo 				vdc->session_id);
28441ae08745Sheppo 			vdc_reset_connection(vdc, B_FALSE);
28451ae08745Sheppo 			mutex_exit(&vdc->lock);
28461ae08745Sheppo 			return;
28471ae08745Sheppo 		}
28481ae08745Sheppo 
28491ae08745Sheppo 		switch (vio_msg.tag.vio_msgtype) {
28501ae08745Sheppo 		case VIO_TYPE_CTRL:
28511ae08745Sheppo 			status = vdc_process_ctrl_msg(vdc, vio_msg);
28521ae08745Sheppo 			break;
28531ae08745Sheppo 		case VIO_TYPE_DATA:
28541ae08745Sheppo 			status = vdc_process_data_msg(vdc, vio_msg);
28551ae08745Sheppo 			break;
28561ae08745Sheppo 		case VIO_TYPE_ERR:
28571ae08745Sheppo 			status = vdc_process_err_msg(vdc, vio_msg);
28581ae08745Sheppo 			break;
28591ae08745Sheppo 		default:
28601ae08745Sheppo 			PR1("%s", __func__);
28611ae08745Sheppo 			status = EINVAL;
28621ae08745Sheppo 			break;
28631ae08745Sheppo 		}
28641ae08745Sheppo 
28651ae08745Sheppo 		if (status != 0) {
28661ae08745Sheppo 			PR0("%s[%d] Error (%d) occcurred processing msg\n",
28671ae08745Sheppo 					__func__, vdc->instance, status);
28681ae08745Sheppo 			vdc_reset_connection(vdc, B_FALSE);
28691ae08745Sheppo 		}
28701ae08745Sheppo 	}
28711ae08745Sheppo 	_NOTE(NOTREACHED)
28721ae08745Sheppo }
28731ae08745Sheppo 
28741ae08745Sheppo /*
28751ae08745Sheppo  * Function:
28761ae08745Sheppo  *	vdc_process_ctrl_msg()
28771ae08745Sheppo  *
28781ae08745Sheppo  * Description:
28791ae08745Sheppo  *	This function is called by the message processing thread each time
28801ae08745Sheppo  *	an LDC message with a msgtype of VIO_TYPE_CTRL is received.
28811ae08745Sheppo  *
28821ae08745Sheppo  * Arguments:
28831ae08745Sheppo  *	vdc	- soft state pointer for this instance of the device driver.
28841ae08745Sheppo  *	msg	- the LDC message sent by vds
28851ae08745Sheppo  *
28861ae08745Sheppo  * Return Codes:
28871ae08745Sheppo  *	0	- Success.
28881ae08745Sheppo  *	EPROTO	- A message was received which shouldn't have happened according
28891ae08745Sheppo  *		  to the protocol
28901ae08745Sheppo  *	ENOTSUP	- An action which is allowed according to the protocol but which
28911ae08745Sheppo  *		  isn't (or doesn't need to be) implemented yet.
28921ae08745Sheppo  *	EINVAL	- An invalid value was returned as part of a message.
28931ae08745Sheppo  */
28941ae08745Sheppo static int
28951ae08745Sheppo vdc_process_ctrl_msg(vdc_t *vdc, vio_msg_t msg)
28961ae08745Sheppo {
28971ae08745Sheppo 	int			status = -1;
28981ae08745Sheppo 
28991ae08745Sheppo 	ASSERT(msg.tag.vio_msgtype == VIO_TYPE_CTRL);
29001ae08745Sheppo 	ASSERT(vdc != NULL);
29011ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
29021ae08745Sheppo 
29031ae08745Sheppo 	/* Depending on which state we are in; process the message */
29041ae08745Sheppo 	switch (vdc->state) {
29051ae08745Sheppo 	case VD_STATE_INIT:
2906*0a55fbb7Slm66018 		status = vdc_handle_ver_msg(vdc, (vio_ver_msg_t *)&msg);
2907*0a55fbb7Slm66018 		break;
2908*0a55fbb7Slm66018 
2909*0a55fbb7Slm66018 	case VD_STATE_VER:
2910*0a55fbb7Slm66018 		status = vdc_handle_attr_msg(vdc, (vd_attr_msg_t *)&msg);
2911*0a55fbb7Slm66018 		break;
2912*0a55fbb7Slm66018 
2913*0a55fbb7Slm66018 	case VD_STATE_ATTR:
2914*0a55fbb7Slm66018 		status = vdc_handle_dring_reg_msg(vdc,
2915*0a55fbb7Slm66018 				(vio_dring_reg_msg_t *)&msg);
2916*0a55fbb7Slm66018 		break;
2917*0a55fbb7Slm66018 
2918*0a55fbb7Slm66018 	case VD_STATE_RDX:
2919*0a55fbb7Slm66018 		if (msg.tag.vio_subtype_env != VIO_RDX) {
29201ae08745Sheppo 			status = EPROTO;
29211ae08745Sheppo 			break;
29221ae08745Sheppo 		}
29231ae08745Sheppo 
2924*0a55fbb7Slm66018 		PR0("%s: Received RDX - handshake successful\n", __func__);
29251ae08745Sheppo 
2926*0a55fbb7Slm66018 		vdc->hshake_cnt = 0;	/* reset failed handshake count */
2927*0a55fbb7Slm66018 		status = 0;
2928*0a55fbb7Slm66018 		vdc->state = VD_STATE_DATA;
2929*0a55fbb7Slm66018 
2930*0a55fbb7Slm66018 		cv_broadcast(&vdc->attach_cv);
2931*0a55fbb7Slm66018 		break;
2932*0a55fbb7Slm66018 
2933*0a55fbb7Slm66018 	case VD_STATE_DATA:
2934*0a55fbb7Slm66018 	default:
2935*0a55fbb7Slm66018 		cmn_err(CE_NOTE, "[%d] Unexpected handshake state %d",
2936*0a55fbb7Slm66018 				vdc->instance, vdc->state);
29371ae08745Sheppo 		status = EPROTO;
29381ae08745Sheppo 		break;
2939*0a55fbb7Slm66018 	}
29401ae08745Sheppo 
2941*0a55fbb7Slm66018 	return (status);
2942*0a55fbb7Slm66018 }
2943*0a55fbb7Slm66018 
2944*0a55fbb7Slm66018 
2945*0a55fbb7Slm66018 /*
2946*0a55fbb7Slm66018  * Function:
2947*0a55fbb7Slm66018  *	vdc_process_data_msg()
2948*0a55fbb7Slm66018  *
2949*0a55fbb7Slm66018  * Description:
2950*0a55fbb7Slm66018  *	This function is called by the message processing thread each time
2951*0a55fbb7Slm66018  *	a message with a msgtype of VIO_TYPE_DATA is received. It will either
2952*0a55fbb7Slm66018  *	be an ACK or NACK from vds[1] which vdc handles as follows.
2953*0a55fbb7Slm66018  *		ACK	- wake up the waiting thread
2954*0a55fbb7Slm66018  *		NACK	- resend any messages necessary
2955*0a55fbb7Slm66018  *
2956*0a55fbb7Slm66018  *	[1] Although the message format allows it, vds should not send a
2957*0a55fbb7Slm66018  *	    VIO_SUBTYPE_INFO message to vdc asking it to read data; if for
2958*0a55fbb7Slm66018  *	    some bizarre reason it does, vdc will reset the connection.
2959*0a55fbb7Slm66018  *
2960*0a55fbb7Slm66018  * Arguments:
2961*0a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
2962*0a55fbb7Slm66018  *	msg	- the LDC message sent by vds
2963*0a55fbb7Slm66018  *
2964*0a55fbb7Slm66018  * Return Code:
2965*0a55fbb7Slm66018  *	0	- Success.
2966*0a55fbb7Slm66018  *	> 0	- error value returned by LDC
2967*0a55fbb7Slm66018  */
2968*0a55fbb7Slm66018 static int
2969*0a55fbb7Slm66018 vdc_process_data_msg(vdc_t *vdc, vio_msg_t msg)
2970*0a55fbb7Slm66018 {
2971*0a55fbb7Slm66018 	int			status = 0;
2972*0a55fbb7Slm66018 	vdc_local_desc_t	*local_dep = NULL;
2973*0a55fbb7Slm66018 	vio_dring_msg_t		*dring_msg = NULL;
2974*0a55fbb7Slm66018 	uint_t			num_msgs;
2975*0a55fbb7Slm66018 	uint_t			start;
2976*0a55fbb7Slm66018 	uint_t			end;
2977*0a55fbb7Slm66018 	uint_t			i;
2978*0a55fbb7Slm66018 
2979*0a55fbb7Slm66018 	ASSERT(msg.tag.vio_msgtype == VIO_TYPE_DATA);
2980*0a55fbb7Slm66018 	ASSERT(vdc != NULL);
2981*0a55fbb7Slm66018 	ASSERT(mutex_owned(&vdc->lock));
2982*0a55fbb7Slm66018 
2983*0a55fbb7Slm66018 	dring_msg = (vio_dring_msg_t *)&msg;
2984*0a55fbb7Slm66018 
2985*0a55fbb7Slm66018 	/*
2986*0a55fbb7Slm66018 	 * Check to see if the message has bogus data
2987*0a55fbb7Slm66018 	 */
2988*0a55fbb7Slm66018 	start = dring_msg->start_idx;
2989*0a55fbb7Slm66018 	end = dring_msg->end_idx;
2990*0a55fbb7Slm66018 	if ((start >= VD_DRING_LEN) || (end >= VD_DRING_LEN)) {
2991*0a55fbb7Slm66018 		vdc_msg("%s: Bogus ACK data : start %d, end %d\n",
2992*0a55fbb7Slm66018 			__func__, start, end);
2993*0a55fbb7Slm66018 		return (EPROTO);
2994*0a55fbb7Slm66018 	}
2995*0a55fbb7Slm66018 
2996*0a55fbb7Slm66018 	/*
2997*0a55fbb7Slm66018 	 * calculate the number of messages that vds ACK'ed
2998*0a55fbb7Slm66018 	 *
2999*0a55fbb7Slm66018 	 * Assumes, (like the rest of vdc) that there is a 1:1 mapping
3000*0a55fbb7Slm66018 	 * between requests and Dring entries.
3001*0a55fbb7Slm66018 	 */
3002*0a55fbb7Slm66018 	num_msgs = (end >= start) ?
3003*0a55fbb7Slm66018 			(end - start + 1) :
3004*0a55fbb7Slm66018 			(VD_DRING_LEN - start + end + 1);
3005*0a55fbb7Slm66018 
3006*0a55fbb7Slm66018 	/*
3007*0a55fbb7Slm66018 	 * Verify that the sequence number is what vdc expects.
3008*0a55fbb7Slm66018 	 */
3009*0a55fbb7Slm66018 	if (!vdc_verify_seq_num(vdc, dring_msg, num_msgs)) {
3010*0a55fbb7Slm66018 		return (ENXIO);
3011*0a55fbb7Slm66018 	}
3012*0a55fbb7Slm66018 
3013*0a55fbb7Slm66018 	/*
3014*0a55fbb7Slm66018 	 * Wake the thread waiting for each DRing entry ACK'ed
3015*0a55fbb7Slm66018 	 */
3016*0a55fbb7Slm66018 	for (i = 0; i < num_msgs; i++) {
3017*0a55fbb7Slm66018 		int idx = (start + i) % VD_DRING_LEN;
3018*0a55fbb7Slm66018 
3019*0a55fbb7Slm66018 		local_dep = &vdc->local_dring[idx];
3020*0a55fbb7Slm66018 		mutex_enter(&local_dep->lock);
3021*0a55fbb7Slm66018 		cv_signal(&local_dep->cv);
3022*0a55fbb7Slm66018 		mutex_exit(&local_dep->lock);
3023*0a55fbb7Slm66018 	}
3024*0a55fbb7Slm66018 
3025*0a55fbb7Slm66018 	if (msg.tag.vio_subtype == VIO_SUBTYPE_NACK) {
3026*0a55fbb7Slm66018 		PR0("%s: DATA NACK\n", __func__);
3027*0a55fbb7Slm66018 		VDC_DUMP_DRING_MSG(dring_msg);
3028*0a55fbb7Slm66018 		vdc_reset_connection(vdc, B_FALSE);
3029*0a55fbb7Slm66018 
3030*0a55fbb7Slm66018 		/* we need to drop the lock to trigger the handshake */
3031*0a55fbb7Slm66018 		mutex_exit(&vdc->lock);
3032*0a55fbb7Slm66018 		vdc_init_handshake_negotiation(vdc);
3033*0a55fbb7Slm66018 		mutex_enter(&vdc->lock);
3034*0a55fbb7Slm66018 	} else if (msg.tag.vio_subtype == VIO_SUBTYPE_INFO) {
3035*0a55fbb7Slm66018 		status = EPROTO;
3036*0a55fbb7Slm66018 	}
3037*0a55fbb7Slm66018 
3038*0a55fbb7Slm66018 	return (status);
3039*0a55fbb7Slm66018 }
3040*0a55fbb7Slm66018 
3041*0a55fbb7Slm66018 /*
3042*0a55fbb7Slm66018  * Function:
3043*0a55fbb7Slm66018  *	vdc_process_err_msg()
3044*0a55fbb7Slm66018  *
3045*0a55fbb7Slm66018  * NOTE: No error messages are used as part of the vDisk protocol
3046*0a55fbb7Slm66018  */
3047*0a55fbb7Slm66018 static int
3048*0a55fbb7Slm66018 vdc_process_err_msg(vdc_t *vdc, vio_msg_t msg)
3049*0a55fbb7Slm66018 {
3050*0a55fbb7Slm66018 	_NOTE(ARGUNUSED(vdc))
3051*0a55fbb7Slm66018 	_NOTE(ARGUNUSED(msg))
3052*0a55fbb7Slm66018 
3053*0a55fbb7Slm66018 	ASSERT(msg.tag.vio_msgtype == VIO_TYPE_ERR);
3054*0a55fbb7Slm66018 	cmn_err(CE_NOTE, "[%d] Got an ERR msg", vdc->instance);
3055*0a55fbb7Slm66018 
3056*0a55fbb7Slm66018 	return (ENOTSUP);
3057*0a55fbb7Slm66018 }
3058*0a55fbb7Slm66018 
3059*0a55fbb7Slm66018 /*
3060*0a55fbb7Slm66018  * Function:
3061*0a55fbb7Slm66018  *	vdc_handle_ver_msg()
3062*0a55fbb7Slm66018  *
3063*0a55fbb7Slm66018  * Description:
3064*0a55fbb7Slm66018  *
3065*0a55fbb7Slm66018  * Arguments:
3066*0a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
3067*0a55fbb7Slm66018  *	ver_msg	- LDC message sent by vDisk server
3068*0a55fbb7Slm66018  *
3069*0a55fbb7Slm66018  * Return Code:
3070*0a55fbb7Slm66018  *	0	- Success
3071*0a55fbb7Slm66018  */
3072*0a55fbb7Slm66018 static int
3073*0a55fbb7Slm66018 vdc_handle_ver_msg(vdc_t *vdc, vio_ver_msg_t *ver_msg)
3074*0a55fbb7Slm66018 {
3075*0a55fbb7Slm66018 	int status = 0;
3076*0a55fbb7Slm66018 
3077*0a55fbb7Slm66018 	ASSERT(vdc != NULL);
3078*0a55fbb7Slm66018 	ASSERT(mutex_owned(&vdc->lock));
3079*0a55fbb7Slm66018 
3080*0a55fbb7Slm66018 	if (ver_msg->tag.vio_subtype_env != VIO_VER_INFO) {
3081*0a55fbb7Slm66018 		return (EPROTO);
3082*0a55fbb7Slm66018 	}
3083*0a55fbb7Slm66018 
3084*0a55fbb7Slm66018 	if (ver_msg->dev_class != VDEV_DISK_SERVER) {
3085*0a55fbb7Slm66018 		return (EINVAL);
3086*0a55fbb7Slm66018 	}
3087*0a55fbb7Slm66018 
3088*0a55fbb7Slm66018 	switch (ver_msg->tag.vio_subtype) {
3089*0a55fbb7Slm66018 	case VIO_SUBTYPE_ACK:
3090*0a55fbb7Slm66018 		/*
3091*0a55fbb7Slm66018 		 * We check to see if the version returned is indeed supported
3092*0a55fbb7Slm66018 		 * (The server may have also adjusted the minor number downwards
3093*0a55fbb7Slm66018 		 * and if so 'ver_msg' will contain the actual version agreed)
3094*0a55fbb7Slm66018 		 */
3095*0a55fbb7Slm66018 		if (vdc_is_supported_version(ver_msg)) {
3096*0a55fbb7Slm66018 			vdc->ver.major = ver_msg->ver_major;
3097*0a55fbb7Slm66018 			vdc->ver.minor = ver_msg->ver_minor;
3098*0a55fbb7Slm66018 			ASSERT(vdc->ver.major > 0);
3099*0a55fbb7Slm66018 
3100*0a55fbb7Slm66018 			vdc->state = VD_STATE_VER;
3101*0a55fbb7Slm66018 			status = vdc_init_attr_negotiation(vdc);
3102*0a55fbb7Slm66018 		} else {
3103*0a55fbb7Slm66018 			status = EPROTO;
3104*0a55fbb7Slm66018 		}
3105*0a55fbb7Slm66018 		break;
3106*0a55fbb7Slm66018 
3107*0a55fbb7Slm66018 	case VIO_SUBTYPE_NACK:
3108*0a55fbb7Slm66018 		/*
3109*0a55fbb7Slm66018 		 * call vdc_is_supported_version() which will return the next
3110*0a55fbb7Slm66018 		 * supported version (if any) in 'ver_msg'
3111*0a55fbb7Slm66018 		 */
3112*0a55fbb7Slm66018 		(void) vdc_is_supported_version(ver_msg);
3113*0a55fbb7Slm66018 		if (ver_msg->ver_major > 0) {
3114*0a55fbb7Slm66018 			size_t len = sizeof (*ver_msg);
3115*0a55fbb7Slm66018 
3116*0a55fbb7Slm66018 			ASSERT(vdc->ver.major > 0);
3117*0a55fbb7Slm66018 
3118*0a55fbb7Slm66018 			/* reset the necessary fields and resend */
3119*0a55fbb7Slm66018 			ver_msg->tag.vio_subtype = VIO_SUBTYPE_INFO;
3120*0a55fbb7Slm66018 			ver_msg->dev_class = VDEV_DISK;
3121*0a55fbb7Slm66018 
3122*0a55fbb7Slm66018 			status = vdc_send(vdc, (caddr_t)ver_msg, &len);
3123*0a55fbb7Slm66018 			PR0("[%d] Resend VER info (LDC status = %d)\n",
3124*0a55fbb7Slm66018 					vdc->instance, status);
3125*0a55fbb7Slm66018 			if (len != sizeof (*ver_msg))
3126*0a55fbb7Slm66018 				status = EBADMSG;
3127*0a55fbb7Slm66018 		} else {
3128*0a55fbb7Slm66018 			cmn_err(CE_NOTE, "[%d] No common version with "
3129*0a55fbb7Slm66018 					"vDisk server", vdc->instance);
3130*0a55fbb7Slm66018 			status = ENOTSUP;
3131*0a55fbb7Slm66018 		}
3132*0a55fbb7Slm66018 
3133*0a55fbb7Slm66018 		break;
31341ae08745Sheppo 	case VIO_SUBTYPE_INFO:
31351ae08745Sheppo 		/*
31361ae08745Sheppo 		 * Handle the case where vds starts handshake
31371ae08745Sheppo 		 * (for now only vdc is the instigatior)
31381ae08745Sheppo 		 */
31391ae08745Sheppo 		status = ENOTSUP;
31401ae08745Sheppo 		break;
31411ae08745Sheppo 
31421ae08745Sheppo 	default:
3143*0a55fbb7Slm66018 		status = EINVAL;
31441ae08745Sheppo 		break;
31451ae08745Sheppo 	}
31461ae08745Sheppo 
3147*0a55fbb7Slm66018 	return (status);
3148*0a55fbb7Slm66018 }
3149*0a55fbb7Slm66018 
3150*0a55fbb7Slm66018 /*
3151*0a55fbb7Slm66018  * Function:
3152*0a55fbb7Slm66018  *	vdc_handle_attr_msg()
3153*0a55fbb7Slm66018  *
3154*0a55fbb7Slm66018  * Description:
3155*0a55fbb7Slm66018  *
3156*0a55fbb7Slm66018  * Arguments:
3157*0a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
3158*0a55fbb7Slm66018  *	attr_msg	- LDC message sent by vDisk server
3159*0a55fbb7Slm66018  *
3160*0a55fbb7Slm66018  * Return Code:
3161*0a55fbb7Slm66018  *	0	- Success
3162*0a55fbb7Slm66018  */
3163*0a55fbb7Slm66018 static int
3164*0a55fbb7Slm66018 vdc_handle_attr_msg(vdc_t *vdc, vd_attr_msg_t *attr_msg)
3165*0a55fbb7Slm66018 {
3166*0a55fbb7Slm66018 	int status = 0;
3167*0a55fbb7Slm66018 
3168*0a55fbb7Slm66018 	ASSERT(vdc != NULL);
3169*0a55fbb7Slm66018 	ASSERT(mutex_owned(&vdc->lock));
3170*0a55fbb7Slm66018 
3171*0a55fbb7Slm66018 	if (attr_msg->tag.vio_subtype_env != VIO_ATTR_INFO) {
3172*0a55fbb7Slm66018 		return (EPROTO);
3173*0a55fbb7Slm66018 	}
3174*0a55fbb7Slm66018 
3175*0a55fbb7Slm66018 	switch (attr_msg->tag.vio_subtype) {
31761ae08745Sheppo 	case VIO_SUBTYPE_ACK:
31771ae08745Sheppo 		/*
31781ae08745Sheppo 		 * We now verify the attributes sent by vds.
31791ae08745Sheppo 		 */
31801ae08745Sheppo 		vdc->vdisk_size = attr_msg->vdisk_size;
31811ae08745Sheppo 		vdc->vdisk_type = attr_msg->vdisk_type;
31821ae08745Sheppo 
31831ae08745Sheppo 		if ((attr_msg->max_xfer_sz != vdc->max_xfer_sz) ||
31841ae08745Sheppo 		    (attr_msg->vdisk_block_size != vdc->block_size)) {
31851ae08745Sheppo 			/*
31861ae08745Sheppo 			 * Future support: step down to the block size
31871ae08745Sheppo 			 * and max transfer size suggested by the
31881ae08745Sheppo 			 * server. (If this value is less than 128K
31891ae08745Sheppo 			 * then multiple Dring entries per request
31901ae08745Sheppo 			 * would need to be implemented)
31911ae08745Sheppo 			 */
31921ae08745Sheppo 			cmn_err(CE_NOTE, "[%d] Couldn't process block "
3193*0a55fbb7Slm66018 				"attributes from vds", vdc->instance);
31941ae08745Sheppo 			status = EINVAL;
31951ae08745Sheppo 			break;
31961ae08745Sheppo 		}
31971ae08745Sheppo 
31981ae08745Sheppo 		if ((attr_msg->xfer_mode != VIO_DRING_MODE) ||
31991ae08745Sheppo 		    (attr_msg->vdisk_size > INT64_MAX) ||
32001ae08745Sheppo 		    (attr_msg->vdisk_type > VD_DISK_TYPE_DISK)) {
32011ae08745Sheppo 			vdc_msg("%s[%d] Couldn't process attrs "
32021ae08745Sheppo 			    "from vds", __func__, vdc->instance);
32031ae08745Sheppo 			status = EINVAL;
32041ae08745Sheppo 			break;
32051ae08745Sheppo 		}
32061ae08745Sheppo 
32071ae08745Sheppo 		vdc->state = VD_STATE_ATTR;
32081ae08745Sheppo 		status = vdc_init_dring_negotiate(vdc);
32091ae08745Sheppo 		break;
32101ae08745Sheppo 
32111ae08745Sheppo 	case VIO_SUBTYPE_NACK:
32121ae08745Sheppo 		/*
32131ae08745Sheppo 		 * vds could not handle the attributes we sent so we
32141ae08745Sheppo 		 * stop negotiating.
32151ae08745Sheppo 		 */
32161ae08745Sheppo 		status = EPROTO;
32171ae08745Sheppo 		break;
32181ae08745Sheppo 
32191ae08745Sheppo 	case VIO_SUBTYPE_INFO:
32201ae08745Sheppo 		/*
32211ae08745Sheppo 		 * Handle the case where vds starts the handshake
32221ae08745Sheppo 		 * (for now; vdc is the only supported instigatior)
32231ae08745Sheppo 		 */
32241ae08745Sheppo 		status = ENOTSUP;
32251ae08745Sheppo 		break;
32261ae08745Sheppo 
32271ae08745Sheppo 	default:
32281ae08745Sheppo 		status = ENOTSUP;
32291ae08745Sheppo 		break;
32301ae08745Sheppo 	}
32311ae08745Sheppo 
3232*0a55fbb7Slm66018 	return (status);
32331ae08745Sheppo }
32341ae08745Sheppo 
3235*0a55fbb7Slm66018 /*
3236*0a55fbb7Slm66018  * Function:
3237*0a55fbb7Slm66018  *	vdc_handle_dring_reg_msg()
3238*0a55fbb7Slm66018  *
3239*0a55fbb7Slm66018  * Description:
3240*0a55fbb7Slm66018  *
3241*0a55fbb7Slm66018  * Arguments:
3242*0a55fbb7Slm66018  *	vdc		- soft state pointer for this instance of the driver.
3243*0a55fbb7Slm66018  *	dring_msg	- LDC message sent by vDisk server
3244*0a55fbb7Slm66018  *
3245*0a55fbb7Slm66018  * Return Code:
3246*0a55fbb7Slm66018  *	0	- Success
3247*0a55fbb7Slm66018  */
3248*0a55fbb7Slm66018 static int
3249*0a55fbb7Slm66018 vdc_handle_dring_reg_msg(vdc_t *vdc, vio_dring_reg_msg_t *dring_msg)
3250*0a55fbb7Slm66018 {
3251*0a55fbb7Slm66018 	int		status = 0;
3252*0a55fbb7Slm66018 	vio_rdx_msg_t	msg = {0};
3253*0a55fbb7Slm66018 	size_t		msglen = sizeof (msg);
32541ae08745Sheppo 
3255*0a55fbb7Slm66018 	ASSERT(vdc != NULL);
3256*0a55fbb7Slm66018 	ASSERT(mutex_owned(&vdc->lock));
3257*0a55fbb7Slm66018 
3258*0a55fbb7Slm66018 	if (dring_msg->tag.vio_subtype_env != VIO_DRING_REG) {
3259*0a55fbb7Slm66018 		return (EPROTO);
3260*0a55fbb7Slm66018 	}
3261*0a55fbb7Slm66018 
3262*0a55fbb7Slm66018 	switch (dring_msg->tag.vio_subtype) {
3263*0a55fbb7Slm66018 	case VIO_SUBTYPE_ACK:
32641ae08745Sheppo 		/* save the received dring_ident */
32651ae08745Sheppo 		vdc->dring_ident = dring_msg->dring_ident;
32661ae08745Sheppo 		PR0("%s[%d] Received dring ident=0x%lx\n",
32671ae08745Sheppo 			__func__, vdc->instance, vdc->dring_ident);
32681ae08745Sheppo 
32691ae08745Sheppo 		/*
32701ae08745Sheppo 		 * Send an RDX message to vds to indicate we are ready
32711ae08745Sheppo 		 * to send data
32721ae08745Sheppo 		 */
32731ae08745Sheppo 		msg.tag.vio_msgtype = VIO_TYPE_CTRL;
32741ae08745Sheppo 		msg.tag.vio_subtype = VIO_SUBTYPE_INFO;
32751ae08745Sheppo 		msg.tag.vio_subtype_env = VIO_RDX;
32761ae08745Sheppo 		msg.tag.vio_sid = vdc->session_id;
3277*0a55fbb7Slm66018 		status = vdc_send(vdc, (caddr_t)&msg, &msglen);
32781ae08745Sheppo 		if (status != 0) {
32791ae08745Sheppo 			cmn_err(CE_NOTE, "[%d] Failed to send RDX"
32801ae08745Sheppo 				" message (%d)", vdc->instance, status);
32811ae08745Sheppo 			break;
32821ae08745Sheppo 		}
32831ae08745Sheppo 
32841ae08745Sheppo 		vdc->state = VD_STATE_RDX;
32851ae08745Sheppo 		break;
32861ae08745Sheppo 
32871ae08745Sheppo 	case VIO_SUBTYPE_NACK:
32881ae08745Sheppo 		/*
32891ae08745Sheppo 		 * vds could not handle the DRing info we sent so we
32901ae08745Sheppo 		 * stop negotiating.
32911ae08745Sheppo 		 */
32921ae08745Sheppo 		cmn_err(CE_CONT, "server could not register DRing\n");
32931ae08745Sheppo 		vdc_reset_connection(vdc, B_FALSE);
32941ae08745Sheppo 		vdc_destroy_descriptor_ring(vdc);
32951ae08745Sheppo 		status = EPROTO;
32961ae08745Sheppo 		break;
32971ae08745Sheppo 
32981ae08745Sheppo 	case VIO_SUBTYPE_INFO:
32991ae08745Sheppo 		/*
33001ae08745Sheppo 		 * Handle the case where vds starts handshake
33011ae08745Sheppo 		 * (for now only vdc is the instigatior)
33021ae08745Sheppo 		 */
33031ae08745Sheppo 		status = ENOTSUP;
33041ae08745Sheppo 		break;
33051ae08745Sheppo 	default:
33061ae08745Sheppo 		status = ENOTSUP;
33071ae08745Sheppo 	}
33081ae08745Sheppo 
33091ae08745Sheppo 	return (status);
33101ae08745Sheppo }
33111ae08745Sheppo 
33121ae08745Sheppo /*
33131ae08745Sheppo  * Function:
33141ae08745Sheppo  *	vdc_verify_seq_num()
33151ae08745Sheppo  *
33161ae08745Sheppo  * Description:
33171ae08745Sheppo  *	This functions verifies that the sequence number sent back by vds with
33181ae08745Sheppo  *	the latest message correctly follows the last request processed.
33191ae08745Sheppo  *
33201ae08745Sheppo  * Arguments:
33211ae08745Sheppo  *	vdc		- soft state pointer for this instance of the driver.
33221ae08745Sheppo  *	dring_msg	- pointer to the LDC message sent by vds
33231ae08745Sheppo  *	num_msgs	- the number of requests being acknowledged
33241ae08745Sheppo  *
33251ae08745Sheppo  * Return Code:
33261ae08745Sheppo  *	B_TRUE	- Success.
33271ae08745Sheppo  *	B_FALSE	- The seq numbers are so out of sync, vdc cannot deal with them
33281ae08745Sheppo  */
33291ae08745Sheppo static boolean_t
33301ae08745Sheppo vdc_verify_seq_num(vdc_t *vdc, vio_dring_msg_t *dring_msg, int num_msgs)
33311ae08745Sheppo {
33321ae08745Sheppo 	ASSERT(vdc != NULL);
33331ae08745Sheppo 	ASSERT(dring_msg != NULL);
33341ae08745Sheppo 
33351ae08745Sheppo 	/*
33361ae08745Sheppo 	 * Check to see if the messages were responded to in the correct
33371ae08745Sheppo 	 * order by vds. There are 3 possible scenarios:
33381ae08745Sheppo 	 *	- the seq_num we expected is returned (everything is OK)
33391ae08745Sheppo 	 *	- a seq_num earlier than the last one acknowledged is returned,
33401ae08745Sheppo 	 *	  if so something is seriously wrong so we reset the connection
33411ae08745Sheppo 	 *	- a seq_num greater than what we expected is returned.
33421ae08745Sheppo 	 */
33431ae08745Sheppo 	if (dring_msg->seq_num != (vdc->seq_num_reply + num_msgs)) {
33441ae08745Sheppo 		vdc_msg("%s[%d]: Bogus seq_num %d, expected %d\n",
33451ae08745Sheppo 			__func__, vdc->instance, dring_msg->seq_num,
33461ae08745Sheppo 			vdc->seq_num_reply + num_msgs);
33471ae08745Sheppo 		if (dring_msg->seq_num < (vdc->seq_num_reply + num_msgs)) {
33481ae08745Sheppo 			return (B_FALSE);
33491ae08745Sheppo 		} else {
33501ae08745Sheppo 			/*
33511ae08745Sheppo 			 * vds has responded with a seq_num greater than what we
33521ae08745Sheppo 			 * expected
33531ae08745Sheppo 			 */
33541ae08745Sheppo 			return (B_FALSE);
33551ae08745Sheppo 		}
33561ae08745Sheppo 	}
33571ae08745Sheppo 	vdc->seq_num_reply += num_msgs;
33581ae08745Sheppo 
33591ae08745Sheppo 	return (B_TRUE);
33601ae08745Sheppo }
33611ae08745Sheppo 
3362*0a55fbb7Slm66018 
3363*0a55fbb7Slm66018 /*
3364*0a55fbb7Slm66018  * Function:
3365*0a55fbb7Slm66018  *	vdc_is_supported_version()
3366*0a55fbb7Slm66018  *
3367*0a55fbb7Slm66018  * Description:
3368*0a55fbb7Slm66018  *	This routine checks if the major/minor version numbers specified in
3369*0a55fbb7Slm66018  *	'ver_msg' are supported. If not it finds the next version that is
3370*0a55fbb7Slm66018  *	in the supported version list 'vdc_version[]' and sets the fields in
3371*0a55fbb7Slm66018  *	'ver_msg' to those values
3372*0a55fbb7Slm66018  *
3373*0a55fbb7Slm66018  * Arguments:
3374*0a55fbb7Slm66018  *	ver_msg	- LDC message sent by vDisk server
3375*0a55fbb7Slm66018  *
3376*0a55fbb7Slm66018  * Return Code:
3377*0a55fbb7Slm66018  *	B_TRUE	- Success
3378*0a55fbb7Slm66018  *	B_FALSE	- Version not supported
3379*0a55fbb7Slm66018  */
3380*0a55fbb7Slm66018 static boolean_t
3381*0a55fbb7Slm66018 vdc_is_supported_version(vio_ver_msg_t *ver_msg)
3382*0a55fbb7Slm66018 {
3383*0a55fbb7Slm66018 	int vdc_num_versions = sizeof (vdc_version) / sizeof (vdc_version[0]);
3384*0a55fbb7Slm66018 
3385*0a55fbb7Slm66018 	for (int i = 0; i < vdc_num_versions; i++) {
3386*0a55fbb7Slm66018 		ASSERT(vdc_version[i].major > 0);
3387*0a55fbb7Slm66018 		ASSERT((i == 0) ||
3388*0a55fbb7Slm66018 		    (vdc_version[i].major < vdc_version[i-1].major));
3389*0a55fbb7Slm66018 
3390*0a55fbb7Slm66018 		/*
3391*0a55fbb7Slm66018 		 * If the major versions match, adjust the minor version, if
3392*0a55fbb7Slm66018 		 * necessary, down to the highest value supported by this
3393*0a55fbb7Slm66018 		 * client. The server should support all minor versions lower
3394*0a55fbb7Slm66018 		 * than the value it sent
3395*0a55fbb7Slm66018 		 */
3396*0a55fbb7Slm66018 		if (ver_msg->ver_major == vdc_version[i].major) {
3397*0a55fbb7Slm66018 			if (ver_msg->ver_minor > vdc_version[i].minor) {
3398*0a55fbb7Slm66018 				PR0("Adjusting minor version from %u to %u",
3399*0a55fbb7Slm66018 				    ver_msg->ver_minor, vdc_version[i].minor);
3400*0a55fbb7Slm66018 				ver_msg->ver_minor = vdc_version[i].minor;
3401*0a55fbb7Slm66018 			}
3402*0a55fbb7Slm66018 			return (B_TRUE);
3403*0a55fbb7Slm66018 		}
3404*0a55fbb7Slm66018 
3405*0a55fbb7Slm66018 		/*
3406*0a55fbb7Slm66018 		 * If the message contains a higher major version number, set
3407*0a55fbb7Slm66018 		 * the message's major/minor versions to the current values
3408*0a55fbb7Slm66018 		 * and return false, so this message will get resent with
3409*0a55fbb7Slm66018 		 * these values, and the server will potentially try again
3410*0a55fbb7Slm66018 		 * with the same or a lower version
3411*0a55fbb7Slm66018 		 */
3412*0a55fbb7Slm66018 		if (ver_msg->ver_major > vdc_version[i].major) {
3413*0a55fbb7Slm66018 			ver_msg->ver_major = vdc_version[i].major;
3414*0a55fbb7Slm66018 			ver_msg->ver_minor = vdc_version[i].minor;
3415*0a55fbb7Slm66018 			PR0("Suggesting major/minor (0x%x/0x%x)\n",
3416*0a55fbb7Slm66018 				ver_msg->ver_major, ver_msg->ver_minor);
3417*0a55fbb7Slm66018 
3418*0a55fbb7Slm66018 			return (B_FALSE);
3419*0a55fbb7Slm66018 		}
3420*0a55fbb7Slm66018 
3421*0a55fbb7Slm66018 		/*
3422*0a55fbb7Slm66018 		 * Otherwise, the message's major version is less than the
3423*0a55fbb7Slm66018 		 * current major version, so continue the loop to the next
3424*0a55fbb7Slm66018 		 * (lower) supported version
3425*0a55fbb7Slm66018 		 */
3426*0a55fbb7Slm66018 	}
3427*0a55fbb7Slm66018 
3428*0a55fbb7Slm66018 	/*
3429*0a55fbb7Slm66018 	 * No common version was found; "ground" the version pair in the
3430*0a55fbb7Slm66018 	 * message to terminate negotiation
3431*0a55fbb7Slm66018 	 */
3432*0a55fbb7Slm66018 	ver_msg->ver_major = 0;
3433*0a55fbb7Slm66018 	ver_msg->ver_minor = 0;
3434*0a55fbb7Slm66018 
3435*0a55fbb7Slm66018 	return (B_FALSE);
3436*0a55fbb7Slm66018 }
34371ae08745Sheppo /* -------------------------------------------------------------------------- */
34381ae08745Sheppo 
34391ae08745Sheppo /*
34401ae08745Sheppo  * DKIO(7) support
34411ae08745Sheppo  */
34421ae08745Sheppo 
34431ae08745Sheppo typedef struct vdc_dk_arg {
34441ae08745Sheppo 	struct dk_callback	dkc;
34451ae08745Sheppo 	int			mode;
34461ae08745Sheppo 	dev_t			dev;
34471ae08745Sheppo 	vdc_t			*vdc;
34481ae08745Sheppo } vdc_dk_arg_t;
34491ae08745Sheppo 
34501ae08745Sheppo /*
34511ae08745Sheppo  * Function:
34521ae08745Sheppo  * 	vdc_dkio_flush_cb()
34531ae08745Sheppo  *
34541ae08745Sheppo  * Description:
34551ae08745Sheppo  *	This routine is a callback for DKIOCFLUSHWRITECACHE which can be called
34561ae08745Sheppo  *	by kernel code.
34571ae08745Sheppo  *
34581ae08745Sheppo  * Arguments:
34591ae08745Sheppo  *	arg	- a pointer to a vdc_dk_arg_t structure.
34601ae08745Sheppo  */
34611ae08745Sheppo void
34621ae08745Sheppo vdc_dkio_flush_cb(void *arg)
34631ae08745Sheppo {
34641ae08745Sheppo 	struct vdc_dk_arg	*dk_arg = (struct vdc_dk_arg *)arg;
34651ae08745Sheppo 	struct dk_callback	*dkc = NULL;
34661ae08745Sheppo 	vdc_t			*vdc = NULL;
34671ae08745Sheppo 	int			rv;
34681ae08745Sheppo 
34691ae08745Sheppo 	if (dk_arg == NULL) {
34701ae08745Sheppo 		vdc_msg("%s[?] DKIOCFLUSHWRITECACHE arg is NULL\n", __func__);
34711ae08745Sheppo 		return;
34721ae08745Sheppo 	}
34731ae08745Sheppo 	dkc = &dk_arg->dkc;
34741ae08745Sheppo 	vdc = dk_arg->vdc;
34751ae08745Sheppo 	ASSERT(vdc != NULL);
34761ae08745Sheppo 
34771ae08745Sheppo 	rv = vdc_populate_descriptor(vdc, NULL, 0, VD_OP_FLUSH,
34781ae08745Sheppo 		dk_arg->mode, SDPART(getminor(dk_arg->dev)));
34791ae08745Sheppo 	if (rv != 0) {
34801ae08745Sheppo 		PR0("%s[%d] DKIOCFLUSHWRITECACHE failed : model %x\n",
34811ae08745Sheppo 			__func__, vdc->instance,
34821ae08745Sheppo 			ddi_model_convert_from(dk_arg->mode & FMODELS));
34831ae08745Sheppo 		return;
34841ae08745Sheppo 	}
34851ae08745Sheppo 
34861ae08745Sheppo 	/*
34871ae08745Sheppo 	 * Trigger the call back to notify the caller the the ioctl call has
34881ae08745Sheppo 	 * been completed.
34891ae08745Sheppo 	 */
34901ae08745Sheppo 	if ((dk_arg->mode & FKIOCTL) &&
34911ae08745Sheppo 	    (dkc != NULL) &&
34921ae08745Sheppo 	    (dkc->dkc_callback != NULL)) {
34931ae08745Sheppo 		ASSERT(dkc->dkc_cookie != NULL);
34941ae08745Sheppo 		(*dkc->dkc_callback)(dkc->dkc_cookie, ENOTSUP);
34951ae08745Sheppo 	}
34961ae08745Sheppo 
34971ae08745Sheppo 	/* Indicate that one less DKIO write flush is outstanding */
34981ae08745Sheppo 	mutex_enter(&vdc->lock);
34991ae08745Sheppo 	vdc->dkio_flush_pending--;
35001ae08745Sheppo 	ASSERT(vdc->dkio_flush_pending >= 0);
35011ae08745Sheppo 	mutex_exit(&vdc->lock);
35021ae08745Sheppo }
35031ae08745Sheppo 
35041ae08745Sheppo /*
35051ae08745Sheppo  * This structure is used in the DKIO(7I) array below.
35061ae08745Sheppo  */
35071ae08745Sheppo typedef struct vdc_dk_ioctl {
35081ae08745Sheppo 	uint8_t		op;		/* VD_OP_XXX value */
35091ae08745Sheppo 	int		cmd;		/* Solaris ioctl operation number */
35101ae08745Sheppo 	size_t		nbytes;		/* size of structure to be copied */
3511*0a55fbb7Slm66018 
3512*0a55fbb7Slm66018 	/* function to convert between vDisk and Solaris structure formats */
3513*0a55fbb7Slm66018 	int	(*convert)(void *vd_buf, void *ioctl_arg, int mode, int dir);
35141ae08745Sheppo } vdc_dk_ioctl_t;
35151ae08745Sheppo 
35161ae08745Sheppo /*
35171ae08745Sheppo  * Subset of DKIO(7I) operations currently supported
35181ae08745Sheppo  */
35191ae08745Sheppo static vdc_dk_ioctl_t	dk_ioctl[] = {
3520*0a55fbb7Slm66018 	{VD_OP_FLUSH,		DKIOCFLUSHWRITECACHE,	sizeof (int),
3521*0a55fbb7Slm66018 		vdc_null_copy_func},
3522*0a55fbb7Slm66018 	{VD_OP_GET_WCE,		DKIOCGETWCE,		sizeof (int),
3523*0a55fbb7Slm66018 		vdc_null_copy_func},
3524*0a55fbb7Slm66018 	{VD_OP_SET_WCE,		DKIOCSETWCE,		sizeof (int),
3525*0a55fbb7Slm66018 		vdc_null_copy_func},
3526*0a55fbb7Slm66018 	{VD_OP_GET_VTOC,	DKIOCGVTOC,		sizeof (vd_vtoc_t),
3527*0a55fbb7Slm66018 		vdc_get_vtoc_convert},
3528*0a55fbb7Slm66018 	{VD_OP_SET_VTOC,	DKIOCSVTOC,		sizeof (vd_vtoc_t),
3529*0a55fbb7Slm66018 		vdc_set_vtoc_convert},
3530*0a55fbb7Slm66018 	{VD_OP_SET_DISKGEOM,	DKIOCSGEOM,		sizeof (vd_geom_t),
3531*0a55fbb7Slm66018 		vdc_get_geom_convert},
3532*0a55fbb7Slm66018 	{VD_OP_GET_DISKGEOM,	DKIOCGGEOM,		sizeof (vd_geom_t),
3533*0a55fbb7Slm66018 		vdc_get_geom_convert},
3534*0a55fbb7Slm66018 	{VD_OP_GET_DISKGEOM,	DKIOCG_PHYGEOM,		sizeof (vd_geom_t),
3535*0a55fbb7Slm66018 		vdc_get_geom_convert},
3536*0a55fbb7Slm66018 	{VD_OP_GET_DISKGEOM, DKIOCG_VIRTGEOM,		sizeof (vd_geom_t),
3537*0a55fbb7Slm66018 		vdc_get_geom_convert},
3538*0a55fbb7Slm66018 	{VD_OP_SET_DISKGEOM, DKIOCSGEOM,		sizeof (vd_geom_t),
3539*0a55fbb7Slm66018 		vdc_set_geom_convert},
3540*0a55fbb7Slm66018 
3541*0a55fbb7Slm66018 	/*
3542*0a55fbb7Slm66018 	 * These particular ioctls are not sent to the server - vdc fakes up
3543*0a55fbb7Slm66018 	 * the necessary info.
3544*0a55fbb7Slm66018 	 */
3545*0a55fbb7Slm66018 	{0, DKIOCINFO, sizeof (struct dk_cinfo), vdc_null_copy_func},
3546*0a55fbb7Slm66018 	{0, DKIOCGMEDIAINFO, sizeof (struct dk_minfo), vdc_null_copy_func},
3547*0a55fbb7Slm66018 	{0, USCSICMD,	sizeof (struct uscsi_cmd), vdc_null_copy_func},
3548*0a55fbb7Slm66018 	{0, DKIOCREMOVABLE, 0, vdc_null_copy_func},
3549*0a55fbb7Slm66018 	{0, CDROMREADOFFSET, 0, vdc_null_copy_func}
35501ae08745Sheppo };
35511ae08745Sheppo 
35521ae08745Sheppo /*
35531ae08745Sheppo  * Function:
35541ae08745Sheppo  *	vd_process_ioctl()
35551ae08745Sheppo  *
35561ae08745Sheppo  * Description:
3557*0a55fbb7Slm66018  *	This routine processes disk specific ioctl calls
35581ae08745Sheppo  *
35591ae08745Sheppo  * Arguments:
35601ae08745Sheppo  *	dev	- the device number
35611ae08745Sheppo  *	cmd	- the operation [dkio(7I)] to be processed
35621ae08745Sheppo  *	arg	- pointer to user provided structure
35631ae08745Sheppo  *		  (contains data to be set or reference parameter for get)
35641ae08745Sheppo  *	mode	- bit flag, indicating open settings, 32/64 bit type, etc
35651ae08745Sheppo  *
35661ae08745Sheppo  * Return Code:
35671ae08745Sheppo  *	0
35681ae08745Sheppo  *	EFAULT
35691ae08745Sheppo  *	ENXIO
35701ae08745Sheppo  *	EIO
35711ae08745Sheppo  *	ENOTSUP
35721ae08745Sheppo  */
35731ae08745Sheppo static int
35741ae08745Sheppo vd_process_ioctl(dev_t dev, int cmd, caddr_t arg, int mode)
35751ae08745Sheppo {
35761ae08745Sheppo 	int		instance = SDUNIT(getminor(dev));
35771ae08745Sheppo 	vdc_t		*vdc = NULL;
35781ae08745Sheppo 	int		rv = -1;
35791ae08745Sheppo 	int		idx = 0;		/* index into dk_ioctl[] */
35801ae08745Sheppo 	size_t		len = 0;		/* #bytes to send to vds */
35811ae08745Sheppo 	size_t		alloc_len = 0;		/* #bytes to allocate mem for */
35821ae08745Sheppo 	caddr_t		mem_p = NULL;
35831ae08745Sheppo 	size_t		nioctls = (sizeof (dk_ioctl)) / (sizeof (dk_ioctl[0]));
35841ae08745Sheppo 
35851ae08745Sheppo 	PR0("%s: Processing ioctl(%x) for dev %x : model %x\n",
35861ae08745Sheppo 		__func__, cmd, dev, ddi_model_convert_from(mode & FMODELS));
35871ae08745Sheppo 
35881ae08745Sheppo 	vdc = ddi_get_soft_state(vdc_state, instance);
35891ae08745Sheppo 	if (vdc == NULL) {
35901ae08745Sheppo 		cmn_err(CE_NOTE, "![%d] Could not get soft state structure",
35911ae08745Sheppo 		    instance);
35921ae08745Sheppo 		return (ENXIO);
35931ae08745Sheppo 	}
35941ae08745Sheppo 
35951ae08745Sheppo 	/*
35961ae08745Sheppo 	 * Check to see if we can communicate with the vDisk server
35971ae08745Sheppo 	 */
3598*0a55fbb7Slm66018 	if (!vdc_is_able_to_tx_data(vdc, O_NONBLOCK)) {
35991ae08745Sheppo 		PR0("%s[%d] Not ready to transmit data\n", __func__, instance);
36001ae08745Sheppo 		return (ENOLINK);
36011ae08745Sheppo 	}
36021ae08745Sheppo 
36031ae08745Sheppo 	/*
36041ae08745Sheppo 	 * Validate the ioctl operation to be performed.
36051ae08745Sheppo 	 *
36061ae08745Sheppo 	 * If we have looped through the array without finding a match then we
36071ae08745Sheppo 	 * don't support this ioctl.
36081ae08745Sheppo 	 */
36091ae08745Sheppo 	for (idx = 0; idx < nioctls; idx++) {
36101ae08745Sheppo 		if (cmd == dk_ioctl[idx].cmd)
36111ae08745Sheppo 			break;
36121ae08745Sheppo 	}
36131ae08745Sheppo 
36141ae08745Sheppo 	if (idx >= nioctls) {
36151ae08745Sheppo 		PR0("%s[%d] Unsupported ioctl(%x)\n",
36161ae08745Sheppo 				__func__, vdc->instance, cmd);
36171ae08745Sheppo 		return (ENOTSUP);
36181ae08745Sheppo 	}
36191ae08745Sheppo 
3620*0a55fbb7Slm66018 	len = dk_ioctl[idx].nbytes;
36211ae08745Sheppo 
36221ae08745Sheppo 	/*
3623*0a55fbb7Slm66018 	 * Deal with the ioctls which the server does not provide. vdc can
3624*0a55fbb7Slm66018 	 * fake these up and return immediately
36251ae08745Sheppo 	 */
36261ae08745Sheppo 	switch (cmd) {
36271ae08745Sheppo 	case CDROMREADOFFSET:
36281ae08745Sheppo 	case DKIOCREMOVABLE:
3629*0a55fbb7Slm66018 	case USCSICMD:
36301ae08745Sheppo 		return (ENOTTY);
36311ae08745Sheppo 
36321ae08745Sheppo 	case DKIOCINFO:
36331ae08745Sheppo 		{
36341ae08745Sheppo 			struct dk_cinfo	cinfo;
36351ae08745Sheppo 			if (vdc->cinfo == NULL)
36361ae08745Sheppo 				return (ENXIO);
36371ae08745Sheppo 
36381ae08745Sheppo 			bcopy(vdc->cinfo, &cinfo, sizeof (struct dk_cinfo));
36391ae08745Sheppo 			cinfo.dki_partition = SDPART(getminor(dev));
36401ae08745Sheppo 
36411ae08745Sheppo 			rv = ddi_copyout(&cinfo, (void *)arg,
36421ae08745Sheppo 					sizeof (struct dk_cinfo), mode);
36431ae08745Sheppo 			if (rv != 0)
36441ae08745Sheppo 				return (EFAULT);
36451ae08745Sheppo 
36461ae08745Sheppo 			return (0);
36471ae08745Sheppo 		}
36481ae08745Sheppo 
36491ae08745Sheppo 	case DKIOCGMEDIAINFO:
36501ae08745Sheppo 		if (vdc->minfo == NULL)
36511ae08745Sheppo 			return (ENXIO);
36521ae08745Sheppo 
36531ae08745Sheppo 		rv = ddi_copyout(vdc->minfo, (void *)arg,
36541ae08745Sheppo 				sizeof (struct dk_minfo), mode);
36551ae08745Sheppo 		if (rv != 0)
36561ae08745Sheppo 			return (EFAULT);
36571ae08745Sheppo 
36581ae08745Sheppo 		return (0);
36591ae08745Sheppo 	}
36601ae08745Sheppo 
36611ae08745Sheppo 	/* catch programming error in vdc - should be a VD_OP_XXX ioctl */
3662*0a55fbb7Slm66018 	ASSERT(dk_ioctl[idx].op != 0);
36631ae08745Sheppo 
36641ae08745Sheppo 	/* LDC requires that the memory being mapped is 8-byte aligned */
36651ae08745Sheppo 	alloc_len = P2ROUNDUP(len, sizeof (uint64_t));
36661ae08745Sheppo 	PR1("%s[%d]: struct size %d alloc %d\n",
36671ae08745Sheppo 			__func__, instance, len, alloc_len);
36681ae08745Sheppo 
3669*0a55fbb7Slm66018 	ASSERT(alloc_len != 0);	/* sanity check */
36701ae08745Sheppo 	mem_p = kmem_zalloc(alloc_len, KM_SLEEP);
36711ae08745Sheppo 
3672*0a55fbb7Slm66018 	/*
3673*0a55fbb7Slm66018 	 * Call the conversion function for this ioctl whhich if necessary
3674*0a55fbb7Slm66018 	 * converts from the Solaris format to the format ARC'ed
3675*0a55fbb7Slm66018 	 * as part of the vDisk protocol (FWARC 2006/195)
3676*0a55fbb7Slm66018 	 */
3677*0a55fbb7Slm66018 	ASSERT(dk_ioctl[idx].convert != NULL);
3678*0a55fbb7Slm66018 	rv = (dk_ioctl[idx].convert)(arg, mem_p, mode, VD_COPYIN);
36791ae08745Sheppo 	if (rv != 0) {
3680*0a55fbb7Slm66018 		PR0("%s[%d]: convert returned %d for ioctl 0x%x\n",
3681*0a55fbb7Slm66018 				__func__, instance, rv, cmd);
36821ae08745Sheppo 		if (mem_p != NULL)
36831ae08745Sheppo 			kmem_free(mem_p, alloc_len);
3684*0a55fbb7Slm66018 		return (rv);
36851ae08745Sheppo 	}
36861ae08745Sheppo 
36871ae08745Sheppo 	/*
36881ae08745Sheppo 	 * handle the special case of DKIOCFLUSHWRITECACHE
36891ae08745Sheppo 	 */
36901ae08745Sheppo 	if (cmd == DKIOCFLUSHWRITECACHE) {
36911ae08745Sheppo 		struct dk_callback *dkc = (struct dk_callback *)arg;
36921ae08745Sheppo 
36931ae08745Sheppo 		PR0("%s[%d]: DKIOCFLUSHWRITECACHE\n", __func__, instance);
36941ae08745Sheppo 
36951ae08745Sheppo 		/* no mem should have been allocated hence no need to free it */
36961ae08745Sheppo 		ASSERT(mem_p == NULL);
36971ae08745Sheppo 
36981ae08745Sheppo 		/*
36991ae08745Sheppo 		 * If arg is NULL, we break here and the call operates
37001ae08745Sheppo 		 * synchronously; waiting for vds to return.
37011ae08745Sheppo 		 *
37021ae08745Sheppo 		 * i.e. after the request to vds returns successfully,
37031ae08745Sheppo 		 * all writes completed prior to the ioctl will have been
37041ae08745Sheppo 		 * flushed from the disk write cache to persistent media.
37051ae08745Sheppo 		 */
37061ae08745Sheppo 		if (dkc != NULL) {
37071ae08745Sheppo 			vdc_dk_arg_t	arg;
37081ae08745Sheppo 			arg.mode = mode;
37091ae08745Sheppo 			arg.dev = dev;
37101ae08745Sheppo 			bcopy(dkc, &arg.dkc, sizeof (*dkc));
37111ae08745Sheppo 
37121ae08745Sheppo 			mutex_enter(&vdc->lock);
37131ae08745Sheppo 			vdc->dkio_flush_pending++;
37141ae08745Sheppo 			arg.vdc = vdc;
37151ae08745Sheppo 			mutex_exit(&vdc->lock);
37161ae08745Sheppo 
37171ae08745Sheppo 			/* put the request on a task queue */
37181ae08745Sheppo 			rv = taskq_dispatch(system_taskq, vdc_dkio_flush_cb,
37191ae08745Sheppo 				(void *)&arg, DDI_SLEEP);
37201ae08745Sheppo 
37211ae08745Sheppo 			return (rv == NULL ? ENOMEM : 0);
37221ae08745Sheppo 		}
37231ae08745Sheppo 	}
37241ae08745Sheppo 
37251ae08745Sheppo 	/*
37261ae08745Sheppo 	 * send request to vds to service the ioctl.
37271ae08745Sheppo 	 */
3728*0a55fbb7Slm66018 	rv = vdc_populate_descriptor(vdc, mem_p, alloc_len, dk_ioctl[idx].op,
3729*0a55fbb7Slm66018 			mode, SDPART((getminor(dev))));
37301ae08745Sheppo 	if (rv != 0) {
37311ae08745Sheppo 		/*
37321ae08745Sheppo 		 * This is not necessarily an error. The ioctl could
37331ae08745Sheppo 		 * be returning a value such as ENOTTY to indicate
37341ae08745Sheppo 		 * that the ioctl is not applicable.
37351ae08745Sheppo 		 */
37361ae08745Sheppo 		PR0("%s[%d]: vds returned %d for ioctl 0x%x\n",
37371ae08745Sheppo 			__func__, instance, rv, cmd);
37381ae08745Sheppo 		if (mem_p != NULL)
37391ae08745Sheppo 			kmem_free(mem_p, alloc_len);
37401ae08745Sheppo 		return (rv);
37411ae08745Sheppo 	}
37421ae08745Sheppo 
37431ae08745Sheppo 	/*
37441ae08745Sheppo 	 * If the VTOC has been changed, then vdc needs to update the copy
37451ae08745Sheppo 	 * it saved in the soft state structure and try and update the device
37461ae08745Sheppo 	 * node properties. Failing to set the properties should not cause
37471ae08745Sheppo 	 * an error to be return the caller though.
37481ae08745Sheppo 	 */
37491ae08745Sheppo 	if (cmd == DKIOCSVTOC) {
37501ae08745Sheppo 		bcopy(mem_p, vdc->vtoc, sizeof (struct vtoc));
37511ae08745Sheppo 		if (vdc_create_device_nodes_props(vdc)) {
37521ae08745Sheppo 			cmn_err(CE_NOTE, "![%d] Failed to update device nodes"
37531ae08745Sheppo 				" properties", instance);
37541ae08745Sheppo 		}
37551ae08745Sheppo 	}
37561ae08745Sheppo 
37571ae08745Sheppo 	/*
3758*0a55fbb7Slm66018 	 * Call the conversion function (if it exists) for this ioctl
3759*0a55fbb7Slm66018 	 * which converts from the format ARC'ed as part of the vDisk
3760*0a55fbb7Slm66018 	 * protocol (FWARC 2006/195) back to a format understood by
3761*0a55fbb7Slm66018 	 * the rest of Solaris.
37621ae08745Sheppo 	 */
3763*0a55fbb7Slm66018 	rv = (dk_ioctl[idx].convert)(mem_p, arg, mode, VD_COPYOUT);
3764*0a55fbb7Slm66018 	if (rv != 0) {
3765*0a55fbb7Slm66018 		PR0("%s[%d]: convert returned %d for ioctl 0x%x\n",
3766*0a55fbb7Slm66018 				__func__, instance, rv, cmd);
37671ae08745Sheppo 		if (mem_p != NULL)
37681ae08745Sheppo 			kmem_free(mem_p, alloc_len);
3769*0a55fbb7Slm66018 		return (rv);
37701ae08745Sheppo 	}
37711ae08745Sheppo 
37721ae08745Sheppo 	if (mem_p != NULL)
37731ae08745Sheppo 		kmem_free(mem_p, alloc_len);
37741ae08745Sheppo 
37751ae08745Sheppo 	return (rv);
37761ae08745Sheppo }
37771ae08745Sheppo 
37781ae08745Sheppo /*
37791ae08745Sheppo  * Function:
3780*0a55fbb7Slm66018  *
3781*0a55fbb7Slm66018  * Description:
3782*0a55fbb7Slm66018  *	This is an empty conversion function used by ioctl calls which
3783*0a55fbb7Slm66018  *	do not need to convert the data being passed in/out to userland
3784*0a55fbb7Slm66018  */
3785*0a55fbb7Slm66018 static int
3786*0a55fbb7Slm66018 vdc_null_copy_func(void *from, void *to, int mode, int dir)
3787*0a55fbb7Slm66018 {
3788*0a55fbb7Slm66018 	_NOTE(ARGUNUSED(from))
3789*0a55fbb7Slm66018 	_NOTE(ARGUNUSED(to))
3790*0a55fbb7Slm66018 	_NOTE(ARGUNUSED(mode))
3791*0a55fbb7Slm66018 	_NOTE(ARGUNUSED(dir))
3792*0a55fbb7Slm66018 
3793*0a55fbb7Slm66018 	return (0);
3794*0a55fbb7Slm66018 }
3795*0a55fbb7Slm66018 
3796*0a55fbb7Slm66018 /*
3797*0a55fbb7Slm66018  * Function:
3798*0a55fbb7Slm66018  *	vdc_get_vtoc_convert()
3799*0a55fbb7Slm66018  *
3800*0a55fbb7Slm66018  * Description:
3801*0a55fbb7Slm66018  *	This routine fakes up the disk info needed for some DKIO ioctls.
3802*0a55fbb7Slm66018  *
3803*0a55fbb7Slm66018  * Arguments:
3804*0a55fbb7Slm66018  *	from	- the buffer containing the data to be copied from
3805*0a55fbb7Slm66018  *	to	- the buffer to be copied to
3806*0a55fbb7Slm66018  *	mode	- flags passed to ioctl() call
3807*0a55fbb7Slm66018  *	dir	- the "direction" of the copy - VD_COPYIN or VD_COPYOUT
3808*0a55fbb7Slm66018  *
3809*0a55fbb7Slm66018  * Return Code:
3810*0a55fbb7Slm66018  *	0	- Success
3811*0a55fbb7Slm66018  *	ENXIO	- incorrect buffer passed in.
3812*0a55fbb7Slm66018  *	EFAULT	- ddi_copyxxx routine encountered an error.
3813*0a55fbb7Slm66018  */
3814*0a55fbb7Slm66018 static int
3815*0a55fbb7Slm66018 vdc_get_vtoc_convert(void *from, void *to, int mode, int dir)
3816*0a55fbb7Slm66018 {
3817*0a55fbb7Slm66018 	void		*tmp_mem = NULL;
3818*0a55fbb7Slm66018 	void		*tmp_memp;
3819*0a55fbb7Slm66018 	struct vtoc	vt;
3820*0a55fbb7Slm66018 	struct vtoc32	vt32;
3821*0a55fbb7Slm66018 	int		copy_len = 0;
3822*0a55fbb7Slm66018 	int		rv = 0;
3823*0a55fbb7Slm66018 
3824*0a55fbb7Slm66018 	if (dir != VD_COPYOUT)
3825*0a55fbb7Slm66018 		return (0);	/* nothing to do */
3826*0a55fbb7Slm66018 
3827*0a55fbb7Slm66018 	if ((from == NULL) || (to == NULL))
3828*0a55fbb7Slm66018 		return (ENXIO);
3829*0a55fbb7Slm66018 
3830*0a55fbb7Slm66018 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32)
3831*0a55fbb7Slm66018 		copy_len = sizeof (struct vtoc32);
3832*0a55fbb7Slm66018 	else
3833*0a55fbb7Slm66018 		copy_len = sizeof (struct vtoc);
3834*0a55fbb7Slm66018 
3835*0a55fbb7Slm66018 	tmp_mem = kmem_alloc(copy_len, KM_SLEEP);
3836*0a55fbb7Slm66018 
3837*0a55fbb7Slm66018 	VD_VTOC2VTOC((vd_vtoc_t *)from, &vt);
3838*0a55fbb7Slm66018 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
3839*0a55fbb7Slm66018 		vtoctovtoc32(vt, vt32);
3840*0a55fbb7Slm66018 		tmp_memp = &vt32;
3841*0a55fbb7Slm66018 	} else {
3842*0a55fbb7Slm66018 		tmp_memp = &vt;
3843*0a55fbb7Slm66018 	}
3844*0a55fbb7Slm66018 	rv = ddi_copyout(tmp_memp, to, copy_len, mode);
3845*0a55fbb7Slm66018 	if (rv != 0)
3846*0a55fbb7Slm66018 		rv = EFAULT;
3847*0a55fbb7Slm66018 
3848*0a55fbb7Slm66018 	kmem_free(tmp_mem, copy_len);
3849*0a55fbb7Slm66018 	return (rv);
3850*0a55fbb7Slm66018 }
3851*0a55fbb7Slm66018 
3852*0a55fbb7Slm66018 /*
3853*0a55fbb7Slm66018  * Function:
3854*0a55fbb7Slm66018  *	vdc_set_vtoc_convert()
3855*0a55fbb7Slm66018  *
3856*0a55fbb7Slm66018  * Description:
3857*0a55fbb7Slm66018  *
3858*0a55fbb7Slm66018  * Arguments:
3859*0a55fbb7Slm66018  *	from	- Buffer with data
3860*0a55fbb7Slm66018  *	to	- Buffer where data is to be copied to
3861*0a55fbb7Slm66018  *	mode	- flags passed to ioctl
3862*0a55fbb7Slm66018  *	dir	- direction of copy (in or out)
3863*0a55fbb7Slm66018  *
3864*0a55fbb7Slm66018  * Return Code:
3865*0a55fbb7Slm66018  *	0	- Success
3866*0a55fbb7Slm66018  *	ENXIO	- Invalid buffer passed in
3867*0a55fbb7Slm66018  *	EFAULT	- ddi_copyin of data failed
3868*0a55fbb7Slm66018  */
3869*0a55fbb7Slm66018 static int
3870*0a55fbb7Slm66018 vdc_set_vtoc_convert(void *from, void *to, int mode, int dir)
3871*0a55fbb7Slm66018 {
3872*0a55fbb7Slm66018 	void		*tmp_mem = NULL;
3873*0a55fbb7Slm66018 	struct vtoc	vt;
3874*0a55fbb7Slm66018 	struct vtoc	*vtp = &vt;
3875*0a55fbb7Slm66018 	vd_vtoc_t	vtvd;
3876*0a55fbb7Slm66018 	int		copy_len = 0;
3877*0a55fbb7Slm66018 	int		rv = 0;
3878*0a55fbb7Slm66018 
3879*0a55fbb7Slm66018 	if (dir != VD_COPYIN)
3880*0a55fbb7Slm66018 		return (0);	/* nothing to do */
3881*0a55fbb7Slm66018 
3882*0a55fbb7Slm66018 	if ((from == NULL) || (to == NULL))
3883*0a55fbb7Slm66018 		return (ENXIO);
3884*0a55fbb7Slm66018 
3885*0a55fbb7Slm66018 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32)
3886*0a55fbb7Slm66018 		copy_len = sizeof (struct vtoc32);
3887*0a55fbb7Slm66018 	else
3888*0a55fbb7Slm66018 		copy_len = sizeof (struct vtoc);
3889*0a55fbb7Slm66018 
3890*0a55fbb7Slm66018 	tmp_mem = kmem_alloc(copy_len, KM_SLEEP);
3891*0a55fbb7Slm66018 
3892*0a55fbb7Slm66018 	rv = ddi_copyin(from, tmp_mem, copy_len, mode);
3893*0a55fbb7Slm66018 	if (rv != 0) {
3894*0a55fbb7Slm66018 		kmem_free(tmp_mem, copy_len);
3895*0a55fbb7Slm66018 		return (EFAULT);
3896*0a55fbb7Slm66018 	}
3897*0a55fbb7Slm66018 
3898*0a55fbb7Slm66018 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
3899*0a55fbb7Slm66018 		vtoc32tovtoc((*(struct vtoc32 *)tmp_mem), vt);
3900*0a55fbb7Slm66018 	} else {
3901*0a55fbb7Slm66018 		vtp = tmp_mem;
3902*0a55fbb7Slm66018 	}
3903*0a55fbb7Slm66018 
3904*0a55fbb7Slm66018 	VTOC2VD_VTOC(vtp, &vtvd);
3905*0a55fbb7Slm66018 	bcopy(&vtvd, to, sizeof (vd_vtoc_t));
3906*0a55fbb7Slm66018 	kmem_free(tmp_mem, copy_len);
3907*0a55fbb7Slm66018 
3908*0a55fbb7Slm66018 	return (0);
3909*0a55fbb7Slm66018 }
3910*0a55fbb7Slm66018 
3911*0a55fbb7Slm66018 /*
3912*0a55fbb7Slm66018  * Function:
3913*0a55fbb7Slm66018  *	vdc_get_geom_convert()
3914*0a55fbb7Slm66018  *
3915*0a55fbb7Slm66018  * Description:
3916*0a55fbb7Slm66018  *
3917*0a55fbb7Slm66018  * Arguments:
3918*0a55fbb7Slm66018  *	from	- Buffer with data
3919*0a55fbb7Slm66018  *	to	- Buffer where data is to be copied to
3920*0a55fbb7Slm66018  *	mode	- flags passed to ioctl
3921*0a55fbb7Slm66018  *	dir	- direction of copy (in or out)
3922*0a55fbb7Slm66018  *
3923*0a55fbb7Slm66018  * Return Code:
3924*0a55fbb7Slm66018  *	0	- Success
3925*0a55fbb7Slm66018  *	ENXIO	- Invalid buffer passed in
3926*0a55fbb7Slm66018  *	EFAULT	- ddi_copyin of data failed
3927*0a55fbb7Slm66018  */
3928*0a55fbb7Slm66018 static int
3929*0a55fbb7Slm66018 vdc_get_geom_convert(void *from, void *to, int mode, int dir)
3930*0a55fbb7Slm66018 {
3931*0a55fbb7Slm66018 	struct dk_geom	geom;
3932*0a55fbb7Slm66018 	int	copy_len = sizeof (struct dk_geom);
3933*0a55fbb7Slm66018 	int	rv = 0;
3934*0a55fbb7Slm66018 
3935*0a55fbb7Slm66018 	if (dir != VD_COPYOUT)
3936*0a55fbb7Slm66018 		return (0);	/* nothing to do */
3937*0a55fbb7Slm66018 
3938*0a55fbb7Slm66018 	if ((from == NULL) || (to == NULL))
3939*0a55fbb7Slm66018 		return (ENXIO);
3940*0a55fbb7Slm66018 
3941*0a55fbb7Slm66018 	VD_GEOM2DK_GEOM((vd_geom_t *)from, &geom);
3942*0a55fbb7Slm66018 	rv = ddi_copyout(&geom, to, copy_len, mode);
3943*0a55fbb7Slm66018 	if (rv != 0)
3944*0a55fbb7Slm66018 		rv = EFAULT;
3945*0a55fbb7Slm66018 
3946*0a55fbb7Slm66018 	return (rv);
3947*0a55fbb7Slm66018 }
3948*0a55fbb7Slm66018 
3949*0a55fbb7Slm66018 /*
3950*0a55fbb7Slm66018  * Function:
3951*0a55fbb7Slm66018  *	vdc_set_geom_convert()
3952*0a55fbb7Slm66018  *
3953*0a55fbb7Slm66018  * Description:
3954*0a55fbb7Slm66018  *	This routine performs the necessary convertions from the DKIOCSVTOC
3955*0a55fbb7Slm66018  *	Solaris structure to the format defined in FWARC 2006/195
3956*0a55fbb7Slm66018  *
3957*0a55fbb7Slm66018  * Arguments:
3958*0a55fbb7Slm66018  *	from	- Buffer with data
3959*0a55fbb7Slm66018  *	to	- Buffer where data is to be copied to
3960*0a55fbb7Slm66018  *	mode	- flags passed to ioctl
3961*0a55fbb7Slm66018  *	dir	- direction of copy (in or out)
3962*0a55fbb7Slm66018  *
3963*0a55fbb7Slm66018  * Return Code:
3964*0a55fbb7Slm66018  *	0	- Success
3965*0a55fbb7Slm66018  *	ENXIO	- Invalid buffer passed in
3966*0a55fbb7Slm66018  *	EFAULT	- ddi_copyin of data failed
3967*0a55fbb7Slm66018  */
3968*0a55fbb7Slm66018 static int
3969*0a55fbb7Slm66018 vdc_set_geom_convert(void *from, void *to, int mode, int dir)
3970*0a55fbb7Slm66018 {
3971*0a55fbb7Slm66018 	vd_geom_t	vdgeom;
3972*0a55fbb7Slm66018 	void		*tmp_mem = NULL;
3973*0a55fbb7Slm66018 	int		copy_len = sizeof (struct dk_geom);
3974*0a55fbb7Slm66018 	int		rv = 0;
3975*0a55fbb7Slm66018 
3976*0a55fbb7Slm66018 	if (dir != VD_COPYIN)
3977*0a55fbb7Slm66018 		return (0);	/* nothing to do */
3978*0a55fbb7Slm66018 
3979*0a55fbb7Slm66018 	if ((from == NULL) || (to == NULL))
3980*0a55fbb7Slm66018 		return (ENXIO);
3981*0a55fbb7Slm66018 
3982*0a55fbb7Slm66018 	tmp_mem = kmem_alloc(copy_len, KM_SLEEP);
3983*0a55fbb7Slm66018 
3984*0a55fbb7Slm66018 	rv = ddi_copyin(from, tmp_mem, copy_len, mode);
3985*0a55fbb7Slm66018 	if (rv != 0) {
3986*0a55fbb7Slm66018 		kmem_free(tmp_mem, copy_len);
3987*0a55fbb7Slm66018 		return (EFAULT);
3988*0a55fbb7Slm66018 	}
3989*0a55fbb7Slm66018 	DK_GEOM2VD_GEOM((struct dk_geom *)tmp_mem, &vdgeom);
3990*0a55fbb7Slm66018 	bcopy(&vdgeom, to, sizeof (vdgeom));
3991*0a55fbb7Slm66018 	kmem_free(tmp_mem, copy_len);
3992*0a55fbb7Slm66018 
3993*0a55fbb7Slm66018 	return (0);
3994*0a55fbb7Slm66018 }
3995*0a55fbb7Slm66018 
3996*0a55fbb7Slm66018 /*
3997*0a55fbb7Slm66018  * Function:
39981ae08745Sheppo  *	vdc_create_fake_geometry()
39991ae08745Sheppo  *
40001ae08745Sheppo  * Description:
40011ae08745Sheppo  *	This routine fakes up the disk info needed for some DKIO ioctls.
40021ae08745Sheppo  *		- DKIOCINFO
40031ae08745Sheppo  *		- DKIOCGMEDIAINFO
40041ae08745Sheppo  *
40051ae08745Sheppo  *	[ just like lofi(7D) and ramdisk(7D) ]
40061ae08745Sheppo  *
40071ae08745Sheppo  * Arguments:
40081ae08745Sheppo  *	vdc	- soft state pointer for this instance of the device driver.
40091ae08745Sheppo  *
40101ae08745Sheppo  * Return Code:
40111ae08745Sheppo  *	0	- Success
40121ae08745Sheppo  */
40131ae08745Sheppo static int
40141ae08745Sheppo vdc_create_fake_geometry(vdc_t *vdc)
40151ae08745Sheppo {
4016*0a55fbb7Slm66018 	int	rv = 0;
4017*0a55fbb7Slm66018 
40181ae08745Sheppo 	ASSERT(vdc != NULL);
40191ae08745Sheppo 
40201ae08745Sheppo 	/*
40211ae08745Sheppo 	 * DKIOCINFO support
40221ae08745Sheppo 	 */
40231ae08745Sheppo 	vdc->cinfo = kmem_zalloc(sizeof (struct dk_cinfo), KM_SLEEP);
40241ae08745Sheppo 
40251ae08745Sheppo 	(void) strcpy(vdc->cinfo->dki_cname, VDC_DRIVER_NAME);
40261ae08745Sheppo 	(void) strcpy(vdc->cinfo->dki_dname, VDC_DRIVER_NAME);
40271ae08745Sheppo 	vdc->cinfo->dki_maxtransfer = vdc->max_xfer_sz / vdc->block_size;
40281ae08745Sheppo 	vdc->cinfo->dki_ctype = DKC_SCSI_CCS;
40291ae08745Sheppo 	vdc->cinfo->dki_flags = DKI_FMTVOL;
40301ae08745Sheppo 	vdc->cinfo->dki_cnum = 0;
40311ae08745Sheppo 	vdc->cinfo->dki_addr = 0;
40321ae08745Sheppo 	vdc->cinfo->dki_space = 0;
40331ae08745Sheppo 	vdc->cinfo->dki_prio = 0;
40341ae08745Sheppo 	vdc->cinfo->dki_vec = 0;
40351ae08745Sheppo 	vdc->cinfo->dki_unit = vdc->instance;
40361ae08745Sheppo 	vdc->cinfo->dki_slave = 0;
40371ae08745Sheppo 	/*
40381ae08745Sheppo 	 * The partition number will be created on the fly depending on the
40391ae08745Sheppo 	 * actual slice (i.e. minor node) that is used to request the data.
40401ae08745Sheppo 	 */
40411ae08745Sheppo 	vdc->cinfo->dki_partition = 0;
40421ae08745Sheppo 
40431ae08745Sheppo 	/*
40441ae08745Sheppo 	 * DKIOCGMEDIAINFO support
40451ae08745Sheppo 	 */
4046*0a55fbb7Slm66018 	if (vdc->minfo == NULL)
40471ae08745Sheppo 		vdc->minfo = kmem_zalloc(sizeof (struct dk_minfo), KM_SLEEP);
40481ae08745Sheppo 	vdc->minfo->dki_media_type = DK_FIXED_DISK;
40491ae08745Sheppo 	vdc->minfo->dki_capacity = 1;
40501ae08745Sheppo 	vdc->minfo->dki_lbsize = DEV_BSIZE;
40511ae08745Sheppo 
4052*0a55fbb7Slm66018 	return (rv);
4053*0a55fbb7Slm66018 }
4054*0a55fbb7Slm66018 
4055*0a55fbb7Slm66018 /*
4056*0a55fbb7Slm66018  * Function:
4057*0a55fbb7Slm66018  *	vdc_setup_disk_layout()
4058*0a55fbb7Slm66018  *
4059*0a55fbb7Slm66018  * Description:
4060*0a55fbb7Slm66018  *	This routine discovers all the necessary details about the "disk"
4061*0a55fbb7Slm66018  *	by requesting the data that is available from the vDisk server and by
4062*0a55fbb7Slm66018  *	faking up the rest of the data.
4063*0a55fbb7Slm66018  *
4064*0a55fbb7Slm66018  * Arguments:
4065*0a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
4066*0a55fbb7Slm66018  *
4067*0a55fbb7Slm66018  * Return Code:
4068*0a55fbb7Slm66018  *	0	- Success
4069*0a55fbb7Slm66018  */
4070*0a55fbb7Slm66018 static int
4071*0a55fbb7Slm66018 vdc_setup_disk_layout(vdc_t *vdc)
4072*0a55fbb7Slm66018 {
4073*0a55fbb7Slm66018 	dev_t	dev;
4074*0a55fbb7Slm66018 	int	slice = 0;
4075*0a55fbb7Slm66018 	int	rv;
4076*0a55fbb7Slm66018 
4077*0a55fbb7Slm66018 	ASSERT(vdc != NULL);
4078*0a55fbb7Slm66018 
4079*0a55fbb7Slm66018 	rv = vdc_create_fake_geometry(vdc);
4080*0a55fbb7Slm66018 	if (rv != 0) {
4081*0a55fbb7Slm66018 		cmn_err(CE_NOTE, "[%d] Failed to create disk geometry (err%d)",
4082*0a55fbb7Slm66018 				vdc->instance, rv);
4083*0a55fbb7Slm66018 	}
4084*0a55fbb7Slm66018 
4085*0a55fbb7Slm66018 	if (vdc->vtoc == NULL)
4086*0a55fbb7Slm66018 		vdc->vtoc = kmem_zalloc(sizeof (struct vtoc), KM_SLEEP);
4087*0a55fbb7Slm66018 
4088*0a55fbb7Slm66018 	dev = makedevice(ddi_driver_major(vdc->dip),
4089*0a55fbb7Slm66018 				VD_MAKE_DEV(vdc->instance, 0));
4090*0a55fbb7Slm66018 	rv = vd_process_ioctl(dev, DKIOCGVTOC, (caddr_t)vdc->vtoc, FKIOCTL);
4091*0a55fbb7Slm66018 	if (rv) {
4092*0a55fbb7Slm66018 		cmn_err(CE_NOTE, "[%d] Failed to get VTOC (err=%d)",
4093*0a55fbb7Slm66018 				vdc->instance, rv);
4094*0a55fbb7Slm66018 		return (rv);
4095*0a55fbb7Slm66018 	}
4096*0a55fbb7Slm66018 
4097*0a55fbb7Slm66018 	/*
4098*0a55fbb7Slm66018 	 * Read disk label from start of disk
4099*0a55fbb7Slm66018 	 */
4100*0a55fbb7Slm66018 	vdc->label = kmem_zalloc(DK_LABEL_SIZE, KM_SLEEP);
4101*0a55fbb7Slm66018 
4102*0a55fbb7Slm66018 	/*
4103*0a55fbb7Slm66018 	 * find the slice that represents the entire "disk" and use that to
4104*0a55fbb7Slm66018 	 * read the disk label. The convention in Solaris is that slice 2
4105*0a55fbb7Slm66018 	 * represents the whole disk so we check that it is otherwise we
4106*0a55fbb7Slm66018 	 * default to slice 0
4107*0a55fbb7Slm66018 	 */
4108*0a55fbb7Slm66018 	if ((vdc->vdisk_type == VD_DISK_TYPE_DISK) &&
4109*0a55fbb7Slm66018 	    (vdc->vtoc->v_part[2].p_tag == V_BACKUP)) {
4110*0a55fbb7Slm66018 		slice = 2;
4111*0a55fbb7Slm66018 	} else {
4112*0a55fbb7Slm66018 		slice = 0;
4113*0a55fbb7Slm66018 	}
4114*0a55fbb7Slm66018 	rv = vdc_populate_descriptor(vdc, (caddr_t)vdc->label, DK_LABEL_SIZE,
4115*0a55fbb7Slm66018 			VD_OP_BREAD, 0, slice);
4116*0a55fbb7Slm66018 
4117*0a55fbb7Slm66018 	return (rv);
41181ae08745Sheppo }
4119