xref: /titanic_53/usr/src/uts/sun4v/io/vdc.c (revision d10e4ef2fabf16c3237c6d6592496df3eac6a1ef)
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>
72*d10e4ef2Snarayan #include <sys/sdt.h>
731ae08745Sheppo #include <sys/stat.h>
741ae08745Sheppo #include <sys/sunddi.h>
751ae08745Sheppo #include <sys/types.h>
761ae08745Sheppo #include <sys/promif.h>
771ae08745Sheppo #include <sys/vtoc.h>
781ae08745Sheppo #include <sys/archsystm.h>
791ae08745Sheppo #include <sys/sysmacros.h>
801ae08745Sheppo 
811ae08745Sheppo #include <sys/cdio.h>
821ae08745Sheppo #include <sys/dktp/cm.h>
831ae08745Sheppo #include <sys/dktp/fdisk.h>
841ae08745Sheppo #include <sys/scsi/generic/sense.h>
851ae08745Sheppo #include <sys/scsi/impl/uscsi.h>	/* Needed for defn of USCSICMD ioctl */
861ae08745Sheppo #include <sys/scsi/targets/sddef.h>
871ae08745Sheppo 
881ae08745Sheppo #include <sys/ldoms.h>
891ae08745Sheppo #include <sys/ldc.h>
901ae08745Sheppo #include <sys/vio_common.h>
911ae08745Sheppo #include <sys/vio_mailbox.h>
921ae08745Sheppo #include <sys/vdsk_common.h>
931ae08745Sheppo #include <sys/vdsk_mailbox.h>
941ae08745Sheppo #include <sys/vdc.h>
951ae08745Sheppo 
961ae08745Sheppo /*
971ae08745Sheppo  * function prototypes
981ae08745Sheppo  */
991ae08745Sheppo 
1001ae08745Sheppo /* standard driver functions */
1011ae08745Sheppo static int	vdc_open(dev_t *dev, int flag, int otyp, cred_t *cred);
1021ae08745Sheppo static int	vdc_close(dev_t dev, int flag, int otyp, cred_t *cred);
1031ae08745Sheppo static int	vdc_strategy(struct buf *buf);
1041ae08745Sheppo static int	vdc_print(dev_t dev, char *str);
1051ae08745Sheppo static int	vdc_dump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk);
1061ae08745Sheppo static int	vdc_read(dev_t dev, struct uio *uio, cred_t *cred);
1071ae08745Sheppo static int	vdc_write(dev_t dev, struct uio *uio, cred_t *cred);
1081ae08745Sheppo static int	vdc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
1091ae08745Sheppo 			cred_t *credp, int *rvalp);
1101ae08745Sheppo static int	vdc_aread(dev_t dev, struct aio_req *aio, cred_t *cred);
1111ae08745Sheppo static int	vdc_awrite(dev_t dev, struct aio_req *aio, cred_t *cred);
1121ae08745Sheppo 
1131ae08745Sheppo static int	vdc_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
1141ae08745Sheppo 			void *arg, void **resultp);
1151ae08745Sheppo static int	vdc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
1161ae08745Sheppo static int	vdc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
1171ae08745Sheppo 
1181ae08745Sheppo /* setup */
1190a55fbb7Slm66018 static int	vdc_send(vdc_t *vdc, caddr_t pkt, size_t *msglen);
1201ae08745Sheppo static int	vdc_do_ldc_init(vdc_t *vdc);
1211ae08745Sheppo static int	vdc_start_ldc_connection(vdc_t *vdc);
1221ae08745Sheppo static int	vdc_create_device_nodes(vdc_t *vdc);
1231ae08745Sheppo static int	vdc_create_device_nodes_props(vdc_t *vdc);
1241ae08745Sheppo static int	vdc_get_ldc_id(dev_info_t *dip, uint64_t *ldc_id);
1250a55fbb7Slm66018 static int	vdc_do_ldc_up(vdc_t *vdc);
1261ae08745Sheppo static void	vdc_terminate_ldc(vdc_t *vdc);
1271ae08745Sheppo static int	vdc_init_descriptor_ring(vdc_t *vdc);
1281ae08745Sheppo static void	vdc_destroy_descriptor_ring(vdc_t *vdc);
1291ae08745Sheppo 
1301ae08745Sheppo /* handshake with vds */
1311ae08745Sheppo static void		vdc_init_handshake_negotiation(void *arg);
1320a55fbb7Slm66018 static int		vdc_init_ver_negotiation(vdc_t *vdc, vio_ver_t ver);
1331ae08745Sheppo static int		vdc_init_attr_negotiation(vdc_t *vdc);
1341ae08745Sheppo static int		vdc_init_dring_negotiate(vdc_t *vdc);
1351ae08745Sheppo static void		vdc_reset_connection(vdc_t *vdc, boolean_t resetldc);
1361ae08745Sheppo static boolean_t	vdc_is_able_to_tx_data(vdc_t *vdc, int flag);
1370a55fbb7Slm66018 static boolean_t	vdc_is_supported_version(vio_ver_msg_t *ver_msg);
1381ae08745Sheppo 
1390a55fbb7Slm66018 /* processing incoming messages from vDisk server */
1401ae08745Sheppo static void	vdc_process_msg_thread(vdc_t *vdc);
1411ae08745Sheppo static void	vdc_process_msg(void *arg);
1420a55fbb7Slm66018 static void	vdc_do_process_msg(vdc_t *vdc);
1430a55fbb7Slm66018 static uint_t	vdc_handle_cb(uint64_t event, caddr_t arg);
1441ae08745Sheppo static int	vdc_process_ctrl_msg(vdc_t *vdc, vio_msg_t msg);
1451ae08745Sheppo static int	vdc_process_data_msg(vdc_t *vdc, vio_msg_t msg);
1461ae08745Sheppo static int	vdc_process_err_msg(vdc_t *vdc, vio_msg_t msg);
1470a55fbb7Slm66018 static int	vdc_handle_ver_msg(vdc_t *vdc, vio_ver_msg_t *ver_msg);
1480a55fbb7Slm66018 static int	vdc_handle_attr_msg(vdc_t *vdc, vd_attr_msg_t *attr_msg);
1490a55fbb7Slm66018 static int	vdc_handle_dring_reg_msg(vdc_t *vdc, vio_dring_reg_msg_t *msg);
1501ae08745Sheppo static int	vdc_get_next_dring_entry_id(vdc_t *vdc, uint_t needed);
1511ae08745Sheppo static int	vdc_populate_descriptor(vdc_t *vdc, caddr_t addr,
1521ae08745Sheppo 			size_t nbytes, int op, uint64_t arg, uint64_t slice);
1531ae08745Sheppo static int	vdc_wait_for_descriptor_update(vdc_t *vdc, uint_t idx,
1541ae08745Sheppo 			vio_dring_msg_t dmsg);
1551ae08745Sheppo static int	vdc_depopulate_descriptor(vdc_t *vdc, uint_t idx);
1561ae08745Sheppo static int	vdc_populate_mem_hdl(vdc_t *vdc, uint_t idx,
1571ae08745Sheppo 			caddr_t addr, size_t nbytes, int operation);
1581ae08745Sheppo static boolean_t vdc_verify_seq_num(vdc_t *vdc, vio_dring_msg_t *dring_msg, int
1591ae08745Sheppo 			num_msgs);
1601ae08745Sheppo 
1611ae08745Sheppo /* dkio */
1621ae08745Sheppo static int	vd_process_ioctl(dev_t dev, int cmd, caddr_t arg, int mode);
1631ae08745Sheppo static int	vdc_create_fake_geometry(vdc_t *vdc);
1640a55fbb7Slm66018 static int	vdc_setup_disk_layout(vdc_t *vdc);
165*d10e4ef2Snarayan static int	vdc_null_copy_func(vdc_t *vdc, void *from, void *to,
166*d10e4ef2Snarayan 		    int mode, int dir);
167*d10e4ef2Snarayan static int	vdc_get_vtoc_convert(vdc_t *vdc, void *from, void *to,
168*d10e4ef2Snarayan 		    int mode, int dir);
169*d10e4ef2Snarayan static int	vdc_set_vtoc_convert(vdc_t *vdc, void *from, void *to,
170*d10e4ef2Snarayan 		    int mode, int dir);
171*d10e4ef2Snarayan static int	vdc_get_geom_convert(vdc_t *vdc, void *from, void *to,
172*d10e4ef2Snarayan 		    int mode, int dir);
173*d10e4ef2Snarayan static int	vdc_set_geom_convert(vdc_t *vdc, void *from, void *to,
174*d10e4ef2Snarayan 		    int mode, int dir);
175*d10e4ef2Snarayan static int	vdc_uscsicmd_convert(vdc_t *vdc, void *from, void *to,
176*d10e4ef2Snarayan 		    int mode, int dir);
1771ae08745Sheppo 
1781ae08745Sheppo /*
1791ae08745Sheppo  * Module variables
1801ae08745Sheppo  */
1811ae08745Sheppo uint64_t	vdc_hz_timeout;
1821ae08745Sheppo uint64_t	vdc_usec_timeout = VDC_USEC_TIMEOUT_MIN;
183*d10e4ef2Snarayan uint64_t	vdc_usec_timeout_dump = VDC_USEC_TIMEOUT_MIN / 300;
184*d10e4ef2Snarayan uint64_t	vdc_usec_timeout_dring = 10 * MILLISEC;
1851ae08745Sheppo static int	vdc_retries = VDC_RETRIES;
1861ae08745Sheppo static int	vdc_dump_retries = VDC_RETRIES * 10;
1871ae08745Sheppo 
1881ae08745Sheppo /* Soft state pointer */
1891ae08745Sheppo static void	*vdc_state;
1901ae08745Sheppo 
1911ae08745Sheppo /* variable level controlling the verbosity of the error/debug messages */
1921ae08745Sheppo int	vdc_msglevel = 0;
1931ae08745Sheppo 
1940a55fbb7Slm66018 /*
1950a55fbb7Slm66018  * Supported vDisk protocol version pairs.
1960a55fbb7Slm66018  *
1970a55fbb7Slm66018  * The first array entry is the latest and preferred version.
1980a55fbb7Slm66018  */
1990a55fbb7Slm66018 static const vio_ver_t	vdc_version[] = {{1, 0}};
2001ae08745Sheppo 
2011ae08745Sheppo static void
2021ae08745Sheppo vdc_msg(const char *format, ...)
2031ae08745Sheppo {
2041ae08745Sheppo 	va_list	args;
2051ae08745Sheppo 
2061ae08745Sheppo 	va_start(args, format);
2071ae08745Sheppo 	vcmn_err(CE_CONT, format, args);
2081ae08745Sheppo 	va_end(args);
2091ae08745Sheppo }
2101ae08745Sheppo 
2111ae08745Sheppo static struct cb_ops vdc_cb_ops = {
2121ae08745Sheppo 	vdc_open,	/* cb_open */
2131ae08745Sheppo 	vdc_close,	/* cb_close */
2141ae08745Sheppo 	vdc_strategy,	/* cb_strategy */
2151ae08745Sheppo 	vdc_print,	/* cb_print */
2161ae08745Sheppo 	vdc_dump,	/* cb_dump */
2171ae08745Sheppo 	vdc_read,	/* cb_read */
2181ae08745Sheppo 	vdc_write,	/* cb_write */
2191ae08745Sheppo 	vdc_ioctl,	/* cb_ioctl */
2201ae08745Sheppo 	nodev,		/* cb_devmap */
2211ae08745Sheppo 	nodev,		/* cb_mmap */
2221ae08745Sheppo 	nodev,		/* cb_segmap */
2231ae08745Sheppo 	nochpoll,	/* cb_chpoll */
2241ae08745Sheppo 	ddi_prop_op,	/* cb_prop_op */
2251ae08745Sheppo 	NULL,		/* cb_str */
2261ae08745Sheppo 	D_MP | D_64BIT,	/* cb_flag */
2271ae08745Sheppo 	CB_REV,		/* cb_rev */
2281ae08745Sheppo 	vdc_aread,	/* cb_aread */
2291ae08745Sheppo 	vdc_awrite	/* cb_awrite */
2301ae08745Sheppo };
2311ae08745Sheppo 
2321ae08745Sheppo static struct dev_ops vdc_ops = {
2331ae08745Sheppo 	DEVO_REV,	/* devo_rev */
2341ae08745Sheppo 	0,		/* devo_refcnt */
2351ae08745Sheppo 	vdc_getinfo,	/* devo_getinfo */
2361ae08745Sheppo 	nulldev,	/* devo_identify */
2371ae08745Sheppo 	nulldev,	/* devo_probe */
2381ae08745Sheppo 	vdc_attach,	/* devo_attach */
2391ae08745Sheppo 	vdc_detach,	/* devo_detach */
2401ae08745Sheppo 	nodev,		/* devo_reset */
2411ae08745Sheppo 	&vdc_cb_ops,	/* devo_cb_ops */
2421ae08745Sheppo 	NULL,		/* devo_bus_ops */
2431ae08745Sheppo 	nulldev		/* devo_power */
2441ae08745Sheppo };
2451ae08745Sheppo 
2461ae08745Sheppo static struct modldrv modldrv = {
2471ae08745Sheppo 	&mod_driverops,
2481ae08745Sheppo 	"virtual disk client %I%",
2491ae08745Sheppo 	&vdc_ops,
2501ae08745Sheppo };
2511ae08745Sheppo 
2521ae08745Sheppo static struct modlinkage modlinkage = {
2531ae08745Sheppo 	MODREV_1,
2541ae08745Sheppo 	&modldrv,
2551ae08745Sheppo 	NULL
2561ae08745Sheppo };
2571ae08745Sheppo 
2581ae08745Sheppo /* -------------------------------------------------------------------------- */
2591ae08745Sheppo 
2601ae08745Sheppo /*
2611ae08745Sheppo  * Device Driver housekeeping and setup
2621ae08745Sheppo  */
2631ae08745Sheppo 
2641ae08745Sheppo int
2651ae08745Sheppo _init(void)
2661ae08745Sheppo {
2671ae08745Sheppo 	int	status;
2681ae08745Sheppo 
2691ae08745Sheppo 	if ((status = ddi_soft_state_init(&vdc_state, sizeof (vdc_t), 1)) != 0)
2701ae08745Sheppo 		return (status);
2711ae08745Sheppo 	if ((status = mod_install(&modlinkage)) != 0)
2721ae08745Sheppo 		ddi_soft_state_fini(&vdc_state);
2731ae08745Sheppo 	return (status);
2741ae08745Sheppo }
2751ae08745Sheppo 
2761ae08745Sheppo int
2771ae08745Sheppo _info(struct modinfo *modinfop)
2781ae08745Sheppo {
2791ae08745Sheppo 	return (mod_info(&modlinkage, modinfop));
2801ae08745Sheppo }
2811ae08745Sheppo 
2821ae08745Sheppo int
2831ae08745Sheppo _fini(void)
2841ae08745Sheppo {
2851ae08745Sheppo 	int	status;
2861ae08745Sheppo 
2871ae08745Sheppo 	if ((status = mod_remove(&modlinkage)) != 0)
2881ae08745Sheppo 		return (status);
2891ae08745Sheppo 	ddi_soft_state_fini(&vdc_state);
2901ae08745Sheppo 	return (0);
2911ae08745Sheppo }
2921ae08745Sheppo 
2931ae08745Sheppo static int
2941ae08745Sheppo vdc_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,  void *arg, void **resultp)
2951ae08745Sheppo {
2961ae08745Sheppo 	_NOTE(ARGUNUSED(dip))
2971ae08745Sheppo 
2981ae08745Sheppo 	int	instance = SDUNIT(getminor((dev_t)arg));
2991ae08745Sheppo 	vdc_t	*vdc = NULL;
3001ae08745Sheppo 
3011ae08745Sheppo 	switch (cmd) {
3021ae08745Sheppo 	case DDI_INFO_DEVT2DEVINFO:
3031ae08745Sheppo 		if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) {
3041ae08745Sheppo 			*resultp = NULL;
3051ae08745Sheppo 			return (DDI_FAILURE);
3061ae08745Sheppo 		}
3071ae08745Sheppo 		*resultp = vdc->dip;
3081ae08745Sheppo 		return (DDI_SUCCESS);
3091ae08745Sheppo 	case DDI_INFO_DEVT2INSTANCE:
3101ae08745Sheppo 		*resultp = (void *)(uintptr_t)instance;
3111ae08745Sheppo 		return (DDI_SUCCESS);
3121ae08745Sheppo 	default:
3131ae08745Sheppo 		*resultp = NULL;
3141ae08745Sheppo 		return (DDI_FAILURE);
3151ae08745Sheppo 	}
3161ae08745Sheppo }
3171ae08745Sheppo 
3181ae08745Sheppo static int
3191ae08745Sheppo vdc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
3201ae08745Sheppo {
3211ae08745Sheppo 	int	instance;
3221ae08745Sheppo 	int	rv;
3231ae08745Sheppo 	uint_t	retries = 0;
3241ae08745Sheppo 	vdc_t	*vdc = NULL;
3251ae08745Sheppo 
3261ae08745Sheppo 	switch (cmd) {
3271ae08745Sheppo 	case DDI_DETACH:
3281ae08745Sheppo 		/* the real work happens below */
3291ae08745Sheppo 		break;
3301ae08745Sheppo 	case DDI_SUSPEND:
3311ae08745Sheppo 		/* nothing to do for this non-device */
3321ae08745Sheppo 		return (DDI_SUCCESS);
3331ae08745Sheppo 	default:
3341ae08745Sheppo 		return (DDI_FAILURE);
3351ae08745Sheppo 	}
3361ae08745Sheppo 
3371ae08745Sheppo 	ASSERT(cmd == DDI_DETACH);
3381ae08745Sheppo 	instance = ddi_get_instance(dip);
3391ae08745Sheppo 	PR1("%s[%d] Entered\n", __func__, instance);
3401ae08745Sheppo 
3411ae08745Sheppo 	if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) {
3421ae08745Sheppo 		vdc_msg("%s[%d]:  Could not get state structure.",
3431ae08745Sheppo 		    __func__, instance);
3441ae08745Sheppo 		return (DDI_FAILURE);
3451ae08745Sheppo 	}
3461ae08745Sheppo 
3471ae08745Sheppo 	if (vdc->open) {
3481ae08745Sheppo 		PR0("%s[%d]: Cannot detach: device is open",
3491ae08745Sheppo 				__func__, instance);
3501ae08745Sheppo 		return (DDI_FAILURE);
3511ae08745Sheppo 	}
3521ae08745Sheppo 
3531ae08745Sheppo 	PR0("%s[%d] proceeding...\n", __func__, instance);
3541ae08745Sheppo 
3551ae08745Sheppo 	/*
3561ae08745Sheppo 	 * try and disable callbacks to prevent another handshake
3571ae08745Sheppo 	 */
3581ae08745Sheppo 	rv = ldc_set_cb_mode(vdc->ldc_handle, LDC_CB_DISABLE);
3591ae08745Sheppo 	PR0("%s[%d] callback disabled (rv=%d)\n", __func__, instance, rv);
3601ae08745Sheppo 
3611ae08745Sheppo 	/*
3621ae08745Sheppo 	 * Prevent any more attempts to start a handshake with the vdisk
3631ae08745Sheppo 	 * server and tear down the existing connection.
3641ae08745Sheppo 	 */
3651ae08745Sheppo 	mutex_enter(&vdc->lock);
3661ae08745Sheppo 	vdc->initialized |= VDC_HANDSHAKE_STOP;
3671ae08745Sheppo 	vdc_reset_connection(vdc, B_TRUE);
3681ae08745Sheppo 	mutex_exit(&vdc->lock);
3691ae08745Sheppo 
3701ae08745Sheppo 	if (vdc->initialized & VDC_THREAD) {
3711ae08745Sheppo 		mutex_enter(&vdc->msg_proc_lock);
3721ae08745Sheppo 		vdc->msg_proc_thr_state = VDC_THR_STOP;
3731ae08745Sheppo 		vdc->msg_pending = B_TRUE;
3741ae08745Sheppo 		cv_signal(&vdc->msg_proc_cv);
3751ae08745Sheppo 
3761ae08745Sheppo 		while (vdc->msg_proc_thr_state != VDC_THR_DONE) {
3771ae08745Sheppo 			PR0("%s[%d]: Waiting for thread to exit\n",
3781ae08745Sheppo 				__func__, instance);
3791ae08745Sheppo 			rv = cv_timedwait(&vdc->msg_proc_cv,
3801ae08745Sheppo 				&vdc->msg_proc_lock, VD_GET_TIMEOUT_HZ(1));
3811ae08745Sheppo 			if ((rv == -1) && (retries++ > vdc_retries))
3821ae08745Sheppo 				break;
3831ae08745Sheppo 		}
3841ae08745Sheppo 		mutex_exit(&vdc->msg_proc_lock);
3851ae08745Sheppo 	}
3861ae08745Sheppo 
3871ae08745Sheppo 	mutex_enter(&vdc->lock);
3881ae08745Sheppo 
3891ae08745Sheppo 	if (vdc->initialized & VDC_DRING)
3901ae08745Sheppo 		vdc_destroy_descriptor_ring(vdc);
3911ae08745Sheppo 
3921ae08745Sheppo 	if (vdc->initialized & VDC_LDC)
3931ae08745Sheppo 		vdc_terminate_ldc(vdc);
3941ae08745Sheppo 
3951ae08745Sheppo 	mutex_exit(&vdc->lock);
3961ae08745Sheppo 
3971ae08745Sheppo 	if (vdc->initialized & VDC_MINOR) {
3981ae08745Sheppo 		ddi_prop_remove_all(dip);
3991ae08745Sheppo 		ddi_remove_minor_node(dip, NULL);
4001ae08745Sheppo 	}
4011ae08745Sheppo 
4021ae08745Sheppo 	if (vdc->initialized & VDC_LOCKS) {
4031ae08745Sheppo 		mutex_destroy(&vdc->lock);
4041ae08745Sheppo 		mutex_destroy(&vdc->attach_lock);
4051ae08745Sheppo 		mutex_destroy(&vdc->msg_proc_lock);
4061ae08745Sheppo 		mutex_destroy(&vdc->dring_lock);
4071ae08745Sheppo 		cv_destroy(&vdc->cv);
4081ae08745Sheppo 		cv_destroy(&vdc->attach_cv);
4091ae08745Sheppo 		cv_destroy(&vdc->msg_proc_cv);
4101ae08745Sheppo 	}
4111ae08745Sheppo 
4121ae08745Sheppo 	if (vdc->minfo)
4131ae08745Sheppo 		kmem_free(vdc->minfo, sizeof (struct dk_minfo));
4141ae08745Sheppo 
4151ae08745Sheppo 	if (vdc->cinfo)
4161ae08745Sheppo 		kmem_free(vdc->cinfo, sizeof (struct dk_cinfo));
4171ae08745Sheppo 
4181ae08745Sheppo 	if (vdc->vtoc)
4191ae08745Sheppo 		kmem_free(vdc->vtoc, sizeof (struct vtoc));
4201ae08745Sheppo 
4210a55fbb7Slm66018 	if (vdc->label)
4220a55fbb7Slm66018 		kmem_free(vdc->label, DK_LABEL_SIZE);
4230a55fbb7Slm66018 
4241ae08745Sheppo 	if (vdc->initialized & VDC_SOFT_STATE)
4251ae08745Sheppo 		ddi_soft_state_free(vdc_state, instance);
4261ae08745Sheppo 
4271ae08745Sheppo 	PR0("%s[%d] End %p\n", __func__, instance, vdc);
4281ae08745Sheppo 
4291ae08745Sheppo 	return (DDI_SUCCESS);
4301ae08745Sheppo }
4311ae08745Sheppo 
4321ae08745Sheppo 
4331ae08745Sheppo static int
4341ae08745Sheppo vdc_do_attach(dev_info_t *dip)
4351ae08745Sheppo {
4361ae08745Sheppo 	int		instance;
4371ae08745Sheppo 	vdc_t		*vdc = NULL;
4381ae08745Sheppo 	int		status;
4391ae08745Sheppo 	uint_t		retries = 0;
4401ae08745Sheppo 
4411ae08745Sheppo 	ASSERT(dip != NULL);
4421ae08745Sheppo 
4431ae08745Sheppo 	instance = ddi_get_instance(dip);
4441ae08745Sheppo 	if (ddi_soft_state_zalloc(vdc_state, instance) != DDI_SUCCESS) {
4451ae08745Sheppo 		vdc_msg("%s:(%d): Couldn't alloc state structure",
4461ae08745Sheppo 		    __func__, instance);
4471ae08745Sheppo 		return (DDI_FAILURE);
4481ae08745Sheppo 	}
4491ae08745Sheppo 
4501ae08745Sheppo 	if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) {
4511ae08745Sheppo 		vdc_msg("%s:(%d): Could not get state structure.",
4521ae08745Sheppo 		    __func__, instance);
4531ae08745Sheppo 		return (DDI_FAILURE);
4541ae08745Sheppo 	}
4551ae08745Sheppo 
4561ae08745Sheppo 	/*
4571ae08745Sheppo 	 * We assign the value to initialized in this case to zero out the
4581ae08745Sheppo 	 * variable and then set bits in it to indicate what has been done
4591ae08745Sheppo 	 */
4601ae08745Sheppo 	vdc->initialized = VDC_SOFT_STATE;
4611ae08745Sheppo 
4621ae08745Sheppo 	vdc_hz_timeout = drv_usectohz(vdc_usec_timeout);
4631ae08745Sheppo 
4641ae08745Sheppo 	vdc->dip	= dip;
4651ae08745Sheppo 	vdc->instance	= instance;
4661ae08745Sheppo 	vdc->open	= 0;
4671ae08745Sheppo 	vdc->vdisk_type	= VD_DISK_TYPE_UNK;
4681ae08745Sheppo 	vdc->state	= VD_STATE_INIT;
4691ae08745Sheppo 	vdc->ldc_state	= 0;
4701ae08745Sheppo 	vdc->session_id = 0;
4711ae08745Sheppo 	vdc->block_size = DEV_BSIZE;
4728e6a2a04Slm66018 	vdc->max_xfer_sz = maxphys / DEV_BSIZE;
4731ae08745Sheppo 
4741ae08745Sheppo 	vdc->vtoc = NULL;
4751ae08745Sheppo 	vdc->cinfo = NULL;
4761ae08745Sheppo 	vdc->minfo = NULL;
4771ae08745Sheppo 
4781ae08745Sheppo 	mutex_init(&vdc->lock, NULL, MUTEX_DRIVER, NULL);
4791ae08745Sheppo 	mutex_init(&vdc->attach_lock, NULL, MUTEX_DRIVER, NULL);
4801ae08745Sheppo 	mutex_init(&vdc->msg_proc_lock, NULL, MUTEX_DRIVER, NULL);
4811ae08745Sheppo 	mutex_init(&vdc->dring_lock, NULL, MUTEX_DRIVER, NULL);
4821ae08745Sheppo 	cv_init(&vdc->cv, NULL, CV_DRIVER, NULL);
4831ae08745Sheppo 	cv_init(&vdc->attach_cv, NULL, CV_DRIVER, NULL);
4841ae08745Sheppo 	cv_init(&vdc->msg_proc_cv, NULL, CV_DRIVER, NULL);
4851ae08745Sheppo 	vdc->initialized |= VDC_LOCKS;
4861ae08745Sheppo 
4871ae08745Sheppo 	vdc->msg_pending = B_FALSE;
4881ae08745Sheppo 	vdc->msg_proc_thr_id = thread_create(NULL, 0, vdc_process_msg_thread,
4891ae08745Sheppo 		vdc, 0, &p0, TS_RUN, minclsyspri);
4901ae08745Sheppo 	if (vdc->msg_proc_thr_id == NULL) {
4911ae08745Sheppo 		cmn_err(CE_NOTE, "[%d] Failed to create msg processing thread",
4921ae08745Sheppo 				instance);
4931ae08745Sheppo 		return (DDI_FAILURE);
4941ae08745Sheppo 	}
4951ae08745Sheppo 	vdc->initialized |= VDC_THREAD;
4961ae08745Sheppo 
4971ae08745Sheppo 	/* initialise LDC channel which will be used to communicate with vds */
4981ae08745Sheppo 	if (vdc_do_ldc_init(vdc) != 0) {
4991ae08745Sheppo 		cmn_err(CE_NOTE, "[%d] Couldn't initialize LDC", instance);
5001ae08745Sheppo 		return (DDI_FAILURE);
5011ae08745Sheppo 	}
5021ae08745Sheppo 
5031ae08745Sheppo 	/* Bring up connection with vds via LDC */
5041ae08745Sheppo 	status = vdc_start_ldc_connection(vdc);
5051ae08745Sheppo 	if (status != 0) {
5061ae08745Sheppo 		vdc_msg("%s[%d]  Could not start LDC", __func__, instance);
5071ae08745Sheppo 		return (DDI_FAILURE);
5081ae08745Sheppo 	}
5091ae08745Sheppo 
5101ae08745Sheppo 	/*
5111ae08745Sheppo 	 * We need to wait until the handshake has completed before leaving
5121ae08745Sheppo 	 * the attach(). This is to allow the device node(s) to be created
5131ae08745Sheppo 	 * and the first usage of the filesystem to succeed.
5141ae08745Sheppo 	 */
5151ae08745Sheppo 	mutex_enter(&vdc->attach_lock);
5161ae08745Sheppo 	while ((vdc->ldc_state != LDC_UP) ||
5171ae08745Sheppo 		(vdc->state != VD_STATE_DATA)) {
5181ae08745Sheppo 
5191ae08745Sheppo 		PR0("%s[%d] handshake in progress [VD %d (LDC %d)]\n",
5201ae08745Sheppo 			__func__, instance, vdc->state, vdc->ldc_state);
5211ae08745Sheppo 
5221ae08745Sheppo 		status = cv_timedwait(&vdc->attach_cv, &vdc->attach_lock,
5231ae08745Sheppo 				VD_GET_TIMEOUT_HZ(1));
5241ae08745Sheppo 		if (status == -1) {
5251ae08745Sheppo 			if (retries >= vdc_retries) {
5261ae08745Sheppo 				PR0("%s[%d] Give up handshake wait.\n",
5271ae08745Sheppo 						__func__, instance);
5281ae08745Sheppo 				mutex_exit(&vdc->attach_lock);
5291ae08745Sheppo 				return (DDI_FAILURE);
5301ae08745Sheppo 			} else {
5311ae08745Sheppo 				PR0("%s[%d] Retry #%d for handshake.\n",
5321ae08745Sheppo 						__func__, instance, retries);
5330a55fbb7Slm66018 				vdc_init_handshake_negotiation(vdc);
5341ae08745Sheppo 				retries++;
5351ae08745Sheppo 			}
5361ae08745Sheppo 		}
5371ae08745Sheppo 	}
5381ae08745Sheppo 	mutex_exit(&vdc->attach_lock);
5391ae08745Sheppo 
5400a55fbb7Slm66018 	/*
5410a55fbb7Slm66018 	 * Once the handshake is complete, we can use the DRing to send
5420a55fbb7Slm66018 	 * requests to the vDisk server to calculate the geometry and
5430a55fbb7Slm66018 	 * VTOC of the "disk"
5440a55fbb7Slm66018 	 */
5450a55fbb7Slm66018 	status = vdc_setup_disk_layout(vdc);
5460a55fbb7Slm66018 	if (status != 0) {
5470a55fbb7Slm66018 		cmn_err(CE_NOTE, "[%d] Failed to discover disk layout (err%d)",
5480a55fbb7Slm66018 				vdc->instance, status);
5491ae08745Sheppo 	}
5501ae08745Sheppo 
5511ae08745Sheppo 	/*
5521ae08745Sheppo 	 * Now that we have the device info we can create the
5531ae08745Sheppo 	 * device nodes and properties
5541ae08745Sheppo 	 */
5551ae08745Sheppo 	status = vdc_create_device_nodes(vdc);
5561ae08745Sheppo 	if (status) {
5571ae08745Sheppo 		cmn_err(CE_NOTE, "[%d] Failed to create device nodes",
5581ae08745Sheppo 				instance);
5591ae08745Sheppo 		return (status);
5601ae08745Sheppo 	}
5611ae08745Sheppo 	status = vdc_create_device_nodes_props(vdc);
5621ae08745Sheppo 	if (status) {
5631ae08745Sheppo 		cmn_err(CE_NOTE, "[%d] Failed to create device nodes"
5640a55fbb7Slm66018 				" properties (%d)", instance, status);
5651ae08745Sheppo 		return (status);
5661ae08745Sheppo 	}
5671ae08745Sheppo 
5681ae08745Sheppo 	ddi_report_dev(dip);
5691ae08745Sheppo 
5701ae08745Sheppo 	PR0("%s[%d] Attach completed\n", __func__, instance);
5711ae08745Sheppo 	return (status);
5721ae08745Sheppo }
5731ae08745Sheppo 
5741ae08745Sheppo static int
5751ae08745Sheppo vdc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
5761ae08745Sheppo {
5771ae08745Sheppo 	int	status;
5781ae08745Sheppo 
5791ae08745Sheppo 	switch (cmd) {
5801ae08745Sheppo 	case DDI_ATTACH:
5811ae08745Sheppo 		if ((status = vdc_do_attach(dip)) != 0)
5821ae08745Sheppo 			(void) vdc_detach(dip, DDI_DETACH);
5831ae08745Sheppo 		return (status);
5841ae08745Sheppo 	case DDI_RESUME:
5851ae08745Sheppo 		/* nothing to do for this non-device */
5861ae08745Sheppo 		return (DDI_SUCCESS);
5871ae08745Sheppo 	default:
5881ae08745Sheppo 		return (DDI_FAILURE);
5891ae08745Sheppo 	}
5901ae08745Sheppo }
5911ae08745Sheppo 
5921ae08745Sheppo static int
5931ae08745Sheppo vdc_do_ldc_init(vdc_t *vdc)
5941ae08745Sheppo {
5951ae08745Sheppo 	int			status = 0;
5961ae08745Sheppo 	ldc_status_t		ldc_state;
5971ae08745Sheppo 	ldc_attr_t		ldc_attr;
5981ae08745Sheppo 	uint64_t		ldc_id = 0;
5991ae08745Sheppo 	dev_info_t		*dip = NULL;
6001ae08745Sheppo 
6011ae08745Sheppo 	ASSERT(vdc != NULL);
6021ae08745Sheppo 
6031ae08745Sheppo 	dip = vdc->dip;
6041ae08745Sheppo 	vdc->initialized |= VDC_LDC;
6051ae08745Sheppo 
6061ae08745Sheppo 	if ((status = vdc_get_ldc_id(dip, &ldc_id)) != 0) {
6071ae08745Sheppo 		vdc_msg("%s:  Failed to get <ldc_id> property\n", __func__);
6081ae08745Sheppo 		return (EIO);
6091ae08745Sheppo 	}
6101ae08745Sheppo 	vdc->ldc_id = ldc_id;
6111ae08745Sheppo 
6121ae08745Sheppo 	ldc_attr.devclass = LDC_DEV_BLK;
6131ae08745Sheppo 	ldc_attr.instance = vdc->instance;
6141ae08745Sheppo 	ldc_attr.mode = LDC_MODE_UNRELIABLE;	/* unreliable transport */
6151ae08745Sheppo 	ldc_attr.qlen = VD_LDC_QLEN;
6161ae08745Sheppo 
6171ae08745Sheppo 	if ((vdc->initialized & VDC_LDC_INIT) == 0) {
6181ae08745Sheppo 		status = ldc_init(ldc_id, &ldc_attr, &vdc->ldc_handle);
6191ae08745Sheppo 		if (status != 0) {
6201ae08745Sheppo 			cmn_err(CE_NOTE, "[%d] ldc_init(chan %ld) returned %d",
6211ae08745Sheppo 					vdc->instance, ldc_id, status);
6221ae08745Sheppo 			return (status);
6231ae08745Sheppo 		}
6241ae08745Sheppo 		vdc->initialized |= VDC_LDC_INIT;
6251ae08745Sheppo 	}
6261ae08745Sheppo 	status = ldc_status(vdc->ldc_handle, &ldc_state);
6271ae08745Sheppo 	if (status != 0) {
6281ae08745Sheppo 		vdc_msg("Cannot discover LDC status [err=%d].", status);
6291ae08745Sheppo 		return (status);
6301ae08745Sheppo 	}
6311ae08745Sheppo 	vdc->ldc_state = ldc_state;
6321ae08745Sheppo 
6331ae08745Sheppo 	if ((vdc->initialized & VDC_LDC_CB) == 0) {
6341ae08745Sheppo 		status = ldc_reg_callback(vdc->ldc_handle, vdc_handle_cb,
6351ae08745Sheppo 		    (caddr_t)vdc);
6361ae08745Sheppo 		if (status != 0) {
6371ae08745Sheppo 			vdc_msg("%s: ldc_reg_callback()=%d", __func__, status);
6381ae08745Sheppo 			return (status);
6391ae08745Sheppo 		}
6401ae08745Sheppo 		vdc->initialized |= VDC_LDC_CB;
6411ae08745Sheppo 	}
6421ae08745Sheppo 
6431ae08745Sheppo 	vdc->initialized |= VDC_LDC;
6441ae08745Sheppo 
6451ae08745Sheppo 	/*
6461ae08745Sheppo 	 * At this stage we have initialised LDC, we will now try and open
6471ae08745Sheppo 	 * the connection.
6481ae08745Sheppo 	 */
6491ae08745Sheppo 	if (vdc->ldc_state == LDC_INIT) {
6501ae08745Sheppo 		status = ldc_open(vdc->ldc_handle);
6511ae08745Sheppo 		if (status != 0) {
6521ae08745Sheppo 			cmn_err(CE_NOTE, "[%d] ldc_open(chan %ld) returned %d",
6531ae08745Sheppo 					vdc->instance, vdc->ldc_id, status);
6541ae08745Sheppo 			return (status);
6551ae08745Sheppo 		}
6561ae08745Sheppo 		vdc->initialized |= VDC_LDC_OPEN;
6571ae08745Sheppo 	}
6581ae08745Sheppo 
6591ae08745Sheppo 	return (status);
6601ae08745Sheppo }
6611ae08745Sheppo 
6621ae08745Sheppo static int
6631ae08745Sheppo vdc_start_ldc_connection(vdc_t *vdc)
6641ae08745Sheppo {
6651ae08745Sheppo 	int		status = 0;
6661ae08745Sheppo 
6671ae08745Sheppo 	ASSERT(vdc != NULL);
6681ae08745Sheppo 
6691ae08745Sheppo 	mutex_enter(&vdc->lock);
6701ae08745Sheppo 
6711ae08745Sheppo 	if (vdc->ldc_state == LDC_UP) {
6721ae08745Sheppo 		PR0("%s:  LDC is already UP ..\n", __func__);
6731ae08745Sheppo 		mutex_exit(&vdc->lock);
6741ae08745Sheppo 		return (0);
6751ae08745Sheppo 	}
6761ae08745Sheppo 
6770a55fbb7Slm66018 	status = vdc_do_ldc_up(vdc);
6781ae08745Sheppo 
6791ae08745Sheppo 	PR0("%s[%d] Finished bringing up LDC\n", __func__, vdc->instance);
6801ae08745Sheppo 
6811ae08745Sheppo 	mutex_exit(&vdc->lock);
6821ae08745Sheppo 
6831ae08745Sheppo 	return (status);
6841ae08745Sheppo }
6851ae08745Sheppo 
6861ae08745Sheppo 
6871ae08745Sheppo /*
6881ae08745Sheppo  * Function:
6891ae08745Sheppo  *	vdc_create_device_nodes
6901ae08745Sheppo  *
6911ae08745Sheppo  * Description:
6921ae08745Sheppo  *	This function creates the block and character device nodes under
6931ae08745Sheppo  *	/devices along with the node properties. It is called as part of
6941ae08745Sheppo  *	the attach(9E) of the instance during the handshake with vds after
6951ae08745Sheppo  *	vds has sent the attributes to vdc.
6961ae08745Sheppo  *
6971ae08745Sheppo  *	If the device is of type VD_DISK_TYPE_SLICE then the minor node
6981ae08745Sheppo  *	of 2 is used in keeping with the Solaris convention that slice 2
6991ae08745Sheppo  *	refers to a whole disk. Slices start at 'a'
7001ae08745Sheppo  *
7011ae08745Sheppo  * Parameters:
7021ae08745Sheppo  *	vdc 		- soft state pointer
7031ae08745Sheppo  *
7041ae08745Sheppo  * Return Values
7051ae08745Sheppo  *	0		- Success
7061ae08745Sheppo  *	EIO		- Failed to create node
7071ae08745Sheppo  *	EINVAL		- Unknown type of disk exported
7081ae08745Sheppo  */
7091ae08745Sheppo static int
7101ae08745Sheppo vdc_create_device_nodes(vdc_t *vdc)
7111ae08745Sheppo {
7121ae08745Sheppo 	/* uses NNNN which is OK as long as # of disks <= 10000 */
7131ae08745Sheppo 	char		name[sizeof ("disk@NNNN:s,raw")];
7141ae08745Sheppo 	dev_info_t	*dip = NULL;
7151ae08745Sheppo 	int		instance;
7161ae08745Sheppo 	int		num_slices = 1;
7171ae08745Sheppo 	int		i;
7181ae08745Sheppo 
7191ae08745Sheppo 	ASSERT(vdc != NULL);
7201ae08745Sheppo 
7211ae08745Sheppo 	instance = vdc->instance;
7221ae08745Sheppo 	dip = vdc->dip;
7231ae08745Sheppo 
7241ae08745Sheppo 	switch (vdc->vdisk_type) {
7251ae08745Sheppo 	case VD_DISK_TYPE_DISK:
7261ae08745Sheppo 		num_slices = V_NUMPAR;
7271ae08745Sheppo 		break;
7281ae08745Sheppo 	case VD_DISK_TYPE_SLICE:
7291ae08745Sheppo 		num_slices = 1;
7301ae08745Sheppo 		break;
7311ae08745Sheppo 	case VD_DISK_TYPE_UNK:
7321ae08745Sheppo 	default:
7331ae08745Sheppo 		return (EINVAL);
7341ae08745Sheppo 	}
7351ae08745Sheppo 
7361ae08745Sheppo 	for (i = 0; i < num_slices; i++) {
7371ae08745Sheppo 		(void) snprintf(name, sizeof (name), "%c", 'a' + i);
7381ae08745Sheppo 		if (ddi_create_minor_node(dip, name, S_IFBLK,
7391ae08745Sheppo 		    VD_MAKE_DEV(instance, i), DDI_NT_BLOCK, 0) != DDI_SUCCESS) {
7401ae08745Sheppo 			vdc_msg("%s[%d]: Couldn't add block node %s.",
7411ae08745Sheppo 				__func__, instance, name);
7421ae08745Sheppo 			return (EIO);
7431ae08745Sheppo 		}
7441ae08745Sheppo 
7451ae08745Sheppo 		/* if any device node is created we set this flag */
7461ae08745Sheppo 		vdc->initialized |= VDC_MINOR;
7471ae08745Sheppo 
7481ae08745Sheppo 		(void) snprintf(name, sizeof (name), "%c%s",
7491ae08745Sheppo 			'a' + i, ",raw");
7501ae08745Sheppo 		if (ddi_create_minor_node(dip, name, S_IFCHR,
7511ae08745Sheppo 		    VD_MAKE_DEV(instance, i), DDI_NT_BLOCK, 0) != DDI_SUCCESS) {
7521ae08745Sheppo 			vdc_msg("%s[%d]:  Could not add raw node %s.",
7531ae08745Sheppo 				__func__, instance, name);
7541ae08745Sheppo 			return (EIO);
7551ae08745Sheppo 		}
7561ae08745Sheppo 	}
7571ae08745Sheppo 
7581ae08745Sheppo 	return (0);
7591ae08745Sheppo }
7601ae08745Sheppo 
7611ae08745Sheppo /*
7621ae08745Sheppo  * Function:
7631ae08745Sheppo  *	vdc_create_device_nodes_props
7641ae08745Sheppo  *
7651ae08745Sheppo  * Description:
7661ae08745Sheppo  *	This function creates the block and character device nodes under
7671ae08745Sheppo  *	/devices along with the node properties. It is called as part of
7681ae08745Sheppo  *	the attach(9E) of the instance during the handshake with vds after
7691ae08745Sheppo  *	vds has sent the attributes to vdc.
7701ae08745Sheppo  *
7711ae08745Sheppo  * Parameters:
7721ae08745Sheppo  *	vdc 		- soft state pointer
7731ae08745Sheppo  *
7741ae08745Sheppo  * Return Values
7751ae08745Sheppo  *	0		- Success
7761ae08745Sheppo  *	EIO		- Failed to create device node property
7771ae08745Sheppo  *	EINVAL		- Unknown type of disk exported
7781ae08745Sheppo  */
7791ae08745Sheppo static int
7801ae08745Sheppo vdc_create_device_nodes_props(vdc_t *vdc)
7811ae08745Sheppo {
7821ae08745Sheppo 	dev_info_t	*dip = NULL;
7831ae08745Sheppo 	int		instance;
7841ae08745Sheppo 	int		num_slices = 1;
7851ae08745Sheppo 	int64_t		size = 0;
7861ae08745Sheppo 	dev_t		dev;
7871ae08745Sheppo 	int		rv;
7881ae08745Sheppo 	int		i;
7891ae08745Sheppo 
7901ae08745Sheppo 	ASSERT(vdc != NULL);
7911ae08745Sheppo 
7921ae08745Sheppo 	instance = vdc->instance;
7931ae08745Sheppo 	dip = vdc->dip;
7941ae08745Sheppo 
7951ae08745Sheppo 	if ((vdc->vtoc == NULL) || (vdc->vtoc->v_sanity != VTOC_SANE)) {
7961ae08745Sheppo 		cmn_err(CE_NOTE, "![%d] Could not create device node property."
7971ae08745Sheppo 				" No VTOC available", instance);
7981ae08745Sheppo 		return (ENXIO);
7991ae08745Sheppo 	}
8001ae08745Sheppo 
8011ae08745Sheppo 	switch (vdc->vdisk_type) {
8021ae08745Sheppo 	case VD_DISK_TYPE_DISK:
8031ae08745Sheppo 		num_slices = V_NUMPAR;
8041ae08745Sheppo 		break;
8051ae08745Sheppo 	case VD_DISK_TYPE_SLICE:
8061ae08745Sheppo 		num_slices = 1;
8071ae08745Sheppo 		break;
8081ae08745Sheppo 	case VD_DISK_TYPE_UNK:
8091ae08745Sheppo 	default:
8101ae08745Sheppo 		return (EINVAL);
8111ae08745Sheppo 	}
8121ae08745Sheppo 
8131ae08745Sheppo 	for (i = 0; i < num_slices; i++) {
8141ae08745Sheppo 		dev = makedevice(ddi_driver_major(dip),
8151ae08745Sheppo 			VD_MAKE_DEV(instance, i));
8161ae08745Sheppo 
8171ae08745Sheppo 		size = vdc->vtoc->v_part[i].p_size * vdc->vtoc->v_sectorsz;
8181ae08745Sheppo 		PR0("%s[%d] sz %ld (%ld Mb)  p_size %lx\n",
8191ae08745Sheppo 				__func__, instance, size, size / (1024 * 1024),
8201ae08745Sheppo 				vdc->vtoc->v_part[i].p_size);
8211ae08745Sheppo 
8221ae08745Sheppo 		rv = ddi_prop_update_int64(dev, dip, VDC_SIZE_PROP_NAME, size);
8231ae08745Sheppo 		if (rv != DDI_PROP_SUCCESS) {
8241ae08745Sheppo 			vdc_msg("%s:(%d): Couldn't add \"%s\" [%d]\n",
8251ae08745Sheppo 				__func__, instance, VDC_SIZE_PROP_NAME, size);
8261ae08745Sheppo 			return (EIO);
8271ae08745Sheppo 		}
8281ae08745Sheppo 
8291ae08745Sheppo 		rv = ddi_prop_update_int64(dev, dip, VDC_NBLOCKS_PROP_NAME,
8301ae08745Sheppo 			lbtodb(size));
8311ae08745Sheppo 		if (rv != DDI_PROP_SUCCESS) {
8321ae08745Sheppo 			vdc_msg("%s:(%d): Couldn't add \"%s\" [%d]\n", __func__,
8331ae08745Sheppo 				instance, VDC_NBLOCKS_PROP_NAME, lbtodb(size));
8341ae08745Sheppo 			return (EIO);
8351ae08745Sheppo 		}
8361ae08745Sheppo 	}
8371ae08745Sheppo 
8381ae08745Sheppo 	return (0);
8391ae08745Sheppo }
8401ae08745Sheppo 
8411ae08745Sheppo static int
8421ae08745Sheppo vdc_open(dev_t *dev, int flag, int otyp, cred_t *cred)
8431ae08745Sheppo {
8441ae08745Sheppo 	_NOTE(ARGUNUSED(cred))
8451ae08745Sheppo 
8461ae08745Sheppo 	int		instance;
8471ae08745Sheppo 	vdc_t		*vdc;
8481ae08745Sheppo 
8491ae08745Sheppo 	ASSERT(dev != NULL);
8501ae08745Sheppo 	instance = SDUNIT(getminor(*dev));
8511ae08745Sheppo 
8521ae08745Sheppo 	PR0("%s[%d] minor = %d flag = %x, otyp = %x\n", __func__, instance,
8531ae08745Sheppo 			getminor(*dev), flag, otyp);
8541ae08745Sheppo 
8551ae08745Sheppo 	if ((otyp != OTYP_CHR) && (otyp != OTYP_BLK))
8561ae08745Sheppo 		return (EINVAL);
8571ae08745Sheppo 
8581ae08745Sheppo 	if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) {
8591ae08745Sheppo 		vdc_msg("%s[%d] Could not get state.", __func__, instance);
8601ae08745Sheppo 		return (ENXIO);
8611ae08745Sheppo 	}
8621ae08745Sheppo 
8631ae08745Sheppo 	/*
8641ae08745Sheppo 	 * Check to see if we can communicate with vds
8651ae08745Sheppo 	 */
8660a55fbb7Slm66018 	if (!vdc_is_able_to_tx_data(vdc, flag)) {
8671ae08745Sheppo 		PR0("%s[%d] Not ready to transmit data\n", __func__, instance);
8681ae08745Sheppo 		return (ENOLINK);
8691ae08745Sheppo 	}
8701ae08745Sheppo 
8711ae08745Sheppo 	mutex_enter(&vdc->lock);
8721ae08745Sheppo 	vdc->open++;
8731ae08745Sheppo 	mutex_exit(&vdc->lock);
8741ae08745Sheppo 
8751ae08745Sheppo 	return (0);
8761ae08745Sheppo }
8771ae08745Sheppo 
8781ae08745Sheppo static int
8791ae08745Sheppo vdc_close(dev_t dev, int flag, int otyp, cred_t *cred)
8801ae08745Sheppo {
8811ae08745Sheppo 	_NOTE(ARGUNUSED(cred))
8821ae08745Sheppo 
8831ae08745Sheppo 	int	instance;
8841ae08745Sheppo 	vdc_t	*vdc;
8851ae08745Sheppo 
8861ae08745Sheppo 	instance = SDUNIT(getminor(dev));
8871ae08745Sheppo 
8881ae08745Sheppo 	PR0("%s[%d] flag = %x, otyp = %x\n", __func__, instance, flag, otyp);
8891ae08745Sheppo 
8901ae08745Sheppo 	if ((otyp != OTYP_CHR) && (otyp != OTYP_BLK))
8911ae08745Sheppo 		return (EINVAL);
8921ae08745Sheppo 
8931ae08745Sheppo 	if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) {
8941ae08745Sheppo 		vdc_msg("%s[%d] Could not get state.", __func__, instance);
8951ae08745Sheppo 		return (ENXIO);
8961ae08745Sheppo 	}
8971ae08745Sheppo 
8981ae08745Sheppo 	/*
8991ae08745Sheppo 	 * Check to see if we can communicate with vds
9001ae08745Sheppo 	 */
9010a55fbb7Slm66018 	if (!vdc_is_able_to_tx_data(vdc, 0)) {
9021ae08745Sheppo 		PR0("%s[%d] Not ready to transmit data\n", __func__, instance);
9031ae08745Sheppo 		return (ETIMEDOUT);
9041ae08745Sheppo 	}
9051ae08745Sheppo 
9061ae08745Sheppo 	if (vdc->dkio_flush_pending) {
9071ae08745Sheppo 		PR0("%s[%d]: Cannot detach: %d outstanding DKIO flushes",
9081ae08745Sheppo 			__func__, instance, vdc->dkio_flush_pending);
9091ae08745Sheppo 		return (EBUSY);
9101ae08745Sheppo 	}
9111ae08745Sheppo 
9121ae08745Sheppo 	/*
9131ae08745Sheppo 	 * Should not need the mutex here, since the framework should protect
9141ae08745Sheppo 	 * against more opens on this device, but just in case.
9151ae08745Sheppo 	 */
9161ae08745Sheppo 	mutex_enter(&vdc->lock);
9171ae08745Sheppo 	vdc->open--;
9181ae08745Sheppo 	mutex_exit(&vdc->lock);
9191ae08745Sheppo 
9201ae08745Sheppo 	return (0);
9211ae08745Sheppo }
9221ae08745Sheppo 
9231ae08745Sheppo static int
9241ae08745Sheppo vdc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
9251ae08745Sheppo {
9261ae08745Sheppo 	_NOTE(ARGUNUSED(credp))
9271ae08745Sheppo 	_NOTE(ARGUNUSED(rvalp))
9281ae08745Sheppo 
9291ae08745Sheppo 	return (vd_process_ioctl(dev, cmd, (caddr_t)arg, mode));
9301ae08745Sheppo }
9311ae08745Sheppo 
9321ae08745Sheppo static int
9331ae08745Sheppo vdc_print(dev_t dev, char *str)
9341ae08745Sheppo {
9351ae08745Sheppo 	cmn_err(CE_NOTE, "vdc%d:  %s", SDUNIT(getminor(dev)), str);
9361ae08745Sheppo 	return (0);
9371ae08745Sheppo }
9381ae08745Sheppo 
9391ae08745Sheppo static int
9401ae08745Sheppo vdc_dump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk)
9411ae08745Sheppo {
942*d10e4ef2Snarayan 	buf_t	*buf;	/* BWRITE requests need to be in a buf_t structure */
943*d10e4ef2Snarayan 	int	rv;
944*d10e4ef2Snarayan 	size_t	nbytes = nblk * DEV_BSIZE;
9451ae08745Sheppo 	int	instance = SDUNIT(getminor(dev));
946*d10e4ef2Snarayan 	vdc_t	*vdc = NULL;
9471ae08745Sheppo 
9481ae08745Sheppo 	if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) {
9491ae08745Sheppo 		vdc_msg("%s (%d):  Could not get state.", __func__, instance);
9501ae08745Sheppo 		return (ENXIO);
9511ae08745Sheppo 	}
9521ae08745Sheppo 
953*d10e4ef2Snarayan 	buf = kmem_alloc(sizeof (buf_t), KM_SLEEP);
954*d10e4ef2Snarayan 	bioinit(buf);
955*d10e4ef2Snarayan 	buf->b_un.b_addr = addr;
956*d10e4ef2Snarayan 	buf->b_bcount = nbytes;
957*d10e4ef2Snarayan 	buf->b_flags = B_BUSY | B_WRITE;
958*d10e4ef2Snarayan 	buf->b_dev = dev;
959*d10e4ef2Snarayan 	rv = vdc_populate_descriptor(vdc, (caddr_t)buf, nbytes,
960*d10e4ef2Snarayan 			VD_OP_BWRITE, blkno, SDPART(getminor(dev)));
961*d10e4ef2Snarayan 
962*d10e4ef2Snarayan 	/*
963*d10e4ef2Snarayan 	 * If the OS instance is panicking, the call above will ensure that
964*d10e4ef2Snarayan 	 * the descriptor is done before returning. This should always be
965*d10e4ef2Snarayan 	 * case when coming through this function but we check just in case
966*d10e4ef2Snarayan 	 * and wait if necessary for the vDisk server to ACK and trigger
967*d10e4ef2Snarayan 	 * the biodone.
968*d10e4ef2Snarayan 	 */
969*d10e4ef2Snarayan 	if (!ddi_in_panic())
970*d10e4ef2Snarayan 		rv = biowait(buf);
971*d10e4ef2Snarayan 
972*d10e4ef2Snarayan 	biofini(buf);
973*d10e4ef2Snarayan 	kmem_free(buf, sizeof (buf_t));
9741ae08745Sheppo 
9751ae08745Sheppo 	PR1("%s: status=%d\n", __func__, rv);
9761ae08745Sheppo 
9771ae08745Sheppo 	return (rv);
9781ae08745Sheppo }
9791ae08745Sheppo 
9801ae08745Sheppo /* -------------------------------------------------------------------------- */
9811ae08745Sheppo 
9821ae08745Sheppo /*
9831ae08745Sheppo  * Disk access routines
9841ae08745Sheppo  *
9851ae08745Sheppo  */
9861ae08745Sheppo 
9871ae08745Sheppo /*
9881ae08745Sheppo  * vdc_strategy()
9891ae08745Sheppo  *
9901ae08745Sheppo  * Return Value:
9911ae08745Sheppo  *	0:	As per strategy(9E), the strategy() function must return 0
9921ae08745Sheppo  *		[ bioerror(9f) sets b_flags to the proper error code ]
9931ae08745Sheppo  */
9941ae08745Sheppo static int
9951ae08745Sheppo vdc_strategy(struct buf *buf)
9961ae08745Sheppo {
9971ae08745Sheppo 	int		rv = -1;
9981ae08745Sheppo 	vdc_t		*vdc = NULL;
9991ae08745Sheppo 	int		instance = SDUNIT(getminor(buf->b_edev));
10001ae08745Sheppo 	int	op = (buf->b_flags & B_READ) ? VD_OP_BREAD : VD_OP_BWRITE;
10011ae08745Sheppo 
10021ae08745Sheppo 	PR1("%s: %s %ld bytes at block %ld : b_addr=0x%p",
10031ae08745Sheppo 	    __func__, (buf->b_flags & B_READ) ? "Read" : "Write",
10041ae08745Sheppo 	    buf->b_bcount, buf->b_lblkno, buf->b_un.b_addr);
10051ae08745Sheppo 
10061ae08745Sheppo 	if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) {
10071ae08745Sheppo 		vdc_msg("%s[%d]:  Could not get state.", __func__, instance);
10081ae08745Sheppo 		bioerror(buf, ENXIO);
10091ae08745Sheppo 		biodone(buf);
10101ae08745Sheppo 		return (0);
10111ae08745Sheppo 	}
10121ae08745Sheppo 
1013*d10e4ef2Snarayan 	DTRACE_IO2(vstart, buf_t *, buf, vdc_t *, vdc);
1014*d10e4ef2Snarayan 
10151ae08745Sheppo 	ASSERT(buf->b_bcount <= (vdc->max_xfer_sz * vdc->block_size));
10161ae08745Sheppo 
10170a55fbb7Slm66018 	if (!vdc_is_able_to_tx_data(vdc, O_NONBLOCK)) {
1018*d10e4ef2Snarayan 		PR0("%s: Not ready to transmit data\n", __func__);
10191ae08745Sheppo 		bioerror(buf, ENXIO);
10201ae08745Sheppo 		biodone(buf);
10211ae08745Sheppo 		return (0);
10221ae08745Sheppo 	}
10231ae08745Sheppo 	bp_mapin(buf);
10241ae08745Sheppo 
1025*d10e4ef2Snarayan 	rv = vdc_populate_descriptor(vdc, (caddr_t)buf, buf->b_bcount, op,
10261ae08745Sheppo 			buf->b_lblkno, SDPART(getminor(buf->b_edev)));
10271ae08745Sheppo 
1028*d10e4ef2Snarayan 	/*
1029*d10e4ef2Snarayan 	 * If the request was successfully sent, the strategy call returns and
1030*d10e4ef2Snarayan 	 * the ACK handler calls the bioxxx functions when the vDisk server is
1031*d10e4ef2Snarayan 	 * done.
1032*d10e4ef2Snarayan 	 */
1033*d10e4ef2Snarayan 	if (rv) {
1034*d10e4ef2Snarayan 		PR0("[%d] Failed to read/write (err=%d)\n", instance, rv);
10351ae08745Sheppo 		bioerror(buf, rv);
10361ae08745Sheppo 		biodone(buf);
1037*d10e4ef2Snarayan 	}
1038*d10e4ef2Snarayan 
10391ae08745Sheppo 	return (0);
10401ae08745Sheppo }
10411ae08745Sheppo 
10421ae08745Sheppo 
10431ae08745Sheppo static int
10441ae08745Sheppo vdc_read(dev_t dev, struct uio *uio, cred_t *cred)
10451ae08745Sheppo {
10461ae08745Sheppo 	_NOTE(ARGUNUSED(cred))
10471ae08745Sheppo 
10481ae08745Sheppo 	PR1("vdc_read():  Entered");
10491ae08745Sheppo 	return (physio(vdc_strategy, NULL, dev, B_READ, minphys, uio));
10501ae08745Sheppo }
10511ae08745Sheppo 
10521ae08745Sheppo static int
10531ae08745Sheppo vdc_write(dev_t dev, struct uio *uio, cred_t *cred)
10541ae08745Sheppo {
10551ae08745Sheppo 	_NOTE(ARGUNUSED(cred))
10561ae08745Sheppo 
10571ae08745Sheppo 	PR1("vdc_write():  Entered");
10581ae08745Sheppo 	return (physio(vdc_strategy, NULL, dev, B_WRITE, minphys, uio));
10591ae08745Sheppo }
10601ae08745Sheppo 
10611ae08745Sheppo static int
10621ae08745Sheppo vdc_aread(dev_t dev, struct aio_req *aio, cred_t *cred)
10631ae08745Sheppo {
10641ae08745Sheppo 	_NOTE(ARGUNUSED(cred))
10651ae08745Sheppo 
10661ae08745Sheppo 	PR1("vdc_aread():  Entered");
10671ae08745Sheppo 	return (aphysio(vdc_strategy, anocancel, dev, B_READ, minphys, aio));
10681ae08745Sheppo }
10691ae08745Sheppo 
10701ae08745Sheppo static int
10711ae08745Sheppo vdc_awrite(dev_t dev, struct aio_req *aio, cred_t *cred)
10721ae08745Sheppo {
10731ae08745Sheppo 	_NOTE(ARGUNUSED(cred))
10741ae08745Sheppo 
10751ae08745Sheppo 	PR1("vdc_awrite():  Entered");
10761ae08745Sheppo 	return (aphysio(vdc_strategy, anocancel, dev, B_WRITE, minphys, aio));
10771ae08745Sheppo }
10781ae08745Sheppo 
10791ae08745Sheppo 
10801ae08745Sheppo /* -------------------------------------------------------------------------- */
10811ae08745Sheppo 
10821ae08745Sheppo /*
10831ae08745Sheppo  * Handshake support
10841ae08745Sheppo  */
10851ae08745Sheppo 
10861ae08745Sheppo /*
10871ae08745Sheppo  * vdc_init_handshake_negotiation
10881ae08745Sheppo  *
10891ae08745Sheppo  * Description:
10901ae08745Sheppo  *	This function is called to trigger the handshake negotiations between
10911ae08745Sheppo  *	the client (vdc) and the server (vds). It may be called multiple times.
10921ae08745Sheppo  *
10931ae08745Sheppo  * Parameters:
10941ae08745Sheppo  *	vdc - soft state pointer
10951ae08745Sheppo  */
10961ae08745Sheppo static void
10971ae08745Sheppo vdc_init_handshake_negotiation(void *arg)
10981ae08745Sheppo {
10991ae08745Sheppo 	vdc_t		*vdc = (vdc_t *)(void *)arg;
11000a55fbb7Slm66018 	ldc_status_t	ldc_state;
11011ae08745Sheppo 	vd_state_t	state;
11020a55fbb7Slm66018 	int		status;
11031ae08745Sheppo 
11041ae08745Sheppo 	ASSERT(vdc != NULL);
11051ae08745Sheppo 
11060a55fbb7Slm66018 	PR0("[%d] Initializing vdc<->vds handshake\n", vdc->instance);
11070a55fbb7Slm66018 
11080a55fbb7Slm66018 	/* get LDC state */
11090a55fbb7Slm66018 	status = ldc_status(vdc->ldc_handle, &ldc_state);
11100a55fbb7Slm66018 	if (status != 0) {
11110a55fbb7Slm66018 		cmn_err(CE_NOTE, "[%d] Couldn't get LDC status: err=%d",
11120a55fbb7Slm66018 				vdc->instance, status);
11130a55fbb7Slm66018 		return;
11140a55fbb7Slm66018 	}
11151ae08745Sheppo 
11161ae08745Sheppo 	/*
11170a55fbb7Slm66018 	 * If the LDC connection is not UP we bring it up now and return.
11180a55fbb7Slm66018 	 * The handshake will be started again when the callback is
11190a55fbb7Slm66018 	 * triggered due to the UP event.
11200a55fbb7Slm66018 	 */
11210a55fbb7Slm66018 	if (ldc_state != LDC_UP) {
11220a55fbb7Slm66018 		PR0("[%d] Triggering an LDC_UP and returning\n", vdc->instance);
11230a55fbb7Slm66018 		(void) vdc_do_ldc_up(vdc);
11240a55fbb7Slm66018 		return;
11250a55fbb7Slm66018 	}
11260a55fbb7Slm66018 
11270a55fbb7Slm66018 	mutex_enter(&vdc->lock);
11280a55fbb7Slm66018 	/*
11291ae08745Sheppo 	 * Do not continue if another thread has triggered a handshake which
11300a55fbb7Slm66018 	 * has not been reset or detach() has stopped further handshakes.
11311ae08745Sheppo 	 */
11321ae08745Sheppo 	if (vdc->initialized & (VDC_HANDSHAKE | VDC_HANDSHAKE_STOP)) {
11331ae08745Sheppo 		PR0("%s[%d] Negotiation not triggered. [init=%x]\n",
11341ae08745Sheppo 			__func__, vdc->instance, vdc->initialized);
11351ae08745Sheppo 		mutex_exit(&vdc->lock);
11361ae08745Sheppo 		return;
11371ae08745Sheppo 	}
11381ae08745Sheppo 
11390a55fbb7Slm66018 	if (vdc->hshake_cnt++ > vdc_retries) {
11400a55fbb7Slm66018 		cmn_err(CE_NOTE, "[%d] Failed repeatedly to complete handshake"
11410a55fbb7Slm66018 				"with vDisk server", vdc->instance);
11420a55fbb7Slm66018 		mutex_exit(&vdc->lock);
11430a55fbb7Slm66018 		return;
11440a55fbb7Slm66018 	}
11451ae08745Sheppo 
11461ae08745Sheppo 	vdc->initialized |= VDC_HANDSHAKE;
11470a55fbb7Slm66018 	vdc->ldc_state = ldc_state;
11481ae08745Sheppo 
11491ae08745Sheppo 	state = vdc->state;
11501ae08745Sheppo 
11511ae08745Sheppo 	if (state == VD_STATE_INIT) {
11520a55fbb7Slm66018 		/*
11530a55fbb7Slm66018 		 * Set the desired version parameter to the first entry in the
11540a55fbb7Slm66018 		 * version array. If this specific version is not supported,
11550a55fbb7Slm66018 		 * the response handling code will step down the version number
11560a55fbb7Slm66018 		 * to the next array entry and deal with it accordingly.
11570a55fbb7Slm66018 		 */
11580a55fbb7Slm66018 		(void) vdc_init_ver_negotiation(vdc, vdc_version[0]);
11591ae08745Sheppo 	} else if (state == VD_STATE_VER) {
11601ae08745Sheppo 		(void) vdc_init_attr_negotiation(vdc);
11611ae08745Sheppo 	} else if (state == VD_STATE_ATTR) {
11621ae08745Sheppo 		(void) vdc_init_dring_negotiate(vdc);
11631ae08745Sheppo 	} else if (state == VD_STATE_DATA) {
11641ae08745Sheppo 		/*
11651ae08745Sheppo 		 * nothing to do - we have already completed the negotiation
11661ae08745Sheppo 		 * and we can transmit data when ready.
11671ae08745Sheppo 		 */
11681ae08745Sheppo 		PR0("%s[%d] Negotiation triggered after handshake completed",
11691ae08745Sheppo 			__func__, vdc->instance);
11701ae08745Sheppo 	}
11711ae08745Sheppo 
11721ae08745Sheppo 	mutex_exit(&vdc->lock);
11731ae08745Sheppo }
11741ae08745Sheppo 
11750a55fbb7Slm66018 /*
11760a55fbb7Slm66018  * Function:
11770a55fbb7Slm66018  *	vdc_init_ver_negotiation()
11780a55fbb7Slm66018  *
11790a55fbb7Slm66018  * Description:
11800a55fbb7Slm66018  *
11810a55fbb7Slm66018  * Arguments:
11820a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
11830a55fbb7Slm66018  *
11840a55fbb7Slm66018  * Return Code:
11850a55fbb7Slm66018  *	0	- Success
11860a55fbb7Slm66018  */
11871ae08745Sheppo static int
11880a55fbb7Slm66018 vdc_init_ver_negotiation(vdc_t *vdc, vio_ver_t ver)
11891ae08745Sheppo {
11901ae08745Sheppo 	vio_ver_msg_t	pkt;
11911ae08745Sheppo 	size_t		msglen = sizeof (pkt);
11921ae08745Sheppo 	int		status = -1;
11931ae08745Sheppo 
11941ae08745Sheppo 	PR0("%s: Entered.\n", __func__);
11951ae08745Sheppo 
11961ae08745Sheppo 	ASSERT(vdc != NULL);
11971ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
11981ae08745Sheppo 
11991ae08745Sheppo 	/*
12001ae08745Sheppo 	 * set the Session ID to a unique value
12011ae08745Sheppo 	 * (the lower 32 bits of the clock tick)
12021ae08745Sheppo 	 */
12031ae08745Sheppo 	vdc->session_id = ((uint32_t)gettick() & 0xffffffff);
12041ae08745Sheppo 
12051ae08745Sheppo 	pkt.tag.vio_msgtype = VIO_TYPE_CTRL;
12061ae08745Sheppo 	pkt.tag.vio_subtype = VIO_SUBTYPE_INFO;
12071ae08745Sheppo 	pkt.tag.vio_subtype_env = VIO_VER_INFO;
12081ae08745Sheppo 	pkt.tag.vio_sid = vdc->session_id;
12091ae08745Sheppo 	pkt.dev_class = VDEV_DISK;
12100a55fbb7Slm66018 	pkt.ver_major = ver.major;
12110a55fbb7Slm66018 	pkt.ver_minor = ver.minor;
12121ae08745Sheppo 
12130a55fbb7Slm66018 	status = vdc_send(vdc, (caddr_t)&pkt, &msglen);
12141ae08745Sheppo 	PR0("%s: vdc_send(status = %d)\n", __func__, status);
12151ae08745Sheppo 
12161ae08745Sheppo 	if ((status != 0) || (msglen != sizeof (vio_ver_msg_t))) {
12171ae08745Sheppo 		PR0("%s[%d] vdc_send failed: id(%lx) rv(%d) size(%d)\n",
12181ae08745Sheppo 				__func__, vdc->instance, vdc->ldc_handle,
12191ae08745Sheppo 				status, msglen);
12201ae08745Sheppo 		if (msglen != sizeof (vio_ver_msg_t))
12211ae08745Sheppo 			status = ENOMSG;
12221ae08745Sheppo 	}
12231ae08745Sheppo 
12241ae08745Sheppo 	return (status);
12251ae08745Sheppo }
12261ae08745Sheppo 
12270a55fbb7Slm66018 /*
12280a55fbb7Slm66018  * Function:
12290a55fbb7Slm66018  *	vdc_init_attr_negotiation()
12300a55fbb7Slm66018  *
12310a55fbb7Slm66018  * Description:
12320a55fbb7Slm66018  *
12330a55fbb7Slm66018  * Arguments:
12340a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
12350a55fbb7Slm66018  *
12360a55fbb7Slm66018  * Return Code:
12370a55fbb7Slm66018  *	0	- Success
12380a55fbb7Slm66018  */
12391ae08745Sheppo static int
12401ae08745Sheppo vdc_init_attr_negotiation(vdc_t *vdc)
12411ae08745Sheppo {
12421ae08745Sheppo 	vd_attr_msg_t	pkt;
12431ae08745Sheppo 	size_t		msglen = sizeof (pkt);
12441ae08745Sheppo 	int		status;
12451ae08745Sheppo 
12461ae08745Sheppo 	ASSERT(vdc != NULL);
12471ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
12481ae08745Sheppo 
12491ae08745Sheppo 	PR0("%s[%d] entered\n", __func__, vdc->instance);
12501ae08745Sheppo 
12511ae08745Sheppo 	/* fill in tag */
12521ae08745Sheppo 	pkt.tag.vio_msgtype = VIO_TYPE_CTRL;
12531ae08745Sheppo 	pkt.tag.vio_subtype = VIO_SUBTYPE_INFO;
12541ae08745Sheppo 	pkt.tag.vio_subtype_env = VIO_ATTR_INFO;
12551ae08745Sheppo 	pkt.tag.vio_sid = vdc->session_id;
12561ae08745Sheppo 	/* fill in payload */
12571ae08745Sheppo 	pkt.max_xfer_sz = vdc->max_xfer_sz;
12581ae08745Sheppo 	pkt.vdisk_block_size = vdc->block_size;
12591ae08745Sheppo 	pkt.xfer_mode = VIO_DRING_MODE;
12601ae08745Sheppo 	pkt.operations = 0;	/* server will set bits of valid operations */
12611ae08745Sheppo 	pkt.vdisk_type = 0;	/* server will set to valid device type */
12621ae08745Sheppo 	pkt.vdisk_size = 0;	/* server will set to valid size */
12631ae08745Sheppo 
12640a55fbb7Slm66018 	status = vdc_send(vdc, (caddr_t)&pkt, &msglen);
12651ae08745Sheppo 	PR0("%s: vdc_send(status = %d)\n", __func__, status);
12661ae08745Sheppo 
12671ae08745Sheppo 	if ((status != 0) || (msglen != sizeof (vio_ver_msg_t))) {
12681ae08745Sheppo 		PR0("%s[%d] ldc_write failed: id(%lx) rv(%d) size (%d)\n",
12691ae08745Sheppo 			__func__, vdc->instance, vdc->ldc_handle,
12701ae08745Sheppo 			status, msglen);
12711ae08745Sheppo 		if (msglen != sizeof (vio_ver_msg_t))
12721ae08745Sheppo 			status = ENOMSG;
12731ae08745Sheppo 	}
12741ae08745Sheppo 
12751ae08745Sheppo 	return (status);
12761ae08745Sheppo }
12771ae08745Sheppo 
12780a55fbb7Slm66018 /*
12790a55fbb7Slm66018  * Function:
12800a55fbb7Slm66018  *	vdc_init_dring_negotiate()
12810a55fbb7Slm66018  *
12820a55fbb7Slm66018  * Description:
12830a55fbb7Slm66018  *
12840a55fbb7Slm66018  * Arguments:
12850a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
12860a55fbb7Slm66018  *
12870a55fbb7Slm66018  * Return Code:
12880a55fbb7Slm66018  *	0	- Success
12890a55fbb7Slm66018  */
12901ae08745Sheppo static int
12911ae08745Sheppo vdc_init_dring_negotiate(vdc_t *vdc)
12921ae08745Sheppo {
12931ae08745Sheppo 	vio_dring_reg_msg_t	pkt;
12941ae08745Sheppo 	size_t			msglen = sizeof (pkt);
12951ae08745Sheppo 	int			status = -1;
12961ae08745Sheppo 
12971ae08745Sheppo 	ASSERT(vdc != NULL);
12981ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
12991ae08745Sheppo 
13001ae08745Sheppo 	status = vdc_init_descriptor_ring(vdc);
13011ae08745Sheppo 	if (status != 0) {
13021ae08745Sheppo 		cmn_err(CE_CONT, "[%d] Failed to init DRing (status = %d)\n",
13031ae08745Sheppo 				vdc->instance, status);
13040a55fbb7Slm66018 		vdc_destroy_descriptor_ring(vdc);
13051ae08745Sheppo 		vdc_reset_connection(vdc, B_FALSE);
13061ae08745Sheppo 		return (status);
13071ae08745Sheppo 	}
13080a55fbb7Slm66018 	PR0("%s[%d] Init of descriptor ring completed (status = %d)\n",
13090a55fbb7Slm66018 			__func__, vdc->instance, status);
13101ae08745Sheppo 
13111ae08745Sheppo 	/* fill in tag */
13121ae08745Sheppo 	pkt.tag.vio_msgtype = VIO_TYPE_CTRL;
13131ae08745Sheppo 	pkt.tag.vio_subtype = VIO_SUBTYPE_INFO;
13141ae08745Sheppo 	pkt.tag.vio_subtype_env = VIO_DRING_REG;
13151ae08745Sheppo 	pkt.tag.vio_sid = vdc->session_id;
13161ae08745Sheppo 	/* fill in payload */
13171ae08745Sheppo 	pkt.dring_ident = 0;
13181ae08745Sheppo 	pkt.num_descriptors = VD_DRING_LEN;
13191ae08745Sheppo 	pkt.descriptor_size = VD_DRING_ENTRY_SZ;
13201ae08745Sheppo 	pkt.options = (VIO_TX_DRING | VIO_RX_DRING);
13211ae08745Sheppo 	pkt.ncookies = vdc->dring_cookie_count;
13221ae08745Sheppo 	pkt.cookie[0] = vdc->dring_cookie[0];	/* for now just one cookie */
13231ae08745Sheppo 
13240a55fbb7Slm66018 	status = vdc_send(vdc, (caddr_t)&pkt, &msglen);
13251ae08745Sheppo 	if (status != 0) {
13261ae08745Sheppo 		PR0("%s[%d] Failed to register DRing (status = %d)\n",
13271ae08745Sheppo 				__func__, vdc->instance, status);
13281ae08745Sheppo 		vdc_reset_connection(vdc, B_FALSE);
13291ae08745Sheppo 	}
13301ae08745Sheppo 
13311ae08745Sheppo 	return (status);
13321ae08745Sheppo }
13331ae08745Sheppo 
13341ae08745Sheppo 
13351ae08745Sheppo /* -------------------------------------------------------------------------- */
13361ae08745Sheppo 
13371ae08745Sheppo /*
13381ae08745Sheppo  * LDC helper routines
13391ae08745Sheppo  */
13401ae08745Sheppo 
13411ae08745Sheppo /*
13421ae08745Sheppo  * Function:
13431ae08745Sheppo  *	vdc_send()
13441ae08745Sheppo  *
13451ae08745Sheppo  * Description:
13461ae08745Sheppo  *	The function encapsulates the call to write a message using LDC.
13471ae08745Sheppo  *	If LDC indicates that the call failed due to the queue being full,
13481ae08745Sheppo  *	we retry the ldc_write() [ up to 'vdc_retries' time ], otherwise
13491ae08745Sheppo  *	we return the error returned by LDC.
13501ae08745Sheppo  *
13511ae08745Sheppo  * Arguments:
13521ae08745Sheppo  *	ldc_handle	- LDC handle for the channel this instance of vdc uses
13531ae08745Sheppo  *	pkt		- address of LDC message to be sent
13541ae08745Sheppo  *	msglen		- the size of the message being sent. When the function
13551ae08745Sheppo  *			  returns, this contains the number of bytes written.
13561ae08745Sheppo  *
13571ae08745Sheppo  * Return Code:
13581ae08745Sheppo  *	0		- Success.
13591ae08745Sheppo  *	EINVAL		- pkt or msglen were NULL
13601ae08745Sheppo  *	ECONNRESET	- The connection was not up.
13611ae08745Sheppo  *	EWOULDBLOCK	- LDC queue is full
13621ae08745Sheppo  *	xxx		- other error codes returned by ldc_write
13631ae08745Sheppo  */
13641ae08745Sheppo static int
13650a55fbb7Slm66018 vdc_send(vdc_t *vdc, caddr_t pkt, size_t *msglen)
13661ae08745Sheppo {
13671ae08745Sheppo 	size_t	size = 0;
13681ae08745Sheppo 	int	retries = 0;
13691ae08745Sheppo 	int	status = 0;
13701ae08745Sheppo 
13710a55fbb7Slm66018 	ASSERT(vdc != NULL);
13720a55fbb7Slm66018 	ASSERT(mutex_owned(&vdc->lock));
13731ae08745Sheppo 	ASSERT(msglen != NULL);
13741ae08745Sheppo 	ASSERT(*msglen != 0);
13751ae08745Sheppo 
13761ae08745Sheppo 	do {
13771ae08745Sheppo 		size = *msglen;
13780a55fbb7Slm66018 		status = ldc_write(vdc->ldc_handle, pkt, &size);
13791ae08745Sheppo 	} while (status == EWOULDBLOCK && retries++ < vdc_retries);
13801ae08745Sheppo 
13810a55fbb7Slm66018 	/* if LDC had serious issues --- reset vdc state */
13820a55fbb7Slm66018 	if (status == EIO || status == ECONNRESET) {
13830a55fbb7Slm66018 		vdc_reset_connection(vdc, B_TRUE);
13840a55fbb7Slm66018 	}
13850a55fbb7Slm66018 
13861ae08745Sheppo 	/* return the last size written */
13871ae08745Sheppo 	*msglen = size;
13881ae08745Sheppo 
13891ae08745Sheppo 	return (status);
13901ae08745Sheppo }
13911ae08745Sheppo 
13921ae08745Sheppo /*
13931ae08745Sheppo  * Function:
13941ae08745Sheppo  *	vdc_get_ldc_id()
13951ae08745Sheppo  *
13961ae08745Sheppo  * Description:
13971ae08745Sheppo  *	This function gets the 'ldc-id' for this particular instance of vdc.
13981ae08745Sheppo  *	The id returned is the guest domain channel endpoint LDC uses for
13991ae08745Sheppo  *	communication with vds.
14001ae08745Sheppo  *
14011ae08745Sheppo  * Arguments:
14021ae08745Sheppo  *	dip	- dev info pointer for this instance of the device driver.
14031ae08745Sheppo  *	ldc_id	- pointer to variable used to return the 'ldc-id' found.
14041ae08745Sheppo  *
14051ae08745Sheppo  * Return Code:
14061ae08745Sheppo  *	0	- Success.
14071ae08745Sheppo  *	ENOENT	- Expected node or property did not exist.
14081ae08745Sheppo  *	ENXIO	- Unexpected error communicating with MD framework
14091ae08745Sheppo  */
14101ae08745Sheppo static int
14111ae08745Sheppo vdc_get_ldc_id(dev_info_t *dip, uint64_t *ldc_id)
14121ae08745Sheppo {
14131ae08745Sheppo 	int		status = ENOENT;
14141ae08745Sheppo 	char		*node_name = NULL;
14151ae08745Sheppo 	md_t		*mdp = NULL;
14161ae08745Sheppo 	int		num_nodes;
14171ae08745Sheppo 	int		num_vdevs;
14181ae08745Sheppo 	int		num_chans;
14191ae08745Sheppo 	mde_cookie_t	rootnode;
14201ae08745Sheppo 	mde_cookie_t	*listp = NULL;
14211ae08745Sheppo 	mde_cookie_t	*chanp = NULL;
14221ae08745Sheppo 	boolean_t	found_inst = B_FALSE;
14231ae08745Sheppo 	int		listsz;
14241ae08745Sheppo 	int		idx;
14251ae08745Sheppo 	uint64_t	md_inst;
14261ae08745Sheppo 	int		obp_inst;
14271ae08745Sheppo 	int		instance = ddi_get_instance(dip);
14281ae08745Sheppo 
14291ae08745Sheppo 	ASSERT(ldc_id != NULL);
14301ae08745Sheppo 	*ldc_id = 0;
14311ae08745Sheppo 
14321ae08745Sheppo 	/*
14331ae08745Sheppo 	 * Get the OBP instance number for comparison with the MD instance
14341ae08745Sheppo 	 *
14351ae08745Sheppo 	 * The "cfg-handle" property of a vdc node in an MD contains the MD's
14361ae08745Sheppo 	 * notion of "instance", or unique identifier, for that node; OBP
14371ae08745Sheppo 	 * stores the value of the "cfg-handle" MD property as the value of
14381ae08745Sheppo 	 * the "reg" property on the node in the device tree it builds from
14391ae08745Sheppo 	 * the MD and passes to Solaris.  Thus, we look up the devinfo node's
14401ae08745Sheppo 	 * "reg" property value to uniquely identify this device instance.
14411ae08745Sheppo 	 * If the "reg" property cannot be found, the device tree state is
14421ae08745Sheppo 	 * presumably so broken that there is no point in continuing.
14431ae08745Sheppo 	 */
14441ae08745Sheppo 	if (!ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, OBP_REG)) {
14451ae08745Sheppo 		cmn_err(CE_WARN, "'%s' property does not exist", OBP_REG);
14461ae08745Sheppo 		return (ENOENT);
14471ae08745Sheppo 	}
14481ae08745Sheppo 	obp_inst = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
14491ae08745Sheppo 			OBP_REG, -1);
14501ae08745Sheppo 	PR1("%s[%d]: OBP inst=%d\n", __func__, instance, obp_inst);
14511ae08745Sheppo 
14521ae08745Sheppo 	/*
14531ae08745Sheppo 	 * We now walk the MD nodes and if an instance of a vdc node matches
14541ae08745Sheppo 	 * the instance got from OBP we get the ldc-id property.
14551ae08745Sheppo 	 */
14561ae08745Sheppo 	if ((mdp = md_get_handle()) == NULL) {
14571ae08745Sheppo 		cmn_err(CE_WARN, "unable to init machine description");
14581ae08745Sheppo 		return (ENXIO);
14591ae08745Sheppo 	}
14601ae08745Sheppo 
14611ae08745Sheppo 	num_nodes = md_node_count(mdp);
14621ae08745Sheppo 	ASSERT(num_nodes > 0);
14631ae08745Sheppo 
14641ae08745Sheppo 	listsz = num_nodes * sizeof (mde_cookie_t);
14651ae08745Sheppo 
14661ae08745Sheppo 	/* allocate memory for nodes */
14671ae08745Sheppo 	listp = kmem_zalloc(listsz, KM_SLEEP);
14681ae08745Sheppo 	chanp = kmem_zalloc(listsz, KM_SLEEP);
14691ae08745Sheppo 
14701ae08745Sheppo 	rootnode = md_root_node(mdp);
14711ae08745Sheppo 	ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE);
14721ae08745Sheppo 
14731ae08745Sheppo 	/*
14741ae08745Sheppo 	 * Search for all the virtual devices, we will then check to see which
14751ae08745Sheppo 	 * ones are disk nodes.
14761ae08745Sheppo 	 */
14771ae08745Sheppo 	num_vdevs = md_scan_dag(mdp, rootnode,
14781ae08745Sheppo 			md_find_name(mdp, VDC_MD_VDEV_NAME),
14791ae08745Sheppo 			md_find_name(mdp, "fwd"), listp);
14801ae08745Sheppo 
14811ae08745Sheppo 	if (num_vdevs <= 0) {
14821ae08745Sheppo 		cmn_err(CE_NOTE, "No '%s' node found", VDC_MD_VDEV_NAME);
14831ae08745Sheppo 		status = ENOENT;
14841ae08745Sheppo 		goto done;
14851ae08745Sheppo 	}
14861ae08745Sheppo 
14871ae08745Sheppo 	PR1("%s[%d] num_vdevs=%d\n", __func__, instance, num_vdevs);
14881ae08745Sheppo 	for (idx = 0; idx < num_vdevs; idx++) {
14891ae08745Sheppo 		status = md_get_prop_str(mdp, listp[idx], "name", &node_name);
14901ae08745Sheppo 		if ((status != 0) || (node_name == NULL)) {
14911ae08745Sheppo 			cmn_err(CE_NOTE, "Unable to get name of node type '%s'"
14921ae08745Sheppo 					": err %d", VDC_MD_VDEV_NAME, status);
14931ae08745Sheppo 			continue;
14941ae08745Sheppo 		}
14951ae08745Sheppo 
14961ae08745Sheppo 		PR1("%s[%d] Found node %s\n", __func__, instance, node_name);
14971ae08745Sheppo 		if (strcmp(VDC_MD_DISK_NAME, node_name) == 0) {
14981ae08745Sheppo 			status = md_get_prop_val(mdp, listp[idx],
14991ae08745Sheppo 					VDC_MD_CFG_HDL, &md_inst);
15001ae08745Sheppo 			PR1("%s[%d] vdc inst# in MD=%d\n",
15011ae08745Sheppo 					__func__, instance, md_inst);
15021ae08745Sheppo 			if ((status == 0) && (md_inst == obp_inst)) {
15031ae08745Sheppo 				found_inst = B_TRUE;
15041ae08745Sheppo 				break;
15051ae08745Sheppo 			}
15061ae08745Sheppo 		}
15071ae08745Sheppo 	}
15081ae08745Sheppo 
15090a55fbb7Slm66018 	if (!found_inst) {
15101ae08745Sheppo 		cmn_err(CE_NOTE, "Unable to find correct '%s' node",
15111ae08745Sheppo 				VDC_MD_DISK_NAME);
15121ae08745Sheppo 		status = ENOENT;
15131ae08745Sheppo 		goto done;
15141ae08745Sheppo 	}
15151ae08745Sheppo 	PR0("%s[%d] MD inst=%d\n", __func__, instance, md_inst);
15161ae08745Sheppo 
15171ae08745Sheppo 	/* get the channels for this node */
15181ae08745Sheppo 	num_chans = md_scan_dag(mdp, listp[idx],
15191ae08745Sheppo 			md_find_name(mdp, VDC_MD_CHAN_NAME),
15201ae08745Sheppo 			md_find_name(mdp, "fwd"), chanp);
15211ae08745Sheppo 
15221ae08745Sheppo 	/* expecting at least one channel */
15231ae08745Sheppo 	if (num_chans <= 0) {
15241ae08745Sheppo 		cmn_err(CE_NOTE, "No '%s' node for '%s' port",
15251ae08745Sheppo 				VDC_MD_CHAN_NAME, VDC_MD_VDEV_NAME);
15261ae08745Sheppo 		status = ENOENT;
15271ae08745Sheppo 		goto done;
15281ae08745Sheppo 
15291ae08745Sheppo 	} else if (num_chans != 1) {
15301ae08745Sheppo 		PR0("%s[%d] Expected 1 '%s' node for '%s' port, found %d\n",
15311ae08745Sheppo 			__func__, instance, VDC_MD_CHAN_NAME, VDC_MD_VDEV_NAME,
15321ae08745Sheppo 			num_chans);
15331ae08745Sheppo 	}
15341ae08745Sheppo 
15351ae08745Sheppo 	/*
15361ae08745Sheppo 	 * We use the first channel found (index 0), irrespective of how
15371ae08745Sheppo 	 * many are there in total.
15381ae08745Sheppo 	 */
15391ae08745Sheppo 	if (md_get_prop_val(mdp, chanp[0], VDC_ID_PROP, ldc_id) != 0) {
15401ae08745Sheppo 		cmn_err(CE_NOTE, "Channel '%s' property not found",
15411ae08745Sheppo 				VDC_ID_PROP);
15421ae08745Sheppo 		status = ENOENT;
15431ae08745Sheppo 	}
15441ae08745Sheppo 
15451ae08745Sheppo 	PR0("%s[%d] LDC id is 0x%lx\n", __func__, instance, *ldc_id);
15461ae08745Sheppo 
15471ae08745Sheppo done:
15481ae08745Sheppo 	if (chanp)
15491ae08745Sheppo 		kmem_free(chanp, listsz);
15501ae08745Sheppo 	if (listp)
15511ae08745Sheppo 		kmem_free(listp, listsz);
15521ae08745Sheppo 
15531ae08745Sheppo 	(void) md_fini_handle(mdp);
15541ae08745Sheppo 
15551ae08745Sheppo 	return (status);
15561ae08745Sheppo }
15571ae08745Sheppo 
15580a55fbb7Slm66018 static int
15590a55fbb7Slm66018 vdc_do_ldc_up(vdc_t *vdc)
15600a55fbb7Slm66018 {
15610a55fbb7Slm66018 	int	status;
15620a55fbb7Slm66018 
15630a55fbb7Slm66018 	PR0("[%d] Bringing up channel %x\n", vdc->instance, vdc->ldc_id);
15640a55fbb7Slm66018 
15650a55fbb7Slm66018 	if ((status = ldc_up(vdc->ldc_handle)) != 0) {
15660a55fbb7Slm66018 		switch (status) {
15670a55fbb7Slm66018 		case ECONNREFUSED:	/* listener not ready at other end */
15680a55fbb7Slm66018 			PR0("%s: ldc_up(%d,...) return %d\n",
15690a55fbb7Slm66018 					__func__, vdc->ldc_id, status);
15700a55fbb7Slm66018 			status = 0;
15710a55fbb7Slm66018 			break;
15720a55fbb7Slm66018 		default:
15730a55fbb7Slm66018 			cmn_err(CE_NOTE, "[%d] Failed to bring up LDC: "
15740a55fbb7Slm66018 					"channel=%ld, err=%d",
15750a55fbb7Slm66018 					vdc->instance, vdc->ldc_id, status);
15760a55fbb7Slm66018 		}
15770a55fbb7Slm66018 	}
15780a55fbb7Slm66018 
15790a55fbb7Slm66018 	return (status);
15800a55fbb7Slm66018 }
15810a55fbb7Slm66018 
15821ae08745Sheppo 
15831ae08745Sheppo /*
15841ae08745Sheppo  * vdc_is_able_to_tx_data()
15851ae08745Sheppo  *
15861ae08745Sheppo  * Description:
15871ae08745Sheppo  *	This function checks if we are able to send data to the
15881ae08745Sheppo  *	vDisk server (vds). The LDC connection needs to be up and
15891ae08745Sheppo  *	vdc & vds need to have completed the handshake negotiation.
15901ae08745Sheppo  *
15911ae08745Sheppo  * Parameters:
15921ae08745Sheppo  *	vdc 		- soft state pointer
15931ae08745Sheppo  *	flag		- flag to indicate if we can block or not
15941ae08745Sheppo  *			  [ If O_NONBLOCK or O_NDELAY (which are defined in
15951ae08745Sheppo  *			    open(2)) are set then do not block)
15961ae08745Sheppo  *
15971ae08745Sheppo  * Return Values
15981ae08745Sheppo  *	B_TRUE		- can talk to vds
15991ae08745Sheppo  *	B_FALSE		- unable to talk to vds
16001ae08745Sheppo  */
16011ae08745Sheppo static boolean_t
16021ae08745Sheppo vdc_is_able_to_tx_data(vdc_t *vdc, int flag)
16031ae08745Sheppo {
16041ae08745Sheppo 	vd_state_t	state;
16051ae08745Sheppo 	uint32_t	ldc_state;
16061ae08745Sheppo 	uint_t		retries = 0;
16071ae08745Sheppo 	int		rv = -1;
16081ae08745Sheppo 
16091ae08745Sheppo 	ASSERT(vdc != NULL);
16101ae08745Sheppo 
16111ae08745Sheppo 	mutex_enter(&vdc->lock);
16121ae08745Sheppo 	state = vdc->state;
16131ae08745Sheppo 	ldc_state = vdc->ldc_state;
16141ae08745Sheppo 	mutex_exit(&vdc->lock);
16151ae08745Sheppo 
16161ae08745Sheppo 	if ((state == VD_STATE_DATA) && (ldc_state == LDC_UP))
16171ae08745Sheppo 		return (B_TRUE);
16181ae08745Sheppo 
16191ae08745Sheppo 	if ((flag & O_NONBLOCK) || (flag & O_NDELAY)) {
16201ae08745Sheppo 		PR0("%s[%d] Not ready to tx - state %d LDC state %d\n",
16211ae08745Sheppo 			__func__, vdc->instance, state, ldc_state);
16221ae08745Sheppo 		return (B_FALSE);
16231ae08745Sheppo 	}
16241ae08745Sheppo 
16251ae08745Sheppo 	/*
16261ae08745Sheppo 	 * We want to check and see if any negotiations triggered earlier
16271ae08745Sheppo 	 * have succeeded. We are prepared to wait a little while in case
16281ae08745Sheppo 	 * they are still in progress.
16291ae08745Sheppo 	 */
16301ae08745Sheppo 	mutex_enter(&vdc->lock);
16311ae08745Sheppo 	while ((vdc->ldc_state != LDC_UP) || (vdc->state != VD_STATE_DATA)) {
16321ae08745Sheppo 		PR0("%s: Waiting for connection at state %d (LDC state %d)\n",
16331ae08745Sheppo 			__func__, vdc->state, vdc->ldc_state);
16341ae08745Sheppo 
16351ae08745Sheppo 		rv = cv_timedwait(&vdc->cv, &vdc->lock,
16361ae08745Sheppo 			VD_GET_TIMEOUT_HZ(retries));
16371ae08745Sheppo 
16381ae08745Sheppo 		/*
16391ae08745Sheppo 		 * An rv of -1 indicates that we timed out without the LDC
16401ae08745Sheppo 		 * state changing so it looks like the other side (vdc) is
16411ae08745Sheppo 		 * not yet ready/responding.
16421ae08745Sheppo 		 *
16431ae08745Sheppo 		 * Any other value of rv indicates that the LDC triggered an
16441ae08745Sheppo 		 * interrupt so we just loop again, check the handshake state
16451ae08745Sheppo 		 * and keep waiting if necessary.
16461ae08745Sheppo 		 */
16471ae08745Sheppo 		if (rv == -1) {
16481ae08745Sheppo 			if (retries >= vdc_retries) {
16491ae08745Sheppo 				PR0("%s[%d] handshake wait timed out.\n",
16501ae08745Sheppo 						__func__, vdc->instance);
16511ae08745Sheppo 				mutex_exit(&vdc->lock);
16521ae08745Sheppo 				return (B_FALSE);
16531ae08745Sheppo 			} else {
16541ae08745Sheppo 				PR1("%s[%d] Retry #%d for handshake timedout\n",
16551ae08745Sheppo 					__func__, vdc->instance, retries);
16561ae08745Sheppo 				retries++;
16571ae08745Sheppo 			}
16581ae08745Sheppo 		}
16591ae08745Sheppo 	}
16601ae08745Sheppo 
16611ae08745Sheppo 	ASSERT(vdc->ldc_state == LDC_UP);
16621ae08745Sheppo 	ASSERT(vdc->state == VD_STATE_DATA);
16631ae08745Sheppo 
16641ae08745Sheppo 	mutex_exit(&vdc->lock);
16651ae08745Sheppo 
16661ae08745Sheppo 	return (B_TRUE);
16671ae08745Sheppo }
16681ae08745Sheppo 
16691ae08745Sheppo 
16700a55fbb7Slm66018 /*
16710a55fbb7Slm66018  * Function:
16720a55fbb7Slm66018  *	vdc_terminate_ldc()
16730a55fbb7Slm66018  *
16740a55fbb7Slm66018  * Description:
16750a55fbb7Slm66018  *
16760a55fbb7Slm66018  * Arguments:
16770a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
16780a55fbb7Slm66018  *
16790a55fbb7Slm66018  * Return Code:
16800a55fbb7Slm66018  *	None
16810a55fbb7Slm66018  */
16821ae08745Sheppo static void
16831ae08745Sheppo vdc_terminate_ldc(vdc_t *vdc)
16841ae08745Sheppo {
16851ae08745Sheppo 	int	instance = ddi_get_instance(vdc->dip);
16861ae08745Sheppo 
16871ae08745Sheppo 	ASSERT(vdc != NULL);
16881ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
16891ae08745Sheppo 
16901ae08745Sheppo 	PR0("%s[%d] initialized=%x\n", __func__, instance, vdc->initialized);
16911ae08745Sheppo 
16921ae08745Sheppo 	if (vdc->initialized & VDC_LDC_OPEN) {
16931ae08745Sheppo 		PR0("%s[%d]: ldc_close()\n", __func__, instance);
16941ae08745Sheppo 		(void) ldc_close(vdc->ldc_handle);
16951ae08745Sheppo 	}
16961ae08745Sheppo 	if (vdc->initialized & VDC_LDC_CB) {
16971ae08745Sheppo 		PR0("%s[%d]: ldc_unreg_callback()\n", __func__, instance);
16981ae08745Sheppo 		(void) ldc_unreg_callback(vdc->ldc_handle);
16991ae08745Sheppo 	}
17001ae08745Sheppo 	if (vdc->initialized & VDC_LDC) {
17011ae08745Sheppo 		PR0("%s[%d]: ldc_fini()\n", __func__, instance);
17021ae08745Sheppo 		(void) ldc_fini(vdc->ldc_handle);
17031ae08745Sheppo 		vdc->ldc_handle = NULL;
17041ae08745Sheppo 	}
17051ae08745Sheppo 
17061ae08745Sheppo 	vdc->initialized &= ~(VDC_LDC | VDC_LDC_CB | VDC_LDC_OPEN);
17071ae08745Sheppo }
17081ae08745Sheppo 
17090a55fbb7Slm66018 /*
17100a55fbb7Slm66018  * Function:
17110a55fbb7Slm66018  *	vdc_reset_connection()
17120a55fbb7Slm66018  *
17130a55fbb7Slm66018  * Description:
17140a55fbb7Slm66018  *
17150a55fbb7Slm66018  * Arguments:
17160a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
17170a55fbb7Slm66018  *	reset_ldc - Flag whether or not to reset the LDC connection also.
17180a55fbb7Slm66018  *
17190a55fbb7Slm66018  * Return Code:
17200a55fbb7Slm66018  *	None
17210a55fbb7Slm66018  */
17221ae08745Sheppo static void
17231ae08745Sheppo vdc_reset_connection(vdc_t *vdc, boolean_t reset_ldc)
17241ae08745Sheppo {
17251ae08745Sheppo 	int	status;
17261ae08745Sheppo 
17271ae08745Sheppo 	ASSERT(vdc != NULL);
17281ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
17291ae08745Sheppo 
17301ae08745Sheppo 	PR0("%s[%d] Entered\n", __func__, vdc->instance);
17311ae08745Sheppo 
17321ae08745Sheppo 	vdc->state = VD_STATE_INIT;
17331ae08745Sheppo 
17340a55fbb7Slm66018 	if (reset_ldc) {
17351ae08745Sheppo 		status = ldc_reset(vdc->ldc_handle);
17361ae08745Sheppo 		PR0("%s[%d]  ldc_reset() = %d\n",
17371ae08745Sheppo 				__func__, vdc->instance, status);
17381ae08745Sheppo 	}
17391ae08745Sheppo 
17401ae08745Sheppo 	vdc->initialized &= ~VDC_HANDSHAKE;
17411ae08745Sheppo 	PR0("%s[%d] init=%x\n", __func__, vdc->instance, vdc->initialized);
17421ae08745Sheppo }
17431ae08745Sheppo 
17441ae08745Sheppo /* -------------------------------------------------------------------------- */
17451ae08745Sheppo 
17461ae08745Sheppo /*
17471ae08745Sheppo  * Descriptor Ring helper routines
17481ae08745Sheppo  */
17491ae08745Sheppo 
17500a55fbb7Slm66018 /*
17510a55fbb7Slm66018  * Function:
17520a55fbb7Slm66018  *	vdc_init_descriptor_ring()
17530a55fbb7Slm66018  *
17540a55fbb7Slm66018  * Description:
17550a55fbb7Slm66018  *
17560a55fbb7Slm66018  * Arguments:
17570a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
17580a55fbb7Slm66018  *
17590a55fbb7Slm66018  * Return Code:
17600a55fbb7Slm66018  *	0	- Success
17610a55fbb7Slm66018  */
17621ae08745Sheppo static int
17631ae08745Sheppo vdc_init_descriptor_ring(vdc_t *vdc)
17641ae08745Sheppo {
17651ae08745Sheppo 	vd_dring_entry_t	*dep = NULL;	/* DRing Entry pointer */
17660a55fbb7Slm66018 	int	status = 0;
17671ae08745Sheppo 	int	i;
17681ae08745Sheppo 
17690a55fbb7Slm66018 	PR0("%s[%d] initialized=%x\n",
17700a55fbb7Slm66018 			__func__, vdc->instance, vdc->initialized);
17711ae08745Sheppo 
17721ae08745Sheppo 	ASSERT(vdc != NULL);
17731ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
17741ae08745Sheppo 	ASSERT(vdc->ldc_handle != NULL);
17751ae08745Sheppo 
17760a55fbb7Slm66018 	if ((vdc->initialized & VDC_DRING_INIT) == 0) {
17770a55fbb7Slm66018 		PR0("%s[%d] ldc_mem_dring_create\n", __func__, vdc->instance);
17781ae08745Sheppo 		status = ldc_mem_dring_create(VD_DRING_LEN, VD_DRING_ENTRY_SZ,
17791ae08745Sheppo 				&vdc->ldc_dring_hdl);
17801ae08745Sheppo 		if ((vdc->ldc_dring_hdl == NULL) || (status != 0)) {
17811ae08745Sheppo 			PR0("%s: Failed to create a descriptor ring", __func__);
17821ae08745Sheppo 			return (status);
17831ae08745Sheppo 		}
17841ae08745Sheppo 		vdc->dring_entry_size = VD_DRING_ENTRY_SZ;
17851ae08745Sheppo 		vdc->dring_len = VD_DRING_LEN;
17860a55fbb7Slm66018 		vdc->initialized |= VDC_DRING_INIT;
17870a55fbb7Slm66018 	}
17881ae08745Sheppo 
17890a55fbb7Slm66018 	if ((vdc->initialized & VDC_DRING_BOUND) == 0) {
17900a55fbb7Slm66018 		PR0("%s[%d] ldc_mem_dring_bind\n", __func__, vdc->instance);
17910a55fbb7Slm66018 		vdc->dring_cookie =
17920a55fbb7Slm66018 			kmem_zalloc(sizeof (ldc_mem_cookie_t), KM_SLEEP);
17931ae08745Sheppo 
17941ae08745Sheppo 		status = ldc_mem_dring_bind(vdc->ldc_handle, vdc->ldc_dring_hdl,
17950a55fbb7Slm66018 				LDC_SHADOW_MAP, LDC_MEM_RW,
17960a55fbb7Slm66018 				&vdc->dring_cookie[0],
17971ae08745Sheppo 				&vdc->dring_cookie_count);
17981ae08745Sheppo 		if (status != 0) {
17990a55fbb7Slm66018 			PR0("%s: Failed to bind descriptor ring (%p) "
18000a55fbb7Slm66018 				"to channel (%p)\n",
18011ae08745Sheppo 				__func__, vdc->ldc_dring_hdl, vdc->ldc_handle);
18021ae08745Sheppo 			return (status);
18031ae08745Sheppo 		}
18041ae08745Sheppo 		ASSERT(vdc->dring_cookie_count == 1);
18051ae08745Sheppo 		vdc->initialized |= VDC_DRING_BOUND;
18060a55fbb7Slm66018 	}
18071ae08745Sheppo 
18081ae08745Sheppo 	status = ldc_mem_dring_info(vdc->ldc_dring_hdl, &vdc->dring_mem_info);
18091ae08745Sheppo 	if (status != 0) {
18101ae08745Sheppo 		PR0("%s: Failed to get info for descriptor ring (%p)\n",
18111ae08745Sheppo 			__func__, vdc->ldc_dring_hdl);
18121ae08745Sheppo 		return (status);
18131ae08745Sheppo 	}
18141ae08745Sheppo 
18150a55fbb7Slm66018 	if ((vdc->initialized & VDC_DRING_LOCAL) == 0) {
18160a55fbb7Slm66018 		PR0("%s[%d] local dring\n", __func__, vdc->instance);
18170a55fbb7Slm66018 
18181ae08745Sheppo 		/* Allocate the local copy of this dring */
18190a55fbb7Slm66018 		vdc->local_dring =
18200a55fbb7Slm66018 			kmem_zalloc(VD_DRING_LEN * sizeof (vdc_local_desc_t),
18211ae08745Sheppo 						KM_SLEEP);
18221ae08745Sheppo 		vdc->initialized |= VDC_DRING_LOCAL;
18230a55fbb7Slm66018 	}
18241ae08745Sheppo 
18251ae08745Sheppo 	/*
18260a55fbb7Slm66018 	 * Mark all DRing entries as free and initialize the private
18270a55fbb7Slm66018 	 * descriptor's memory handles. If any entry is initialized,
18280a55fbb7Slm66018 	 * we need to free it later so we set the bit in 'initialized'
18290a55fbb7Slm66018 	 * at the start.
18301ae08745Sheppo 	 */
18311ae08745Sheppo 	vdc->initialized |= VDC_DRING_ENTRY;
18321ae08745Sheppo 	for (i = 0; i < VD_DRING_LEN; i++) {
18331ae08745Sheppo 		dep = VDC_GET_DRING_ENTRY_PTR(vdc, i);
18341ae08745Sheppo 		dep->hdr.dstate = VIO_DESC_FREE;
18351ae08745Sheppo 
18361ae08745Sheppo 		status = ldc_mem_alloc_handle(vdc->ldc_handle,
18371ae08745Sheppo 				&vdc->local_dring[i].desc_mhdl);
18381ae08745Sheppo 		if (status != 0) {
18391ae08745Sheppo 			cmn_err(CE_NOTE, "![%d] Failed to alloc mem handle for"
18401ae08745Sheppo 					" descriptor %d", vdc->instance, i);
18411ae08745Sheppo 			return (status);
18421ae08745Sheppo 		}
18431ae08745Sheppo 		vdc->local_dring[i].flags = VIO_DESC_FREE;
18441ae08745Sheppo 		vdc->local_dring[i].dep = dep;
18451ae08745Sheppo 
18461ae08745Sheppo 		mutex_init(&vdc->local_dring[i].lock, NULL, MUTEX_DRIVER, NULL);
18471ae08745Sheppo 		cv_init(&vdc->local_dring[i].cv, NULL, CV_DRIVER, NULL);
18481ae08745Sheppo 	}
18491ae08745Sheppo 
18501ae08745Sheppo 	/*
18511ae08745Sheppo 	 * We init the index of the last DRing entry used. Since the code to
18521ae08745Sheppo 	 * get the next available entry increments it before selecting one,
18531ae08745Sheppo 	 * we set it to the last DRing entry so that it wraps around to zero
18541ae08745Sheppo 	 * for the 1st entry to be used.
18551ae08745Sheppo 	 */
18561ae08745Sheppo 	vdc->dring_curr_idx = VD_DRING_LEN - 1;
18571ae08745Sheppo 
18581ae08745Sheppo 	return (status);
18591ae08745Sheppo }
18601ae08745Sheppo 
18610a55fbb7Slm66018 /*
18620a55fbb7Slm66018  * Function:
18630a55fbb7Slm66018  *	vdc_destroy_descriptor_ring()
18640a55fbb7Slm66018  *
18650a55fbb7Slm66018  * Description:
18660a55fbb7Slm66018  *
18670a55fbb7Slm66018  * Arguments:
18680a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
18690a55fbb7Slm66018  *
18700a55fbb7Slm66018  * Return Code:
18710a55fbb7Slm66018  *	None
18720a55fbb7Slm66018  */
18731ae08745Sheppo static void
18741ae08745Sheppo vdc_destroy_descriptor_ring(vdc_t *vdc)
18751ae08745Sheppo {
18760a55fbb7Slm66018 	vdc_local_desc_t	*ldep = NULL;	/* Local Dring Entry Pointer */
18771ae08745Sheppo 	ldc_mem_handle_t	mhdl = NULL;
18781ae08745Sheppo 	int			status = -1;
18791ae08745Sheppo 	int			i;	/* loop */
18801ae08745Sheppo 
18811ae08745Sheppo 	ASSERT(vdc != NULL);
18821ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
18831ae08745Sheppo 	ASSERT(vdc->state == VD_STATE_INIT);
18841ae08745Sheppo 
18851ae08745Sheppo 	PR0("%s: Entered\n", __func__);
18861ae08745Sheppo 
18871ae08745Sheppo 	if (vdc->initialized & VDC_DRING_ENTRY) {
18880a55fbb7Slm66018 		PR0("[%d] Removing Local DRing entries\n", vdc->instance);
18891ae08745Sheppo 		for (i = 0; i < VD_DRING_LEN; i++) {
18900a55fbb7Slm66018 			ldep = &vdc->local_dring[i];
18910a55fbb7Slm66018 			mhdl = ldep->desc_mhdl;
18921ae08745Sheppo 
18930a55fbb7Slm66018 			if (mhdl == NULL)
18940a55fbb7Slm66018 				continue;
18950a55fbb7Slm66018 
18961ae08745Sheppo 			(void) ldc_mem_free_handle(mhdl);
18970a55fbb7Slm66018 			mutex_destroy(&ldep->lock);
18980a55fbb7Slm66018 			cv_destroy(&ldep->cv);
18991ae08745Sheppo 		}
19001ae08745Sheppo 		vdc->initialized &= ~VDC_DRING_ENTRY;
19011ae08745Sheppo 	}
19021ae08745Sheppo 
19031ae08745Sheppo 	if (vdc->initialized & VDC_DRING_LOCAL) {
19040a55fbb7Slm66018 		PR0("[%d] Freeing Local DRing\n", vdc->instance);
19051ae08745Sheppo 		kmem_free(vdc->local_dring,
19061ae08745Sheppo 				VD_DRING_LEN * sizeof (vdc_local_desc_t));
19071ae08745Sheppo 		vdc->initialized &= ~VDC_DRING_LOCAL;
19081ae08745Sheppo 	}
19091ae08745Sheppo 
19101ae08745Sheppo 	if (vdc->initialized & VDC_DRING_BOUND) {
19110a55fbb7Slm66018 		PR0("[%d] Unbinding DRing\n", vdc->instance);
19121ae08745Sheppo 		status = ldc_mem_dring_unbind(vdc->ldc_dring_hdl);
19131ae08745Sheppo 		if (status == 0) {
19141ae08745Sheppo 			vdc->initialized &= ~VDC_DRING_BOUND;
19151ae08745Sheppo 		} else {
19161ae08745Sheppo 			vdc_msg("%s: Failed to unbind Descriptor Ring (%lx)\n",
19171ae08745Sheppo 				vdc->ldc_dring_hdl);
19181ae08745Sheppo 		}
19191ae08745Sheppo 	}
19201ae08745Sheppo 
19211ae08745Sheppo 	if (vdc->initialized & VDC_DRING_INIT) {
19220a55fbb7Slm66018 		PR0("[%d] Destroying DRing\n", vdc->instance);
19231ae08745Sheppo 		status = ldc_mem_dring_destroy(vdc->ldc_dring_hdl);
19241ae08745Sheppo 		if (status == 0) {
19251ae08745Sheppo 			vdc->ldc_dring_hdl = NULL;
19261ae08745Sheppo 			bzero(&vdc->dring_mem_info, sizeof (ldc_mem_info_t));
19271ae08745Sheppo 			vdc->initialized &= ~VDC_DRING_INIT;
19281ae08745Sheppo 		} else {
19291ae08745Sheppo 			vdc_msg("%s: Failed to destroy Descriptor Ring (%lx)\n",
19301ae08745Sheppo 					vdc->ldc_dring_hdl);
19311ae08745Sheppo 		}
19321ae08745Sheppo 	}
19331ae08745Sheppo }
19341ae08745Sheppo 
19351ae08745Sheppo /*
19361ae08745Sheppo  * vdc_get_next_dring_entry_idx()
19371ae08745Sheppo  *
19381ae08745Sheppo  * Description:
19391ae08745Sheppo  *	This function gets the index of the next Descriptor Ring entry available
1940*d10e4ef2Snarayan  *	If the ring is full, it will back off and wait for the next entry to be
1941*d10e4ef2Snarayan  *	freed (the ACK handler will signal).
19421ae08745Sheppo  *
19431ae08745Sheppo  * Return Value:
19441ae08745Sheppo  *	0 <= rv < VD_DRING_LEN		Next available slot
19451ae08745Sheppo  *	-1 				DRing is full
19461ae08745Sheppo  */
19471ae08745Sheppo static int
19481ae08745Sheppo vdc_get_next_dring_entry_idx(vdc_t *vdc, uint_t num_slots_needed)
19491ae08745Sheppo {
19501ae08745Sheppo 	_NOTE(ARGUNUSED(num_slots_needed))
19511ae08745Sheppo 
1952*d10e4ef2Snarayan 	vd_dring_entry_t	*dep = NULL;	/* DRing Entry Pointer */
1953*d10e4ef2Snarayan 	vdc_local_desc_t	*ldep = NULL;	/* Local DRing Entry Pointer */
19541ae08745Sheppo 	int			idx = -1;
19551ae08745Sheppo 
19561ae08745Sheppo 	ASSERT(vdc != NULL);
19571ae08745Sheppo 	ASSERT(vdc->dring_len == VD_DRING_LEN);
19581ae08745Sheppo 	ASSERT(vdc->dring_curr_idx >= 0);
19591ae08745Sheppo 	ASSERT(vdc->dring_curr_idx < VD_DRING_LEN);
19601ae08745Sheppo 	ASSERT(mutex_owned(&vdc->dring_lock));
19611ae08745Sheppo 
1962*d10e4ef2Snarayan 	/* pick the next descriptor after the last one used */
1963*d10e4ef2Snarayan 	idx = (vdc->dring_curr_idx + 1) % VD_DRING_LEN;
1964*d10e4ef2Snarayan 	ldep = &vdc->local_dring[idx];
1965*d10e4ef2Snarayan 	ASSERT(ldep != NULL);
1966*d10e4ef2Snarayan 	dep = ldep->dep;
19671ae08745Sheppo 	ASSERT(dep != NULL);
19681ae08745Sheppo 
1969*d10e4ef2Snarayan 	mutex_enter(&ldep->lock);
19701ae08745Sheppo 	if (dep->hdr.dstate == VIO_DESC_FREE) {
19711ae08745Sheppo 		vdc->dring_curr_idx = idx;
19721ae08745Sheppo 	} else {
1973*d10e4ef2Snarayan 		DTRACE_PROBE(full);
1974*d10e4ef2Snarayan 		(void) cv_timedwait(&ldep->cv, &ldep->lock,
1975*d10e4ef2Snarayan 					VD_GET_TIMEOUT_HZ(1));
1976*d10e4ef2Snarayan 		if (dep->hdr.dstate == VIO_DESC_FREE) {
1977*d10e4ef2Snarayan 			vdc->dring_curr_idx = idx;
1978*d10e4ef2Snarayan 		} else {
1979*d10e4ef2Snarayan 			PR0("[%d] Entry %d unavailable still in state %d\n",
1980*d10e4ef2Snarayan 					vdc->instance, idx, dep->hdr.dstate);
1981*d10e4ef2Snarayan 			idx = -1; /* indicate that the ring is full */
19821ae08745Sheppo 		}
1983*d10e4ef2Snarayan 	}
1984*d10e4ef2Snarayan 	mutex_exit(&ldep->lock);
19851ae08745Sheppo 
1986*d10e4ef2Snarayan 	return (idx);
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
2000*d10e4ef2Snarayan  *	addr	- address of structure to be written. In the case of block
2001*d10e4ef2Snarayan  *		  reads and writes this structure will be a buf_t and the
2002*d10e4ef2Snarayan  *		  address of the data to be written will be in the b_un.b_addr
2003*d10e4ef2Snarayan  *		  field. Otherwise the value of addr will be the address
2004*d10e4ef2Snarayan  *		  to be written.
20051ae08745Sheppo  *	nbytes	- number of bytes to read/write
20061ae08745Sheppo  *	operation - operation we want vds to perform (VD_OP_XXX)
20071ae08745Sheppo  *	arg	- parameter to be sent to server (depends on VD_OP_XXX type)
20081ae08745Sheppo  *			. mode for ioctl(9e)
20091ae08745Sheppo  *			. LP64 diskaddr_t (block I/O)
20101ae08745Sheppo  *	slice	- the disk slice this request is for
20111ae08745Sheppo  *
20121ae08745Sheppo  * Return Codes:
20131ae08745Sheppo  *	0
20141ae08745Sheppo  *	EAGAIN
20151ae08745Sheppo  *		EFAULT
20161ae08745Sheppo  *		ENXIO
20171ae08745Sheppo  *		EIO
20181ae08745Sheppo  */
20191ae08745Sheppo static int
20201ae08745Sheppo vdc_populate_descriptor(vdc_t *vdc, caddr_t addr, size_t nbytes, int operation,
20211ae08745Sheppo 				uint64_t arg, uint64_t slice)
20221ae08745Sheppo {
20231ae08745Sheppo 	vdc_local_desc_t *local_dep = NULL;	/* Local Dring Entry Pointer */
20241ae08745Sheppo 	vd_dring_entry_t *dep = NULL;		/* Dring Entry Pointer */
20251ae08745Sheppo 	int			idx = 0;	/* Index of DRing entry used */
20261ae08745Sheppo 	vio_dring_msg_t		dmsg;
20271ae08745Sheppo 	size_t			msglen = sizeof (dmsg);
20281ae08745Sheppo 	int			retries = 0;
20298e6a2a04Slm66018 	int			rv;
20301ae08745Sheppo 
20311ae08745Sheppo 	ASSERT(vdc != NULL);
20321ae08745Sheppo 	ASSERT(slice < V_NUMPAR);
20331ae08745Sheppo 
20341ae08745Sheppo 	/*
20351ae08745Sheppo 	 * Get next available DRing entry.
20361ae08745Sheppo 	 */
20371ae08745Sheppo 	mutex_enter(&vdc->dring_lock);
20381ae08745Sheppo 	idx = vdc_get_next_dring_entry_idx(vdc, 1);
20391ae08745Sheppo 	if (idx == -1) {
20401ae08745Sheppo 		mutex_exit(&vdc->dring_lock);
2041*d10e4ef2Snarayan 		PR0("[%d] no descriptor ring entry avail, last seq=%d\n",
2042*d10e4ef2Snarayan 				vdc->instance, vdc->seq_num - 1);
20431ae08745Sheppo 
20441ae08745Sheppo 		/*
20451ae08745Sheppo 		 * Since strategy should not block we don't wait for the DRing
20461ae08745Sheppo 		 * to empty and instead return
20471ae08745Sheppo 		 */
20481ae08745Sheppo 		return (EAGAIN);
20491ae08745Sheppo 	}
20501ae08745Sheppo 
20511ae08745Sheppo 	ASSERT(idx < VD_DRING_LEN);
20521ae08745Sheppo 	local_dep = &vdc->local_dring[idx];
20531ae08745Sheppo 	dep = local_dep->dep;
20541ae08745Sheppo 	ASSERT(dep != NULL);
20551ae08745Sheppo 
20561ae08745Sheppo 	/*
2057*d10e4ef2Snarayan 	 * We now get the lock for this descriptor before dropping the overall
2058*d10e4ef2Snarayan 	 * DRing lock. This prevents a race condition where another vdc thread
2059*d10e4ef2Snarayan 	 * could grab the descriptor we selected.
20601ae08745Sheppo 	 */
2061*d10e4ef2Snarayan 	ASSERT(!MUTEX_HELD(&local_dep->lock));
20621ae08745Sheppo 	mutex_enter(&local_dep->lock);
2063*d10e4ef2Snarayan 	mutex_exit(&vdc->dring_lock);
20641ae08745Sheppo 
20651ae08745Sheppo 	switch (operation) {
20661ae08745Sheppo 	case VD_OP_BREAD:
20671ae08745Sheppo 	case VD_OP_BWRITE:
2068*d10e4ef2Snarayan 		local_dep->buf = (struct buf *)addr;
2069*d10e4ef2Snarayan 		local_dep->addr = local_dep->buf->b_un.b_addr;
20701ae08745Sheppo 		PR1("buf=%p, block=%lx, nbytes=%lx\n", addr, arg, nbytes);
20711ae08745Sheppo 		dep->payload.addr = (diskaddr_t)arg;
2072*d10e4ef2Snarayan 		rv = vdc_populate_mem_hdl(vdc, idx, local_dep->addr,
2073*d10e4ef2Snarayan 						nbytes, operation);
20741ae08745Sheppo 		break;
20751ae08745Sheppo 
20761ae08745Sheppo 	case VD_OP_GET_VTOC:
20771ae08745Sheppo 	case VD_OP_SET_VTOC:
20781ae08745Sheppo 	case VD_OP_GET_DISKGEOM:
20791ae08745Sheppo 	case VD_OP_SET_DISKGEOM:
20801ae08745Sheppo 	case VD_OP_SCSICMD:
2081*d10e4ef2Snarayan 		local_dep->addr = addr;
20821ae08745Sheppo 		if (nbytes > 0) {
20831ae08745Sheppo 			rv = vdc_populate_mem_hdl(vdc, idx, addr, nbytes,
20841ae08745Sheppo 							operation);
20851ae08745Sheppo 		}
20861ae08745Sheppo 		break;
20878e6a2a04Slm66018 
20888e6a2a04Slm66018 	case VD_OP_FLUSH:
20898e6a2a04Slm66018 	case VD_OP_GET_WCE:
20908e6a2a04Slm66018 	case VD_OP_SET_WCE:
20918e6a2a04Slm66018 		rv = 0;		/* nothing to bind */
20928e6a2a04Slm66018 		break;
20938e6a2a04Slm66018 
20941ae08745Sheppo 	default:
20951ae08745Sheppo 		cmn_err(CE_NOTE, "[%d] Unsupported vDisk operation [%d]\n",
20961ae08745Sheppo 				vdc->instance, operation);
20971ae08745Sheppo 		rv = EINVAL;
20981ae08745Sheppo 	}
20991ae08745Sheppo 
21001ae08745Sheppo 	if (rv != 0) {
21011ae08745Sheppo 		mutex_exit(&local_dep->lock);
21021ae08745Sheppo 		return (rv);
21031ae08745Sheppo 	}
21041ae08745Sheppo 
21051ae08745Sheppo 	/*
21061ae08745Sheppo 	 * fill in the data details into the DRing
21071ae08745Sheppo 	 */
21081ae08745Sheppo 	dep->payload.req_id = VDC_GET_NEXT_REQ_ID(vdc);
21091ae08745Sheppo 	dep->payload.operation = operation;
21101ae08745Sheppo 	dep->payload.nbytes = nbytes;
21111ae08745Sheppo 	dep->payload.status = EINPROGRESS;	/* vds will set valid value */
21121ae08745Sheppo 	dep->payload.slice = slice;
21131ae08745Sheppo 	dep->hdr.dstate = VIO_DESC_READY;
21141ae08745Sheppo 	dep->hdr.ack = 1;		/* request an ACK for every message */
21151ae08745Sheppo 
21161ae08745Sheppo 	local_dep->flags = VIO_DESC_READY;
21171ae08745Sheppo 
21181ae08745Sheppo 	/*
21191ae08745Sheppo 	 * Send a msg with the DRing details to vds
21201ae08745Sheppo 	 */
2121*d10e4ef2Snarayan 	mutex_enter(&vdc->lock);
21221ae08745Sheppo 	VIO_INIT_DRING_DATA_TAG(dmsg);
21231ae08745Sheppo 	VDC_INIT_DRING_DATA_MSG_IDS(dmsg, vdc);
21241ae08745Sheppo 	dmsg.dring_ident = vdc->dring_ident;
21251ae08745Sheppo 	dmsg.start_idx = idx;
21261ae08745Sheppo 	dmsg.end_idx = idx;
21271ae08745Sheppo 
2128*d10e4ef2Snarayan 	DTRACE_IO2(send, vio_dring_msg_t *, &dmsg, vdc_t *, vdc);
2129*d10e4ef2Snarayan 
21301ae08745Sheppo 	PR1("ident=0x%llx, st=%d, end=%d, seq=%d req=%d dep=%p\n",
21311ae08745Sheppo 			vdc->dring_ident, dmsg.start_idx, dmsg.end_idx,
21321ae08745Sheppo 			dmsg.seq_num, dep->payload.req_id, dep);
21331ae08745Sheppo 
21348e6a2a04Slm66018 	rv = vdc_send(vdc, (caddr_t)&dmsg, &msglen);
21358e6a2a04Slm66018 	PR1("%s[%d]: ldc_write() rv=%d\n", __func__, vdc->instance, rv);
21368e6a2a04Slm66018 	if (rv != 0) {
2137*d10e4ef2Snarayan 		mutex_exit(&vdc->lock);
21381ae08745Sheppo 		mutex_exit(&local_dep->lock);
21398e6a2a04Slm66018 		vdc_msg("%s: ldc_write(%d)\n", __func__, rv);
2140*d10e4ef2Snarayan 
2141*d10e4ef2Snarayan 		/* Clear the DRing entry */
2142*d10e4ef2Snarayan 		rv = vdc_depopulate_descriptor(vdc, idx);
2143*d10e4ef2Snarayan 
2144*d10e4ef2Snarayan 		return (rv ? rv : EAGAIN);
21451ae08745Sheppo 	}
21461ae08745Sheppo 
21471ae08745Sheppo 	/*
21480a55fbb7Slm66018 	 * If the message was successfully sent, we increment the sequence
21490a55fbb7Slm66018 	 * number to be used by the next message
21500a55fbb7Slm66018 	 */
21510a55fbb7Slm66018 	vdc->seq_num++;
2152*d10e4ef2Snarayan 	mutex_exit(&vdc->lock);
21531ae08745Sheppo 
21541ae08745Sheppo 	/*
21551ae08745Sheppo 	 * When a guest is panicking, the completion of requests needs to be
21561ae08745Sheppo 	 * handled differently because interrupts are disabled and vdc
21571ae08745Sheppo 	 * will not get messages. We have to poll for the messages instead.
21581ae08745Sheppo 	 */
21591ae08745Sheppo 	if (ddi_in_panic()) {
21601ae08745Sheppo 		int start = 0;
21611ae08745Sheppo 		retries = 0;
21621ae08745Sheppo 		for (;;) {
21631ae08745Sheppo 			msglen = sizeof (dmsg);
21648e6a2a04Slm66018 			rv = ldc_read(vdc->ldc_handle, (caddr_t)&dmsg,
21651ae08745Sheppo 					&msglen);
21668e6a2a04Slm66018 			if (rv) {
21678e6a2a04Slm66018 				rv = EINVAL;
21681ae08745Sheppo 				break;
21691ae08745Sheppo 			}
21701ae08745Sheppo 
21711ae08745Sheppo 			/*
21721ae08745Sheppo 			 * if there are no packets wait and check again
21731ae08745Sheppo 			 */
21748e6a2a04Slm66018 			if ((rv == 0) && (msglen == 0)) {
21751ae08745Sheppo 				if (retries++ > vdc_dump_retries) {
21761ae08745Sheppo 					PR0("[%d] Giving up waiting, idx %d\n",
21771ae08745Sheppo 							vdc->instance, idx);
21788e6a2a04Slm66018 					rv = EAGAIN;
21791ae08745Sheppo 					break;
21801ae08745Sheppo 				}
21811ae08745Sheppo 
21821ae08745Sheppo 				PR1("Waiting for next packet @ %d\n", idx);
2183*d10e4ef2Snarayan 				drv_usecwait(vdc_usec_timeout_dump);
21841ae08745Sheppo 				continue;
21851ae08745Sheppo 			}
21861ae08745Sheppo 
21871ae08745Sheppo 			/*
21881ae08745Sheppo 			 * Ignore all messages that are not ACKs/NACKs to
21891ae08745Sheppo 			 * DRing requests.
21901ae08745Sheppo 			 */
21911ae08745Sheppo 			if ((dmsg.tag.vio_msgtype != VIO_TYPE_DATA) ||
21921ae08745Sheppo 			    (dmsg.tag.vio_subtype_env != VIO_DRING_DATA)) {
21931ae08745Sheppo 				PR0("discarding pkt: type=%d sub=%d env=%d\n",
21941ae08745Sheppo 					dmsg.tag.vio_msgtype,
21951ae08745Sheppo 					dmsg.tag.vio_subtype,
21961ae08745Sheppo 					dmsg.tag.vio_subtype_env);
21971ae08745Sheppo 				continue;
21981ae08745Sheppo 			}
21991ae08745Sheppo 
22001ae08745Sheppo 			/*
22011ae08745Sheppo 			 * set the appropriate return value for the
22021ae08745Sheppo 			 * current request.
22031ae08745Sheppo 			 */
22041ae08745Sheppo 			switch (dmsg.tag.vio_subtype) {
22051ae08745Sheppo 			case VIO_SUBTYPE_ACK:
22068e6a2a04Slm66018 				rv = 0;
22071ae08745Sheppo 				break;
22081ae08745Sheppo 			case VIO_SUBTYPE_NACK:
22098e6a2a04Slm66018 				rv = EAGAIN;
22101ae08745Sheppo 				break;
22111ae08745Sheppo 			default:
22121ae08745Sheppo 				continue;
22131ae08745Sheppo 			}
22141ae08745Sheppo 
22151ae08745Sheppo 			start = dmsg.start_idx;
22161ae08745Sheppo 			if (start >= VD_DRING_LEN) {
22171ae08745Sheppo 				PR0("[%d] Bogus ack data : start %d\n",
22181ae08745Sheppo 					vdc->instance, start);
22191ae08745Sheppo 				continue;
22201ae08745Sheppo 			}
22211ae08745Sheppo 
22221ae08745Sheppo 			dep = VDC_GET_DRING_ENTRY_PTR(vdc, start);
22231ae08745Sheppo 
22241ae08745Sheppo 			PR1("[%d] Dumping start=%d idx=%d state=%d\n",
22251ae08745Sheppo 				vdc->instance, start, idx, dep->hdr.dstate);
22261ae08745Sheppo 
22271ae08745Sheppo 			if (dep->hdr.dstate != VIO_DESC_DONE) {
22281ae08745Sheppo 				PR0("[%d] Entry @ %d - state !DONE %d\n",
22291ae08745Sheppo 					vdc->instance, start, dep->hdr.dstate);
22301ae08745Sheppo 				continue;
22311ae08745Sheppo 			}
22321ae08745Sheppo 
22331ae08745Sheppo 			(void) vdc_depopulate_descriptor(vdc, start);
22341ae08745Sheppo 
22351ae08745Sheppo 			/*
22361ae08745Sheppo 			 * We want to process all Dring entries up to
22371ae08745Sheppo 			 * the current one so that we can return an
22381ae08745Sheppo 			 * error with the correct request.
22391ae08745Sheppo 			 */
22401ae08745Sheppo 			if (idx > start) {
22411ae08745Sheppo 				PR0("[%d] Looping: start %d, idx %d\n",
22421ae08745Sheppo 						vdc->instance, idx, start);
22431ae08745Sheppo 				continue;
22441ae08745Sheppo 			}
22451ae08745Sheppo 
22461ae08745Sheppo 			/* exit - all outstanding requests are completed */
22471ae08745Sheppo 			break;
22481ae08745Sheppo 		}
22491ae08745Sheppo 
22501ae08745Sheppo 		mutex_exit(&local_dep->lock);
22511ae08745Sheppo 
22528e6a2a04Slm66018 		return (rv);
22531ae08745Sheppo 	}
22541ae08745Sheppo 
22551ae08745Sheppo 	/*
2256*d10e4ef2Snarayan 	 * In the case of calls from strategy and dump (in the non-panic case),
2257*d10e4ef2Snarayan 	 * instead of waiting for a response from the vDisk server return now.
2258*d10e4ef2Snarayan 	 * They will be processed asynchronously and the vdc ACK handling code
2259*d10e4ef2Snarayan 	 * will trigger the biodone(9F)
2260*d10e4ef2Snarayan 	 */
2261*d10e4ef2Snarayan 	if ((operation == VD_OP_BREAD) || (operation == VD_OP_BWRITE)) {
2262*d10e4ef2Snarayan 		mutex_exit(&local_dep->lock);
2263*d10e4ef2Snarayan 		return (rv);
2264*d10e4ef2Snarayan 	}
2265*d10e4ef2Snarayan 
2266*d10e4ef2Snarayan 	/*
2267*d10e4ef2Snarayan 	 * In the case of synchronous calls we watch the DRing entries we
2268*d10e4ef2Snarayan 	 * modified and await the response from vds.
22691ae08745Sheppo 	 */
22708e6a2a04Slm66018 	rv = vdc_wait_for_descriptor_update(vdc, idx, dmsg);
22718e6a2a04Slm66018 	if (rv == ETIMEDOUT) {
22721ae08745Sheppo 		/* debug info when dumping state on vds side */
22731ae08745Sheppo 		dep->payload.status = ECANCELED;
22741ae08745Sheppo 	}
22751ae08745Sheppo 
22768e6a2a04Slm66018 	rv = vdc_depopulate_descriptor(vdc, idx);
22778e6a2a04Slm66018 	PR1("%s[%d] Status=%d\n", __func__, vdc->instance, rv);
22781ae08745Sheppo 
22791ae08745Sheppo 	mutex_exit(&local_dep->lock);
22801ae08745Sheppo 
22818e6a2a04Slm66018 	return (rv);
22821ae08745Sheppo }
22831ae08745Sheppo 
22840a55fbb7Slm66018 /*
22850a55fbb7Slm66018  * Function:
22860a55fbb7Slm66018  *	vdc_wait_for_descriptor_update()
22870a55fbb7Slm66018  *
22880a55fbb7Slm66018  * Description:
22890a55fbb7Slm66018  *
22900a55fbb7Slm66018  * Arguments:
22910a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
22920a55fbb7Slm66018  *	idx	- Index of the Descriptor Ring entry being modified
22930a55fbb7Slm66018  *	dmsg	- LDC message sent by vDisk server
22940a55fbb7Slm66018  *
22950a55fbb7Slm66018  * Return Code:
22960a55fbb7Slm66018  *	0	- Success
22970a55fbb7Slm66018  */
22981ae08745Sheppo static int
22991ae08745Sheppo vdc_wait_for_descriptor_update(vdc_t *vdc, uint_t idx, vio_dring_msg_t dmsg)
23001ae08745Sheppo {
23011ae08745Sheppo 	vd_dring_entry_t *dep = NULL;		/* Dring Entry Pointer */
23021ae08745Sheppo 	vdc_local_desc_t *local_dep = NULL;	/* Local Dring Entry Pointer */
23031ae08745Sheppo 	size_t	msglen = sizeof (dmsg);
23041ae08745Sheppo 	int	retries = 0;
23050a55fbb7Slm66018 	int	status = 0;
23061ae08745Sheppo 	int	rv = 0;
23071ae08745Sheppo 
23081ae08745Sheppo 	ASSERT(vdc != NULL);
23091ae08745Sheppo 	ASSERT(idx < VD_DRING_LEN);
23101ae08745Sheppo 	local_dep = &vdc->local_dring[idx];
23111ae08745Sheppo 	ASSERT(local_dep != NULL);
23121ae08745Sheppo 	dep = local_dep->dep;
23131ae08745Sheppo 	ASSERT(dep != NULL);
23141ae08745Sheppo 
23151ae08745Sheppo 	while (dep->hdr.dstate != VIO_DESC_DONE) {
23161ae08745Sheppo 		rv = cv_timedwait(&local_dep->cv, &local_dep->lock,
23171ae08745Sheppo 			VD_GET_TIMEOUT_HZ(retries));
23181ae08745Sheppo 		if (rv == -1) {
23191ae08745Sheppo 			/*
23201ae08745Sheppo 			 * If they persist in ignoring us we'll storm off in a
23211ae08745Sheppo 			 * huff and return ETIMEDOUT to the upper layers.
23221ae08745Sheppo 			 */
23231ae08745Sheppo 			if (retries >= vdc_retries) {
23241ae08745Sheppo 				PR0("%s: Finished waiting on entry %d\n",
23251ae08745Sheppo 					__func__, idx);
23261ae08745Sheppo 				status = ETIMEDOUT;
23271ae08745Sheppo 				break;
23281ae08745Sheppo 			} else {
23291ae08745Sheppo 				retries++;
23301ae08745Sheppo 				PR0("%s[%d]: Timeout #%d on entry %d "
23311ae08745Sheppo 				    "[seq %d][req %d]\n", __func__,
23321ae08745Sheppo 				    vdc->instance,
23331ae08745Sheppo 				    retries, idx, dmsg.seq_num,
23341ae08745Sheppo 				    dep->payload.req_id);
23351ae08745Sheppo 			}
23361ae08745Sheppo 
23371ae08745Sheppo 			if (dep->hdr.dstate & VIO_DESC_ACCEPTED) {
23381ae08745Sheppo 				PR0("%s[%d]: vds has accessed entry %d [seq %d]"
23391ae08745Sheppo 				    "[req %d] but not ack'ed it yet\n",
23401ae08745Sheppo 				    __func__, vdc->instance, idx, dmsg.seq_num,
23411ae08745Sheppo 				    dep->payload.req_id);
23421ae08745Sheppo 				continue;
23431ae08745Sheppo 			}
23441ae08745Sheppo 
23451ae08745Sheppo 			/*
23461ae08745Sheppo 			 * we resend the message as it may have been dropped
23471ae08745Sheppo 			 * and have never made it to the other side (vds).
23481ae08745Sheppo 			 * (We reuse the original message but update seq ID)
23491ae08745Sheppo 			 */
2350*d10e4ef2Snarayan 			mutex_enter(&vdc->lock);
23511ae08745Sheppo 			VDC_INIT_DRING_DATA_MSG_IDS(dmsg, vdc);
23521ae08745Sheppo 			retries = 0;
23530a55fbb7Slm66018 			status = vdc_send(vdc, (caddr_t)&dmsg, &msglen);
23541ae08745Sheppo 			if (status != 0) {
2355*d10e4ef2Snarayan 				mutex_exit(&vdc->lock);
23561ae08745Sheppo 				vdc_msg("%s: Error (%d) while resending after "
23571ae08745Sheppo 					"timeout\n", __func__, status);
23581ae08745Sheppo 				status = ETIMEDOUT;
23591ae08745Sheppo 				break;
23601ae08745Sheppo 			}
23610a55fbb7Slm66018 			/*
23620a55fbb7Slm66018 			 * If the message was successfully sent, we increment
23630a55fbb7Slm66018 			 * the sequence number to be used by the next message.
23640a55fbb7Slm66018 			 */
23650a55fbb7Slm66018 			vdc->seq_num++;
2366*d10e4ef2Snarayan 			mutex_exit(&vdc->lock);
23671ae08745Sheppo 		}
23681ae08745Sheppo 	}
23691ae08745Sheppo 
23701ae08745Sheppo 	return (status);
23711ae08745Sheppo }
23721ae08745Sheppo 
23731ae08745Sheppo 
23740a55fbb7Slm66018 /*
23750a55fbb7Slm66018  * Function:
23760a55fbb7Slm66018  *	vdc_depopulate_descriptor()
23770a55fbb7Slm66018  *
23780a55fbb7Slm66018  * Description:
23790a55fbb7Slm66018  *
23800a55fbb7Slm66018  * Arguments:
23810a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
23820a55fbb7Slm66018  *	idx	- Index of the Descriptor Ring entry being modified
23830a55fbb7Slm66018  *
23840a55fbb7Slm66018  * Return Code:
23850a55fbb7Slm66018  *	0	- Success
23860a55fbb7Slm66018  */
23871ae08745Sheppo static int
23881ae08745Sheppo vdc_depopulate_descriptor(vdc_t *vdc, uint_t idx)
23891ae08745Sheppo {
23901ae08745Sheppo 	vd_dring_entry_t *dep = NULL;		/* Dring Entry Pointer */
23911ae08745Sheppo 	vdc_local_desc_t *ldep = NULL;		/* Local Dring Entry Pointer */
23921ae08745Sheppo 	int		status = ENXIO;
23938e6a2a04Slm66018 	int		operation;
23948e6a2a04Slm66018 	int		rv = 0;
23951ae08745Sheppo 
23961ae08745Sheppo 	ASSERT(vdc != NULL);
23971ae08745Sheppo 	ASSERT(idx < VD_DRING_LEN);
23981ae08745Sheppo 	ldep = &vdc->local_dring[idx];
23991ae08745Sheppo 	ASSERT(ldep != NULL);
24001ae08745Sheppo 	dep = ldep->dep;
24011ae08745Sheppo 	ASSERT(dep != NULL);
24021ae08745Sheppo 
24031ae08745Sheppo 	status = dep->payload.status;
24048e6a2a04Slm66018 	operation = dep->payload.operation;
24051ae08745Sheppo 	VDC_MARK_DRING_ENTRY_FREE(vdc, idx);
24061ae08745Sheppo 	ldep = &vdc->local_dring[idx];
24071ae08745Sheppo 	VIO_SET_DESC_STATE(ldep->flags, VIO_DESC_FREE);
24081ae08745Sheppo 
24098e6a2a04Slm66018 	/* the DKIO W$ operations never bind handles so we can return now */
24108e6a2a04Slm66018 	if ((operation == VD_OP_FLUSH) ||
24118e6a2a04Slm66018 	    (operation == VD_OP_GET_WCE) ||
24128e6a2a04Slm66018 	    (operation == VD_OP_SET_WCE))
24138e6a2a04Slm66018 		return (status);
24148e6a2a04Slm66018 
24151ae08745Sheppo 	/*
24161ae08745Sheppo 	 * If the upper layer passed in a misaligned address we copied the
24171ae08745Sheppo 	 * data into an aligned buffer before sending it to LDC - we now
24181ae08745Sheppo 	 * copy it back to the original buffer.
24191ae08745Sheppo 	 */
24201ae08745Sheppo 	if (ldep->align_addr) {
24211ae08745Sheppo 		ASSERT(ldep->addr != NULL);
24221ae08745Sheppo 		ASSERT(dep->payload.nbytes > 0);
24231ae08745Sheppo 
24241ae08745Sheppo 		bcopy(ldep->align_addr, ldep->addr, dep->payload.nbytes);
24251ae08745Sheppo 		kmem_free(ldep->align_addr,
2426*d10e4ef2Snarayan 			sizeof (caddr_t) * P2ROUNDUP(dep->payload.nbytes, 8));
24271ae08745Sheppo 		ldep->align_addr = NULL;
24281ae08745Sheppo 	}
24291ae08745Sheppo 
24308e6a2a04Slm66018 	rv = ldc_mem_unbind_handle(ldep->desc_mhdl);
24318e6a2a04Slm66018 	if (rv != 0) {
24321ae08745Sheppo 		cmn_err(CE_NOTE, "[%d] unbind mem hdl 0x%lx @ idx %d failed:%d",
24338e6a2a04Slm66018 				vdc->instance, ldep->desc_mhdl, idx, rv);
24348e6a2a04Slm66018 		/*
24358e6a2a04Slm66018 		 * The error returned by the vDisk server is more informative
24368e6a2a04Slm66018 		 * and thus has a higher priority but if it isn't set we ensure
24378e6a2a04Slm66018 		 * that this function returns an error.
24388e6a2a04Slm66018 		 */
24398e6a2a04Slm66018 		if (status == 0)
24408e6a2a04Slm66018 			status = EINVAL;
24411ae08745Sheppo 	}
24421ae08745Sheppo 
24431ae08745Sheppo 	return (status);
24441ae08745Sheppo }
24451ae08745Sheppo 
24460a55fbb7Slm66018 /*
24470a55fbb7Slm66018  * Function:
24480a55fbb7Slm66018  *	vdc_populate_mem_hdl()
24490a55fbb7Slm66018  *
24500a55fbb7Slm66018  * Description:
24510a55fbb7Slm66018  *
24520a55fbb7Slm66018  * Arguments:
24530a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
24540a55fbb7Slm66018  *	idx	- Index of the Descriptor Ring entry being modified
24550a55fbb7Slm66018  *	addr	- virtual address being mapped in
24560a55fbb7Slm66018  *	nybtes	- number of bytes in 'addr'
24570a55fbb7Slm66018  *	operation - the vDisk operation being performed (VD_OP_xxx)
24580a55fbb7Slm66018  *
24590a55fbb7Slm66018  * Return Code:
24600a55fbb7Slm66018  *	0	- Success
24610a55fbb7Slm66018  */
24621ae08745Sheppo static int
24631ae08745Sheppo vdc_populate_mem_hdl(vdc_t *vdc, uint_t idx, caddr_t addr, size_t nbytes,
24641ae08745Sheppo 			int operation)
24651ae08745Sheppo {
24661ae08745Sheppo 	vd_dring_entry_t	*dep = NULL;
24671ae08745Sheppo 	vdc_local_desc_t	*ldep = NULL;
24681ae08745Sheppo 	ldc_mem_handle_t	mhdl;
24691ae08745Sheppo 	caddr_t			vaddr;
24701ae08745Sheppo 	int			perm = LDC_MEM_RW;
24711ae08745Sheppo 	int			rv = 0;
24721ae08745Sheppo 	int			i;
24731ae08745Sheppo 
24741ae08745Sheppo 	ASSERT(vdc != NULL);
24751ae08745Sheppo 	ASSERT(idx < VD_DRING_LEN);
24761ae08745Sheppo 
24771ae08745Sheppo 	dep = VDC_GET_DRING_ENTRY_PTR(vdc, idx);
24781ae08745Sheppo 	ldep = &vdc->local_dring[idx];
24791ae08745Sheppo 	mhdl = ldep->desc_mhdl;
24801ae08745Sheppo 
24811ae08745Sheppo 	switch (operation) {
24821ae08745Sheppo 	case VD_OP_BREAD:
24831ae08745Sheppo 		perm = LDC_MEM_W;
24841ae08745Sheppo 		break;
24851ae08745Sheppo 
24861ae08745Sheppo 	case VD_OP_BWRITE:
24871ae08745Sheppo 		perm = LDC_MEM_R;
24881ae08745Sheppo 		break;
24891ae08745Sheppo 
24901ae08745Sheppo 	case VD_OP_GET_VTOC:
24911ae08745Sheppo 	case VD_OP_SET_VTOC:
24921ae08745Sheppo 	case VD_OP_GET_DISKGEOM:
24931ae08745Sheppo 	case VD_OP_SET_DISKGEOM:
24941ae08745Sheppo 	case VD_OP_SCSICMD:
24951ae08745Sheppo 		perm = LDC_MEM_RW;
24961ae08745Sheppo 		break;
24971ae08745Sheppo 
24981ae08745Sheppo 	default:
24991ae08745Sheppo 		ASSERT(0);	/* catch bad programming in vdc */
25001ae08745Sheppo 	}
25011ae08745Sheppo 
25021ae08745Sheppo 	/*
25031ae08745Sheppo 	 * LDC expects any addresses passed in to be 8-byte aligned. We need
25041ae08745Sheppo 	 * to copy the contents of any misaligned buffers to a newly allocated
25051ae08745Sheppo 	 * buffer and bind it instead (and copy the the contents back to the
25061ae08745Sheppo 	 * original buffer passed in when depopulating the descriptor)
25071ae08745Sheppo 	 */
25081ae08745Sheppo 	vaddr = addr;
25091ae08745Sheppo 	if (((uint64_t)addr & 0x7) != 0) {
2510*d10e4ef2Snarayan 		ASSERT(ldep->align_addr == NULL);
25111ae08745Sheppo 		ldep->align_addr =
2512*d10e4ef2Snarayan 			kmem_zalloc(sizeof (caddr_t) * P2ROUNDUP(nbytes, 8),
2513*d10e4ef2Snarayan 					KM_SLEEP);
25141ae08745Sheppo 		PR0("%s[%d] Misaligned address %lx reallocating "
2515*d10e4ef2Snarayan 		    "(buf=%lx nb=%d op=%d entry=%d)\n",
2516*d10e4ef2Snarayan 		    __func__, vdc->instance, addr, ldep->align_addr, nbytes,
2517*d10e4ef2Snarayan 		    operation, idx);
25181ae08745Sheppo 		bcopy(addr, ldep->align_addr, nbytes);
25191ae08745Sheppo 		vaddr = ldep->align_addr;
25201ae08745Sheppo 	}
25211ae08745Sheppo 
25221ae08745Sheppo 	rv = ldc_mem_bind_handle(mhdl, vaddr, P2ROUNDUP(nbytes, 8),
2523*d10e4ef2Snarayan 		LDC_SHADOW_MAP, perm, &dep->payload.cookie[0],
25241ae08745Sheppo 		&dep->payload.ncookies);
25251ae08745Sheppo 	PR1("%s[%d] bound mem handle; ncookies=%d\n",
25261ae08745Sheppo 			__func__, vdc->instance, dep->payload.ncookies);
25271ae08745Sheppo 	if (rv != 0) {
25281ae08745Sheppo 		vdc_msg("%s[%d] failed to ldc_mem_bind_handle "
25291ae08745Sheppo 		    "(mhdl=%lx, buf=%lx entry=%d err=%d)\n",
25301ae08745Sheppo 		    __func__, vdc->instance, mhdl, addr, idx, rv);
25311ae08745Sheppo 		if (ldep->align_addr) {
25321ae08745Sheppo 			kmem_free(ldep->align_addr,
2533*d10e4ef2Snarayan 				sizeof (caddr_t) * P2ROUNDUP(nbytes, 8));
25341ae08745Sheppo 			ldep->align_addr = NULL;
25351ae08745Sheppo 		}
25361ae08745Sheppo 		return (EAGAIN);
25371ae08745Sheppo 	}
25381ae08745Sheppo 
25391ae08745Sheppo 	/*
25401ae08745Sheppo 	 * Get the other cookies (if any).
25411ae08745Sheppo 	 */
25421ae08745Sheppo 	for (i = 1; i < dep->payload.ncookies; i++) {
25431ae08745Sheppo 		rv = ldc_mem_nextcookie(mhdl, &dep->payload.cookie[i]);
25441ae08745Sheppo 		if (rv != 0) {
25451ae08745Sheppo 			(void) ldc_mem_unbind_handle(mhdl);
25461ae08745Sheppo 			vdc_msg("%s: failed to get next cookie(mhdl=%lx "
25471ae08745Sheppo 				"cnum=%d), err=%d", __func__, mhdl, i, rv);
25481ae08745Sheppo 			if (ldep->align_addr) {
25491ae08745Sheppo 				kmem_free(ldep->align_addr,
25501ae08745Sheppo 					sizeof (caddr_t) * dep->payload.nbytes);
25511ae08745Sheppo 				ldep->align_addr = NULL;
25521ae08745Sheppo 			}
25531ae08745Sheppo 			return (EAGAIN);
25541ae08745Sheppo 		}
25551ae08745Sheppo 	}
25561ae08745Sheppo 
25571ae08745Sheppo 	return (rv);
25581ae08745Sheppo }
25591ae08745Sheppo 
25601ae08745Sheppo /*
25611ae08745Sheppo  * Interrupt handlers for messages from LDC
25621ae08745Sheppo  */
25631ae08745Sheppo 
25640a55fbb7Slm66018 /*
25650a55fbb7Slm66018  * Function:
25660a55fbb7Slm66018  *	vdc_handle_cb()
25670a55fbb7Slm66018  *
25680a55fbb7Slm66018  * Description:
25690a55fbb7Slm66018  *
25700a55fbb7Slm66018  * Arguments:
25710a55fbb7Slm66018  *	event	- Type of event (LDC_EVT_xxx) that triggered the callback
25720a55fbb7Slm66018  *	arg	- soft state pointer for this instance of the device driver.
25730a55fbb7Slm66018  *
25740a55fbb7Slm66018  * Return Code:
25750a55fbb7Slm66018  *	0	- Success
25760a55fbb7Slm66018  */
25771ae08745Sheppo static uint_t
25781ae08745Sheppo vdc_handle_cb(uint64_t event, caddr_t arg)
25791ae08745Sheppo {
25801ae08745Sheppo 	ldc_status_t	ldc_state;
25811ae08745Sheppo 	int		rv = 0;
25821ae08745Sheppo 
25831ae08745Sheppo 	vdc_t	*vdc = (vdc_t *)(void *)arg;
25841ae08745Sheppo 
25851ae08745Sheppo 	ASSERT(vdc != NULL);
25861ae08745Sheppo 
25871ae08745Sheppo 	PR1("%s[%d] event=%x seqID=%d\n",
25881ae08745Sheppo 			__func__, vdc->instance, event, vdc->seq_num);
25891ae08745Sheppo 
25901ae08745Sheppo 	/*
25911ae08745Sheppo 	 * Depending on the type of event that triggered this callback,
25921ae08745Sheppo 	 * we modify the handhske state or read the data.
25931ae08745Sheppo 	 *
25941ae08745Sheppo 	 * NOTE: not done as a switch() as event could be triggered by
25951ae08745Sheppo 	 * a state change and a read request. Also the ordering	of the
25961ae08745Sheppo 	 * check for the event types is deliberate.
25971ae08745Sheppo 	 */
25981ae08745Sheppo 	if (event & LDC_EVT_UP) {
25991ae08745Sheppo 		PR0("%s[%d] Received LDC_EVT_UP\n", __func__, vdc->instance);
26001ae08745Sheppo 
26011ae08745Sheppo 		/* get LDC state */
26021ae08745Sheppo 		rv = ldc_status(vdc->ldc_handle, &ldc_state);
26031ae08745Sheppo 		if (rv != 0) {
26041ae08745Sheppo 			cmn_err(CE_NOTE, "[%d] Couldn't get LDC status %d",
26051ae08745Sheppo 					vdc->instance, rv);
26060a55fbb7Slm66018 			mutex_enter(&vdc->lock);
26071ae08745Sheppo 			vdc_reset_connection(vdc, B_TRUE);
26080a55fbb7Slm66018 			mutex_exit(&vdc->lock);
26091ae08745Sheppo 			return (LDC_SUCCESS);
26101ae08745Sheppo 		}
26111ae08745Sheppo 
26121ae08745Sheppo 		/*
26131ae08745Sheppo 		 * Reset the transaction sequence numbers when LDC comes up.
26141ae08745Sheppo 		 * We then kick off the handshake negotiation with the vDisk
26151ae08745Sheppo 		 * server.
26161ae08745Sheppo 		 */
26171ae08745Sheppo 		mutex_enter(&vdc->lock);
26180a55fbb7Slm66018 		vdc->seq_num = 1;
26191ae08745Sheppo 		vdc->seq_num_reply = 0;
26201ae08745Sheppo 		vdc->ldc_state = ldc_state;
26211ae08745Sheppo 		ASSERT(ldc_state == LDC_UP);
26221ae08745Sheppo 		mutex_exit(&vdc->lock);
26231ae08745Sheppo 
26241ae08745Sheppo 		vdc_init_handshake_negotiation(vdc);
26251ae08745Sheppo 
26261ae08745Sheppo 		ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0);
26271ae08745Sheppo 	}
26281ae08745Sheppo 
26291ae08745Sheppo 	if (event & LDC_EVT_READ) {
26301ae08745Sheppo 		/*
26311ae08745Sheppo 		 * Wake up the worker thread to process the message
26321ae08745Sheppo 		 */
26331ae08745Sheppo 		mutex_enter(&vdc->msg_proc_lock);
26341ae08745Sheppo 		vdc->msg_pending = B_TRUE;
26351ae08745Sheppo 		cv_signal(&vdc->msg_proc_cv);
26361ae08745Sheppo 		mutex_exit(&vdc->msg_proc_lock);
26371ae08745Sheppo 
26381ae08745Sheppo 		ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0);
26391ae08745Sheppo 
26401ae08745Sheppo 		/* that's all we have to do - no need to handle DOWN/RESET */
26411ae08745Sheppo 		return (LDC_SUCCESS);
26421ae08745Sheppo 	}
26431ae08745Sheppo 
26441ae08745Sheppo 	if (event & LDC_EVT_RESET) {
26451ae08745Sheppo 		PR0("%s[%d] Recvd LDC RESET event\n", __func__, vdc->instance);
26460a55fbb7Slm66018 
26470a55fbb7Slm66018 		/* get LDC state */
26480a55fbb7Slm66018 		rv = ldc_status(vdc->ldc_handle, &ldc_state);
26490a55fbb7Slm66018 		if (rv != 0) {
26500a55fbb7Slm66018 			cmn_err(CE_NOTE, "[%d] Couldn't get LDC status %d",
26510a55fbb7Slm66018 					vdc->instance, rv);
26520a55fbb7Slm66018 			ldc_state = LDC_OPEN;
26530a55fbb7Slm66018 		}
26540a55fbb7Slm66018 		mutex_enter(&vdc->lock);
26550a55fbb7Slm66018 		vdc->ldc_state = ldc_state;
26560a55fbb7Slm66018 		vdc_reset_connection(vdc, B_FALSE);
26570a55fbb7Slm66018 		mutex_exit(&vdc->lock);
26580a55fbb7Slm66018 
26590a55fbb7Slm66018 		vdc_init_handshake_negotiation(vdc);
26601ae08745Sheppo 	}
26611ae08745Sheppo 
26621ae08745Sheppo 	if (event & LDC_EVT_DOWN) {
26631ae08745Sheppo 		PR0("%s[%d] Recvd LDC DOWN event\n", __func__, vdc->instance);
26641ae08745Sheppo 
26651ae08745Sheppo 		/* get LDC state */
26661ae08745Sheppo 		rv = ldc_status(vdc->ldc_handle, &ldc_state);
26671ae08745Sheppo 		if (rv != 0) {
26681ae08745Sheppo 			cmn_err(CE_NOTE, "[%d] Couldn't get LDC status %d",
26691ae08745Sheppo 					vdc->instance, rv);
26701ae08745Sheppo 			ldc_state = LDC_OPEN;
26711ae08745Sheppo 		}
26721ae08745Sheppo 		mutex_enter(&vdc->lock);
26731ae08745Sheppo 		vdc->ldc_state = ldc_state;
26741ae08745Sheppo 		vdc_reset_connection(vdc, B_TRUE);
26750a55fbb7Slm66018 		mutex_exit(&vdc->lock);
26761ae08745Sheppo 	}
26771ae08745Sheppo 
26781ae08745Sheppo 	if (event & ~(LDC_EVT_UP | LDC_EVT_RESET | LDC_EVT_DOWN | LDC_EVT_READ))
26791ae08745Sheppo 		cmn_err(CE_NOTE, "![%d] Unexpected LDC event (%lx) received",
26801ae08745Sheppo 				vdc->instance, event);
26811ae08745Sheppo 
26821ae08745Sheppo 	return (LDC_SUCCESS);
26831ae08745Sheppo }
26841ae08745Sheppo 
26851ae08745Sheppo /* -------------------------------------------------------------------------- */
26861ae08745Sheppo 
26871ae08745Sheppo /*
26881ae08745Sheppo  * The following functions process the incoming messages from vds
26891ae08745Sheppo  */
26901ae08745Sheppo 
26911ae08745Sheppo 
26920a55fbb7Slm66018 /*
26930a55fbb7Slm66018  * Function:
26940a55fbb7Slm66018  *	vdc_process_msg_thread()
26950a55fbb7Slm66018  *
26960a55fbb7Slm66018  * Description:
26970a55fbb7Slm66018  *
26980a55fbb7Slm66018  * Arguments:
26990a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
27000a55fbb7Slm66018  *
27010a55fbb7Slm66018  * Return Code:
27020a55fbb7Slm66018  *	None
27030a55fbb7Slm66018  */
27041ae08745Sheppo static void
27051ae08745Sheppo vdc_process_msg_thread(vdc_t *vdc)
27061ae08745Sheppo {
27071ae08745Sheppo 	int		status = 0;
27081ae08745Sheppo 	boolean_t	q_is_empty = B_TRUE;
27091ae08745Sheppo 
27101ae08745Sheppo 	ASSERT(vdc != NULL);
27111ae08745Sheppo 
27121ae08745Sheppo 	mutex_enter(&vdc->msg_proc_lock);
27131ae08745Sheppo 	PR0("%s[%d]: Starting\n", __func__, vdc->instance);
27141ae08745Sheppo 
27151ae08745Sheppo 	vdc->msg_proc_thr_state = VDC_THR_RUNNING;
27161ae08745Sheppo 
27171ae08745Sheppo 	while (vdc->msg_proc_thr_state == VDC_THR_RUNNING) {
27181ae08745Sheppo 
27191ae08745Sheppo 		PR1("%s[%d] Waiting\n", __func__, vdc->instance);
27200a55fbb7Slm66018 		while (!vdc->msg_pending)
27211ae08745Sheppo 			cv_wait(&vdc->msg_proc_cv, &vdc->msg_proc_lock);
27221ae08745Sheppo 
27231ae08745Sheppo 		PR1("%s[%d] Message Received\n", __func__, vdc->instance);
27241ae08745Sheppo 
27251ae08745Sheppo 		/* check if there is data */
27261ae08745Sheppo 		status = ldc_chkq(vdc->ldc_handle, &q_is_empty);
27271ae08745Sheppo 		if ((status != 0) &&
27281ae08745Sheppo 		    (vdc->msg_proc_thr_state == VDC_THR_RUNNING)) {
27291ae08745Sheppo 			cmn_err(CE_NOTE, "[%d] Unable to communicate with vDisk"
27301ae08745Sheppo 					" server. Cannot check LDC queue: %d",
27311ae08745Sheppo 					vdc->instance, status);
27321ae08745Sheppo 			mutex_enter(&vdc->lock);
27330a55fbb7Slm66018 			vdc_reset_connection(vdc, B_FALSE);
27341ae08745Sheppo 			mutex_exit(&vdc->lock);
27351ae08745Sheppo 			vdc->msg_proc_thr_state = VDC_THR_STOP;
27361ae08745Sheppo 			continue;
27371ae08745Sheppo 		}
27381ae08745Sheppo 
27390a55fbb7Slm66018 		if (!q_is_empty) {
27401ae08745Sheppo 			PR1("%s: new pkt(s) available\n", __func__);
27411ae08745Sheppo 			vdc_process_msg(vdc);
27421ae08745Sheppo 		}
27431ae08745Sheppo 
27441ae08745Sheppo 		vdc->msg_pending = B_FALSE;
27451ae08745Sheppo 	}
27461ae08745Sheppo 
27471ae08745Sheppo 	PR0("Message processing thread stopped\n");
27481ae08745Sheppo 	vdc->msg_pending = B_FALSE;
27491ae08745Sheppo 	vdc->msg_proc_thr_state = VDC_THR_DONE;
27501ae08745Sheppo 	cv_signal(&vdc->msg_proc_cv);
27511ae08745Sheppo 	mutex_exit(&vdc->msg_proc_lock);
27521ae08745Sheppo 	thread_exit();
27531ae08745Sheppo }
27541ae08745Sheppo 
27551ae08745Sheppo 
27561ae08745Sheppo /*
27571ae08745Sheppo  * Function:
27581ae08745Sheppo  *	vdc_process_msg()
27591ae08745Sheppo  *
27601ae08745Sheppo  * Description:
27611ae08745Sheppo  *	This function is called by the message processing thread each time it
27621ae08745Sheppo  *	is triggered when LDC sends an interrupt to indicate that there are
27631ae08745Sheppo  *	more packets on the queue. When it is called it will continue to loop
27641ae08745Sheppo  *	and read the messages until there are no more left of the queue. If it
27651ae08745Sheppo  *	encounters an invalid sized message it will drop it and check the next
27661ae08745Sheppo  *	message.
27671ae08745Sheppo  *
27681ae08745Sheppo  * Arguments:
27691ae08745Sheppo  *	arg	- soft state pointer for this instance of the device driver.
27701ae08745Sheppo  *
27711ae08745Sheppo  * Return Code:
27721ae08745Sheppo  *	None.
27731ae08745Sheppo  */
27741ae08745Sheppo static void
27751ae08745Sheppo vdc_process_msg(void *arg)
27761ae08745Sheppo {
27771ae08745Sheppo 	vdc_t		*vdc = (vdc_t *)(void *)arg;
27781ae08745Sheppo 	vio_msg_t	vio_msg;
27791ae08745Sheppo 	size_t		nbytes = sizeof (vio_msg);
27801ae08745Sheppo 	int		status;
27811ae08745Sheppo 
27821ae08745Sheppo 	ASSERT(vdc != NULL);
27831ae08745Sheppo 
27841ae08745Sheppo 	mutex_enter(&vdc->lock);
27851ae08745Sheppo 
27861ae08745Sheppo 	PR1("%s\n", __func__);
27871ae08745Sheppo 
27881ae08745Sheppo 	for (;;) {
27891ae08745Sheppo 
27901ae08745Sheppo 		/* read all messages - until no more left */
27911ae08745Sheppo 		status = ldc_read(vdc->ldc_handle, (caddr_t)&vio_msg, &nbytes);
27921ae08745Sheppo 
27931ae08745Sheppo 		if (status) {
27941ae08745Sheppo 			vdc_msg("%s: ldc_read() failed = %d", __func__, status);
27951ae08745Sheppo 
27961ae08745Sheppo 			/* if status is ECONNRESET --- reset vdc state */
27971ae08745Sheppo 			if (status == EIO || status == ECONNRESET) {
27980a55fbb7Slm66018 				vdc_reset_connection(vdc, B_TRUE);
27991ae08745Sheppo 			}
28001ae08745Sheppo 
28011ae08745Sheppo 			mutex_exit(&vdc->lock);
28021ae08745Sheppo 			return;
28031ae08745Sheppo 		}
28041ae08745Sheppo 
28051ae08745Sheppo 		if ((nbytes > 0) && (nbytes < sizeof (vio_msg_tag_t))) {
28061ae08745Sheppo 			cmn_err(CE_CONT, "![%d] Expect %lu bytes; recv'd %lu\n",
28071ae08745Sheppo 				vdc->instance, sizeof (vio_msg_tag_t), nbytes);
28081ae08745Sheppo 			mutex_exit(&vdc->lock);
28091ae08745Sheppo 			return;
28101ae08745Sheppo 		}
28111ae08745Sheppo 
28121ae08745Sheppo 		if (nbytes == 0) {
28131ae08745Sheppo 			PR2("%s[%d]: ldc_read() done..\n",
28141ae08745Sheppo 					__func__, vdc->instance);
28151ae08745Sheppo 			mutex_exit(&vdc->lock);
28161ae08745Sheppo 			return;
28171ae08745Sheppo 		}
28181ae08745Sheppo 
28191ae08745Sheppo 		PR1("%s[%d] (%x/%x/%x)\n", __func__, vdc->instance,
28201ae08745Sheppo 		    vio_msg.tag.vio_msgtype,
28211ae08745Sheppo 		    vio_msg.tag.vio_subtype,
28221ae08745Sheppo 		    vio_msg.tag.vio_subtype_env);
28231ae08745Sheppo 
28241ae08745Sheppo 		/*
28251ae08745Sheppo 		 * Verify the Session ID of the message
28261ae08745Sheppo 		 *
28271ae08745Sheppo 		 * Every message after the Version has been negotiated should
28281ae08745Sheppo 		 * have the correct session ID set.
28291ae08745Sheppo 		 */
28301ae08745Sheppo 		if ((vio_msg.tag.vio_sid != vdc->session_id) &&
28311ae08745Sheppo 		    (vio_msg.tag.vio_subtype_env != VIO_VER_INFO)) {
28320a55fbb7Slm66018 			cmn_err(CE_NOTE, "[%d] Invalid SID 0x%x, expect 0x%lx",
28330a55fbb7Slm66018 				vdc->instance, vio_msg.tag.vio_sid,
28341ae08745Sheppo 				vdc->session_id);
28351ae08745Sheppo 			vdc_reset_connection(vdc, B_FALSE);
28361ae08745Sheppo 			mutex_exit(&vdc->lock);
28371ae08745Sheppo 			return;
28381ae08745Sheppo 		}
28391ae08745Sheppo 
28401ae08745Sheppo 		switch (vio_msg.tag.vio_msgtype) {
28411ae08745Sheppo 		case VIO_TYPE_CTRL:
28421ae08745Sheppo 			status = vdc_process_ctrl_msg(vdc, vio_msg);
28431ae08745Sheppo 			break;
28441ae08745Sheppo 		case VIO_TYPE_DATA:
28451ae08745Sheppo 			status = vdc_process_data_msg(vdc, vio_msg);
28461ae08745Sheppo 			break;
28471ae08745Sheppo 		case VIO_TYPE_ERR:
28481ae08745Sheppo 			status = vdc_process_err_msg(vdc, vio_msg);
28491ae08745Sheppo 			break;
28501ae08745Sheppo 		default:
28511ae08745Sheppo 			PR1("%s", __func__);
28521ae08745Sheppo 			status = EINVAL;
28531ae08745Sheppo 			break;
28541ae08745Sheppo 		}
28551ae08745Sheppo 
28561ae08745Sheppo 		if (status != 0) {
28571ae08745Sheppo 			PR0("%s[%d] Error (%d) occcurred processing msg\n",
28581ae08745Sheppo 					__func__, vdc->instance, status);
28591ae08745Sheppo 			vdc_reset_connection(vdc, B_FALSE);
28601ae08745Sheppo 		}
28611ae08745Sheppo 	}
28621ae08745Sheppo 	_NOTE(NOTREACHED)
28631ae08745Sheppo }
28641ae08745Sheppo 
28651ae08745Sheppo /*
28661ae08745Sheppo  * Function:
28671ae08745Sheppo  *	vdc_process_ctrl_msg()
28681ae08745Sheppo  *
28691ae08745Sheppo  * Description:
28701ae08745Sheppo  *	This function is called by the message processing thread each time
28711ae08745Sheppo  *	an LDC message with a msgtype of VIO_TYPE_CTRL is received.
28721ae08745Sheppo  *
28731ae08745Sheppo  * Arguments:
28741ae08745Sheppo  *	vdc	- soft state pointer for this instance of the device driver.
28751ae08745Sheppo  *	msg	- the LDC message sent by vds
28761ae08745Sheppo  *
28771ae08745Sheppo  * Return Codes:
28781ae08745Sheppo  *	0	- Success.
28791ae08745Sheppo  *	EPROTO	- A message was received which shouldn't have happened according
28801ae08745Sheppo  *		  to the protocol
28811ae08745Sheppo  *	ENOTSUP	- An action which is allowed according to the protocol but which
28821ae08745Sheppo  *		  isn't (or doesn't need to be) implemented yet.
28831ae08745Sheppo  *	EINVAL	- An invalid value was returned as part of a message.
28841ae08745Sheppo  */
28851ae08745Sheppo static int
28861ae08745Sheppo vdc_process_ctrl_msg(vdc_t *vdc, vio_msg_t msg)
28871ae08745Sheppo {
28881ae08745Sheppo 	int			status = -1;
28891ae08745Sheppo 
28901ae08745Sheppo 	ASSERT(msg.tag.vio_msgtype == VIO_TYPE_CTRL);
28911ae08745Sheppo 	ASSERT(vdc != NULL);
28921ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
28931ae08745Sheppo 
28941ae08745Sheppo 	/* Depending on which state we are in; process the message */
28951ae08745Sheppo 	switch (vdc->state) {
28961ae08745Sheppo 	case VD_STATE_INIT:
28970a55fbb7Slm66018 		status = vdc_handle_ver_msg(vdc, (vio_ver_msg_t *)&msg);
28980a55fbb7Slm66018 		break;
28990a55fbb7Slm66018 
29000a55fbb7Slm66018 	case VD_STATE_VER:
29010a55fbb7Slm66018 		status = vdc_handle_attr_msg(vdc, (vd_attr_msg_t *)&msg);
29020a55fbb7Slm66018 		break;
29030a55fbb7Slm66018 
29040a55fbb7Slm66018 	case VD_STATE_ATTR:
29050a55fbb7Slm66018 		status = vdc_handle_dring_reg_msg(vdc,
29060a55fbb7Slm66018 				(vio_dring_reg_msg_t *)&msg);
29070a55fbb7Slm66018 		break;
29080a55fbb7Slm66018 
29090a55fbb7Slm66018 	case VD_STATE_RDX:
29100a55fbb7Slm66018 		if (msg.tag.vio_subtype_env != VIO_RDX) {
29111ae08745Sheppo 			status = EPROTO;
29121ae08745Sheppo 			break;
29131ae08745Sheppo 		}
29141ae08745Sheppo 
29150a55fbb7Slm66018 		PR0("%s: Received RDX - handshake successful\n", __func__);
29161ae08745Sheppo 
29170a55fbb7Slm66018 		vdc->hshake_cnt = 0;	/* reset failed handshake count */
29180a55fbb7Slm66018 		status = 0;
29190a55fbb7Slm66018 		vdc->state = VD_STATE_DATA;
29200a55fbb7Slm66018 
29210a55fbb7Slm66018 		cv_broadcast(&vdc->attach_cv);
29220a55fbb7Slm66018 		break;
29230a55fbb7Slm66018 
29240a55fbb7Slm66018 	case VD_STATE_DATA:
29250a55fbb7Slm66018 	default:
29260a55fbb7Slm66018 		cmn_err(CE_NOTE, "[%d] Unexpected handshake state %d",
29270a55fbb7Slm66018 				vdc->instance, vdc->state);
29281ae08745Sheppo 		status = EPROTO;
29291ae08745Sheppo 		break;
29300a55fbb7Slm66018 	}
29311ae08745Sheppo 
29320a55fbb7Slm66018 	return (status);
29330a55fbb7Slm66018 }
29340a55fbb7Slm66018 
29350a55fbb7Slm66018 
29360a55fbb7Slm66018 /*
29370a55fbb7Slm66018  * Function:
29380a55fbb7Slm66018  *	vdc_process_data_msg()
29390a55fbb7Slm66018  *
29400a55fbb7Slm66018  * Description:
29410a55fbb7Slm66018  *	This function is called by the message processing thread each time
29420a55fbb7Slm66018  *	a message with a msgtype of VIO_TYPE_DATA is received. It will either
29430a55fbb7Slm66018  *	be an ACK or NACK from vds[1] which vdc handles as follows.
29440a55fbb7Slm66018  *		ACK	- wake up the waiting thread
29450a55fbb7Slm66018  *		NACK	- resend any messages necessary
29460a55fbb7Slm66018  *
29470a55fbb7Slm66018  *	[1] Although the message format allows it, vds should not send a
29480a55fbb7Slm66018  *	    VIO_SUBTYPE_INFO message to vdc asking it to read data; if for
29490a55fbb7Slm66018  *	    some bizarre reason it does, vdc will reset the connection.
29500a55fbb7Slm66018  *
29510a55fbb7Slm66018  * Arguments:
29520a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
29530a55fbb7Slm66018  *	msg	- the LDC message sent by vds
29540a55fbb7Slm66018  *
29550a55fbb7Slm66018  * Return Code:
29560a55fbb7Slm66018  *	0	- Success.
29570a55fbb7Slm66018  *	> 0	- error value returned by LDC
29580a55fbb7Slm66018  */
29590a55fbb7Slm66018 static int
29600a55fbb7Slm66018 vdc_process_data_msg(vdc_t *vdc, vio_msg_t msg)
29610a55fbb7Slm66018 {
29620a55fbb7Slm66018 	int			status = 0;
2963*d10e4ef2Snarayan 	vdc_local_desc_t	*ldep = NULL;
29640a55fbb7Slm66018 	vio_dring_msg_t		*dring_msg = NULL;
29650a55fbb7Slm66018 	uint_t			num_msgs;
29660a55fbb7Slm66018 	uint_t			start;
29670a55fbb7Slm66018 	uint_t			end;
29680a55fbb7Slm66018 	uint_t			i;
29690a55fbb7Slm66018 
29700a55fbb7Slm66018 	ASSERT(msg.tag.vio_msgtype == VIO_TYPE_DATA);
29710a55fbb7Slm66018 	ASSERT(vdc != NULL);
29720a55fbb7Slm66018 	ASSERT(mutex_owned(&vdc->lock));
29730a55fbb7Slm66018 
29740a55fbb7Slm66018 	dring_msg = (vio_dring_msg_t *)&msg;
29750a55fbb7Slm66018 
29760a55fbb7Slm66018 	/*
29770a55fbb7Slm66018 	 * Check to see if the message has bogus data
29780a55fbb7Slm66018 	 */
29790a55fbb7Slm66018 	start = dring_msg->start_idx;
29800a55fbb7Slm66018 	end = dring_msg->end_idx;
29810a55fbb7Slm66018 	if ((start >= VD_DRING_LEN) || (end >= VD_DRING_LEN)) {
29820a55fbb7Slm66018 		vdc_msg("%s: Bogus ACK data : start %d, end %d\n",
29830a55fbb7Slm66018 			__func__, start, end);
29840a55fbb7Slm66018 		return (EPROTO);
29850a55fbb7Slm66018 	}
29860a55fbb7Slm66018 
2987*d10e4ef2Snarayan 	DTRACE_IO2(recv, vio_dring_msg_t, dring_msg, vdc_t *, vdc);
2988*d10e4ef2Snarayan 
29890a55fbb7Slm66018 	/*
29900a55fbb7Slm66018 	 * calculate the number of messages that vds ACK'ed
29910a55fbb7Slm66018 	 *
29920a55fbb7Slm66018 	 * Assumes, (like the rest of vdc) that there is a 1:1 mapping
29930a55fbb7Slm66018 	 * between requests and Dring entries.
29940a55fbb7Slm66018 	 */
29950a55fbb7Slm66018 	num_msgs = (end >= start) ?
29960a55fbb7Slm66018 			(end - start + 1) :
29970a55fbb7Slm66018 			(VD_DRING_LEN - start + end + 1);
29980a55fbb7Slm66018 
29990a55fbb7Slm66018 	/*
30000a55fbb7Slm66018 	 * Verify that the sequence number is what vdc expects.
30010a55fbb7Slm66018 	 */
30020a55fbb7Slm66018 	if (!vdc_verify_seq_num(vdc, dring_msg, num_msgs)) {
30030a55fbb7Slm66018 		return (ENXIO);
30040a55fbb7Slm66018 	}
30050a55fbb7Slm66018 
30060a55fbb7Slm66018 	/*
30070a55fbb7Slm66018 	 * Wake the thread waiting for each DRing entry ACK'ed
30080a55fbb7Slm66018 	 */
30090a55fbb7Slm66018 	for (i = 0; i < num_msgs; i++) {
3010*d10e4ef2Snarayan 		int operation;
30110a55fbb7Slm66018 		int idx = (start + i) % VD_DRING_LEN;
30120a55fbb7Slm66018 
3013*d10e4ef2Snarayan 		ldep = &vdc->local_dring[idx];
3014*d10e4ef2Snarayan 		mutex_enter(&ldep->lock);
3015*d10e4ef2Snarayan 		operation = ldep->dep->payload.operation;
3016*d10e4ef2Snarayan 		if ((operation == VD_OP_BREAD) || (operation == VD_OP_BWRITE)) {
3017*d10e4ef2Snarayan 			/*
3018*d10e4ef2Snarayan 			 * The vDisk server responds when it accepts a
3019*d10e4ef2Snarayan 			 * descriptor so we continue looping and process
3020*d10e4ef2Snarayan 			 * it when it sends the message that it is done.
3021*d10e4ef2Snarayan 			 */
3022*d10e4ef2Snarayan 			if (ldep->dep->hdr.dstate != VIO_DESC_DONE) {
3023*d10e4ef2Snarayan 				mutex_exit(&ldep->lock);
3024*d10e4ef2Snarayan 				continue;
3025*d10e4ef2Snarayan 			}
3026*d10e4ef2Snarayan 			bioerror(ldep->buf, ldep->dep->payload.status);
3027*d10e4ef2Snarayan 			biodone(ldep->buf);
3028*d10e4ef2Snarayan 
3029*d10e4ef2Snarayan 			DTRACE_IO2(vdone, buf_t *, ldep->buf, vdc_t *, vdc);
3030*d10e4ef2Snarayan 
3031*d10e4ef2Snarayan 			/* Clear the DRing entry */
3032*d10e4ef2Snarayan 			status = vdc_depopulate_descriptor(vdc, idx);
3033*d10e4ef2Snarayan 		}
3034*d10e4ef2Snarayan 		cv_signal(&ldep->cv);
3035*d10e4ef2Snarayan 		mutex_exit(&ldep->lock);
30360a55fbb7Slm66018 	}
30370a55fbb7Slm66018 
30380a55fbb7Slm66018 	if (msg.tag.vio_subtype == VIO_SUBTYPE_NACK) {
30390a55fbb7Slm66018 		PR0("%s: DATA NACK\n", __func__);
30400a55fbb7Slm66018 		VDC_DUMP_DRING_MSG(dring_msg);
30410a55fbb7Slm66018 		vdc_reset_connection(vdc, B_FALSE);
30420a55fbb7Slm66018 
30430a55fbb7Slm66018 		/* we need to drop the lock to trigger the handshake */
30440a55fbb7Slm66018 		mutex_exit(&vdc->lock);
30450a55fbb7Slm66018 		vdc_init_handshake_negotiation(vdc);
30460a55fbb7Slm66018 		mutex_enter(&vdc->lock);
30470a55fbb7Slm66018 	} else if (msg.tag.vio_subtype == VIO_SUBTYPE_INFO) {
30480a55fbb7Slm66018 		status = EPROTO;
30490a55fbb7Slm66018 	}
30500a55fbb7Slm66018 
30510a55fbb7Slm66018 	return (status);
30520a55fbb7Slm66018 }
30530a55fbb7Slm66018 
30540a55fbb7Slm66018 /*
30550a55fbb7Slm66018  * Function:
30560a55fbb7Slm66018  *	vdc_process_err_msg()
30570a55fbb7Slm66018  *
30580a55fbb7Slm66018  * NOTE: No error messages are used as part of the vDisk protocol
30590a55fbb7Slm66018  */
30600a55fbb7Slm66018 static int
30610a55fbb7Slm66018 vdc_process_err_msg(vdc_t *vdc, vio_msg_t msg)
30620a55fbb7Slm66018 {
30630a55fbb7Slm66018 	_NOTE(ARGUNUSED(vdc))
30640a55fbb7Slm66018 	_NOTE(ARGUNUSED(msg))
30650a55fbb7Slm66018 
30660a55fbb7Slm66018 	ASSERT(msg.tag.vio_msgtype == VIO_TYPE_ERR);
30670a55fbb7Slm66018 	cmn_err(CE_NOTE, "[%d] Got an ERR msg", vdc->instance);
30680a55fbb7Slm66018 
30690a55fbb7Slm66018 	return (ENOTSUP);
30700a55fbb7Slm66018 }
30710a55fbb7Slm66018 
30720a55fbb7Slm66018 /*
30730a55fbb7Slm66018  * Function:
30740a55fbb7Slm66018  *	vdc_handle_ver_msg()
30750a55fbb7Slm66018  *
30760a55fbb7Slm66018  * Description:
30770a55fbb7Slm66018  *
30780a55fbb7Slm66018  * Arguments:
30790a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
30800a55fbb7Slm66018  *	ver_msg	- LDC message sent by vDisk server
30810a55fbb7Slm66018  *
30820a55fbb7Slm66018  * Return Code:
30830a55fbb7Slm66018  *	0	- Success
30840a55fbb7Slm66018  */
30850a55fbb7Slm66018 static int
30860a55fbb7Slm66018 vdc_handle_ver_msg(vdc_t *vdc, vio_ver_msg_t *ver_msg)
30870a55fbb7Slm66018 {
30880a55fbb7Slm66018 	int status = 0;
30890a55fbb7Slm66018 
30900a55fbb7Slm66018 	ASSERT(vdc != NULL);
30910a55fbb7Slm66018 	ASSERT(mutex_owned(&vdc->lock));
30920a55fbb7Slm66018 
30930a55fbb7Slm66018 	if (ver_msg->tag.vio_subtype_env != VIO_VER_INFO) {
30940a55fbb7Slm66018 		return (EPROTO);
30950a55fbb7Slm66018 	}
30960a55fbb7Slm66018 
30970a55fbb7Slm66018 	if (ver_msg->dev_class != VDEV_DISK_SERVER) {
30980a55fbb7Slm66018 		return (EINVAL);
30990a55fbb7Slm66018 	}
31000a55fbb7Slm66018 
31010a55fbb7Slm66018 	switch (ver_msg->tag.vio_subtype) {
31020a55fbb7Slm66018 	case VIO_SUBTYPE_ACK:
31030a55fbb7Slm66018 		/*
31040a55fbb7Slm66018 		 * We check to see if the version returned is indeed supported
31050a55fbb7Slm66018 		 * (The server may have also adjusted the minor number downwards
31060a55fbb7Slm66018 		 * and if so 'ver_msg' will contain the actual version agreed)
31070a55fbb7Slm66018 		 */
31080a55fbb7Slm66018 		if (vdc_is_supported_version(ver_msg)) {
31090a55fbb7Slm66018 			vdc->ver.major = ver_msg->ver_major;
31100a55fbb7Slm66018 			vdc->ver.minor = ver_msg->ver_minor;
31110a55fbb7Slm66018 			ASSERT(vdc->ver.major > 0);
31120a55fbb7Slm66018 
31130a55fbb7Slm66018 			vdc->state = VD_STATE_VER;
31140a55fbb7Slm66018 			status = vdc_init_attr_negotiation(vdc);
31150a55fbb7Slm66018 		} else {
31160a55fbb7Slm66018 			status = EPROTO;
31170a55fbb7Slm66018 		}
31180a55fbb7Slm66018 		break;
31190a55fbb7Slm66018 
31200a55fbb7Slm66018 	case VIO_SUBTYPE_NACK:
31210a55fbb7Slm66018 		/*
31220a55fbb7Slm66018 		 * call vdc_is_supported_version() which will return the next
31230a55fbb7Slm66018 		 * supported version (if any) in 'ver_msg'
31240a55fbb7Slm66018 		 */
31250a55fbb7Slm66018 		(void) vdc_is_supported_version(ver_msg);
31260a55fbb7Slm66018 		if (ver_msg->ver_major > 0) {
31270a55fbb7Slm66018 			size_t len = sizeof (*ver_msg);
31280a55fbb7Slm66018 
31290a55fbb7Slm66018 			ASSERT(vdc->ver.major > 0);
31300a55fbb7Slm66018 
31310a55fbb7Slm66018 			/* reset the necessary fields and resend */
31320a55fbb7Slm66018 			ver_msg->tag.vio_subtype = VIO_SUBTYPE_INFO;
31330a55fbb7Slm66018 			ver_msg->dev_class = VDEV_DISK;
31340a55fbb7Slm66018 
31350a55fbb7Slm66018 			status = vdc_send(vdc, (caddr_t)ver_msg, &len);
31360a55fbb7Slm66018 			PR0("[%d] Resend VER info (LDC status = %d)\n",
31370a55fbb7Slm66018 					vdc->instance, status);
31380a55fbb7Slm66018 			if (len != sizeof (*ver_msg))
31390a55fbb7Slm66018 				status = EBADMSG;
31400a55fbb7Slm66018 		} else {
31410a55fbb7Slm66018 			cmn_err(CE_NOTE, "[%d] No common version with "
31420a55fbb7Slm66018 					"vDisk server", vdc->instance);
31430a55fbb7Slm66018 			status = ENOTSUP;
31440a55fbb7Slm66018 		}
31450a55fbb7Slm66018 
31460a55fbb7Slm66018 		break;
31471ae08745Sheppo 	case VIO_SUBTYPE_INFO:
31481ae08745Sheppo 		/*
31491ae08745Sheppo 		 * Handle the case where vds starts handshake
31501ae08745Sheppo 		 * (for now only vdc is the instigatior)
31511ae08745Sheppo 		 */
31521ae08745Sheppo 		status = ENOTSUP;
31531ae08745Sheppo 		break;
31541ae08745Sheppo 
31551ae08745Sheppo 	default:
31560a55fbb7Slm66018 		status = EINVAL;
31571ae08745Sheppo 		break;
31581ae08745Sheppo 	}
31591ae08745Sheppo 
31600a55fbb7Slm66018 	return (status);
31610a55fbb7Slm66018 }
31620a55fbb7Slm66018 
31630a55fbb7Slm66018 /*
31640a55fbb7Slm66018  * Function:
31650a55fbb7Slm66018  *	vdc_handle_attr_msg()
31660a55fbb7Slm66018  *
31670a55fbb7Slm66018  * Description:
31680a55fbb7Slm66018  *
31690a55fbb7Slm66018  * Arguments:
31700a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
31710a55fbb7Slm66018  *	attr_msg	- LDC message sent by vDisk server
31720a55fbb7Slm66018  *
31730a55fbb7Slm66018  * Return Code:
31740a55fbb7Slm66018  *	0	- Success
31750a55fbb7Slm66018  */
31760a55fbb7Slm66018 static int
31770a55fbb7Slm66018 vdc_handle_attr_msg(vdc_t *vdc, vd_attr_msg_t *attr_msg)
31780a55fbb7Slm66018 {
31790a55fbb7Slm66018 	int status = 0;
31800a55fbb7Slm66018 
31810a55fbb7Slm66018 	ASSERT(vdc != NULL);
31820a55fbb7Slm66018 	ASSERT(mutex_owned(&vdc->lock));
31830a55fbb7Slm66018 
31840a55fbb7Slm66018 	if (attr_msg->tag.vio_subtype_env != VIO_ATTR_INFO) {
31850a55fbb7Slm66018 		return (EPROTO);
31860a55fbb7Slm66018 	}
31870a55fbb7Slm66018 
31880a55fbb7Slm66018 	switch (attr_msg->tag.vio_subtype) {
31891ae08745Sheppo 	case VIO_SUBTYPE_ACK:
31901ae08745Sheppo 		/*
31911ae08745Sheppo 		 * We now verify the attributes sent by vds.
31921ae08745Sheppo 		 */
31931ae08745Sheppo 		vdc->vdisk_size = attr_msg->vdisk_size;
31941ae08745Sheppo 		vdc->vdisk_type = attr_msg->vdisk_type;
31951ae08745Sheppo 
31961ae08745Sheppo 		if ((attr_msg->max_xfer_sz != vdc->max_xfer_sz) ||
31971ae08745Sheppo 		    (attr_msg->vdisk_block_size != vdc->block_size)) {
31981ae08745Sheppo 			/*
31991ae08745Sheppo 			 * Future support: step down to the block size
32001ae08745Sheppo 			 * and max transfer size suggested by the
32011ae08745Sheppo 			 * server. (If this value is less than 128K
32021ae08745Sheppo 			 * then multiple Dring entries per request
32031ae08745Sheppo 			 * would need to be implemented)
32041ae08745Sheppo 			 */
32051ae08745Sheppo 			cmn_err(CE_NOTE, "[%d] Couldn't process block "
32060a55fbb7Slm66018 				"attributes from vds", vdc->instance);
32071ae08745Sheppo 			status = EINVAL;
32081ae08745Sheppo 			break;
32091ae08745Sheppo 		}
32101ae08745Sheppo 
32111ae08745Sheppo 		if ((attr_msg->xfer_mode != VIO_DRING_MODE) ||
32121ae08745Sheppo 		    (attr_msg->vdisk_size > INT64_MAX) ||
32131ae08745Sheppo 		    (attr_msg->vdisk_type > VD_DISK_TYPE_DISK)) {
32141ae08745Sheppo 			vdc_msg("%s[%d] Couldn't process attrs "
32151ae08745Sheppo 			    "from vds", __func__, vdc->instance);
32161ae08745Sheppo 			status = EINVAL;
32171ae08745Sheppo 			break;
32181ae08745Sheppo 		}
32191ae08745Sheppo 
32201ae08745Sheppo 		vdc->state = VD_STATE_ATTR;
32211ae08745Sheppo 		status = vdc_init_dring_negotiate(vdc);
32221ae08745Sheppo 		break;
32231ae08745Sheppo 
32241ae08745Sheppo 	case VIO_SUBTYPE_NACK:
32251ae08745Sheppo 		/*
32261ae08745Sheppo 		 * vds could not handle the attributes we sent so we
32271ae08745Sheppo 		 * stop negotiating.
32281ae08745Sheppo 		 */
32291ae08745Sheppo 		status = EPROTO;
32301ae08745Sheppo 		break;
32311ae08745Sheppo 
32321ae08745Sheppo 	case VIO_SUBTYPE_INFO:
32331ae08745Sheppo 		/*
32341ae08745Sheppo 		 * Handle the case where vds starts the handshake
32351ae08745Sheppo 		 * (for now; vdc is the only supported instigatior)
32361ae08745Sheppo 		 */
32371ae08745Sheppo 		status = ENOTSUP;
32381ae08745Sheppo 		break;
32391ae08745Sheppo 
32401ae08745Sheppo 	default:
32411ae08745Sheppo 		status = ENOTSUP;
32421ae08745Sheppo 		break;
32431ae08745Sheppo 	}
32441ae08745Sheppo 
32450a55fbb7Slm66018 	return (status);
32461ae08745Sheppo }
32471ae08745Sheppo 
32480a55fbb7Slm66018 /*
32490a55fbb7Slm66018  * Function:
32500a55fbb7Slm66018  *	vdc_handle_dring_reg_msg()
32510a55fbb7Slm66018  *
32520a55fbb7Slm66018  * Description:
32530a55fbb7Slm66018  *
32540a55fbb7Slm66018  * Arguments:
32550a55fbb7Slm66018  *	vdc		- soft state pointer for this instance of the driver.
32560a55fbb7Slm66018  *	dring_msg	- LDC message sent by vDisk server
32570a55fbb7Slm66018  *
32580a55fbb7Slm66018  * Return Code:
32590a55fbb7Slm66018  *	0	- Success
32600a55fbb7Slm66018  */
32610a55fbb7Slm66018 static int
32620a55fbb7Slm66018 vdc_handle_dring_reg_msg(vdc_t *vdc, vio_dring_reg_msg_t *dring_msg)
32630a55fbb7Slm66018 {
32640a55fbb7Slm66018 	int		status = 0;
32650a55fbb7Slm66018 	vio_rdx_msg_t	msg = {0};
32660a55fbb7Slm66018 	size_t		msglen = sizeof (msg);
32671ae08745Sheppo 
32680a55fbb7Slm66018 	ASSERT(vdc != NULL);
32690a55fbb7Slm66018 	ASSERT(mutex_owned(&vdc->lock));
32700a55fbb7Slm66018 
32710a55fbb7Slm66018 	if (dring_msg->tag.vio_subtype_env != VIO_DRING_REG) {
32720a55fbb7Slm66018 		return (EPROTO);
32730a55fbb7Slm66018 	}
32740a55fbb7Slm66018 
32750a55fbb7Slm66018 	switch (dring_msg->tag.vio_subtype) {
32760a55fbb7Slm66018 	case VIO_SUBTYPE_ACK:
32771ae08745Sheppo 		/* save the received dring_ident */
32781ae08745Sheppo 		vdc->dring_ident = dring_msg->dring_ident;
32791ae08745Sheppo 		PR0("%s[%d] Received dring ident=0x%lx\n",
32801ae08745Sheppo 			__func__, vdc->instance, vdc->dring_ident);
32811ae08745Sheppo 
32821ae08745Sheppo 		/*
32831ae08745Sheppo 		 * Send an RDX message to vds to indicate we are ready
32841ae08745Sheppo 		 * to send data
32851ae08745Sheppo 		 */
32861ae08745Sheppo 		msg.tag.vio_msgtype = VIO_TYPE_CTRL;
32871ae08745Sheppo 		msg.tag.vio_subtype = VIO_SUBTYPE_INFO;
32881ae08745Sheppo 		msg.tag.vio_subtype_env = VIO_RDX;
32891ae08745Sheppo 		msg.tag.vio_sid = vdc->session_id;
32900a55fbb7Slm66018 		status = vdc_send(vdc, (caddr_t)&msg, &msglen);
32911ae08745Sheppo 		if (status != 0) {
32921ae08745Sheppo 			cmn_err(CE_NOTE, "[%d] Failed to send RDX"
32931ae08745Sheppo 				" message (%d)", vdc->instance, status);
32941ae08745Sheppo 			break;
32951ae08745Sheppo 		}
32961ae08745Sheppo 
32971ae08745Sheppo 		vdc->state = VD_STATE_RDX;
32981ae08745Sheppo 		break;
32991ae08745Sheppo 
33001ae08745Sheppo 	case VIO_SUBTYPE_NACK:
33011ae08745Sheppo 		/*
33021ae08745Sheppo 		 * vds could not handle the DRing info we sent so we
33031ae08745Sheppo 		 * stop negotiating.
33041ae08745Sheppo 		 */
33051ae08745Sheppo 		cmn_err(CE_CONT, "server could not register DRing\n");
33061ae08745Sheppo 		vdc_reset_connection(vdc, B_FALSE);
33071ae08745Sheppo 		vdc_destroy_descriptor_ring(vdc);
33081ae08745Sheppo 		status = EPROTO;
33091ae08745Sheppo 		break;
33101ae08745Sheppo 
33111ae08745Sheppo 	case VIO_SUBTYPE_INFO:
33121ae08745Sheppo 		/*
33131ae08745Sheppo 		 * Handle the case where vds starts handshake
33141ae08745Sheppo 		 * (for now only vdc is the instigatior)
33151ae08745Sheppo 		 */
33161ae08745Sheppo 		status = ENOTSUP;
33171ae08745Sheppo 		break;
33181ae08745Sheppo 	default:
33191ae08745Sheppo 		status = ENOTSUP;
33201ae08745Sheppo 	}
33211ae08745Sheppo 
33221ae08745Sheppo 	return (status);
33231ae08745Sheppo }
33241ae08745Sheppo 
33251ae08745Sheppo /*
33261ae08745Sheppo  * Function:
33271ae08745Sheppo  *	vdc_verify_seq_num()
33281ae08745Sheppo  *
33291ae08745Sheppo  * Description:
33301ae08745Sheppo  *	This functions verifies that the sequence number sent back by vds with
33311ae08745Sheppo  *	the latest message correctly follows the last request processed.
33321ae08745Sheppo  *
33331ae08745Sheppo  * Arguments:
33341ae08745Sheppo  *	vdc		- soft state pointer for this instance of the driver.
33351ae08745Sheppo  *	dring_msg	- pointer to the LDC message sent by vds
33361ae08745Sheppo  *	num_msgs	- the number of requests being acknowledged
33371ae08745Sheppo  *
33381ae08745Sheppo  * Return Code:
33391ae08745Sheppo  *	B_TRUE	- Success.
33401ae08745Sheppo  *	B_FALSE	- The seq numbers are so out of sync, vdc cannot deal with them
33411ae08745Sheppo  */
33421ae08745Sheppo static boolean_t
33431ae08745Sheppo vdc_verify_seq_num(vdc_t *vdc, vio_dring_msg_t *dring_msg, int num_msgs)
33441ae08745Sheppo {
33451ae08745Sheppo 	ASSERT(vdc != NULL);
33461ae08745Sheppo 	ASSERT(dring_msg != NULL);
3347*d10e4ef2Snarayan 	ASSERT(mutex_owned(&vdc->lock));
33481ae08745Sheppo 
33491ae08745Sheppo 	/*
33501ae08745Sheppo 	 * Check to see if the messages were responded to in the correct
33511ae08745Sheppo 	 * order by vds. There are 3 possible scenarios:
33521ae08745Sheppo 	 *	- the seq_num we expected is returned (everything is OK)
33531ae08745Sheppo 	 *	- a seq_num earlier than the last one acknowledged is returned,
33541ae08745Sheppo 	 *	  if so something is seriously wrong so we reset the connection
33551ae08745Sheppo 	 *	- a seq_num greater than what we expected is returned.
33561ae08745Sheppo 	 */
3357*d10e4ef2Snarayan 	if (dring_msg->seq_num < vdc->seq_num_reply) {
33581ae08745Sheppo 		vdc_msg("%s[%d]: Bogus seq_num %d, expected %d\n",
33591ae08745Sheppo 			__func__, vdc->instance, dring_msg->seq_num,
33601ae08745Sheppo 			vdc->seq_num_reply + num_msgs);
33611ae08745Sheppo 		if (dring_msg->seq_num < (vdc->seq_num_reply + num_msgs)) {
33621ae08745Sheppo 			return (B_FALSE);
33631ae08745Sheppo 		} else {
33641ae08745Sheppo 			/*
33651ae08745Sheppo 			 * vds has responded with a seq_num greater than what we
33661ae08745Sheppo 			 * expected
33671ae08745Sheppo 			 */
33681ae08745Sheppo 			return (B_FALSE);
33691ae08745Sheppo 		}
33701ae08745Sheppo 	}
33711ae08745Sheppo 	vdc->seq_num_reply += num_msgs;
33721ae08745Sheppo 
33731ae08745Sheppo 	return (B_TRUE);
33741ae08745Sheppo }
33751ae08745Sheppo 
33760a55fbb7Slm66018 
33770a55fbb7Slm66018 /*
33780a55fbb7Slm66018  * Function:
33790a55fbb7Slm66018  *	vdc_is_supported_version()
33800a55fbb7Slm66018  *
33810a55fbb7Slm66018  * Description:
33820a55fbb7Slm66018  *	This routine checks if the major/minor version numbers specified in
33830a55fbb7Slm66018  *	'ver_msg' are supported. If not it finds the next version that is
33840a55fbb7Slm66018  *	in the supported version list 'vdc_version[]' and sets the fields in
33850a55fbb7Slm66018  *	'ver_msg' to those values
33860a55fbb7Slm66018  *
33870a55fbb7Slm66018  * Arguments:
33880a55fbb7Slm66018  *	ver_msg	- LDC message sent by vDisk server
33890a55fbb7Slm66018  *
33900a55fbb7Slm66018  * Return Code:
33910a55fbb7Slm66018  *	B_TRUE	- Success
33920a55fbb7Slm66018  *	B_FALSE	- Version not supported
33930a55fbb7Slm66018  */
33940a55fbb7Slm66018 static boolean_t
33950a55fbb7Slm66018 vdc_is_supported_version(vio_ver_msg_t *ver_msg)
33960a55fbb7Slm66018 {
33970a55fbb7Slm66018 	int vdc_num_versions = sizeof (vdc_version) / sizeof (vdc_version[0]);
33980a55fbb7Slm66018 
33990a55fbb7Slm66018 	for (int i = 0; i < vdc_num_versions; i++) {
34000a55fbb7Slm66018 		ASSERT(vdc_version[i].major > 0);
34010a55fbb7Slm66018 		ASSERT((i == 0) ||
34020a55fbb7Slm66018 		    (vdc_version[i].major < vdc_version[i-1].major));
34030a55fbb7Slm66018 
34040a55fbb7Slm66018 		/*
34050a55fbb7Slm66018 		 * If the major versions match, adjust the minor version, if
34060a55fbb7Slm66018 		 * necessary, down to the highest value supported by this
34070a55fbb7Slm66018 		 * client. The server should support all minor versions lower
34080a55fbb7Slm66018 		 * than the value it sent
34090a55fbb7Slm66018 		 */
34100a55fbb7Slm66018 		if (ver_msg->ver_major == vdc_version[i].major) {
34110a55fbb7Slm66018 			if (ver_msg->ver_minor > vdc_version[i].minor) {
34120a55fbb7Slm66018 				PR0("Adjusting minor version from %u to %u",
34130a55fbb7Slm66018 				    ver_msg->ver_minor, vdc_version[i].minor);
34140a55fbb7Slm66018 				ver_msg->ver_minor = vdc_version[i].minor;
34150a55fbb7Slm66018 			}
34160a55fbb7Slm66018 			return (B_TRUE);
34170a55fbb7Slm66018 		}
34180a55fbb7Slm66018 
34190a55fbb7Slm66018 		/*
34200a55fbb7Slm66018 		 * If the message contains a higher major version number, set
34210a55fbb7Slm66018 		 * the message's major/minor versions to the current values
34220a55fbb7Slm66018 		 * and return false, so this message will get resent with
34230a55fbb7Slm66018 		 * these values, and the server will potentially try again
34240a55fbb7Slm66018 		 * with the same or a lower version
34250a55fbb7Slm66018 		 */
34260a55fbb7Slm66018 		if (ver_msg->ver_major > vdc_version[i].major) {
34270a55fbb7Slm66018 			ver_msg->ver_major = vdc_version[i].major;
34280a55fbb7Slm66018 			ver_msg->ver_minor = vdc_version[i].minor;
34290a55fbb7Slm66018 			PR0("Suggesting major/minor (0x%x/0x%x)\n",
34300a55fbb7Slm66018 				ver_msg->ver_major, ver_msg->ver_minor);
34310a55fbb7Slm66018 
34320a55fbb7Slm66018 			return (B_FALSE);
34330a55fbb7Slm66018 		}
34340a55fbb7Slm66018 
34350a55fbb7Slm66018 		/*
34360a55fbb7Slm66018 		 * Otherwise, the message's major version is less than the
34370a55fbb7Slm66018 		 * current major version, so continue the loop to the next
34380a55fbb7Slm66018 		 * (lower) supported version
34390a55fbb7Slm66018 		 */
34400a55fbb7Slm66018 	}
34410a55fbb7Slm66018 
34420a55fbb7Slm66018 	/*
34430a55fbb7Slm66018 	 * No common version was found; "ground" the version pair in the
34440a55fbb7Slm66018 	 * message to terminate negotiation
34450a55fbb7Slm66018 	 */
34460a55fbb7Slm66018 	ver_msg->ver_major = 0;
34470a55fbb7Slm66018 	ver_msg->ver_minor = 0;
34480a55fbb7Slm66018 
34490a55fbb7Slm66018 	return (B_FALSE);
34500a55fbb7Slm66018 }
34511ae08745Sheppo /* -------------------------------------------------------------------------- */
34521ae08745Sheppo 
34531ae08745Sheppo /*
34541ae08745Sheppo  * DKIO(7) support
34551ae08745Sheppo  */
34561ae08745Sheppo 
34571ae08745Sheppo typedef struct vdc_dk_arg {
34581ae08745Sheppo 	struct dk_callback	dkc;
34591ae08745Sheppo 	int			mode;
34601ae08745Sheppo 	dev_t			dev;
34611ae08745Sheppo 	vdc_t			*vdc;
34621ae08745Sheppo } vdc_dk_arg_t;
34631ae08745Sheppo 
34641ae08745Sheppo /*
34651ae08745Sheppo  * Function:
34661ae08745Sheppo  * 	vdc_dkio_flush_cb()
34671ae08745Sheppo  *
34681ae08745Sheppo  * Description:
34691ae08745Sheppo  *	This routine is a callback for DKIOCFLUSHWRITECACHE which can be called
34701ae08745Sheppo  *	by kernel code.
34711ae08745Sheppo  *
34721ae08745Sheppo  * Arguments:
34731ae08745Sheppo  *	arg	- a pointer to a vdc_dk_arg_t structure.
34741ae08745Sheppo  */
34751ae08745Sheppo void
34761ae08745Sheppo vdc_dkio_flush_cb(void *arg)
34771ae08745Sheppo {
34781ae08745Sheppo 	struct vdc_dk_arg	*dk_arg = (struct vdc_dk_arg *)arg;
34791ae08745Sheppo 	struct dk_callback	*dkc = NULL;
34801ae08745Sheppo 	vdc_t			*vdc = NULL;
34811ae08745Sheppo 	int			rv;
34821ae08745Sheppo 
34831ae08745Sheppo 	if (dk_arg == NULL) {
34841ae08745Sheppo 		vdc_msg("%s[?] DKIOCFLUSHWRITECACHE arg is NULL\n", __func__);
34851ae08745Sheppo 		return;
34861ae08745Sheppo 	}
34871ae08745Sheppo 	dkc = &dk_arg->dkc;
34881ae08745Sheppo 	vdc = dk_arg->vdc;
34891ae08745Sheppo 	ASSERT(vdc != NULL);
34901ae08745Sheppo 
34911ae08745Sheppo 	rv = vdc_populate_descriptor(vdc, NULL, 0, VD_OP_FLUSH,
34921ae08745Sheppo 		dk_arg->mode, SDPART(getminor(dk_arg->dev)));
34931ae08745Sheppo 	if (rv != 0) {
34948e6a2a04Slm66018 		PR0("%s[%d] DKIOCFLUSHWRITECACHE failed %d : model %x\n",
34958e6a2a04Slm66018 			__func__, vdc->instance, rv,
34961ae08745Sheppo 			ddi_model_convert_from(dk_arg->mode & FMODELS));
34971ae08745Sheppo 	}
34981ae08745Sheppo 
34991ae08745Sheppo 	/*
35001ae08745Sheppo 	 * Trigger the call back to notify the caller the the ioctl call has
35011ae08745Sheppo 	 * been completed.
35021ae08745Sheppo 	 */
35031ae08745Sheppo 	if ((dk_arg->mode & FKIOCTL) &&
35041ae08745Sheppo 	    (dkc != NULL) &&
35051ae08745Sheppo 	    (dkc->dkc_callback != NULL)) {
35061ae08745Sheppo 		ASSERT(dkc->dkc_cookie != NULL);
35078e6a2a04Slm66018 		(*dkc->dkc_callback)(dkc->dkc_cookie, rv);
35081ae08745Sheppo 	}
35091ae08745Sheppo 
35101ae08745Sheppo 	/* Indicate that one less DKIO write flush is outstanding */
35111ae08745Sheppo 	mutex_enter(&vdc->lock);
35121ae08745Sheppo 	vdc->dkio_flush_pending--;
35131ae08745Sheppo 	ASSERT(vdc->dkio_flush_pending >= 0);
35141ae08745Sheppo 	mutex_exit(&vdc->lock);
35158e6a2a04Slm66018 
35168e6a2a04Slm66018 	/* free the mem that was allocated when the callback was dispatched */
35178e6a2a04Slm66018 	kmem_free(arg, sizeof (vdc_dk_arg_t));
35181ae08745Sheppo }
35191ae08745Sheppo 
35201ae08745Sheppo /*
35211ae08745Sheppo  * This structure is used in the DKIO(7I) array below.
35221ae08745Sheppo  */
35231ae08745Sheppo typedef struct vdc_dk_ioctl {
35241ae08745Sheppo 	uint8_t		op;		/* VD_OP_XXX value */
35251ae08745Sheppo 	int		cmd;		/* Solaris ioctl operation number */
35261ae08745Sheppo 	size_t		nbytes;		/* size of structure to be copied */
35270a55fbb7Slm66018 
35280a55fbb7Slm66018 	/* function to convert between vDisk and Solaris structure formats */
3529*d10e4ef2Snarayan 	int	(*convert)(vdc_t *vdc, void *vd_buf, void *ioctl_arg,
3530*d10e4ef2Snarayan 	    int mode, int dir);
35311ae08745Sheppo } vdc_dk_ioctl_t;
35321ae08745Sheppo 
35331ae08745Sheppo /*
35341ae08745Sheppo  * Subset of DKIO(7I) operations currently supported
35351ae08745Sheppo  */
35361ae08745Sheppo static vdc_dk_ioctl_t	dk_ioctl[] = {
35370a55fbb7Slm66018 	{VD_OP_FLUSH,		DKIOCFLUSHWRITECACHE,	sizeof (int),
35380a55fbb7Slm66018 		vdc_null_copy_func},
35390a55fbb7Slm66018 	{VD_OP_GET_WCE,		DKIOCGETWCE,		sizeof (int),
35400a55fbb7Slm66018 		vdc_null_copy_func},
35410a55fbb7Slm66018 	{VD_OP_SET_WCE,		DKIOCSETWCE,		sizeof (int),
35420a55fbb7Slm66018 		vdc_null_copy_func},
35430a55fbb7Slm66018 	{VD_OP_GET_VTOC,	DKIOCGVTOC,		sizeof (vd_vtoc_t),
35440a55fbb7Slm66018 		vdc_get_vtoc_convert},
35450a55fbb7Slm66018 	{VD_OP_SET_VTOC,	DKIOCSVTOC,		sizeof (vd_vtoc_t),
35460a55fbb7Slm66018 		vdc_set_vtoc_convert},
35470a55fbb7Slm66018 	{VD_OP_GET_DISKGEOM,	DKIOCGGEOM,		sizeof (vd_geom_t),
35480a55fbb7Slm66018 		vdc_get_geom_convert},
35490a55fbb7Slm66018 	{VD_OP_GET_DISKGEOM,	DKIOCG_PHYGEOM,		sizeof (vd_geom_t),
35500a55fbb7Slm66018 		vdc_get_geom_convert},
35510a55fbb7Slm66018 	{VD_OP_GET_DISKGEOM, 	DKIOCG_VIRTGEOM,	sizeof (vd_geom_t),
35520a55fbb7Slm66018 		vdc_get_geom_convert},
35530a55fbb7Slm66018 	{VD_OP_SET_DISKGEOM,	DKIOCSGEOM,		sizeof (vd_geom_t),
35540a55fbb7Slm66018 		vdc_set_geom_convert},
35550a55fbb7Slm66018 
35560a55fbb7Slm66018 	/*
35570a55fbb7Slm66018 	 * These particular ioctls are not sent to the server - vdc fakes up
35580a55fbb7Slm66018 	 * the necessary info.
35590a55fbb7Slm66018 	 */
35600a55fbb7Slm66018 	{0, DKIOCINFO, sizeof (struct dk_cinfo), vdc_null_copy_func},
35610a55fbb7Slm66018 	{0, DKIOCGMEDIAINFO, sizeof (struct dk_minfo), vdc_null_copy_func},
35620a55fbb7Slm66018 	{0, USCSICMD,	sizeof (struct uscsi_cmd), vdc_null_copy_func},
35630a55fbb7Slm66018 	{0, DKIOCREMOVABLE, 0, vdc_null_copy_func},
35640a55fbb7Slm66018 	{0, CDROMREADOFFSET, 0, vdc_null_copy_func}
35651ae08745Sheppo };
35661ae08745Sheppo 
35671ae08745Sheppo /*
35681ae08745Sheppo  * Function:
35691ae08745Sheppo  *	vd_process_ioctl()
35701ae08745Sheppo  *
35711ae08745Sheppo  * Description:
35720a55fbb7Slm66018  *	This routine processes disk specific ioctl calls
35731ae08745Sheppo  *
35741ae08745Sheppo  * Arguments:
35751ae08745Sheppo  *	dev	- the device number
35761ae08745Sheppo  *	cmd	- the operation [dkio(7I)] to be processed
35771ae08745Sheppo  *	arg	- pointer to user provided structure
35781ae08745Sheppo  *		  (contains data to be set or reference parameter for get)
35791ae08745Sheppo  *	mode	- bit flag, indicating open settings, 32/64 bit type, etc
35801ae08745Sheppo  *
35811ae08745Sheppo  * Return Code:
35821ae08745Sheppo  *	0
35831ae08745Sheppo  *	EFAULT
35841ae08745Sheppo  *	ENXIO
35851ae08745Sheppo  *	EIO
35861ae08745Sheppo  *	ENOTSUP
35871ae08745Sheppo  */
35881ae08745Sheppo static int
35891ae08745Sheppo vd_process_ioctl(dev_t dev, int cmd, caddr_t arg, int mode)
35901ae08745Sheppo {
35911ae08745Sheppo 	int		instance = SDUNIT(getminor(dev));
35921ae08745Sheppo 	vdc_t		*vdc = NULL;
35931ae08745Sheppo 	int		rv = -1;
35941ae08745Sheppo 	int		idx = 0;		/* index into dk_ioctl[] */
35951ae08745Sheppo 	size_t		len = 0;		/* #bytes to send to vds */
35961ae08745Sheppo 	size_t		alloc_len = 0;		/* #bytes to allocate mem for */
35971ae08745Sheppo 	caddr_t		mem_p = NULL;
35981ae08745Sheppo 	size_t		nioctls = (sizeof (dk_ioctl)) / (sizeof (dk_ioctl[0]));
3599*d10e4ef2Snarayan 	struct vtoc	vtoc_saved;
36001ae08745Sheppo 
36011ae08745Sheppo 	PR0("%s: Processing ioctl(%x) for dev %x : model %x\n",
36021ae08745Sheppo 		__func__, cmd, dev, ddi_model_convert_from(mode & FMODELS));
36031ae08745Sheppo 
36041ae08745Sheppo 	vdc = ddi_get_soft_state(vdc_state, instance);
36051ae08745Sheppo 	if (vdc == NULL) {
36061ae08745Sheppo 		cmn_err(CE_NOTE, "![%d] Could not get soft state structure",
36071ae08745Sheppo 		    instance);
36081ae08745Sheppo 		return (ENXIO);
36091ae08745Sheppo 	}
36101ae08745Sheppo 
36111ae08745Sheppo 	/*
36121ae08745Sheppo 	 * Check to see if we can communicate with the vDisk server
36131ae08745Sheppo 	 */
36140a55fbb7Slm66018 	if (!vdc_is_able_to_tx_data(vdc, O_NONBLOCK)) {
36151ae08745Sheppo 		PR0("%s[%d] Not ready to transmit data\n", __func__, instance);
36161ae08745Sheppo 		return (ENOLINK);
36171ae08745Sheppo 	}
36181ae08745Sheppo 
36191ae08745Sheppo 	/*
36201ae08745Sheppo 	 * Validate the ioctl operation to be performed.
36211ae08745Sheppo 	 *
36221ae08745Sheppo 	 * If we have looped through the array without finding a match then we
36231ae08745Sheppo 	 * don't support this ioctl.
36241ae08745Sheppo 	 */
36251ae08745Sheppo 	for (idx = 0; idx < nioctls; idx++) {
36261ae08745Sheppo 		if (cmd == dk_ioctl[idx].cmd)
36271ae08745Sheppo 			break;
36281ae08745Sheppo 	}
36291ae08745Sheppo 
36301ae08745Sheppo 	if (idx >= nioctls) {
36311ae08745Sheppo 		PR0("%s[%d] Unsupported ioctl(%x)\n",
36321ae08745Sheppo 				__func__, vdc->instance, cmd);
36331ae08745Sheppo 		return (ENOTSUP);
36341ae08745Sheppo 	}
36351ae08745Sheppo 
36360a55fbb7Slm66018 	len = dk_ioctl[idx].nbytes;
36371ae08745Sheppo 
36381ae08745Sheppo 	/*
36390a55fbb7Slm66018 	 * Deal with the ioctls which the server does not provide. vdc can
36400a55fbb7Slm66018 	 * fake these up and return immediately
36411ae08745Sheppo 	 */
36421ae08745Sheppo 	switch (cmd) {
36431ae08745Sheppo 	case CDROMREADOFFSET:
36441ae08745Sheppo 	case DKIOCREMOVABLE:
36450a55fbb7Slm66018 	case USCSICMD:
36461ae08745Sheppo 		return (ENOTTY);
36471ae08745Sheppo 
36481ae08745Sheppo 	case DKIOCINFO:
36491ae08745Sheppo 		{
36501ae08745Sheppo 			struct dk_cinfo	cinfo;
36511ae08745Sheppo 			if (vdc->cinfo == NULL)
36521ae08745Sheppo 				return (ENXIO);
36531ae08745Sheppo 
36541ae08745Sheppo 			bcopy(vdc->cinfo, &cinfo, sizeof (struct dk_cinfo));
36551ae08745Sheppo 			cinfo.dki_partition = SDPART(getminor(dev));
36561ae08745Sheppo 
36571ae08745Sheppo 			rv = ddi_copyout(&cinfo, (void *)arg,
36581ae08745Sheppo 					sizeof (struct dk_cinfo), mode);
36591ae08745Sheppo 			if (rv != 0)
36601ae08745Sheppo 				return (EFAULT);
36611ae08745Sheppo 
36621ae08745Sheppo 			return (0);
36631ae08745Sheppo 		}
36641ae08745Sheppo 
36651ae08745Sheppo 	case DKIOCGMEDIAINFO:
36668e6a2a04Slm66018 		{
36671ae08745Sheppo 			if (vdc->minfo == NULL)
36681ae08745Sheppo 				return (ENXIO);
36691ae08745Sheppo 
36701ae08745Sheppo 			rv = ddi_copyout(vdc->minfo, (void *)arg,
36711ae08745Sheppo 					sizeof (struct dk_minfo), mode);
36721ae08745Sheppo 			if (rv != 0)
36731ae08745Sheppo 				return (EFAULT);
36741ae08745Sheppo 
36751ae08745Sheppo 			return (0);
36761ae08745Sheppo 		}
36771ae08745Sheppo 
36788e6a2a04Slm66018 	case DKIOCFLUSHWRITECACHE:
36798e6a2a04Slm66018 		{
36808e6a2a04Slm66018 			struct dk_callback *dkc = (struct dk_callback *)arg;
36818e6a2a04Slm66018 			vdc_dk_arg_t	*dkarg = NULL;
36828e6a2a04Slm66018 
36838e6a2a04Slm66018 			PR1("[%d] Flush W$: mode %x\n", instance, mode);
36848e6a2a04Slm66018 
36858e6a2a04Slm66018 			/*
36868e6a2a04Slm66018 			 * If the backing device is not a 'real' disk then the
36878e6a2a04Slm66018 			 * W$ operation request to the vDisk server will fail
36888e6a2a04Slm66018 			 * so we might as well save the cycles and return now.
36898e6a2a04Slm66018 			 */
36908e6a2a04Slm66018 			if (vdc->vdisk_type != VD_DISK_TYPE_DISK)
36918e6a2a04Slm66018 				return (ENOTTY);
36928e6a2a04Slm66018 
36938e6a2a04Slm66018 			/*
36948e6a2a04Slm66018 			 * If arg is NULL, then there is no callback function
36958e6a2a04Slm66018 			 * registered and the call operates synchronously; we
36968e6a2a04Slm66018 			 * break and continue with the rest of the function and
36978e6a2a04Slm66018 			 * wait for vds to return (i.e. after the request to
36988e6a2a04Slm66018 			 * vds returns successfully, all writes completed prior
36998e6a2a04Slm66018 			 * to the ioctl will have been flushed from the disk
37008e6a2a04Slm66018 			 * write cache to persistent media.
37018e6a2a04Slm66018 			 *
37028e6a2a04Slm66018 			 * If a callback function is registered, we dispatch
37038e6a2a04Slm66018 			 * the request on a task queue and return immediately.
37048e6a2a04Slm66018 			 * The callback will deal with informing the calling
37058e6a2a04Slm66018 			 * thread that the flush request is completed.
37068e6a2a04Slm66018 			 */
37078e6a2a04Slm66018 			if (dkc == NULL)
37088e6a2a04Slm66018 				break;
37098e6a2a04Slm66018 
37108e6a2a04Slm66018 			dkarg = kmem_zalloc(sizeof (vdc_dk_arg_t), KM_SLEEP);
37118e6a2a04Slm66018 
37128e6a2a04Slm66018 			dkarg->mode = mode;
37138e6a2a04Slm66018 			dkarg->dev = dev;
37148e6a2a04Slm66018 			bcopy(dkc, &dkarg->dkc, sizeof (*dkc));
37158e6a2a04Slm66018 
37168e6a2a04Slm66018 			mutex_enter(&vdc->lock);
37178e6a2a04Slm66018 			vdc->dkio_flush_pending++;
37188e6a2a04Slm66018 			dkarg->vdc = vdc;
37198e6a2a04Slm66018 			mutex_exit(&vdc->lock);
37208e6a2a04Slm66018 
37218e6a2a04Slm66018 			/* put the request on a task queue */
37228e6a2a04Slm66018 			rv = taskq_dispatch(system_taskq, vdc_dkio_flush_cb,
37238e6a2a04Slm66018 				(void *)dkarg, DDI_SLEEP);
37248e6a2a04Slm66018 
37258e6a2a04Slm66018 			return (rv == NULL ? ENOMEM : 0);
37268e6a2a04Slm66018 		}
37278e6a2a04Slm66018 	}
37288e6a2a04Slm66018 
37291ae08745Sheppo 	/* catch programming error in vdc - should be a VD_OP_XXX ioctl */
37300a55fbb7Slm66018 	ASSERT(dk_ioctl[idx].op != 0);
37311ae08745Sheppo 
37321ae08745Sheppo 	/* LDC requires that the memory being mapped is 8-byte aligned */
37331ae08745Sheppo 	alloc_len = P2ROUNDUP(len, sizeof (uint64_t));
37341ae08745Sheppo 	PR1("%s[%d]: struct size %d alloc %d\n",
37351ae08745Sheppo 			__func__, instance, len, alloc_len);
37361ae08745Sheppo 
37370a55fbb7Slm66018 	ASSERT(alloc_len != 0);	/* sanity check */
37381ae08745Sheppo 	mem_p = kmem_zalloc(alloc_len, KM_SLEEP);
37391ae08745Sheppo 
3740*d10e4ef2Snarayan 	if (cmd == DKIOCSVTOC) {
3741*d10e4ef2Snarayan 		/*
3742*d10e4ef2Snarayan 		 * Save a copy of the current VTOC so that we can roll back
3743*d10e4ef2Snarayan 		 * if the setting of the new VTOC fails.
3744*d10e4ef2Snarayan 		 */
3745*d10e4ef2Snarayan 		bcopy(vdc->vtoc, &vtoc_saved, sizeof (struct vtoc));
3746*d10e4ef2Snarayan 	}
3747*d10e4ef2Snarayan 
37480a55fbb7Slm66018 	/*
37490a55fbb7Slm66018 	 * Call the conversion function for this ioctl whhich if necessary
37500a55fbb7Slm66018 	 * converts from the Solaris format to the format ARC'ed
37510a55fbb7Slm66018 	 * as part of the vDisk protocol (FWARC 2006/195)
37520a55fbb7Slm66018 	 */
37530a55fbb7Slm66018 	ASSERT(dk_ioctl[idx].convert != NULL);
3754*d10e4ef2Snarayan 	rv = (dk_ioctl[idx].convert)(vdc, arg, mem_p, mode, VD_COPYIN);
37551ae08745Sheppo 	if (rv != 0) {
37560a55fbb7Slm66018 		PR0("%s[%d]: convert returned %d for ioctl 0x%x\n",
37570a55fbb7Slm66018 				__func__, instance, rv, cmd);
37581ae08745Sheppo 		if (mem_p != NULL)
37591ae08745Sheppo 			kmem_free(mem_p, alloc_len);
37600a55fbb7Slm66018 		return (rv);
37611ae08745Sheppo 	}
37621ae08745Sheppo 
37631ae08745Sheppo 	/*
37641ae08745Sheppo 	 * send request to vds to service the ioctl.
37651ae08745Sheppo 	 */
37660a55fbb7Slm66018 	rv = vdc_populate_descriptor(vdc, mem_p, alloc_len, dk_ioctl[idx].op,
37670a55fbb7Slm66018 			mode, SDPART((getminor(dev))));
37681ae08745Sheppo 	if (rv != 0) {
37691ae08745Sheppo 		/*
37701ae08745Sheppo 		 * This is not necessarily an error. The ioctl could
37711ae08745Sheppo 		 * be returning a value such as ENOTTY to indicate
37721ae08745Sheppo 		 * that the ioctl is not applicable.
37731ae08745Sheppo 		 */
37741ae08745Sheppo 		PR0("%s[%d]: vds returned %d for ioctl 0x%x\n",
37751ae08745Sheppo 			__func__, instance, rv, cmd);
37761ae08745Sheppo 		if (mem_p != NULL)
37771ae08745Sheppo 			kmem_free(mem_p, alloc_len);
3778*d10e4ef2Snarayan 
3779*d10e4ef2Snarayan 		if (cmd == DKIOCSVTOC) {
3780*d10e4ef2Snarayan 			/* update of the VTOC has failed, roll back */
3781*d10e4ef2Snarayan 			bcopy(&vtoc_saved, vdc->vtoc, sizeof (struct vtoc));
3782*d10e4ef2Snarayan 		}
3783*d10e4ef2Snarayan 
37841ae08745Sheppo 		return (rv);
37851ae08745Sheppo 	}
37861ae08745Sheppo 
37871ae08745Sheppo 	if (cmd == DKIOCSVTOC) {
3788*d10e4ef2Snarayan 		/*
3789*d10e4ef2Snarayan 		 * The VTOC has been changed, try and update the device
3790*d10e4ef2Snarayan 		 * node properties. Failing to set the properties should
3791*d10e4ef2Snarayan 		 * not cause an error to be return the caller though.
3792*d10e4ef2Snarayan 		 */
37931ae08745Sheppo 		if (vdc_create_device_nodes_props(vdc)) {
37941ae08745Sheppo 			cmn_err(CE_NOTE, "![%d] Failed to update device nodes"
3795*d10e4ef2Snarayan 			    " properties", vdc->instance);
37961ae08745Sheppo 		}
37971ae08745Sheppo 	}
37981ae08745Sheppo 
37991ae08745Sheppo 	/*
38000a55fbb7Slm66018 	 * Call the conversion function (if it exists) for this ioctl
38010a55fbb7Slm66018 	 * which converts from the format ARC'ed as part of the vDisk
38020a55fbb7Slm66018 	 * protocol (FWARC 2006/195) back to a format understood by
38030a55fbb7Slm66018 	 * the rest of Solaris.
38041ae08745Sheppo 	 */
3805*d10e4ef2Snarayan 	rv = (dk_ioctl[idx].convert)(vdc, mem_p, arg, mode, VD_COPYOUT);
38060a55fbb7Slm66018 	if (rv != 0) {
38070a55fbb7Slm66018 		PR0("%s[%d]: convert returned %d for ioctl 0x%x\n",
38080a55fbb7Slm66018 				__func__, instance, rv, cmd);
38091ae08745Sheppo 		if (mem_p != NULL)
38101ae08745Sheppo 			kmem_free(mem_p, alloc_len);
38110a55fbb7Slm66018 		return (rv);
38121ae08745Sheppo 	}
38131ae08745Sheppo 
38141ae08745Sheppo 	if (mem_p != NULL)
38151ae08745Sheppo 		kmem_free(mem_p, alloc_len);
38161ae08745Sheppo 
38171ae08745Sheppo 	return (rv);
38181ae08745Sheppo }
38191ae08745Sheppo 
38201ae08745Sheppo /*
38211ae08745Sheppo  * Function:
38220a55fbb7Slm66018  *
38230a55fbb7Slm66018  * Description:
38240a55fbb7Slm66018  *	This is an empty conversion function used by ioctl calls which
38250a55fbb7Slm66018  *	do not need to convert the data being passed in/out to userland
38260a55fbb7Slm66018  */
38270a55fbb7Slm66018 static int
3828*d10e4ef2Snarayan vdc_null_copy_func(vdc_t *vdc, void *from, void *to, int mode, int dir)
38290a55fbb7Slm66018 {
3830*d10e4ef2Snarayan 	_NOTE(ARGUNUSED(vdc))
38310a55fbb7Slm66018 	_NOTE(ARGUNUSED(from))
38320a55fbb7Slm66018 	_NOTE(ARGUNUSED(to))
38330a55fbb7Slm66018 	_NOTE(ARGUNUSED(mode))
38340a55fbb7Slm66018 	_NOTE(ARGUNUSED(dir))
38350a55fbb7Slm66018 
38360a55fbb7Slm66018 	return (0);
38370a55fbb7Slm66018 }
38380a55fbb7Slm66018 
38390a55fbb7Slm66018 /*
38400a55fbb7Slm66018  * Function:
38410a55fbb7Slm66018  *	vdc_get_vtoc_convert()
38420a55fbb7Slm66018  *
38430a55fbb7Slm66018  * Description:
3844*d10e4ef2Snarayan  *	This routine performs the necessary convertions from the DKIOCGVTOC
3845*d10e4ef2Snarayan  *	Solaris structure to the format defined in FWARC 2006/195.
3846*d10e4ef2Snarayan  *
3847*d10e4ef2Snarayan  *	In the struct vtoc definition, the timestamp field is marked as not
3848*d10e4ef2Snarayan  *	supported so it is not part of vDisk protocol (FWARC 2006/195).
3849*d10e4ef2Snarayan  *	However SVM uses that field to check it can write into the VTOC,
3850*d10e4ef2Snarayan  *	so we fake up the info of that field.
38510a55fbb7Slm66018  *
38520a55fbb7Slm66018  * Arguments:
3853*d10e4ef2Snarayan  *	vdc	- the vDisk client
38540a55fbb7Slm66018  *	from	- the buffer containing the data to be copied from
38550a55fbb7Slm66018  *	to	- the buffer to be copied to
38560a55fbb7Slm66018  *	mode	- flags passed to ioctl() call
38570a55fbb7Slm66018  *	dir	- the "direction" of the copy - VD_COPYIN or VD_COPYOUT
38580a55fbb7Slm66018  *
38590a55fbb7Slm66018  * Return Code:
38600a55fbb7Slm66018  *	0	- Success
38610a55fbb7Slm66018  *	ENXIO	- incorrect buffer passed in.
3862*d10e4ef2Snarayan  *	EFAULT	- ddi_copyout routine encountered an error.
38630a55fbb7Slm66018  */
38640a55fbb7Slm66018 static int
3865*d10e4ef2Snarayan vdc_get_vtoc_convert(vdc_t *vdc, void *from, void *to, int mode, int dir)
38660a55fbb7Slm66018 {
3867*d10e4ef2Snarayan 	int		i;
38680a55fbb7Slm66018 	void		*tmp_mem = NULL;
38690a55fbb7Slm66018 	void		*tmp_memp;
38700a55fbb7Slm66018 	struct vtoc	vt;
38710a55fbb7Slm66018 	struct vtoc32	vt32;
38720a55fbb7Slm66018 	int		copy_len = 0;
38730a55fbb7Slm66018 	int		rv = 0;
38740a55fbb7Slm66018 
38750a55fbb7Slm66018 	if (dir != VD_COPYOUT)
38760a55fbb7Slm66018 		return (0);	/* nothing to do */
38770a55fbb7Slm66018 
38780a55fbb7Slm66018 	if ((from == NULL) || (to == NULL))
38790a55fbb7Slm66018 		return (ENXIO);
38800a55fbb7Slm66018 
38810a55fbb7Slm66018 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32)
38820a55fbb7Slm66018 		copy_len = sizeof (struct vtoc32);
38830a55fbb7Slm66018 	else
38840a55fbb7Slm66018 		copy_len = sizeof (struct vtoc);
38850a55fbb7Slm66018 
38860a55fbb7Slm66018 	tmp_mem = kmem_alloc(copy_len, KM_SLEEP);
38870a55fbb7Slm66018 
38880a55fbb7Slm66018 	VD_VTOC2VTOC((vd_vtoc_t *)from, &vt);
3889*d10e4ef2Snarayan 
3890*d10e4ef2Snarayan 	/* fake the VTOC timestamp field */
3891*d10e4ef2Snarayan 	for (i = 0; i < V_NUMPAR; i++) {
3892*d10e4ef2Snarayan 		vt.timestamp[i] = vdc->vtoc->timestamp[i];
3893*d10e4ef2Snarayan 	}
3894*d10e4ef2Snarayan 
38950a55fbb7Slm66018 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
38960a55fbb7Slm66018 		vtoctovtoc32(vt, vt32);
38970a55fbb7Slm66018 		tmp_memp = &vt32;
38980a55fbb7Slm66018 	} else {
38990a55fbb7Slm66018 		tmp_memp = &vt;
39000a55fbb7Slm66018 	}
39010a55fbb7Slm66018 	rv = ddi_copyout(tmp_memp, to, copy_len, mode);
39020a55fbb7Slm66018 	if (rv != 0)
39030a55fbb7Slm66018 		rv = EFAULT;
39040a55fbb7Slm66018 
39050a55fbb7Slm66018 	kmem_free(tmp_mem, copy_len);
39060a55fbb7Slm66018 	return (rv);
39070a55fbb7Slm66018 }
39080a55fbb7Slm66018 
39090a55fbb7Slm66018 /*
39100a55fbb7Slm66018  * Function:
39110a55fbb7Slm66018  *	vdc_set_vtoc_convert()
39120a55fbb7Slm66018  *
39130a55fbb7Slm66018  * Description:
3914*d10e4ef2Snarayan  *	This routine performs the necessary convertions from the DKIOCSVTOC
3915*d10e4ef2Snarayan  *	Solaris structure to the format defined in FWARC 2006/195.
39160a55fbb7Slm66018  *
39170a55fbb7Slm66018  * Arguments:
3918*d10e4ef2Snarayan  *	vdc	- the vDisk client
39190a55fbb7Slm66018  *	from	- Buffer with data
39200a55fbb7Slm66018  *	to	- Buffer where data is to be copied to
39210a55fbb7Slm66018  *	mode	- flags passed to ioctl
39220a55fbb7Slm66018  *	dir	- direction of copy (in or out)
39230a55fbb7Slm66018  *
39240a55fbb7Slm66018  * Return Code:
39250a55fbb7Slm66018  *	0	- Success
39260a55fbb7Slm66018  *	ENXIO	- Invalid buffer passed in
39270a55fbb7Slm66018  *	EFAULT	- ddi_copyin of data failed
39280a55fbb7Slm66018  */
39290a55fbb7Slm66018 static int
3930*d10e4ef2Snarayan vdc_set_vtoc_convert(vdc_t *vdc, void *from, void *to, int mode, int dir)
39310a55fbb7Slm66018 {
39320a55fbb7Slm66018 	void		*tmp_mem = NULL;
39330a55fbb7Slm66018 	struct vtoc	vt;
39340a55fbb7Slm66018 	struct vtoc	*vtp = &vt;
39350a55fbb7Slm66018 	vd_vtoc_t	vtvd;
39360a55fbb7Slm66018 	int		copy_len = 0;
39370a55fbb7Slm66018 	int		rv = 0;
39380a55fbb7Slm66018 
39390a55fbb7Slm66018 	if (dir != VD_COPYIN)
39400a55fbb7Slm66018 		return (0);	/* nothing to do */
39410a55fbb7Slm66018 
39420a55fbb7Slm66018 	if ((from == NULL) || (to == NULL))
39430a55fbb7Slm66018 		return (ENXIO);
39440a55fbb7Slm66018 
39450a55fbb7Slm66018 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32)
39460a55fbb7Slm66018 		copy_len = sizeof (struct vtoc32);
39470a55fbb7Slm66018 	else
39480a55fbb7Slm66018 		copy_len = sizeof (struct vtoc);
39490a55fbb7Slm66018 
39500a55fbb7Slm66018 	tmp_mem = kmem_alloc(copy_len, KM_SLEEP);
39510a55fbb7Slm66018 
39520a55fbb7Slm66018 	rv = ddi_copyin(from, tmp_mem, copy_len, mode);
39530a55fbb7Slm66018 	if (rv != 0) {
39540a55fbb7Slm66018 		kmem_free(tmp_mem, copy_len);
39550a55fbb7Slm66018 		return (EFAULT);
39560a55fbb7Slm66018 	}
39570a55fbb7Slm66018 
39580a55fbb7Slm66018 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
39590a55fbb7Slm66018 		vtoc32tovtoc((*(struct vtoc32 *)tmp_mem), vt);
39600a55fbb7Slm66018 	} else {
39610a55fbb7Slm66018 		vtp = tmp_mem;
39620a55fbb7Slm66018 	}
39630a55fbb7Slm66018 
3964*d10e4ef2Snarayan 	/*
3965*d10e4ef2Snarayan 	 * The VTOC is being changed, then vdc needs to update the copy
3966*d10e4ef2Snarayan 	 * it saved in the soft state structure.
3967*d10e4ef2Snarayan 	 */
3968*d10e4ef2Snarayan 	bcopy(vtp, vdc->vtoc, sizeof (struct vtoc));
3969*d10e4ef2Snarayan 
39700a55fbb7Slm66018 	VTOC2VD_VTOC(vtp, &vtvd);
39710a55fbb7Slm66018 	bcopy(&vtvd, to, sizeof (vd_vtoc_t));
39720a55fbb7Slm66018 	kmem_free(tmp_mem, copy_len);
39730a55fbb7Slm66018 
39740a55fbb7Slm66018 	return (0);
39750a55fbb7Slm66018 }
39760a55fbb7Slm66018 
39770a55fbb7Slm66018 /*
39780a55fbb7Slm66018  * Function:
39790a55fbb7Slm66018  *	vdc_get_geom_convert()
39800a55fbb7Slm66018  *
39810a55fbb7Slm66018  * Description:
3982*d10e4ef2Snarayan  *	This routine performs the necessary convertions from the DKIOCGGEOM,
3983*d10e4ef2Snarayan  *	DKIOCG_PHYSGEOM and DKIOG_VIRTGEOM Solaris structures to the format
3984*d10e4ef2Snarayan  *	defined in FWARC 2006/195
39850a55fbb7Slm66018  *
39860a55fbb7Slm66018  * Arguments:
3987*d10e4ef2Snarayan  *	vdc	- the vDisk client
39880a55fbb7Slm66018  *	from	- Buffer with data
39890a55fbb7Slm66018  *	to	- Buffer where data is to be copied to
39900a55fbb7Slm66018  *	mode	- flags passed to ioctl
39910a55fbb7Slm66018  *	dir	- direction of copy (in or out)
39920a55fbb7Slm66018  *
39930a55fbb7Slm66018  * Return Code:
39940a55fbb7Slm66018  *	0	- Success
39950a55fbb7Slm66018  *	ENXIO	- Invalid buffer passed in
3996*d10e4ef2Snarayan  *	EFAULT	- ddi_copyout of data failed
39970a55fbb7Slm66018  */
39980a55fbb7Slm66018 static int
3999*d10e4ef2Snarayan vdc_get_geom_convert(vdc_t *vdc, void *from, void *to, int mode, int dir)
40000a55fbb7Slm66018 {
4001*d10e4ef2Snarayan 	_NOTE(ARGUNUSED(vdc))
4002*d10e4ef2Snarayan 
40030a55fbb7Slm66018 	struct dk_geom	geom;
40040a55fbb7Slm66018 	int	copy_len = sizeof (struct dk_geom);
40050a55fbb7Slm66018 	int	rv = 0;
40060a55fbb7Slm66018 
40070a55fbb7Slm66018 	if (dir != VD_COPYOUT)
40080a55fbb7Slm66018 		return (0);	/* nothing to do */
40090a55fbb7Slm66018 
40100a55fbb7Slm66018 	if ((from == NULL) || (to == NULL))
40110a55fbb7Slm66018 		return (ENXIO);
40120a55fbb7Slm66018 
40130a55fbb7Slm66018 	VD_GEOM2DK_GEOM((vd_geom_t *)from, &geom);
40140a55fbb7Slm66018 	rv = ddi_copyout(&geom, to, copy_len, mode);
40150a55fbb7Slm66018 	if (rv != 0)
40160a55fbb7Slm66018 		rv = EFAULT;
40170a55fbb7Slm66018 
40180a55fbb7Slm66018 	return (rv);
40190a55fbb7Slm66018 }
40200a55fbb7Slm66018 
40210a55fbb7Slm66018 /*
40220a55fbb7Slm66018  * Function:
40230a55fbb7Slm66018  *	vdc_set_geom_convert()
40240a55fbb7Slm66018  *
40250a55fbb7Slm66018  * Description:
4026*d10e4ef2Snarayan  *	This routine performs the necessary convertions from the DKIOCSGEOM
4027*d10e4ef2Snarayan  *	Solaris structure to the format defined in FWARC 2006/195.
40280a55fbb7Slm66018  *
40290a55fbb7Slm66018  * Arguments:
4030*d10e4ef2Snarayan  *	vdc	- the vDisk client
40310a55fbb7Slm66018  *	from	- Buffer with data
40320a55fbb7Slm66018  *	to	- Buffer where data is to be copied to
40330a55fbb7Slm66018  *	mode	- flags passed to ioctl
40340a55fbb7Slm66018  *	dir	- direction of copy (in or out)
40350a55fbb7Slm66018  *
40360a55fbb7Slm66018  * Return Code:
40370a55fbb7Slm66018  *	0	- Success
40380a55fbb7Slm66018  *	ENXIO	- Invalid buffer passed in
40390a55fbb7Slm66018  *	EFAULT	- ddi_copyin of data failed
40400a55fbb7Slm66018  */
40410a55fbb7Slm66018 static int
4042*d10e4ef2Snarayan vdc_set_geom_convert(vdc_t *vdc, void *from, void *to, int mode, int dir)
40430a55fbb7Slm66018 {
4044*d10e4ef2Snarayan 	_NOTE(ARGUNUSED(vdc))
4045*d10e4ef2Snarayan 
40460a55fbb7Slm66018 	vd_geom_t	vdgeom;
40470a55fbb7Slm66018 	void		*tmp_mem = NULL;
40480a55fbb7Slm66018 	int		copy_len = sizeof (struct dk_geom);
40490a55fbb7Slm66018 	int		rv = 0;
40500a55fbb7Slm66018 
40510a55fbb7Slm66018 	if (dir != VD_COPYIN)
40520a55fbb7Slm66018 		return (0);	/* nothing to do */
40530a55fbb7Slm66018 
40540a55fbb7Slm66018 	if ((from == NULL) || (to == NULL))
40550a55fbb7Slm66018 		return (ENXIO);
40560a55fbb7Slm66018 
40570a55fbb7Slm66018 	tmp_mem = kmem_alloc(copy_len, KM_SLEEP);
40580a55fbb7Slm66018 
40590a55fbb7Slm66018 	rv = ddi_copyin(from, tmp_mem, copy_len, mode);
40600a55fbb7Slm66018 	if (rv != 0) {
40610a55fbb7Slm66018 		kmem_free(tmp_mem, copy_len);
40620a55fbb7Slm66018 		return (EFAULT);
40630a55fbb7Slm66018 	}
40640a55fbb7Slm66018 	DK_GEOM2VD_GEOM((struct dk_geom *)tmp_mem, &vdgeom);
40650a55fbb7Slm66018 	bcopy(&vdgeom, to, sizeof (vdgeom));
40660a55fbb7Slm66018 	kmem_free(tmp_mem, copy_len);
40670a55fbb7Slm66018 
40680a55fbb7Slm66018 	return (0);
40690a55fbb7Slm66018 }
40700a55fbb7Slm66018 
40710a55fbb7Slm66018 /*
40720a55fbb7Slm66018  * Function:
40731ae08745Sheppo  *	vdc_create_fake_geometry()
40741ae08745Sheppo  *
40751ae08745Sheppo  * Description:
40761ae08745Sheppo  *	This routine fakes up the disk info needed for some DKIO ioctls.
40771ae08745Sheppo  *		- DKIOCINFO
40781ae08745Sheppo  *		- DKIOCGMEDIAINFO
40791ae08745Sheppo  *
40801ae08745Sheppo  *	[ just like lofi(7D) and ramdisk(7D) ]
40811ae08745Sheppo  *
40821ae08745Sheppo  * Arguments:
40831ae08745Sheppo  *	vdc	- soft state pointer for this instance of the device driver.
40841ae08745Sheppo  *
40851ae08745Sheppo  * Return Code:
40861ae08745Sheppo  *	0	- Success
40871ae08745Sheppo  */
40881ae08745Sheppo static int
40891ae08745Sheppo vdc_create_fake_geometry(vdc_t *vdc)
40901ae08745Sheppo {
40910a55fbb7Slm66018 	int	rv = 0;
40920a55fbb7Slm66018 
40931ae08745Sheppo 	ASSERT(vdc != NULL);
40941ae08745Sheppo 
40951ae08745Sheppo 	/*
40961ae08745Sheppo 	 * DKIOCINFO support
40971ae08745Sheppo 	 */
40981ae08745Sheppo 	vdc->cinfo = kmem_zalloc(sizeof (struct dk_cinfo), KM_SLEEP);
40991ae08745Sheppo 
41001ae08745Sheppo 	(void) strcpy(vdc->cinfo->dki_cname, VDC_DRIVER_NAME);
41011ae08745Sheppo 	(void) strcpy(vdc->cinfo->dki_dname, VDC_DRIVER_NAME);
41028e6a2a04Slm66018 	/* max_xfer_sz is #blocks so we don't need to divide by DEV_BSIZE */
41038e6a2a04Slm66018 	vdc->cinfo->dki_maxtransfer = vdc->max_xfer_sz;
41041ae08745Sheppo 	vdc->cinfo->dki_ctype = DKC_SCSI_CCS;
41051ae08745Sheppo 	vdc->cinfo->dki_flags = DKI_FMTVOL;
41061ae08745Sheppo 	vdc->cinfo->dki_cnum = 0;
41071ae08745Sheppo 	vdc->cinfo->dki_addr = 0;
41081ae08745Sheppo 	vdc->cinfo->dki_space = 0;
41091ae08745Sheppo 	vdc->cinfo->dki_prio = 0;
41101ae08745Sheppo 	vdc->cinfo->dki_vec = 0;
41111ae08745Sheppo 	vdc->cinfo->dki_unit = vdc->instance;
41121ae08745Sheppo 	vdc->cinfo->dki_slave = 0;
41131ae08745Sheppo 	/*
41141ae08745Sheppo 	 * The partition number will be created on the fly depending on the
41151ae08745Sheppo 	 * actual slice (i.e. minor node) that is used to request the data.
41161ae08745Sheppo 	 */
41171ae08745Sheppo 	vdc->cinfo->dki_partition = 0;
41181ae08745Sheppo 
41191ae08745Sheppo 	/*
41201ae08745Sheppo 	 * DKIOCGMEDIAINFO support
41211ae08745Sheppo 	 */
41220a55fbb7Slm66018 	if (vdc->minfo == NULL)
41231ae08745Sheppo 		vdc->minfo = kmem_zalloc(sizeof (struct dk_minfo), KM_SLEEP);
41241ae08745Sheppo 	vdc->minfo->dki_media_type = DK_FIXED_DISK;
41251ae08745Sheppo 	vdc->minfo->dki_capacity = 1;
41261ae08745Sheppo 	vdc->minfo->dki_lbsize = DEV_BSIZE;
41271ae08745Sheppo 
41280a55fbb7Slm66018 	return (rv);
41290a55fbb7Slm66018 }
41300a55fbb7Slm66018 
41310a55fbb7Slm66018 /*
41320a55fbb7Slm66018  * Function:
41330a55fbb7Slm66018  *	vdc_setup_disk_layout()
41340a55fbb7Slm66018  *
41350a55fbb7Slm66018  * Description:
41360a55fbb7Slm66018  *	This routine discovers all the necessary details about the "disk"
41370a55fbb7Slm66018  *	by requesting the data that is available from the vDisk server and by
41380a55fbb7Slm66018  *	faking up the rest of the data.
41390a55fbb7Slm66018  *
41400a55fbb7Slm66018  * Arguments:
41410a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
41420a55fbb7Slm66018  *
41430a55fbb7Slm66018  * Return Code:
41440a55fbb7Slm66018  *	0	- Success
41450a55fbb7Slm66018  */
41460a55fbb7Slm66018 static int
41470a55fbb7Slm66018 vdc_setup_disk_layout(vdc_t *vdc)
41480a55fbb7Slm66018 {
4149*d10e4ef2Snarayan 	buf_t	*buf;	/* BREAD requests need to be in a buf_t structure */
41500a55fbb7Slm66018 	dev_t	dev;
41510a55fbb7Slm66018 	int	slice = 0;
41520a55fbb7Slm66018 	int	rv;
41530a55fbb7Slm66018 
41540a55fbb7Slm66018 	ASSERT(vdc != NULL);
41550a55fbb7Slm66018 
41560a55fbb7Slm66018 	rv = vdc_create_fake_geometry(vdc);
41570a55fbb7Slm66018 	if (rv != 0) {
41580a55fbb7Slm66018 		cmn_err(CE_NOTE, "[%d] Failed to create disk geometry (err%d)",
41590a55fbb7Slm66018 				vdc->instance, rv);
41600a55fbb7Slm66018 	}
41610a55fbb7Slm66018 
41620a55fbb7Slm66018 	if (vdc->vtoc == NULL)
41630a55fbb7Slm66018 		vdc->vtoc = kmem_zalloc(sizeof (struct vtoc), KM_SLEEP);
41640a55fbb7Slm66018 
41650a55fbb7Slm66018 	dev = makedevice(ddi_driver_major(vdc->dip),
41660a55fbb7Slm66018 				VD_MAKE_DEV(vdc->instance, 0));
41670a55fbb7Slm66018 	rv = vd_process_ioctl(dev, DKIOCGVTOC, (caddr_t)vdc->vtoc, FKIOCTL);
41680a55fbb7Slm66018 	if (rv) {
41690a55fbb7Slm66018 		cmn_err(CE_NOTE, "[%d] Failed to get VTOC (err=%d)",
41700a55fbb7Slm66018 				vdc->instance, rv);
41710a55fbb7Slm66018 		return (rv);
41720a55fbb7Slm66018 	}
41730a55fbb7Slm66018 
41740a55fbb7Slm66018 	/*
41750a55fbb7Slm66018 	 * find the slice that represents the entire "disk" and use that to
41760a55fbb7Slm66018 	 * read the disk label. The convention in Solaris is that slice 2
4177*d10e4ef2Snarayan 	 * represents the whole disk so we check that it is, otherwise we
41780a55fbb7Slm66018 	 * default to slice 0
41790a55fbb7Slm66018 	 */
41800a55fbb7Slm66018 	if ((vdc->vdisk_type == VD_DISK_TYPE_DISK) &&
41810a55fbb7Slm66018 	    (vdc->vtoc->v_part[2].p_tag == V_BACKUP)) {
41820a55fbb7Slm66018 		slice = 2;
41830a55fbb7Slm66018 	} else {
41840a55fbb7Slm66018 		slice = 0;
41850a55fbb7Slm66018 	}
4186*d10e4ef2Snarayan 
4187*d10e4ef2Snarayan 	/*
4188*d10e4ef2Snarayan 	 * Read disk label from start of disk
4189*d10e4ef2Snarayan 	 */
4190*d10e4ef2Snarayan 	vdc->label = kmem_zalloc(DK_LABEL_SIZE, KM_SLEEP);
4191*d10e4ef2Snarayan 	buf = kmem_alloc(sizeof (buf_t), KM_SLEEP);
4192*d10e4ef2Snarayan 	bioinit(buf);
4193*d10e4ef2Snarayan 	buf->b_un.b_addr = (caddr_t)vdc->label;
4194*d10e4ef2Snarayan 	buf->b_bcount = DK_LABEL_SIZE;
4195*d10e4ef2Snarayan 	buf->b_flags = B_BUSY | B_READ;
4196*d10e4ef2Snarayan 	buf->b_dev = dev;
4197*d10e4ef2Snarayan 	rv = vdc_populate_descriptor(vdc, (caddr_t)buf, DK_LABEL_SIZE,
41980a55fbb7Slm66018 			VD_OP_BREAD, 0, slice);
4199*d10e4ef2Snarayan 	rv = biowait(buf);
4200*d10e4ef2Snarayan 	biofini(buf);
4201*d10e4ef2Snarayan 	kmem_free(buf, sizeof (buf_t));
42020a55fbb7Slm66018 
42030a55fbb7Slm66018 	return (rv);
42041ae08745Sheppo }
4205