xref: /titanic_52/usr/src/uts/sun4v/io/vdc.c (revision e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061)
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 
60*e1ebb9ecSlm66018 #include <sys/atomic.h>
611ae08745Sheppo #include <sys/conf.h>
621ae08745Sheppo #include <sys/disp.h>
631ae08745Sheppo #include <sys/ddi.h>
641ae08745Sheppo #include <sys/dkio.h>
651ae08745Sheppo #include <sys/efi_partition.h>
661ae08745Sheppo #include <sys/fcntl.h>
671ae08745Sheppo #include <sys/file.h>
681ae08745Sheppo #include <sys/mach_descrip.h>
691ae08745Sheppo #include <sys/modctl.h>
701ae08745Sheppo #include <sys/mdeg.h>
711ae08745Sheppo #include <sys/note.h>
721ae08745Sheppo #include <sys/open.h>
73d10e4ef2Snarayan #include <sys/sdt.h>
741ae08745Sheppo #include <sys/stat.h>
751ae08745Sheppo #include <sys/sunddi.h>
761ae08745Sheppo #include <sys/types.h>
771ae08745Sheppo #include <sys/promif.h>
781ae08745Sheppo #include <sys/vtoc.h>
791ae08745Sheppo #include <sys/archsystm.h>
801ae08745Sheppo #include <sys/sysmacros.h>
811ae08745Sheppo 
821ae08745Sheppo #include <sys/cdio.h>
831ae08745Sheppo #include <sys/dktp/cm.h>
841ae08745Sheppo #include <sys/dktp/fdisk.h>
851ae08745Sheppo #include <sys/scsi/generic/sense.h>
861ae08745Sheppo #include <sys/scsi/impl/uscsi.h>	/* Needed for defn of USCSICMD ioctl */
871ae08745Sheppo #include <sys/scsi/targets/sddef.h>
881ae08745Sheppo 
891ae08745Sheppo #include <sys/ldoms.h>
901ae08745Sheppo #include <sys/ldc.h>
911ae08745Sheppo #include <sys/vio_common.h>
921ae08745Sheppo #include <sys/vio_mailbox.h>
931ae08745Sheppo #include <sys/vdsk_common.h>
941ae08745Sheppo #include <sys/vdsk_mailbox.h>
951ae08745Sheppo #include <sys/vdc.h>
961ae08745Sheppo 
971ae08745Sheppo /*
981ae08745Sheppo  * function prototypes
991ae08745Sheppo  */
1001ae08745Sheppo 
1011ae08745Sheppo /* standard driver functions */
1021ae08745Sheppo static int	vdc_open(dev_t *dev, int flag, int otyp, cred_t *cred);
1031ae08745Sheppo static int	vdc_close(dev_t dev, int flag, int otyp, cred_t *cred);
1041ae08745Sheppo static int	vdc_strategy(struct buf *buf);
1051ae08745Sheppo static int	vdc_print(dev_t dev, char *str);
1061ae08745Sheppo static int	vdc_dump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk);
1071ae08745Sheppo static int	vdc_read(dev_t dev, struct uio *uio, cred_t *cred);
1081ae08745Sheppo static int	vdc_write(dev_t dev, struct uio *uio, cred_t *cred);
1091ae08745Sheppo static int	vdc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
1101ae08745Sheppo 			cred_t *credp, int *rvalp);
1111ae08745Sheppo static int	vdc_aread(dev_t dev, struct aio_req *aio, cred_t *cred);
1121ae08745Sheppo static int	vdc_awrite(dev_t dev, struct aio_req *aio, cred_t *cred);
1131ae08745Sheppo 
1141ae08745Sheppo static int	vdc_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
1151ae08745Sheppo 			void *arg, void **resultp);
1161ae08745Sheppo static int	vdc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
1171ae08745Sheppo static int	vdc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
1181ae08745Sheppo 
1191ae08745Sheppo /* setup */
1200a55fbb7Slm66018 static int	vdc_send(vdc_t *vdc, caddr_t pkt, size_t *msglen);
1211ae08745Sheppo static int	vdc_do_ldc_init(vdc_t *vdc);
1221ae08745Sheppo static int	vdc_start_ldc_connection(vdc_t *vdc);
1231ae08745Sheppo static int	vdc_create_device_nodes(vdc_t *vdc);
1241ae08745Sheppo static int	vdc_create_device_nodes_props(vdc_t *vdc);
1251ae08745Sheppo static int	vdc_get_ldc_id(dev_info_t *dip, uint64_t *ldc_id);
1260a55fbb7Slm66018 static int	vdc_do_ldc_up(vdc_t *vdc);
1271ae08745Sheppo static void	vdc_terminate_ldc(vdc_t *vdc);
1281ae08745Sheppo static int	vdc_init_descriptor_ring(vdc_t *vdc);
1291ae08745Sheppo static void	vdc_destroy_descriptor_ring(vdc_t *vdc);
1301ae08745Sheppo 
1311ae08745Sheppo /* handshake with vds */
1321ae08745Sheppo static void		vdc_init_handshake_negotiation(void *arg);
1330a55fbb7Slm66018 static int		vdc_init_ver_negotiation(vdc_t *vdc, vio_ver_t ver);
1341ae08745Sheppo static int		vdc_init_attr_negotiation(vdc_t *vdc);
1351ae08745Sheppo static int		vdc_init_dring_negotiate(vdc_t *vdc);
1361ae08745Sheppo static void		vdc_reset_connection(vdc_t *vdc, boolean_t resetldc);
1371ae08745Sheppo static boolean_t	vdc_is_able_to_tx_data(vdc_t *vdc, int flag);
1380a55fbb7Slm66018 static boolean_t	vdc_is_supported_version(vio_ver_msg_t *ver_msg);
1391ae08745Sheppo 
1400a55fbb7Slm66018 /* processing incoming messages from vDisk server */
1411ae08745Sheppo static void	vdc_process_msg_thread(vdc_t *vdc);
1421ae08745Sheppo static void	vdc_process_msg(void *arg);
1430a55fbb7Slm66018 static void	vdc_do_process_msg(vdc_t *vdc);
1440a55fbb7Slm66018 static uint_t	vdc_handle_cb(uint64_t event, caddr_t arg);
1451ae08745Sheppo static int	vdc_process_ctrl_msg(vdc_t *vdc, vio_msg_t msg);
1461ae08745Sheppo static int	vdc_process_data_msg(vdc_t *vdc, vio_msg_t msg);
1471ae08745Sheppo static int	vdc_process_err_msg(vdc_t *vdc, vio_msg_t msg);
1480a55fbb7Slm66018 static int	vdc_handle_ver_msg(vdc_t *vdc, vio_ver_msg_t *ver_msg);
1490a55fbb7Slm66018 static int	vdc_handle_attr_msg(vdc_t *vdc, vd_attr_msg_t *attr_msg);
1500a55fbb7Slm66018 static int	vdc_handle_dring_reg_msg(vdc_t *vdc, vio_dring_reg_msg_t *msg);
1511ae08745Sheppo static int	vdc_get_next_dring_entry_id(vdc_t *vdc, uint_t needed);
1521ae08745Sheppo static int	vdc_populate_descriptor(vdc_t *vdc, caddr_t addr,
1531ae08745Sheppo 			size_t nbytes, int op, uint64_t arg, uint64_t slice);
1541ae08745Sheppo static int	vdc_wait_for_descriptor_update(vdc_t *vdc, uint_t idx,
1551ae08745Sheppo 			vio_dring_msg_t dmsg);
1561ae08745Sheppo static int	vdc_depopulate_descriptor(vdc_t *vdc, uint_t idx);
1571ae08745Sheppo static int	vdc_populate_mem_hdl(vdc_t *vdc, uint_t idx,
1581ae08745Sheppo 			caddr_t addr, size_t nbytes, int operation);
159*e1ebb9ecSlm66018 static int	vdc_verify_seq_num(vdc_t *vdc, vio_dring_msg_t *dring_msg);
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);
165d10e4ef2Snarayan static int	vdc_null_copy_func(vdc_t *vdc, void *from, void *to,
166d10e4ef2Snarayan 		    int mode, int dir);
167d10e4ef2Snarayan static int	vdc_get_vtoc_convert(vdc_t *vdc, void *from, void *to,
168d10e4ef2Snarayan 		    int mode, int dir);
169d10e4ef2Snarayan static int	vdc_set_vtoc_convert(vdc_t *vdc, void *from, void *to,
170d10e4ef2Snarayan 		    int mode, int dir);
171d10e4ef2Snarayan static int	vdc_get_geom_convert(vdc_t *vdc, void *from, void *to,
172d10e4ef2Snarayan 		    int mode, int dir);
173d10e4ef2Snarayan static int	vdc_set_geom_convert(vdc_t *vdc, void *from, void *to,
174d10e4ef2Snarayan 		    int mode, int dir);
175d10e4ef2Snarayan static int	vdc_uscsicmd_convert(vdc_t *vdc, void *from, void *to,
176d10e4ef2Snarayan 		    int mode, int dir);
1771ae08745Sheppo 
1781ae08745Sheppo /*
1791ae08745Sheppo  * Module variables
1801ae08745Sheppo  */
181*e1ebb9ecSlm66018 
182*e1ebb9ecSlm66018 /*
183*e1ebb9ecSlm66018  * Tunable variables to control how long vdc waits before timing out on
184*e1ebb9ecSlm66018  * various operations
185*e1ebb9ecSlm66018  */
186*e1ebb9ecSlm66018 static int	vdc_retries = 10;
187*e1ebb9ecSlm66018 
188*e1ebb9ecSlm66018 /* calculated from 'vdc_usec_timeout' during attach */
189*e1ebb9ecSlm66018 static uint64_t	vdc_hz_timeout;				/* units: Hz */
190*e1ebb9ecSlm66018 static uint64_t	vdc_usec_timeout = 30 * MICROSEC;	/* 30s units: ns */
191*e1ebb9ecSlm66018 
192*e1ebb9ecSlm66018 static uint64_t	vdc_hz_timeout_ldc;			/* units: Hz */
193*e1ebb9ecSlm66018 static uint64_t	vdc_usec_timeout_ldc = 10 * MILLISEC;	/* 0.01s units: ns */
194*e1ebb9ecSlm66018 
195*e1ebb9ecSlm66018 /* values for dumping - need to run in a tighter loop */
196*e1ebb9ecSlm66018 static uint64_t	vdc_usec_timeout_dump = 100 * MILLISEC;	/* 0.1s units: ns */
197*e1ebb9ecSlm66018 static int	vdc_dump_retries = 100;
198*e1ebb9ecSlm66018 
199*e1ebb9ecSlm66018 /* Count of the number of vdc instances attached */
200*e1ebb9ecSlm66018 static volatile uint32_t	vdc_instance_count = 0;
2011ae08745Sheppo 
2021ae08745Sheppo /* Soft state pointer */
2031ae08745Sheppo static void	*vdc_state;
2041ae08745Sheppo 
2051ae08745Sheppo /* variable level controlling the verbosity of the error/debug messages */
2061ae08745Sheppo int	vdc_msglevel = 0;
2071ae08745Sheppo 
2080a55fbb7Slm66018 /*
2090a55fbb7Slm66018  * Supported vDisk protocol version pairs.
2100a55fbb7Slm66018  *
2110a55fbb7Slm66018  * The first array entry is the latest and preferred version.
2120a55fbb7Slm66018  */
2130a55fbb7Slm66018 static const vio_ver_t	vdc_version[] = {{1, 0}};
2141ae08745Sheppo 
2151ae08745Sheppo static struct cb_ops vdc_cb_ops = {
2161ae08745Sheppo 	vdc_open,	/* cb_open */
2171ae08745Sheppo 	vdc_close,	/* cb_close */
2181ae08745Sheppo 	vdc_strategy,	/* cb_strategy */
2191ae08745Sheppo 	vdc_print,	/* cb_print */
2201ae08745Sheppo 	vdc_dump,	/* cb_dump */
2211ae08745Sheppo 	vdc_read,	/* cb_read */
2221ae08745Sheppo 	vdc_write,	/* cb_write */
2231ae08745Sheppo 	vdc_ioctl,	/* cb_ioctl */
2241ae08745Sheppo 	nodev,		/* cb_devmap */
2251ae08745Sheppo 	nodev,		/* cb_mmap */
2261ae08745Sheppo 	nodev,		/* cb_segmap */
2271ae08745Sheppo 	nochpoll,	/* cb_chpoll */
2281ae08745Sheppo 	ddi_prop_op,	/* cb_prop_op */
2291ae08745Sheppo 	NULL,		/* cb_str */
2301ae08745Sheppo 	D_MP | D_64BIT,	/* cb_flag */
2311ae08745Sheppo 	CB_REV,		/* cb_rev */
2321ae08745Sheppo 	vdc_aread,	/* cb_aread */
2331ae08745Sheppo 	vdc_awrite	/* cb_awrite */
2341ae08745Sheppo };
2351ae08745Sheppo 
2361ae08745Sheppo static struct dev_ops vdc_ops = {
2371ae08745Sheppo 	DEVO_REV,	/* devo_rev */
2381ae08745Sheppo 	0,		/* devo_refcnt */
2391ae08745Sheppo 	vdc_getinfo,	/* devo_getinfo */
2401ae08745Sheppo 	nulldev,	/* devo_identify */
2411ae08745Sheppo 	nulldev,	/* devo_probe */
2421ae08745Sheppo 	vdc_attach,	/* devo_attach */
2431ae08745Sheppo 	vdc_detach,	/* devo_detach */
2441ae08745Sheppo 	nodev,		/* devo_reset */
2451ae08745Sheppo 	&vdc_cb_ops,	/* devo_cb_ops */
2461ae08745Sheppo 	NULL,		/* devo_bus_ops */
2471ae08745Sheppo 	nulldev		/* devo_power */
2481ae08745Sheppo };
2491ae08745Sheppo 
2501ae08745Sheppo static struct modldrv modldrv = {
2511ae08745Sheppo 	&mod_driverops,
2521ae08745Sheppo 	"virtual disk client %I%",
2531ae08745Sheppo 	&vdc_ops,
2541ae08745Sheppo };
2551ae08745Sheppo 
2561ae08745Sheppo static struct modlinkage modlinkage = {
2571ae08745Sheppo 	MODREV_1,
2581ae08745Sheppo 	&modldrv,
2591ae08745Sheppo 	NULL
2601ae08745Sheppo };
2611ae08745Sheppo 
2621ae08745Sheppo /* -------------------------------------------------------------------------- */
2631ae08745Sheppo 
2641ae08745Sheppo /*
2651ae08745Sheppo  * Device Driver housekeeping and setup
2661ae08745Sheppo  */
2671ae08745Sheppo 
2681ae08745Sheppo int
2691ae08745Sheppo _init(void)
2701ae08745Sheppo {
2711ae08745Sheppo 	int	status;
2721ae08745Sheppo 
2731ae08745Sheppo 	if ((status = ddi_soft_state_init(&vdc_state, sizeof (vdc_t), 1)) != 0)
2741ae08745Sheppo 		return (status);
2751ae08745Sheppo 	if ((status = mod_install(&modlinkage)) != 0)
2761ae08745Sheppo 		ddi_soft_state_fini(&vdc_state);
2771ae08745Sheppo 	return (status);
2781ae08745Sheppo }
2791ae08745Sheppo 
2801ae08745Sheppo int
2811ae08745Sheppo _info(struct modinfo *modinfop)
2821ae08745Sheppo {
2831ae08745Sheppo 	return (mod_info(&modlinkage, modinfop));
2841ae08745Sheppo }
2851ae08745Sheppo 
2861ae08745Sheppo int
2871ae08745Sheppo _fini(void)
2881ae08745Sheppo {
2891ae08745Sheppo 	int	status;
2901ae08745Sheppo 
2911ae08745Sheppo 	if ((status = mod_remove(&modlinkage)) != 0)
2921ae08745Sheppo 		return (status);
2931ae08745Sheppo 	ddi_soft_state_fini(&vdc_state);
2941ae08745Sheppo 	return (0);
2951ae08745Sheppo }
2961ae08745Sheppo 
2971ae08745Sheppo static int
2981ae08745Sheppo vdc_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,  void *arg, void **resultp)
2991ae08745Sheppo {
3001ae08745Sheppo 	_NOTE(ARGUNUSED(dip))
3011ae08745Sheppo 
3021ae08745Sheppo 	int	instance = SDUNIT(getminor((dev_t)arg));
3031ae08745Sheppo 	vdc_t	*vdc = NULL;
3041ae08745Sheppo 
3051ae08745Sheppo 	switch (cmd) {
3061ae08745Sheppo 	case DDI_INFO_DEVT2DEVINFO:
3071ae08745Sheppo 		if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) {
3081ae08745Sheppo 			*resultp = NULL;
3091ae08745Sheppo 			return (DDI_FAILURE);
3101ae08745Sheppo 		}
3111ae08745Sheppo 		*resultp = vdc->dip;
3121ae08745Sheppo 		return (DDI_SUCCESS);
3131ae08745Sheppo 	case DDI_INFO_DEVT2INSTANCE:
3141ae08745Sheppo 		*resultp = (void *)(uintptr_t)instance;
3151ae08745Sheppo 		return (DDI_SUCCESS);
3161ae08745Sheppo 	default:
3171ae08745Sheppo 		*resultp = NULL;
3181ae08745Sheppo 		return (DDI_FAILURE);
3191ae08745Sheppo 	}
3201ae08745Sheppo }
3211ae08745Sheppo 
3221ae08745Sheppo static int
3231ae08745Sheppo vdc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
3241ae08745Sheppo {
3251ae08745Sheppo 	int	instance;
3261ae08745Sheppo 	int	rv;
3271ae08745Sheppo 	uint_t	retries = 0;
3281ae08745Sheppo 	vdc_t	*vdc = NULL;
3291ae08745Sheppo 
3301ae08745Sheppo 	switch (cmd) {
3311ae08745Sheppo 	case DDI_DETACH:
3321ae08745Sheppo 		/* the real work happens below */
3331ae08745Sheppo 		break;
3341ae08745Sheppo 	case DDI_SUSPEND:
3351ae08745Sheppo 		/* nothing to do for this non-device */
3361ae08745Sheppo 		return (DDI_SUCCESS);
3371ae08745Sheppo 	default:
3381ae08745Sheppo 		return (DDI_FAILURE);
3391ae08745Sheppo 	}
3401ae08745Sheppo 
3411ae08745Sheppo 	ASSERT(cmd == DDI_DETACH);
3421ae08745Sheppo 	instance = ddi_get_instance(dip);
343*e1ebb9ecSlm66018 	DMSG(1, "[%d] Entered\n", instance);
3441ae08745Sheppo 
3451ae08745Sheppo 	if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) {
346*e1ebb9ecSlm66018 		cmn_err(CE_NOTE, "[%d] Couldn't get state structure", instance);
3471ae08745Sheppo 		return (DDI_FAILURE);
3481ae08745Sheppo 	}
3491ae08745Sheppo 
3501ae08745Sheppo 	if (vdc->open) {
351*e1ebb9ecSlm66018 		DMSG(0, "[%d] Cannot detach: device is open", instance);
3521ae08745Sheppo 		return (DDI_FAILURE);
3531ae08745Sheppo 	}
3541ae08745Sheppo 
355*e1ebb9ecSlm66018 	DMSG(0, "[%d] proceeding...\n", instance);
3561ae08745Sheppo 
3571ae08745Sheppo 	/*
3581ae08745Sheppo 	 * try and disable callbacks to prevent another handshake
3591ae08745Sheppo 	 */
3601ae08745Sheppo 	rv = ldc_set_cb_mode(vdc->ldc_handle, LDC_CB_DISABLE);
361*e1ebb9ecSlm66018 	DMSG(0, "[%d] callback disabled (rv=%d)\n", instance, rv);
3621ae08745Sheppo 
3631ae08745Sheppo 	/*
3641ae08745Sheppo 	 * Prevent any more attempts to start a handshake with the vdisk
3651ae08745Sheppo 	 * server and tear down the existing connection.
3661ae08745Sheppo 	 */
3671ae08745Sheppo 	mutex_enter(&vdc->lock);
3681ae08745Sheppo 	vdc->initialized |= VDC_HANDSHAKE_STOP;
3691ae08745Sheppo 	vdc_reset_connection(vdc, B_TRUE);
3701ae08745Sheppo 	mutex_exit(&vdc->lock);
3711ae08745Sheppo 
3721ae08745Sheppo 	if (vdc->initialized & VDC_THREAD) {
3731ae08745Sheppo 		mutex_enter(&vdc->msg_proc_lock);
3741ae08745Sheppo 		vdc->msg_proc_thr_state = VDC_THR_STOP;
3751ae08745Sheppo 		vdc->msg_pending = B_TRUE;
3761ae08745Sheppo 		cv_signal(&vdc->msg_proc_cv);
3771ae08745Sheppo 
3781ae08745Sheppo 		while (vdc->msg_proc_thr_state != VDC_THR_DONE) {
379*e1ebb9ecSlm66018 			DMSG(0, "[%d] Waiting for thread to exit\n", instance);
3801ae08745Sheppo 			rv = cv_timedwait(&vdc->msg_proc_cv,
381*e1ebb9ecSlm66018 				&vdc->msg_proc_lock,
382*e1ebb9ecSlm66018 				VD_GET_TIMEOUT_HZ(vdc_hz_timeout, 1));
3831ae08745Sheppo 			if ((rv == -1) && (retries++ > vdc_retries))
3841ae08745Sheppo 				break;
3851ae08745Sheppo 		}
3861ae08745Sheppo 		mutex_exit(&vdc->msg_proc_lock);
3871ae08745Sheppo 	}
3881ae08745Sheppo 
3891ae08745Sheppo 	mutex_enter(&vdc->lock);
3901ae08745Sheppo 
3911ae08745Sheppo 	if (vdc->initialized & VDC_DRING)
3921ae08745Sheppo 		vdc_destroy_descriptor_ring(vdc);
3931ae08745Sheppo 
3941ae08745Sheppo 	if (vdc->initialized & VDC_LDC)
3951ae08745Sheppo 		vdc_terminate_ldc(vdc);
3961ae08745Sheppo 
3971ae08745Sheppo 	mutex_exit(&vdc->lock);
3981ae08745Sheppo 
3991ae08745Sheppo 	if (vdc->initialized & VDC_MINOR) {
4001ae08745Sheppo 		ddi_prop_remove_all(dip);
4011ae08745Sheppo 		ddi_remove_minor_node(dip, NULL);
4021ae08745Sheppo 	}
4031ae08745Sheppo 
4041ae08745Sheppo 	if (vdc->initialized & VDC_LOCKS) {
4051ae08745Sheppo 		mutex_destroy(&vdc->lock);
4061ae08745Sheppo 		mutex_destroy(&vdc->attach_lock);
4071ae08745Sheppo 		mutex_destroy(&vdc->msg_proc_lock);
4081ae08745Sheppo 		mutex_destroy(&vdc->dring_lock);
4091ae08745Sheppo 		cv_destroy(&vdc->cv);
4101ae08745Sheppo 		cv_destroy(&vdc->attach_cv);
4111ae08745Sheppo 		cv_destroy(&vdc->msg_proc_cv);
4121ae08745Sheppo 	}
4131ae08745Sheppo 
4141ae08745Sheppo 	if (vdc->minfo)
4151ae08745Sheppo 		kmem_free(vdc->minfo, sizeof (struct dk_minfo));
4161ae08745Sheppo 
4171ae08745Sheppo 	if (vdc->cinfo)
4181ae08745Sheppo 		kmem_free(vdc->cinfo, sizeof (struct dk_cinfo));
4191ae08745Sheppo 
4201ae08745Sheppo 	if (vdc->vtoc)
4211ae08745Sheppo 		kmem_free(vdc->vtoc, sizeof (struct vtoc));
4221ae08745Sheppo 
4230a55fbb7Slm66018 	if (vdc->label)
4240a55fbb7Slm66018 		kmem_free(vdc->label, DK_LABEL_SIZE);
4250a55fbb7Slm66018 
4261ae08745Sheppo 	if (vdc->initialized & VDC_SOFT_STATE)
4271ae08745Sheppo 		ddi_soft_state_free(vdc_state, instance);
4281ae08745Sheppo 
429*e1ebb9ecSlm66018 	DMSG(0, "[%d] End %p\n", instance, (void *)vdc);
4301ae08745Sheppo 
4311ae08745Sheppo 	return (DDI_SUCCESS);
4321ae08745Sheppo }
4331ae08745Sheppo 
4341ae08745Sheppo 
4351ae08745Sheppo static int
4361ae08745Sheppo vdc_do_attach(dev_info_t *dip)
4371ae08745Sheppo {
4381ae08745Sheppo 	int		instance;
4391ae08745Sheppo 	vdc_t		*vdc = NULL;
4401ae08745Sheppo 	int		status;
4411ae08745Sheppo 	uint_t		retries = 0;
4421ae08745Sheppo 
4431ae08745Sheppo 	ASSERT(dip != NULL);
4441ae08745Sheppo 
4451ae08745Sheppo 	instance = ddi_get_instance(dip);
4461ae08745Sheppo 	if (ddi_soft_state_zalloc(vdc_state, instance) != DDI_SUCCESS) {
447*e1ebb9ecSlm66018 		cmn_err(CE_NOTE, "[%d] Couldn't alloc state structure",
448*e1ebb9ecSlm66018 		    instance);
4491ae08745Sheppo 		return (DDI_FAILURE);
4501ae08745Sheppo 	}
4511ae08745Sheppo 
4521ae08745Sheppo 	if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) {
453*e1ebb9ecSlm66018 		cmn_err(CE_NOTE, "[%d] Couldn't get state structure", instance);
4541ae08745Sheppo 		return (DDI_FAILURE);
4551ae08745Sheppo 	}
4561ae08745Sheppo 
4571ae08745Sheppo 	/*
4581ae08745Sheppo 	 * We assign the value to initialized in this case to zero out the
4591ae08745Sheppo 	 * variable and then set bits in it to indicate what has been done
4601ae08745Sheppo 	 */
4611ae08745Sheppo 	vdc->initialized = VDC_SOFT_STATE;
4621ae08745Sheppo 
4631ae08745Sheppo 	vdc_hz_timeout = drv_usectohz(vdc_usec_timeout);
464*e1ebb9ecSlm66018 	vdc_hz_timeout_ldc = drv_usectohz(vdc_usec_timeout_ldc);
4651ae08745Sheppo 
4661ae08745Sheppo 	vdc->dip	= dip;
4671ae08745Sheppo 	vdc->instance	= instance;
4681ae08745Sheppo 	vdc->open	= 0;
4691ae08745Sheppo 	vdc->vdisk_type	= VD_DISK_TYPE_UNK;
4701ae08745Sheppo 	vdc->state	= VD_STATE_INIT;
4711ae08745Sheppo 	vdc->ldc_state	= 0;
4721ae08745Sheppo 	vdc->session_id = 0;
4731ae08745Sheppo 	vdc->block_size = DEV_BSIZE;
4748e6a2a04Slm66018 	vdc->max_xfer_sz = maxphys / DEV_BSIZE;
4751ae08745Sheppo 
4761ae08745Sheppo 	vdc->vtoc = NULL;
4771ae08745Sheppo 	vdc->cinfo = NULL;
4781ae08745Sheppo 	vdc->minfo = NULL;
4791ae08745Sheppo 
4801ae08745Sheppo 	mutex_init(&vdc->lock, NULL, MUTEX_DRIVER, NULL);
4811ae08745Sheppo 	mutex_init(&vdc->attach_lock, NULL, MUTEX_DRIVER, NULL);
4821ae08745Sheppo 	mutex_init(&vdc->msg_proc_lock, NULL, MUTEX_DRIVER, NULL);
4831ae08745Sheppo 	mutex_init(&vdc->dring_lock, NULL, MUTEX_DRIVER, NULL);
4841ae08745Sheppo 	cv_init(&vdc->cv, NULL, CV_DRIVER, NULL);
4851ae08745Sheppo 	cv_init(&vdc->attach_cv, NULL, CV_DRIVER, NULL);
4861ae08745Sheppo 	cv_init(&vdc->msg_proc_cv, NULL, CV_DRIVER, NULL);
4871ae08745Sheppo 	vdc->initialized |= VDC_LOCKS;
4881ae08745Sheppo 
4891ae08745Sheppo 	vdc->msg_pending = B_FALSE;
4901ae08745Sheppo 	vdc->msg_proc_thr_id = thread_create(NULL, 0, vdc_process_msg_thread,
4911ae08745Sheppo 		vdc, 0, &p0, TS_RUN, minclsyspri);
4921ae08745Sheppo 	if (vdc->msg_proc_thr_id == NULL) {
4931ae08745Sheppo 		cmn_err(CE_NOTE, "[%d] Failed to create msg processing thread",
4941ae08745Sheppo 				instance);
4951ae08745Sheppo 		return (DDI_FAILURE);
4961ae08745Sheppo 	}
4971ae08745Sheppo 	vdc->initialized |= VDC_THREAD;
4981ae08745Sheppo 
4991ae08745Sheppo 	/* initialise LDC channel which will be used to communicate with vds */
5001ae08745Sheppo 	if (vdc_do_ldc_init(vdc) != 0) {
5011ae08745Sheppo 		cmn_err(CE_NOTE, "[%d] Couldn't initialize LDC", instance);
5021ae08745Sheppo 		return (DDI_FAILURE);
5031ae08745Sheppo 	}
5041ae08745Sheppo 
5051ae08745Sheppo 	/* Bring up connection with vds via LDC */
5061ae08745Sheppo 	status = vdc_start_ldc_connection(vdc);
5071ae08745Sheppo 	if (status != 0) {
508*e1ebb9ecSlm66018 		cmn_err(CE_NOTE, "[%d] Could not start LDC", instance);
5091ae08745Sheppo 		return (DDI_FAILURE);
5101ae08745Sheppo 	}
5111ae08745Sheppo 
5121ae08745Sheppo 	/*
5131ae08745Sheppo 	 * We need to wait until the handshake has completed before leaving
514*e1ebb9ecSlm66018 	 * the attach(). If this is the first vdc device attached (i.e. the root
515*e1ebb9ecSlm66018 	 * filesystem) we will wait much longer in the hope that we can finally
516*e1ebb9ecSlm66018 	 * communicate with the vDisk server (the service domain may be
517*e1ebb9ecSlm66018 	 * rebooting, etc.). This wait is necessary so that the device node(s)
518*e1ebb9ecSlm66018 	 * are created before the attach(9E) return (otherwise the open(9E) will
519*e1ebb9ecSlm66018 	 * fail and and the root file system will not boot).
5201ae08745Sheppo 	 */
521*e1ebb9ecSlm66018 	atomic_inc_32(&vdc_instance_count);
5221ae08745Sheppo 	mutex_enter(&vdc->attach_lock);
523*e1ebb9ecSlm66018 	while ((vdc->ldc_state != LDC_UP) || (vdc->state != VD_STATE_DATA)) {
5241ae08745Sheppo 
525*e1ebb9ecSlm66018 		DMSG(0, "[%d] handshake in progress [VD %d (LDC %d)]\n",
526*e1ebb9ecSlm66018 			instance, vdc->state, vdc->ldc_state);
5271ae08745Sheppo 
5281ae08745Sheppo 		status = cv_timedwait(&vdc->attach_cv, &vdc->attach_lock,
529*e1ebb9ecSlm66018 				VD_GET_TIMEOUT_HZ(vdc_hz_timeout, retries));
5301ae08745Sheppo 		if (status == -1) {
531*e1ebb9ecSlm66018 			/*
532*e1ebb9ecSlm66018 			 * If this is not the first instance attached or we
533*e1ebb9ecSlm66018 			 * have exceeeded the max number of retries we give
534*e1ebb9ecSlm66018 			 * up waiting and do not delay the attach any longer
535*e1ebb9ecSlm66018 			 */
536*e1ebb9ecSlm66018 			if ((vdc_instance_count != 1) ||
537*e1ebb9ecSlm66018 			    (retries >= vdc_retries)) {
538*e1ebb9ecSlm66018 				DMSG(0, "[%d] Giving up wait for handshake\n",
539*e1ebb9ecSlm66018 						instance);
5401ae08745Sheppo 				mutex_exit(&vdc->attach_lock);
5411ae08745Sheppo 				return (DDI_FAILURE);
5421ae08745Sheppo 			} else {
543*e1ebb9ecSlm66018 				DMSG(0, "[%d] Retry #%d for handshake.\n",
544*e1ebb9ecSlm66018 						instance, retries);
5450a55fbb7Slm66018 				vdc_init_handshake_negotiation(vdc);
5461ae08745Sheppo 				retries++;
5471ae08745Sheppo 			}
5481ae08745Sheppo 		}
5491ae08745Sheppo 	}
5501ae08745Sheppo 	mutex_exit(&vdc->attach_lock);
5511ae08745Sheppo 
5520a55fbb7Slm66018 	/*
5530a55fbb7Slm66018 	 * Once the handshake is complete, we can use the DRing to send
5540a55fbb7Slm66018 	 * requests to the vDisk server to calculate the geometry and
5550a55fbb7Slm66018 	 * VTOC of the "disk"
5560a55fbb7Slm66018 	 */
5570a55fbb7Slm66018 	status = vdc_setup_disk_layout(vdc);
5580a55fbb7Slm66018 	if (status != 0) {
5590a55fbb7Slm66018 		cmn_err(CE_NOTE, "[%d] Failed to discover disk layout (err%d)",
5600a55fbb7Slm66018 				vdc->instance, status);
5611ae08745Sheppo 	}
5621ae08745Sheppo 
5631ae08745Sheppo 	/*
5641ae08745Sheppo 	 * Now that we have the device info we can create the
5651ae08745Sheppo 	 * device nodes and properties
5661ae08745Sheppo 	 */
5671ae08745Sheppo 	status = vdc_create_device_nodes(vdc);
5681ae08745Sheppo 	if (status) {
5691ae08745Sheppo 		cmn_err(CE_NOTE, "[%d] Failed to create device nodes",
5701ae08745Sheppo 				instance);
5711ae08745Sheppo 		return (status);
5721ae08745Sheppo 	}
5731ae08745Sheppo 	status = vdc_create_device_nodes_props(vdc);
5741ae08745Sheppo 	if (status) {
5751ae08745Sheppo 		cmn_err(CE_NOTE, "[%d] Failed to create device nodes"
5760a55fbb7Slm66018 				" properties (%d)", instance, status);
5771ae08745Sheppo 		return (status);
5781ae08745Sheppo 	}
5791ae08745Sheppo 
5801ae08745Sheppo 	ddi_report_dev(dip);
5811ae08745Sheppo 
582*e1ebb9ecSlm66018 	DMSG(0, "[%d] Attach completed\n", instance);
5831ae08745Sheppo 	return (status);
5841ae08745Sheppo }
5851ae08745Sheppo 
5861ae08745Sheppo static int
5871ae08745Sheppo vdc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
5881ae08745Sheppo {
5891ae08745Sheppo 	int	status;
5901ae08745Sheppo 
5911ae08745Sheppo 	switch (cmd) {
5921ae08745Sheppo 	case DDI_ATTACH:
5931ae08745Sheppo 		if ((status = vdc_do_attach(dip)) != 0)
5941ae08745Sheppo 			(void) vdc_detach(dip, DDI_DETACH);
5951ae08745Sheppo 		return (status);
5961ae08745Sheppo 	case DDI_RESUME:
5971ae08745Sheppo 		/* nothing to do for this non-device */
5981ae08745Sheppo 		return (DDI_SUCCESS);
5991ae08745Sheppo 	default:
6001ae08745Sheppo 		return (DDI_FAILURE);
6011ae08745Sheppo 	}
6021ae08745Sheppo }
6031ae08745Sheppo 
6041ae08745Sheppo static int
6051ae08745Sheppo vdc_do_ldc_init(vdc_t *vdc)
6061ae08745Sheppo {
6071ae08745Sheppo 	int			status = 0;
6081ae08745Sheppo 	ldc_status_t		ldc_state;
6091ae08745Sheppo 	ldc_attr_t		ldc_attr;
6101ae08745Sheppo 	uint64_t		ldc_id = 0;
6111ae08745Sheppo 	dev_info_t		*dip = NULL;
6121ae08745Sheppo 
6131ae08745Sheppo 	ASSERT(vdc != NULL);
6141ae08745Sheppo 
6151ae08745Sheppo 	dip = vdc->dip;
6161ae08745Sheppo 	vdc->initialized |= VDC_LDC;
6171ae08745Sheppo 
6181ae08745Sheppo 	if ((status = vdc_get_ldc_id(dip, &ldc_id)) != 0) {
619*e1ebb9ecSlm66018 		cmn_err(CE_NOTE, "[%d] Failed to get LDC channel ID property",
620*e1ebb9ecSlm66018 				vdc->instance);
6211ae08745Sheppo 		return (EIO);
6221ae08745Sheppo 	}
6231ae08745Sheppo 	vdc->ldc_id = ldc_id;
6241ae08745Sheppo 
6251ae08745Sheppo 	ldc_attr.devclass = LDC_DEV_BLK;
6261ae08745Sheppo 	ldc_attr.instance = vdc->instance;
6271ae08745Sheppo 	ldc_attr.mode = LDC_MODE_UNRELIABLE;	/* unreliable transport */
628*e1ebb9ecSlm66018 	ldc_attr.mtu = VD_LDC_MTU;
6291ae08745Sheppo 
6301ae08745Sheppo 	if ((vdc->initialized & VDC_LDC_INIT) == 0) {
6311ae08745Sheppo 		status = ldc_init(ldc_id, &ldc_attr, &vdc->ldc_handle);
6321ae08745Sheppo 		if (status != 0) {
6331ae08745Sheppo 			cmn_err(CE_NOTE, "[%d] ldc_init(chan %ld) returned %d",
6341ae08745Sheppo 					vdc->instance, ldc_id, status);
6351ae08745Sheppo 			return (status);
6361ae08745Sheppo 		}
6371ae08745Sheppo 		vdc->initialized |= VDC_LDC_INIT;
6381ae08745Sheppo 	}
6391ae08745Sheppo 	status = ldc_status(vdc->ldc_handle, &ldc_state);
6401ae08745Sheppo 	if (status != 0) {
641*e1ebb9ecSlm66018 		cmn_err(CE_NOTE, "[%d] Cannot discover LDC status [err=%d]",
642*e1ebb9ecSlm66018 				vdc->instance, status);
6431ae08745Sheppo 		return (status);
6441ae08745Sheppo 	}
6451ae08745Sheppo 	vdc->ldc_state = ldc_state;
6461ae08745Sheppo 
6471ae08745Sheppo 	if ((vdc->initialized & VDC_LDC_CB) == 0) {
6481ae08745Sheppo 		status = ldc_reg_callback(vdc->ldc_handle, vdc_handle_cb,
6491ae08745Sheppo 		    (caddr_t)vdc);
6501ae08745Sheppo 		if (status != 0) {
651*e1ebb9ecSlm66018 			cmn_err(CE_NOTE, "[%d] LDC callback reg. failed (%d)",
652*e1ebb9ecSlm66018 					vdc->instance, status);
6531ae08745Sheppo 			return (status);
6541ae08745Sheppo 		}
6551ae08745Sheppo 		vdc->initialized |= VDC_LDC_CB;
6561ae08745Sheppo 	}
6571ae08745Sheppo 
6581ae08745Sheppo 	vdc->initialized |= VDC_LDC;
6591ae08745Sheppo 
6601ae08745Sheppo 	/*
6611ae08745Sheppo 	 * At this stage we have initialised LDC, we will now try and open
6621ae08745Sheppo 	 * the connection.
6631ae08745Sheppo 	 */
6641ae08745Sheppo 	if (vdc->ldc_state == LDC_INIT) {
6651ae08745Sheppo 		status = ldc_open(vdc->ldc_handle);
6661ae08745Sheppo 		if (status != 0) {
6671ae08745Sheppo 			cmn_err(CE_NOTE, "[%d] ldc_open(chan %ld) returned %d",
6681ae08745Sheppo 					vdc->instance, vdc->ldc_id, status);
6691ae08745Sheppo 			return (status);
6701ae08745Sheppo 		}
6711ae08745Sheppo 		vdc->initialized |= VDC_LDC_OPEN;
6721ae08745Sheppo 	}
6731ae08745Sheppo 
6741ae08745Sheppo 	return (status);
6751ae08745Sheppo }
6761ae08745Sheppo 
6771ae08745Sheppo static int
6781ae08745Sheppo vdc_start_ldc_connection(vdc_t *vdc)
6791ae08745Sheppo {
6801ae08745Sheppo 	int		status = 0;
6811ae08745Sheppo 
6821ae08745Sheppo 	ASSERT(vdc != NULL);
6831ae08745Sheppo 
6841ae08745Sheppo 	mutex_enter(&vdc->lock);
6851ae08745Sheppo 
6861ae08745Sheppo 	if (vdc->ldc_state == LDC_UP) {
687*e1ebb9ecSlm66018 		DMSG(0, "[%d] LDC is already UP ..\n", vdc->instance);
6881ae08745Sheppo 		mutex_exit(&vdc->lock);
6891ae08745Sheppo 		return (0);
6901ae08745Sheppo 	}
6911ae08745Sheppo 
6920a55fbb7Slm66018 	status = vdc_do_ldc_up(vdc);
6931ae08745Sheppo 
694*e1ebb9ecSlm66018 	DMSG(0, "[%d] Finished bringing up LDC\n", vdc->instance);
6951ae08745Sheppo 
6961ae08745Sheppo 	mutex_exit(&vdc->lock);
6971ae08745Sheppo 
6981ae08745Sheppo 	return (status);
6991ae08745Sheppo }
7001ae08745Sheppo 
7011ae08745Sheppo 
7021ae08745Sheppo /*
7031ae08745Sheppo  * Function:
7041ae08745Sheppo  *	vdc_create_device_nodes
7051ae08745Sheppo  *
7061ae08745Sheppo  * Description:
7071ae08745Sheppo  *	This function creates the block and character device nodes under
7081ae08745Sheppo  *	/devices along with the node properties. It is called as part of
7091ae08745Sheppo  *	the attach(9E) of the instance during the handshake with vds after
7101ae08745Sheppo  *	vds has sent the attributes to vdc.
7111ae08745Sheppo  *
7121ae08745Sheppo  *	If the device is of type VD_DISK_TYPE_SLICE then the minor node
7131ae08745Sheppo  *	of 2 is used in keeping with the Solaris convention that slice 2
7141ae08745Sheppo  *	refers to a whole disk. Slices start at 'a'
7151ae08745Sheppo  *
7161ae08745Sheppo  * Parameters:
7171ae08745Sheppo  *	vdc 		- soft state pointer
7181ae08745Sheppo  *
7191ae08745Sheppo  * Return Values
7201ae08745Sheppo  *	0		- Success
7211ae08745Sheppo  *	EIO		- Failed to create node
7221ae08745Sheppo  *	EINVAL		- Unknown type of disk exported
7231ae08745Sheppo  */
7241ae08745Sheppo static int
7251ae08745Sheppo vdc_create_device_nodes(vdc_t *vdc)
7261ae08745Sheppo {
7271ae08745Sheppo 	/* uses NNNN which is OK as long as # of disks <= 10000 */
7281ae08745Sheppo 	char		name[sizeof ("disk@NNNN:s,raw")];
7291ae08745Sheppo 	dev_info_t	*dip = NULL;
7301ae08745Sheppo 	int		instance;
7311ae08745Sheppo 	int		num_slices = 1;
7321ae08745Sheppo 	int		i;
7331ae08745Sheppo 
7341ae08745Sheppo 	ASSERT(vdc != NULL);
7351ae08745Sheppo 
7361ae08745Sheppo 	instance = vdc->instance;
7371ae08745Sheppo 	dip = vdc->dip;
7381ae08745Sheppo 
7391ae08745Sheppo 	switch (vdc->vdisk_type) {
7401ae08745Sheppo 	case VD_DISK_TYPE_DISK:
7411ae08745Sheppo 		num_slices = V_NUMPAR;
7421ae08745Sheppo 		break;
7431ae08745Sheppo 	case VD_DISK_TYPE_SLICE:
7441ae08745Sheppo 		num_slices = 1;
7451ae08745Sheppo 		break;
7461ae08745Sheppo 	case VD_DISK_TYPE_UNK:
7471ae08745Sheppo 	default:
7481ae08745Sheppo 		return (EINVAL);
7491ae08745Sheppo 	}
7501ae08745Sheppo 
7511ae08745Sheppo 	for (i = 0; i < num_slices; i++) {
7521ae08745Sheppo 		(void) snprintf(name, sizeof (name), "%c", 'a' + i);
7531ae08745Sheppo 		if (ddi_create_minor_node(dip, name, S_IFBLK,
7541ae08745Sheppo 		    VD_MAKE_DEV(instance, i), DDI_NT_BLOCK, 0) != DDI_SUCCESS) {
755*e1ebb9ecSlm66018 			cmn_err(CE_NOTE, "[%d] Couldn't add block node '%s'",
756*e1ebb9ecSlm66018 				instance, name);
7571ae08745Sheppo 			return (EIO);
7581ae08745Sheppo 		}
7591ae08745Sheppo 
7601ae08745Sheppo 		/* if any device node is created we set this flag */
7611ae08745Sheppo 		vdc->initialized |= VDC_MINOR;
7621ae08745Sheppo 
7631ae08745Sheppo 		(void) snprintf(name, sizeof (name), "%c%s",
7641ae08745Sheppo 			'a' + i, ",raw");
7651ae08745Sheppo 		if (ddi_create_minor_node(dip, name, S_IFCHR,
7661ae08745Sheppo 		    VD_MAKE_DEV(instance, i), DDI_NT_BLOCK, 0) != DDI_SUCCESS) {
767*e1ebb9ecSlm66018 			cmn_err(CE_NOTE, "[%d] Couldn't add raw node '%s'",
768*e1ebb9ecSlm66018 				instance, name);
7691ae08745Sheppo 			return (EIO);
7701ae08745Sheppo 		}
7711ae08745Sheppo 	}
7721ae08745Sheppo 
7731ae08745Sheppo 	return (0);
7741ae08745Sheppo }
7751ae08745Sheppo 
7761ae08745Sheppo /*
7771ae08745Sheppo  * Function:
7781ae08745Sheppo  *	vdc_create_device_nodes_props
7791ae08745Sheppo  *
7801ae08745Sheppo  * Description:
7811ae08745Sheppo  *	This function creates the block and character device nodes under
7821ae08745Sheppo  *	/devices along with the node properties. It is called as part of
7831ae08745Sheppo  *	the attach(9E) of the instance during the handshake with vds after
7841ae08745Sheppo  *	vds has sent the attributes to vdc.
7851ae08745Sheppo  *
7861ae08745Sheppo  * Parameters:
7871ae08745Sheppo  *	vdc 		- soft state pointer
7881ae08745Sheppo  *
7891ae08745Sheppo  * Return Values
7901ae08745Sheppo  *	0		- Success
7911ae08745Sheppo  *	EIO		- Failed to create device node property
7921ae08745Sheppo  *	EINVAL		- Unknown type of disk exported
7931ae08745Sheppo  */
7941ae08745Sheppo static int
7951ae08745Sheppo vdc_create_device_nodes_props(vdc_t *vdc)
7961ae08745Sheppo {
7971ae08745Sheppo 	dev_info_t	*dip = NULL;
7981ae08745Sheppo 	int		instance;
7991ae08745Sheppo 	int		num_slices = 1;
8001ae08745Sheppo 	int64_t		size = 0;
8011ae08745Sheppo 	dev_t		dev;
8021ae08745Sheppo 	int		rv;
8031ae08745Sheppo 	int		i;
8041ae08745Sheppo 
8051ae08745Sheppo 	ASSERT(vdc != NULL);
8061ae08745Sheppo 
8071ae08745Sheppo 	instance = vdc->instance;
8081ae08745Sheppo 	dip = vdc->dip;
8091ae08745Sheppo 
8101ae08745Sheppo 	if ((vdc->vtoc == NULL) || (vdc->vtoc->v_sanity != VTOC_SANE)) {
8111ae08745Sheppo 		cmn_err(CE_NOTE, "![%d] Could not create device node property."
8121ae08745Sheppo 				" No VTOC available", instance);
8131ae08745Sheppo 		return (ENXIO);
8141ae08745Sheppo 	}
8151ae08745Sheppo 
8161ae08745Sheppo 	switch (vdc->vdisk_type) {
8171ae08745Sheppo 	case VD_DISK_TYPE_DISK:
8181ae08745Sheppo 		num_slices = V_NUMPAR;
8191ae08745Sheppo 		break;
8201ae08745Sheppo 	case VD_DISK_TYPE_SLICE:
8211ae08745Sheppo 		num_slices = 1;
8221ae08745Sheppo 		break;
8231ae08745Sheppo 	case VD_DISK_TYPE_UNK:
8241ae08745Sheppo 	default:
8251ae08745Sheppo 		return (EINVAL);
8261ae08745Sheppo 	}
8271ae08745Sheppo 
8281ae08745Sheppo 	for (i = 0; i < num_slices; i++) {
8291ae08745Sheppo 		dev = makedevice(ddi_driver_major(dip),
8301ae08745Sheppo 			VD_MAKE_DEV(instance, i));
8311ae08745Sheppo 
8321ae08745Sheppo 		size = vdc->vtoc->v_part[i].p_size * vdc->vtoc->v_sectorsz;
833*e1ebb9ecSlm66018 		DMSG(0, "[%d] sz %ld (%ld Mb)  p_size %lx\n",
834*e1ebb9ecSlm66018 				instance, size, size / (1024 * 1024),
8351ae08745Sheppo 				vdc->vtoc->v_part[i].p_size);
8361ae08745Sheppo 
8371ae08745Sheppo 		rv = ddi_prop_update_int64(dev, dip, VDC_SIZE_PROP_NAME, size);
8381ae08745Sheppo 		if (rv != DDI_PROP_SUCCESS) {
839*e1ebb9ecSlm66018 			cmn_err(CE_NOTE, "[%d] Couldn't add '%s' prop of [%ld]",
840*e1ebb9ecSlm66018 				instance, VDC_SIZE_PROP_NAME, size);
8411ae08745Sheppo 			return (EIO);
8421ae08745Sheppo 		}
8431ae08745Sheppo 
8441ae08745Sheppo 		rv = ddi_prop_update_int64(dev, dip, VDC_NBLOCKS_PROP_NAME,
8451ae08745Sheppo 			lbtodb(size));
8461ae08745Sheppo 		if (rv != DDI_PROP_SUCCESS) {
847*e1ebb9ecSlm66018 			cmn_err(CE_NOTE, "[%d] Couldn't add '%s' prop [%llu]",
8481ae08745Sheppo 				instance, VDC_NBLOCKS_PROP_NAME, lbtodb(size));
8491ae08745Sheppo 			return (EIO);
8501ae08745Sheppo 		}
8511ae08745Sheppo 	}
8521ae08745Sheppo 
8531ae08745Sheppo 	return (0);
8541ae08745Sheppo }
8551ae08745Sheppo 
8561ae08745Sheppo static int
8571ae08745Sheppo vdc_open(dev_t *dev, int flag, int otyp, cred_t *cred)
8581ae08745Sheppo {
8591ae08745Sheppo 	_NOTE(ARGUNUSED(cred))
8601ae08745Sheppo 
8611ae08745Sheppo 	int		instance;
8621ae08745Sheppo 	vdc_t		*vdc;
8631ae08745Sheppo 
8641ae08745Sheppo 	ASSERT(dev != NULL);
8651ae08745Sheppo 	instance = SDUNIT(getminor(*dev));
8661ae08745Sheppo 
867*e1ebb9ecSlm66018 	DMSG(0, "[%d] minor = %d flag = %x, otyp = %x\n",
868*e1ebb9ecSlm66018 			instance, getminor(*dev), flag, otyp);
8691ae08745Sheppo 
8701ae08745Sheppo 	if ((otyp != OTYP_CHR) && (otyp != OTYP_BLK))
8711ae08745Sheppo 		return (EINVAL);
8721ae08745Sheppo 
8731ae08745Sheppo 	if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) {
874*e1ebb9ecSlm66018 		cmn_err(CE_NOTE, "[%d] Couldn't get state structure", instance);
8751ae08745Sheppo 		return (ENXIO);
8761ae08745Sheppo 	}
8771ae08745Sheppo 
8781ae08745Sheppo 	/*
8791ae08745Sheppo 	 * Check to see if we can communicate with vds
8801ae08745Sheppo 	 */
8810a55fbb7Slm66018 	if (!vdc_is_able_to_tx_data(vdc, flag)) {
882*e1ebb9ecSlm66018 		DMSG(0, "[%d] Not ready to transmit data (flag=%x)\n",
883*e1ebb9ecSlm66018 				instance, flag);
8841ae08745Sheppo 		return (ENOLINK);
8851ae08745Sheppo 	}
8861ae08745Sheppo 
8871ae08745Sheppo 	mutex_enter(&vdc->lock);
8881ae08745Sheppo 	vdc->open++;
8891ae08745Sheppo 	mutex_exit(&vdc->lock);
8901ae08745Sheppo 
8911ae08745Sheppo 	return (0);
8921ae08745Sheppo }
8931ae08745Sheppo 
8941ae08745Sheppo static int
8951ae08745Sheppo vdc_close(dev_t dev, int flag, int otyp, cred_t *cred)
8961ae08745Sheppo {
8971ae08745Sheppo 	_NOTE(ARGUNUSED(cred))
8981ae08745Sheppo 
8991ae08745Sheppo 	int	instance;
9001ae08745Sheppo 	vdc_t	*vdc;
9011ae08745Sheppo 
9021ae08745Sheppo 	instance = SDUNIT(getminor(dev));
9031ae08745Sheppo 
904*e1ebb9ecSlm66018 	DMSG(0, "[%d] flag = %x, otyp = %x\n", instance, flag, otyp);
9051ae08745Sheppo 
9061ae08745Sheppo 	if ((otyp != OTYP_CHR) && (otyp != OTYP_BLK))
9071ae08745Sheppo 		return (EINVAL);
9081ae08745Sheppo 
9091ae08745Sheppo 	if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) {
910*e1ebb9ecSlm66018 		cmn_err(CE_NOTE, "[%d] Couldn't get state structure", instance);
9111ae08745Sheppo 		return (ENXIO);
9121ae08745Sheppo 	}
9131ae08745Sheppo 
9141ae08745Sheppo 	/*
9151ae08745Sheppo 	 * Check to see if we can communicate with vds
9161ae08745Sheppo 	 */
9170a55fbb7Slm66018 	if (!vdc_is_able_to_tx_data(vdc, 0)) {
918*e1ebb9ecSlm66018 		DMSG(0, "[%d] Not ready to transmit data (flag=%x)\n",
919*e1ebb9ecSlm66018 				instance, flag);
9201ae08745Sheppo 		return (ETIMEDOUT);
9211ae08745Sheppo 	}
9221ae08745Sheppo 
9231ae08745Sheppo 	if (vdc->dkio_flush_pending) {
924*e1ebb9ecSlm66018 		DMSG(0, "[%d] Cannot detach: %d outstanding DKIO flushes\n",
925*e1ebb9ecSlm66018 			instance, vdc->dkio_flush_pending);
9261ae08745Sheppo 		return (EBUSY);
9271ae08745Sheppo 	}
9281ae08745Sheppo 
9291ae08745Sheppo 	/*
9301ae08745Sheppo 	 * Should not need the mutex here, since the framework should protect
9311ae08745Sheppo 	 * against more opens on this device, but just in case.
9321ae08745Sheppo 	 */
9331ae08745Sheppo 	mutex_enter(&vdc->lock);
9341ae08745Sheppo 	vdc->open--;
9351ae08745Sheppo 	mutex_exit(&vdc->lock);
9361ae08745Sheppo 
9371ae08745Sheppo 	return (0);
9381ae08745Sheppo }
9391ae08745Sheppo 
9401ae08745Sheppo static int
9411ae08745Sheppo vdc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
9421ae08745Sheppo {
9431ae08745Sheppo 	_NOTE(ARGUNUSED(credp))
9441ae08745Sheppo 	_NOTE(ARGUNUSED(rvalp))
9451ae08745Sheppo 
9461ae08745Sheppo 	return (vd_process_ioctl(dev, cmd, (caddr_t)arg, mode));
9471ae08745Sheppo }
9481ae08745Sheppo 
9491ae08745Sheppo static int
9501ae08745Sheppo vdc_print(dev_t dev, char *str)
9511ae08745Sheppo {
9521ae08745Sheppo 	cmn_err(CE_NOTE, "vdc%d:  %s", SDUNIT(getminor(dev)), str);
9531ae08745Sheppo 	return (0);
9541ae08745Sheppo }
9551ae08745Sheppo 
9561ae08745Sheppo static int
9571ae08745Sheppo vdc_dump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk)
9581ae08745Sheppo {
959d10e4ef2Snarayan 	buf_t	*buf;	/* BWRITE requests need to be in a buf_t structure */
960d10e4ef2Snarayan 	int	rv;
961d10e4ef2Snarayan 	size_t	nbytes = nblk * DEV_BSIZE;
9621ae08745Sheppo 	int	instance = SDUNIT(getminor(dev));
963d10e4ef2Snarayan 	vdc_t	*vdc = NULL;
9641ae08745Sheppo 
9651ae08745Sheppo 	if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) {
966*e1ebb9ecSlm66018 		cmn_err(CE_NOTE, "[%d] Couldn't get state structure", instance);
9671ae08745Sheppo 		return (ENXIO);
9681ae08745Sheppo 	}
9691ae08745Sheppo 
970d10e4ef2Snarayan 	buf = kmem_alloc(sizeof (buf_t), KM_SLEEP);
971d10e4ef2Snarayan 	bioinit(buf);
972d10e4ef2Snarayan 	buf->b_un.b_addr = addr;
973d10e4ef2Snarayan 	buf->b_bcount = nbytes;
974d10e4ef2Snarayan 	buf->b_flags = B_BUSY | B_WRITE;
975d10e4ef2Snarayan 	buf->b_dev = dev;
976d10e4ef2Snarayan 	rv = vdc_populate_descriptor(vdc, (caddr_t)buf, nbytes,
977d10e4ef2Snarayan 			VD_OP_BWRITE, blkno, SDPART(getminor(dev)));
978d10e4ef2Snarayan 
979d10e4ef2Snarayan 	/*
980d10e4ef2Snarayan 	 * If the OS instance is panicking, the call above will ensure that
981d10e4ef2Snarayan 	 * the descriptor is done before returning. This should always be
982d10e4ef2Snarayan 	 * case when coming through this function but we check just in case
983d10e4ef2Snarayan 	 * and wait if necessary for the vDisk server to ACK and trigger
984d10e4ef2Snarayan 	 * the biodone.
985d10e4ef2Snarayan 	 */
986d10e4ef2Snarayan 	if (!ddi_in_panic())
987d10e4ef2Snarayan 		rv = biowait(buf);
988d10e4ef2Snarayan 
989d10e4ef2Snarayan 	biofini(buf);
990d10e4ef2Snarayan 	kmem_free(buf, sizeof (buf_t));
9911ae08745Sheppo 
992*e1ebb9ecSlm66018 	DMSG(1, "[%d] status=%d\n", instance, rv);
9931ae08745Sheppo 
9941ae08745Sheppo 	return (rv);
9951ae08745Sheppo }
9961ae08745Sheppo 
9971ae08745Sheppo /* -------------------------------------------------------------------------- */
9981ae08745Sheppo 
9991ae08745Sheppo /*
10001ae08745Sheppo  * Disk access routines
10011ae08745Sheppo  *
10021ae08745Sheppo  */
10031ae08745Sheppo 
10041ae08745Sheppo /*
10051ae08745Sheppo  * vdc_strategy()
10061ae08745Sheppo  *
10071ae08745Sheppo  * Return Value:
10081ae08745Sheppo  *	0:	As per strategy(9E), the strategy() function must return 0
10091ae08745Sheppo  *		[ bioerror(9f) sets b_flags to the proper error code ]
10101ae08745Sheppo  */
10111ae08745Sheppo static int
10121ae08745Sheppo vdc_strategy(struct buf *buf)
10131ae08745Sheppo {
10141ae08745Sheppo 	int		rv = -1;
10151ae08745Sheppo 	vdc_t		*vdc = NULL;
10161ae08745Sheppo 	int		instance = SDUNIT(getminor(buf->b_edev));
10171ae08745Sheppo 	int	op = (buf->b_flags & B_READ) ? VD_OP_BREAD : VD_OP_BWRITE;
10181ae08745Sheppo 
1019*e1ebb9ecSlm66018 	DMSG(2, "[%d] %s %ld bytes at block %llx : b_addr=0x%p",
1020*e1ebb9ecSlm66018 	    instance, (buf->b_flags & B_READ) ? "Read" : "Write",
1021*e1ebb9ecSlm66018 	    buf->b_bcount, buf->b_lblkno, (void *)buf->b_un.b_addr);
10221ae08745Sheppo 
10231ae08745Sheppo 	if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) {
1024*e1ebb9ecSlm66018 		cmn_err(CE_NOTE, "[%d] Couldn't get state structure", instance);
10251ae08745Sheppo 		bioerror(buf, ENXIO);
10261ae08745Sheppo 		biodone(buf);
10271ae08745Sheppo 		return (0);
10281ae08745Sheppo 	}
10291ae08745Sheppo 
1030d10e4ef2Snarayan 	DTRACE_IO2(vstart, buf_t *, buf, vdc_t *, vdc);
1031d10e4ef2Snarayan 
10320a55fbb7Slm66018 	if (!vdc_is_able_to_tx_data(vdc, O_NONBLOCK)) {
1033*e1ebb9ecSlm66018 		DMSG(0, "[%d] Not ready to transmit data\n", instance);
10341ae08745Sheppo 		bioerror(buf, ENXIO);
10351ae08745Sheppo 		biodone(buf);
10361ae08745Sheppo 		return (0);
10371ae08745Sheppo 	}
10381ae08745Sheppo 	bp_mapin(buf);
10391ae08745Sheppo 
1040d10e4ef2Snarayan 	rv = vdc_populate_descriptor(vdc, (caddr_t)buf, buf->b_bcount, op,
10411ae08745Sheppo 			buf->b_lblkno, SDPART(getminor(buf->b_edev)));
10421ae08745Sheppo 
1043d10e4ef2Snarayan 	/*
1044d10e4ef2Snarayan 	 * If the request was successfully sent, the strategy call returns and
1045d10e4ef2Snarayan 	 * the ACK handler calls the bioxxx functions when the vDisk server is
1046d10e4ef2Snarayan 	 * done.
1047d10e4ef2Snarayan 	 */
1048d10e4ef2Snarayan 	if (rv) {
1049*e1ebb9ecSlm66018 		DMSG(0, "[%d] Failed to read/write (err=%d)\n", instance, rv);
10501ae08745Sheppo 		bioerror(buf, rv);
10511ae08745Sheppo 		biodone(buf);
1052d10e4ef2Snarayan 	}
1053d10e4ef2Snarayan 
10541ae08745Sheppo 	return (0);
10551ae08745Sheppo }
10561ae08745Sheppo 
10571ae08745Sheppo 
10581ae08745Sheppo static int
10591ae08745Sheppo vdc_read(dev_t dev, struct uio *uio, cred_t *cred)
10601ae08745Sheppo {
10611ae08745Sheppo 	_NOTE(ARGUNUSED(cred))
10621ae08745Sheppo 
1063*e1ebb9ecSlm66018 	DMSG(1, "[%d] Entered", SDUNIT(getminor(dev)));
10641ae08745Sheppo 	return (physio(vdc_strategy, NULL, dev, B_READ, minphys, uio));
10651ae08745Sheppo }
10661ae08745Sheppo 
10671ae08745Sheppo static int
10681ae08745Sheppo vdc_write(dev_t dev, struct uio *uio, cred_t *cred)
10691ae08745Sheppo {
10701ae08745Sheppo 	_NOTE(ARGUNUSED(cred))
10711ae08745Sheppo 
1072*e1ebb9ecSlm66018 	DMSG(1, "[%d] Entered", SDUNIT(getminor(dev)));
10731ae08745Sheppo 	return (physio(vdc_strategy, NULL, dev, B_WRITE, minphys, uio));
10741ae08745Sheppo }
10751ae08745Sheppo 
10761ae08745Sheppo static int
10771ae08745Sheppo vdc_aread(dev_t dev, struct aio_req *aio, cred_t *cred)
10781ae08745Sheppo {
10791ae08745Sheppo 	_NOTE(ARGUNUSED(cred))
10801ae08745Sheppo 
1081*e1ebb9ecSlm66018 	DMSG(1, "[%d] Entered", SDUNIT(getminor(dev)));
10821ae08745Sheppo 	return (aphysio(vdc_strategy, anocancel, dev, B_READ, minphys, aio));
10831ae08745Sheppo }
10841ae08745Sheppo 
10851ae08745Sheppo static int
10861ae08745Sheppo vdc_awrite(dev_t dev, struct aio_req *aio, cred_t *cred)
10871ae08745Sheppo {
10881ae08745Sheppo 	_NOTE(ARGUNUSED(cred))
10891ae08745Sheppo 
1090*e1ebb9ecSlm66018 	DMSG(1, "[%d] Entered", SDUNIT(getminor(dev)));
10911ae08745Sheppo 	return (aphysio(vdc_strategy, anocancel, dev, B_WRITE, minphys, aio));
10921ae08745Sheppo }
10931ae08745Sheppo 
10941ae08745Sheppo 
10951ae08745Sheppo /* -------------------------------------------------------------------------- */
10961ae08745Sheppo 
10971ae08745Sheppo /*
10981ae08745Sheppo  * Handshake support
10991ae08745Sheppo  */
11001ae08745Sheppo 
11011ae08745Sheppo /*
11021ae08745Sheppo  * vdc_init_handshake_negotiation
11031ae08745Sheppo  *
11041ae08745Sheppo  * Description:
11051ae08745Sheppo  *	This function is called to trigger the handshake negotiations between
11061ae08745Sheppo  *	the client (vdc) and the server (vds). It may be called multiple times.
11071ae08745Sheppo  *
11081ae08745Sheppo  * Parameters:
11091ae08745Sheppo  *	vdc - soft state pointer
11101ae08745Sheppo  */
11111ae08745Sheppo static void
11121ae08745Sheppo vdc_init_handshake_negotiation(void *arg)
11131ae08745Sheppo {
11141ae08745Sheppo 	vdc_t		*vdc = (vdc_t *)(void *)arg;
11150a55fbb7Slm66018 	ldc_status_t	ldc_state;
11161ae08745Sheppo 	vd_state_t	state;
11170a55fbb7Slm66018 	int		status;
11181ae08745Sheppo 
11191ae08745Sheppo 	ASSERT(vdc != NULL);
11201ae08745Sheppo 
1121*e1ebb9ecSlm66018 	DMSG(0, "[%d] Initializing vdc<->vds handshake\n", vdc->instance);
11220a55fbb7Slm66018 
11230a55fbb7Slm66018 	/* get LDC state */
11240a55fbb7Slm66018 	status = ldc_status(vdc->ldc_handle, &ldc_state);
11250a55fbb7Slm66018 	if (status != 0) {
1126*e1ebb9ecSlm66018 		cmn_err(CE_NOTE, "[%d] Couldn't get LDC status (err=%d)",
11270a55fbb7Slm66018 				vdc->instance, status);
11280a55fbb7Slm66018 		return;
11290a55fbb7Slm66018 	}
11301ae08745Sheppo 
11311ae08745Sheppo 	/*
11320a55fbb7Slm66018 	 * If the LDC connection is not UP we bring it up now and return.
11330a55fbb7Slm66018 	 * The handshake will be started again when the callback is
11340a55fbb7Slm66018 	 * triggered due to the UP event.
11350a55fbb7Slm66018 	 */
11360a55fbb7Slm66018 	if (ldc_state != LDC_UP) {
1137*e1ebb9ecSlm66018 		DMSG(0, "[%d] Triggering LDC_UP & returning\n", vdc->instance);
11380a55fbb7Slm66018 		(void) vdc_do_ldc_up(vdc);
11390a55fbb7Slm66018 		return;
11400a55fbb7Slm66018 	}
11410a55fbb7Slm66018 
11420a55fbb7Slm66018 	mutex_enter(&vdc->lock);
11430a55fbb7Slm66018 	/*
11441ae08745Sheppo 	 * Do not continue if another thread has triggered a handshake which
11450a55fbb7Slm66018 	 * has not been reset or detach() has stopped further handshakes.
11461ae08745Sheppo 	 */
11471ae08745Sheppo 	if (vdc->initialized & (VDC_HANDSHAKE | VDC_HANDSHAKE_STOP)) {
1148*e1ebb9ecSlm66018 		DMSG(0, "[%d] Negotiation not triggered. [init=%x]\n",
1149*e1ebb9ecSlm66018 			vdc->instance, vdc->initialized);
11501ae08745Sheppo 		mutex_exit(&vdc->lock);
11511ae08745Sheppo 		return;
11521ae08745Sheppo 	}
11531ae08745Sheppo 
11540a55fbb7Slm66018 	if (vdc->hshake_cnt++ > vdc_retries) {
11550a55fbb7Slm66018 		cmn_err(CE_NOTE, "[%d] Failed repeatedly to complete handshake"
11560a55fbb7Slm66018 				"with vDisk server", vdc->instance);
11570a55fbb7Slm66018 		mutex_exit(&vdc->lock);
11580a55fbb7Slm66018 		return;
11590a55fbb7Slm66018 	}
11601ae08745Sheppo 
11611ae08745Sheppo 	vdc->initialized |= VDC_HANDSHAKE;
11620a55fbb7Slm66018 	vdc->ldc_state = ldc_state;
11631ae08745Sheppo 
11641ae08745Sheppo 	state = vdc->state;
11651ae08745Sheppo 
11661ae08745Sheppo 	if (state == VD_STATE_INIT) {
11670a55fbb7Slm66018 		/*
11680a55fbb7Slm66018 		 * Set the desired version parameter to the first entry in the
11690a55fbb7Slm66018 		 * version array. If this specific version is not supported,
11700a55fbb7Slm66018 		 * the response handling code will step down the version number
11710a55fbb7Slm66018 		 * to the next array entry and deal with it accordingly.
11720a55fbb7Slm66018 		 */
11730a55fbb7Slm66018 		(void) vdc_init_ver_negotiation(vdc, vdc_version[0]);
11741ae08745Sheppo 	} else if (state == VD_STATE_VER) {
11751ae08745Sheppo 		(void) vdc_init_attr_negotiation(vdc);
11761ae08745Sheppo 	} else if (state == VD_STATE_ATTR) {
11771ae08745Sheppo 		(void) vdc_init_dring_negotiate(vdc);
11781ae08745Sheppo 	} else if (state == VD_STATE_DATA) {
11791ae08745Sheppo 		/*
11801ae08745Sheppo 		 * nothing to do - we have already completed the negotiation
11811ae08745Sheppo 		 * and we can transmit data when ready.
11821ae08745Sheppo 		 */
1183*e1ebb9ecSlm66018 		DMSG(0, "[%d] Negotiation triggered after handshake completed",
1184*e1ebb9ecSlm66018 			vdc->instance);
11851ae08745Sheppo 	}
11861ae08745Sheppo 
11871ae08745Sheppo 	mutex_exit(&vdc->lock);
11881ae08745Sheppo }
11891ae08745Sheppo 
11900a55fbb7Slm66018 /*
11910a55fbb7Slm66018  * Function:
11920a55fbb7Slm66018  *	vdc_init_ver_negotiation()
11930a55fbb7Slm66018  *
11940a55fbb7Slm66018  * Description:
11950a55fbb7Slm66018  *
11960a55fbb7Slm66018  * Arguments:
11970a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
11980a55fbb7Slm66018  *
11990a55fbb7Slm66018  * Return Code:
12000a55fbb7Slm66018  *	0	- Success
12010a55fbb7Slm66018  */
12021ae08745Sheppo static int
12030a55fbb7Slm66018 vdc_init_ver_negotiation(vdc_t *vdc, vio_ver_t ver)
12041ae08745Sheppo {
12051ae08745Sheppo 	vio_ver_msg_t	pkt;
12061ae08745Sheppo 	size_t		msglen = sizeof (pkt);
12071ae08745Sheppo 	int		status = -1;
12081ae08745Sheppo 
12091ae08745Sheppo 	ASSERT(vdc != NULL);
12101ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
12111ae08745Sheppo 
1212*e1ebb9ecSlm66018 	DMSG(0, "[%d] Entered.\n", vdc->instance);
1213*e1ebb9ecSlm66018 
12141ae08745Sheppo 	/*
12151ae08745Sheppo 	 * set the Session ID to a unique value
12161ae08745Sheppo 	 * (the lower 32 bits of the clock tick)
12171ae08745Sheppo 	 */
12181ae08745Sheppo 	vdc->session_id = ((uint32_t)gettick() & 0xffffffff);
1219*e1ebb9ecSlm66018 	DMSG(0, "[%d] Set SID to 0x%lx\n", vdc->instance, vdc->session_id);
12201ae08745Sheppo 
12211ae08745Sheppo 	pkt.tag.vio_msgtype = VIO_TYPE_CTRL;
12221ae08745Sheppo 	pkt.tag.vio_subtype = VIO_SUBTYPE_INFO;
12231ae08745Sheppo 	pkt.tag.vio_subtype_env = VIO_VER_INFO;
12241ae08745Sheppo 	pkt.tag.vio_sid = vdc->session_id;
12251ae08745Sheppo 	pkt.dev_class = VDEV_DISK;
12260a55fbb7Slm66018 	pkt.ver_major = ver.major;
12270a55fbb7Slm66018 	pkt.ver_minor = ver.minor;
12281ae08745Sheppo 
12290a55fbb7Slm66018 	status = vdc_send(vdc, (caddr_t)&pkt, &msglen);
1230*e1ebb9ecSlm66018 	DMSG(0, "[%d] Ver info sent (status = %d)\n", vdc->instance, status);
12311ae08745Sheppo 
12321ae08745Sheppo 	if ((status != 0) || (msglen != sizeof (vio_ver_msg_t))) {
1233*e1ebb9ecSlm66018 		cmn_err(CE_NOTE, "[%d] Failed to send Ver negotiation info: "
1234*e1ebb9ecSlm66018 				"id(%lx) rv(%d) size(%ld)",
1235*e1ebb9ecSlm66018 				vdc->instance, vdc->ldc_handle,
12361ae08745Sheppo 				status, msglen);
12371ae08745Sheppo 		if (msglen != sizeof (vio_ver_msg_t))
12381ae08745Sheppo 			status = ENOMSG;
12391ae08745Sheppo 	}
12401ae08745Sheppo 
12411ae08745Sheppo 	return (status);
12421ae08745Sheppo }
12431ae08745Sheppo 
12440a55fbb7Slm66018 /*
12450a55fbb7Slm66018  * Function:
12460a55fbb7Slm66018  *	vdc_init_attr_negotiation()
12470a55fbb7Slm66018  *
12480a55fbb7Slm66018  * Description:
12490a55fbb7Slm66018  *
12500a55fbb7Slm66018  * Arguments:
12510a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
12520a55fbb7Slm66018  *
12530a55fbb7Slm66018  * Return Code:
12540a55fbb7Slm66018  *	0	- Success
12550a55fbb7Slm66018  */
12561ae08745Sheppo static int
12571ae08745Sheppo vdc_init_attr_negotiation(vdc_t *vdc)
12581ae08745Sheppo {
12591ae08745Sheppo 	vd_attr_msg_t	pkt;
12601ae08745Sheppo 	size_t		msglen = sizeof (pkt);
12611ae08745Sheppo 	int		status;
12621ae08745Sheppo 
12631ae08745Sheppo 	ASSERT(vdc != NULL);
12641ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
12651ae08745Sheppo 
1266*e1ebb9ecSlm66018 	DMSG(0, "[%d] entered\n", vdc->instance);
12671ae08745Sheppo 
12681ae08745Sheppo 	/* fill in tag */
12691ae08745Sheppo 	pkt.tag.vio_msgtype = VIO_TYPE_CTRL;
12701ae08745Sheppo 	pkt.tag.vio_subtype = VIO_SUBTYPE_INFO;
12711ae08745Sheppo 	pkt.tag.vio_subtype_env = VIO_ATTR_INFO;
12721ae08745Sheppo 	pkt.tag.vio_sid = vdc->session_id;
12731ae08745Sheppo 	/* fill in payload */
12741ae08745Sheppo 	pkt.max_xfer_sz = vdc->max_xfer_sz;
12751ae08745Sheppo 	pkt.vdisk_block_size = vdc->block_size;
12761ae08745Sheppo 	pkt.xfer_mode = VIO_DRING_MODE;
12771ae08745Sheppo 	pkt.operations = 0;	/* server will set bits of valid operations */
12781ae08745Sheppo 	pkt.vdisk_type = 0;	/* server will set to valid device type */
12791ae08745Sheppo 	pkt.vdisk_size = 0;	/* server will set to valid size */
12801ae08745Sheppo 
12810a55fbb7Slm66018 	status = vdc_send(vdc, (caddr_t)&pkt, &msglen);
1282*e1ebb9ecSlm66018 	DMSG(0, "[%d] Attr info sent (status = %d)\n", vdc->instance, status);
12831ae08745Sheppo 
12841ae08745Sheppo 	if ((status != 0) || (msglen != sizeof (vio_ver_msg_t))) {
1285*e1ebb9ecSlm66018 		cmn_err(CE_NOTE, "[%d] Failed to send Attr negotiation info: "
1286*e1ebb9ecSlm66018 				"id(%lx) rv(%d) size(%ld)",
1287*e1ebb9ecSlm66018 				vdc->instance, vdc->ldc_handle,
12881ae08745Sheppo 				status, msglen);
12891ae08745Sheppo 		if (msglen != sizeof (vio_ver_msg_t))
12901ae08745Sheppo 			status = ENOMSG;
12911ae08745Sheppo 	}
12921ae08745Sheppo 
12931ae08745Sheppo 	return (status);
12941ae08745Sheppo }
12951ae08745Sheppo 
12960a55fbb7Slm66018 /*
12970a55fbb7Slm66018  * Function:
12980a55fbb7Slm66018  *	vdc_init_dring_negotiate()
12990a55fbb7Slm66018  *
13000a55fbb7Slm66018  * Description:
13010a55fbb7Slm66018  *
13020a55fbb7Slm66018  * Arguments:
13030a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
13040a55fbb7Slm66018  *
13050a55fbb7Slm66018  * Return Code:
13060a55fbb7Slm66018  *	0	- Success
13070a55fbb7Slm66018  */
13081ae08745Sheppo static int
13091ae08745Sheppo vdc_init_dring_negotiate(vdc_t *vdc)
13101ae08745Sheppo {
13111ae08745Sheppo 	vio_dring_reg_msg_t	pkt;
13121ae08745Sheppo 	size_t			msglen = sizeof (pkt);
13131ae08745Sheppo 	int			status = -1;
13141ae08745Sheppo 
13151ae08745Sheppo 	ASSERT(vdc != NULL);
13161ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
13171ae08745Sheppo 
13181ae08745Sheppo 	status = vdc_init_descriptor_ring(vdc);
13191ae08745Sheppo 	if (status != 0) {
13201ae08745Sheppo 		cmn_err(CE_CONT, "[%d] Failed to init DRing (status = %d)\n",
13211ae08745Sheppo 				vdc->instance, status);
13220a55fbb7Slm66018 		vdc_destroy_descriptor_ring(vdc);
1323*e1ebb9ecSlm66018 		vdc_reset_connection(vdc, B_TRUE);
13241ae08745Sheppo 		return (status);
13251ae08745Sheppo 	}
1326*e1ebb9ecSlm66018 	DMSG(0, "[%d] Init of descriptor ring completed (status = %d)\n",
1327*e1ebb9ecSlm66018 			vdc->instance, status);
13281ae08745Sheppo 
13291ae08745Sheppo 	/* fill in tag */
13301ae08745Sheppo 	pkt.tag.vio_msgtype = VIO_TYPE_CTRL;
13311ae08745Sheppo 	pkt.tag.vio_subtype = VIO_SUBTYPE_INFO;
13321ae08745Sheppo 	pkt.tag.vio_subtype_env = VIO_DRING_REG;
13331ae08745Sheppo 	pkt.tag.vio_sid = vdc->session_id;
13341ae08745Sheppo 	/* fill in payload */
13351ae08745Sheppo 	pkt.dring_ident = 0;
1336*e1ebb9ecSlm66018 	pkt.num_descriptors = vdc->dring_len;
1337*e1ebb9ecSlm66018 	pkt.descriptor_size = vdc->dring_entry_size;
13381ae08745Sheppo 	pkt.options = (VIO_TX_DRING | VIO_RX_DRING);
13391ae08745Sheppo 	pkt.ncookies = vdc->dring_cookie_count;
13401ae08745Sheppo 	pkt.cookie[0] = vdc->dring_cookie[0];	/* for now just one cookie */
13411ae08745Sheppo 
13420a55fbb7Slm66018 	status = vdc_send(vdc, (caddr_t)&pkt, &msglen);
13431ae08745Sheppo 	if (status != 0) {
1344*e1ebb9ecSlm66018 		cmn_err(CE_NOTE, "[%d] Failed to register DRing (err = %d)",
1345*e1ebb9ecSlm66018 				vdc->instance, status);
1346*e1ebb9ecSlm66018 		vdc_reset_connection(vdc, B_TRUE);
13471ae08745Sheppo 	}
13481ae08745Sheppo 
13491ae08745Sheppo 	return (status);
13501ae08745Sheppo }
13511ae08745Sheppo 
13521ae08745Sheppo 
13531ae08745Sheppo /* -------------------------------------------------------------------------- */
13541ae08745Sheppo 
13551ae08745Sheppo /*
13561ae08745Sheppo  * LDC helper routines
13571ae08745Sheppo  */
13581ae08745Sheppo 
13591ae08745Sheppo /*
13601ae08745Sheppo  * Function:
13611ae08745Sheppo  *	vdc_send()
13621ae08745Sheppo  *
13631ae08745Sheppo  * Description:
13641ae08745Sheppo  *	The function encapsulates the call to write a message using LDC.
13651ae08745Sheppo  *	If LDC indicates that the call failed due to the queue being full,
13661ae08745Sheppo  *	we retry the ldc_write() [ up to 'vdc_retries' time ], otherwise
13671ae08745Sheppo  *	we return the error returned by LDC.
13681ae08745Sheppo  *
13691ae08745Sheppo  * Arguments:
13701ae08745Sheppo  *	ldc_handle	- LDC handle for the channel this instance of vdc uses
13711ae08745Sheppo  *	pkt		- address of LDC message to be sent
13721ae08745Sheppo  *	msglen		- the size of the message being sent. When the function
13731ae08745Sheppo  *			  returns, this contains the number of bytes written.
13741ae08745Sheppo  *
13751ae08745Sheppo  * Return Code:
13761ae08745Sheppo  *	0		- Success.
13771ae08745Sheppo  *	EINVAL		- pkt or msglen were NULL
13781ae08745Sheppo  *	ECONNRESET	- The connection was not up.
13791ae08745Sheppo  *	EWOULDBLOCK	- LDC queue is full
13801ae08745Sheppo  *	xxx		- other error codes returned by ldc_write
13811ae08745Sheppo  */
13821ae08745Sheppo static int
13830a55fbb7Slm66018 vdc_send(vdc_t *vdc, caddr_t pkt, size_t *msglen)
13841ae08745Sheppo {
13851ae08745Sheppo 	size_t	size = 0;
13861ae08745Sheppo 	int	retries = 0;
13871ae08745Sheppo 	int	status = 0;
13881ae08745Sheppo 
13890a55fbb7Slm66018 	ASSERT(vdc != NULL);
13900a55fbb7Slm66018 	ASSERT(mutex_owned(&vdc->lock));
13911ae08745Sheppo 	ASSERT(msglen != NULL);
13921ae08745Sheppo 	ASSERT(*msglen != 0);
13931ae08745Sheppo 
13941ae08745Sheppo 	do {
13951ae08745Sheppo 		size = *msglen;
13960a55fbb7Slm66018 		status = ldc_write(vdc->ldc_handle, pkt, &size);
1397*e1ebb9ecSlm66018 		if (status == EWOULDBLOCK)
1398*e1ebb9ecSlm66018 			delay(vdc_hz_timeout_ldc);
13991ae08745Sheppo 	} while (status == EWOULDBLOCK && retries++ < vdc_retries);
14001ae08745Sheppo 
14010a55fbb7Slm66018 	/* if LDC had serious issues --- reset vdc state */
14020a55fbb7Slm66018 	if (status == EIO || status == ECONNRESET) {
14030a55fbb7Slm66018 		vdc_reset_connection(vdc, B_TRUE);
14040a55fbb7Slm66018 	}
14050a55fbb7Slm66018 
14061ae08745Sheppo 	/* return the last size written */
14071ae08745Sheppo 	*msglen = size;
14081ae08745Sheppo 
14091ae08745Sheppo 	return (status);
14101ae08745Sheppo }
14111ae08745Sheppo 
14121ae08745Sheppo /*
14131ae08745Sheppo  * Function:
14141ae08745Sheppo  *	vdc_get_ldc_id()
14151ae08745Sheppo  *
14161ae08745Sheppo  * Description:
14171ae08745Sheppo  *	This function gets the 'ldc-id' for this particular instance of vdc.
14181ae08745Sheppo  *	The id returned is the guest domain channel endpoint LDC uses for
14191ae08745Sheppo  *	communication with vds.
14201ae08745Sheppo  *
14211ae08745Sheppo  * Arguments:
14221ae08745Sheppo  *	dip	- dev info pointer for this instance of the device driver.
14231ae08745Sheppo  *	ldc_id	- pointer to variable used to return the 'ldc-id' found.
14241ae08745Sheppo  *
14251ae08745Sheppo  * Return Code:
14261ae08745Sheppo  *	0	- Success.
14271ae08745Sheppo  *	ENOENT	- Expected node or property did not exist.
14281ae08745Sheppo  *	ENXIO	- Unexpected error communicating with MD framework
14291ae08745Sheppo  */
14301ae08745Sheppo static int
14311ae08745Sheppo vdc_get_ldc_id(dev_info_t *dip, uint64_t *ldc_id)
14321ae08745Sheppo {
14331ae08745Sheppo 	int		status = ENOENT;
14341ae08745Sheppo 	char		*node_name = NULL;
14351ae08745Sheppo 	md_t		*mdp = NULL;
14361ae08745Sheppo 	int		num_nodes;
14371ae08745Sheppo 	int		num_vdevs;
14381ae08745Sheppo 	int		num_chans;
14391ae08745Sheppo 	mde_cookie_t	rootnode;
14401ae08745Sheppo 	mde_cookie_t	*listp = NULL;
14411ae08745Sheppo 	mde_cookie_t	*chanp = NULL;
14421ae08745Sheppo 	boolean_t	found_inst = B_FALSE;
14431ae08745Sheppo 	int		listsz;
14441ae08745Sheppo 	int		idx;
14451ae08745Sheppo 	uint64_t	md_inst;
14461ae08745Sheppo 	int		obp_inst;
14471ae08745Sheppo 	int		instance = ddi_get_instance(dip);
14481ae08745Sheppo 
14491ae08745Sheppo 	ASSERT(ldc_id != NULL);
14501ae08745Sheppo 	*ldc_id = 0;
14511ae08745Sheppo 
14521ae08745Sheppo 	/*
14531ae08745Sheppo 	 * Get the OBP instance number for comparison with the MD instance
14541ae08745Sheppo 	 *
14551ae08745Sheppo 	 * The "cfg-handle" property of a vdc node in an MD contains the MD's
14561ae08745Sheppo 	 * notion of "instance", or unique identifier, for that node; OBP
14571ae08745Sheppo 	 * stores the value of the "cfg-handle" MD property as the value of
14581ae08745Sheppo 	 * the "reg" property on the node in the device tree it builds from
14591ae08745Sheppo 	 * the MD and passes to Solaris.  Thus, we look up the devinfo node's
14601ae08745Sheppo 	 * "reg" property value to uniquely identify this device instance.
14611ae08745Sheppo 	 * If the "reg" property cannot be found, the device tree state is
14621ae08745Sheppo 	 * presumably so broken that there is no point in continuing.
14631ae08745Sheppo 	 */
14641ae08745Sheppo 	if (!ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, OBP_REG)) {
14651ae08745Sheppo 		cmn_err(CE_WARN, "'%s' property does not exist", OBP_REG);
14661ae08745Sheppo 		return (ENOENT);
14671ae08745Sheppo 	}
14681ae08745Sheppo 	obp_inst = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
14691ae08745Sheppo 			OBP_REG, -1);
1470*e1ebb9ecSlm66018 	DMSG(1, "[%d] OBP inst=%d\n", instance, obp_inst);
14711ae08745Sheppo 
14721ae08745Sheppo 	/*
14731ae08745Sheppo 	 * We now walk the MD nodes and if an instance of a vdc node matches
14741ae08745Sheppo 	 * the instance got from OBP we get the ldc-id property.
14751ae08745Sheppo 	 */
14761ae08745Sheppo 	if ((mdp = md_get_handle()) == NULL) {
14771ae08745Sheppo 		cmn_err(CE_WARN, "unable to init machine description");
14781ae08745Sheppo 		return (ENXIO);
14791ae08745Sheppo 	}
14801ae08745Sheppo 
14811ae08745Sheppo 	num_nodes = md_node_count(mdp);
14821ae08745Sheppo 	ASSERT(num_nodes > 0);
14831ae08745Sheppo 
14841ae08745Sheppo 	listsz = num_nodes * sizeof (mde_cookie_t);
14851ae08745Sheppo 
14861ae08745Sheppo 	/* allocate memory for nodes */
14871ae08745Sheppo 	listp = kmem_zalloc(listsz, KM_SLEEP);
14881ae08745Sheppo 	chanp = kmem_zalloc(listsz, KM_SLEEP);
14891ae08745Sheppo 
14901ae08745Sheppo 	rootnode = md_root_node(mdp);
14911ae08745Sheppo 	ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE);
14921ae08745Sheppo 
14931ae08745Sheppo 	/*
14941ae08745Sheppo 	 * Search for all the virtual devices, we will then check to see which
14951ae08745Sheppo 	 * ones are disk nodes.
14961ae08745Sheppo 	 */
14971ae08745Sheppo 	num_vdevs = md_scan_dag(mdp, rootnode,
14981ae08745Sheppo 			md_find_name(mdp, VDC_MD_VDEV_NAME),
14991ae08745Sheppo 			md_find_name(mdp, "fwd"), listp);
15001ae08745Sheppo 
15011ae08745Sheppo 	if (num_vdevs <= 0) {
15021ae08745Sheppo 		cmn_err(CE_NOTE, "No '%s' node found", VDC_MD_VDEV_NAME);
15031ae08745Sheppo 		status = ENOENT;
15041ae08745Sheppo 		goto done;
15051ae08745Sheppo 	}
15061ae08745Sheppo 
1507*e1ebb9ecSlm66018 	DMSG(1, "[%d] num_vdevs=%d\n", instance, num_vdevs);
15081ae08745Sheppo 	for (idx = 0; idx < num_vdevs; idx++) {
15091ae08745Sheppo 		status = md_get_prop_str(mdp, listp[idx], "name", &node_name);
15101ae08745Sheppo 		if ((status != 0) || (node_name == NULL)) {
15111ae08745Sheppo 			cmn_err(CE_NOTE, "Unable to get name of node type '%s'"
15121ae08745Sheppo 					": err %d", VDC_MD_VDEV_NAME, status);
15131ae08745Sheppo 			continue;
15141ae08745Sheppo 		}
15151ae08745Sheppo 
1516*e1ebb9ecSlm66018 		DMSG(1, "[%d] Found node '%s'\n", instance, node_name);
15171ae08745Sheppo 		if (strcmp(VDC_MD_DISK_NAME, node_name) == 0) {
15181ae08745Sheppo 			status = md_get_prop_val(mdp, listp[idx],
15191ae08745Sheppo 					VDC_MD_CFG_HDL, &md_inst);
1520*e1ebb9ecSlm66018 			DMSG(1, "[%d] vdc inst in MD=%lx\n", instance, md_inst);
15211ae08745Sheppo 			if ((status == 0) && (md_inst == obp_inst)) {
15221ae08745Sheppo 				found_inst = B_TRUE;
15231ae08745Sheppo 				break;
15241ae08745Sheppo 			}
15251ae08745Sheppo 		}
15261ae08745Sheppo 	}
15271ae08745Sheppo 
15280a55fbb7Slm66018 	if (!found_inst) {
15291ae08745Sheppo 		cmn_err(CE_NOTE, "Unable to find correct '%s' node",
15301ae08745Sheppo 				VDC_MD_DISK_NAME);
15311ae08745Sheppo 		status = ENOENT;
15321ae08745Sheppo 		goto done;
15331ae08745Sheppo 	}
1534*e1ebb9ecSlm66018 	DMSG(0, "[%d] MD inst=%lx\n", instance, md_inst);
15351ae08745Sheppo 
15361ae08745Sheppo 	/* get the channels for this node */
15371ae08745Sheppo 	num_chans = md_scan_dag(mdp, listp[idx],
15381ae08745Sheppo 			md_find_name(mdp, VDC_MD_CHAN_NAME),
15391ae08745Sheppo 			md_find_name(mdp, "fwd"), chanp);
15401ae08745Sheppo 
15411ae08745Sheppo 	/* expecting at least one channel */
15421ae08745Sheppo 	if (num_chans <= 0) {
15431ae08745Sheppo 		cmn_err(CE_NOTE, "No '%s' node for '%s' port",
15441ae08745Sheppo 				VDC_MD_CHAN_NAME, VDC_MD_VDEV_NAME);
15451ae08745Sheppo 		status = ENOENT;
15461ae08745Sheppo 		goto done;
15471ae08745Sheppo 
15481ae08745Sheppo 	} else if (num_chans != 1) {
1549*e1ebb9ecSlm66018 		DMSG(0, "[%d] Expected 1 '%s' node for '%s' port, found %d\n",
1550*e1ebb9ecSlm66018 			instance, VDC_MD_CHAN_NAME, VDC_MD_VDEV_NAME,
15511ae08745Sheppo 			num_chans);
15521ae08745Sheppo 	}
15531ae08745Sheppo 
15541ae08745Sheppo 	/*
15551ae08745Sheppo 	 * We use the first channel found (index 0), irrespective of how
15561ae08745Sheppo 	 * many are there in total.
15571ae08745Sheppo 	 */
15581ae08745Sheppo 	if (md_get_prop_val(mdp, chanp[0], VDC_ID_PROP, ldc_id) != 0) {
15591ae08745Sheppo 		cmn_err(CE_NOTE, "Channel '%s' property not found",
15601ae08745Sheppo 				VDC_ID_PROP);
15611ae08745Sheppo 		status = ENOENT;
15621ae08745Sheppo 	}
15631ae08745Sheppo 
1564*e1ebb9ecSlm66018 	DMSG(0, "[%d] LDC id is 0x%lx\n", instance, *ldc_id);
15651ae08745Sheppo 
15661ae08745Sheppo done:
15671ae08745Sheppo 	if (chanp)
15681ae08745Sheppo 		kmem_free(chanp, listsz);
15691ae08745Sheppo 	if (listp)
15701ae08745Sheppo 		kmem_free(listp, listsz);
15711ae08745Sheppo 
15721ae08745Sheppo 	(void) md_fini_handle(mdp);
15731ae08745Sheppo 
15741ae08745Sheppo 	return (status);
15751ae08745Sheppo }
15761ae08745Sheppo 
15770a55fbb7Slm66018 static int
15780a55fbb7Slm66018 vdc_do_ldc_up(vdc_t *vdc)
15790a55fbb7Slm66018 {
15800a55fbb7Slm66018 	int	status;
15810a55fbb7Slm66018 
1582*e1ebb9ecSlm66018 	DMSG(0, "[%d] Bringing up channel %lx\n", vdc->instance, vdc->ldc_id);
15830a55fbb7Slm66018 
15840a55fbb7Slm66018 	if ((status = ldc_up(vdc->ldc_handle)) != 0) {
15850a55fbb7Slm66018 		switch (status) {
15860a55fbb7Slm66018 		case ECONNREFUSED:	/* listener not ready at other end */
1587*e1ebb9ecSlm66018 			DMSG(0, "[%d] ldc_up(%lx,...) return %d\n",
1588*e1ebb9ecSlm66018 					vdc->instance, vdc->ldc_id, status);
15890a55fbb7Slm66018 			status = 0;
15900a55fbb7Slm66018 			break;
15910a55fbb7Slm66018 		default:
15920a55fbb7Slm66018 			cmn_err(CE_NOTE, "[%d] Failed to bring up LDC: "
15930a55fbb7Slm66018 					"channel=%ld, err=%d",
15940a55fbb7Slm66018 					vdc->instance, vdc->ldc_id, status);
15950a55fbb7Slm66018 		}
15960a55fbb7Slm66018 	}
15970a55fbb7Slm66018 
15980a55fbb7Slm66018 	return (status);
15990a55fbb7Slm66018 }
16000a55fbb7Slm66018 
16011ae08745Sheppo 
16021ae08745Sheppo /*
16031ae08745Sheppo  * vdc_is_able_to_tx_data()
16041ae08745Sheppo  *
16051ae08745Sheppo  * Description:
16061ae08745Sheppo  *	This function checks if we are able to send data to the
16071ae08745Sheppo  *	vDisk server (vds). The LDC connection needs to be up and
16081ae08745Sheppo  *	vdc & vds need to have completed the handshake negotiation.
16091ae08745Sheppo  *
16101ae08745Sheppo  * Parameters:
16111ae08745Sheppo  *	vdc 		- soft state pointer
16121ae08745Sheppo  *	flag		- flag to indicate if we can block or not
16131ae08745Sheppo  *			  [ If O_NONBLOCK or O_NDELAY (which are defined in
16141ae08745Sheppo  *			    open(2)) are set then do not block)
16151ae08745Sheppo  *
16161ae08745Sheppo  * Return Values
16171ae08745Sheppo  *	B_TRUE		- can talk to vds
16181ae08745Sheppo  *	B_FALSE		- unable to talk to vds
16191ae08745Sheppo  */
16201ae08745Sheppo static boolean_t
16211ae08745Sheppo vdc_is_able_to_tx_data(vdc_t *vdc, int flag)
16221ae08745Sheppo {
16231ae08745Sheppo 	vd_state_t	state;
16241ae08745Sheppo 	uint32_t	ldc_state;
16251ae08745Sheppo 	uint_t		retries = 0;
16261ae08745Sheppo 	int		rv = -1;
16271ae08745Sheppo 
16281ae08745Sheppo 	ASSERT(vdc != NULL);
16291ae08745Sheppo 
16301ae08745Sheppo 	mutex_enter(&vdc->lock);
16311ae08745Sheppo 	state = vdc->state;
16321ae08745Sheppo 	ldc_state = vdc->ldc_state;
16331ae08745Sheppo 	mutex_exit(&vdc->lock);
16341ae08745Sheppo 
16351ae08745Sheppo 	if ((state == VD_STATE_DATA) && (ldc_state == LDC_UP))
16361ae08745Sheppo 		return (B_TRUE);
16371ae08745Sheppo 
16381ae08745Sheppo 	if ((flag & O_NONBLOCK) || (flag & O_NDELAY)) {
1639*e1ebb9ecSlm66018 		DMSG(0, "[%d] Not ready to tx - state %d LDC state %d\n",
1640*e1ebb9ecSlm66018 			vdc->instance, state, ldc_state);
16411ae08745Sheppo 		return (B_FALSE);
16421ae08745Sheppo 	}
16431ae08745Sheppo 
16441ae08745Sheppo 	/*
16451ae08745Sheppo 	 * We want to check and see if any negotiations triggered earlier
16461ae08745Sheppo 	 * have succeeded. We are prepared to wait a little while in case
16471ae08745Sheppo 	 * they are still in progress.
16481ae08745Sheppo 	 */
16491ae08745Sheppo 	mutex_enter(&vdc->lock);
16501ae08745Sheppo 	while ((vdc->ldc_state != LDC_UP) || (vdc->state != VD_STATE_DATA)) {
1651*e1ebb9ecSlm66018 		DMSG(0, "[%d] Waiting for connection. (state %d : LDC %d)\n",
1652*e1ebb9ecSlm66018 			vdc->instance, vdc->state, vdc->ldc_state);
16531ae08745Sheppo 
16541ae08745Sheppo 		rv = cv_timedwait(&vdc->cv, &vdc->lock,
1655*e1ebb9ecSlm66018 			VD_GET_TIMEOUT_HZ(vdc_hz_timeout, retries));
16561ae08745Sheppo 
16571ae08745Sheppo 		/*
16581ae08745Sheppo 		 * An rv of -1 indicates that we timed out without the LDC
16591ae08745Sheppo 		 * state changing so it looks like the other side (vdc) is
16601ae08745Sheppo 		 * not yet ready/responding.
16611ae08745Sheppo 		 *
16621ae08745Sheppo 		 * Any other value of rv indicates that the LDC triggered an
16631ae08745Sheppo 		 * interrupt so we just loop again, check the handshake state
16641ae08745Sheppo 		 * and keep waiting if necessary.
16651ae08745Sheppo 		 */
16661ae08745Sheppo 		if (rv == -1) {
16671ae08745Sheppo 			if (retries >= vdc_retries) {
1668*e1ebb9ecSlm66018 				DMSG(0, "[%d] handshake wait timed out\n",
1669*e1ebb9ecSlm66018 						vdc->instance);
16701ae08745Sheppo 				mutex_exit(&vdc->lock);
16711ae08745Sheppo 				return (B_FALSE);
16721ae08745Sheppo 			} else {
1673*e1ebb9ecSlm66018 				DMSG(1, "[%d] Handshake retry #%d timed out\n",
1674*e1ebb9ecSlm66018 					vdc->instance, retries);
16751ae08745Sheppo 				retries++;
16761ae08745Sheppo 			}
16771ae08745Sheppo 		}
16781ae08745Sheppo 	}
16791ae08745Sheppo 
16801ae08745Sheppo 	ASSERT(vdc->ldc_state == LDC_UP);
16811ae08745Sheppo 	ASSERT(vdc->state == VD_STATE_DATA);
16821ae08745Sheppo 
16831ae08745Sheppo 	mutex_exit(&vdc->lock);
16841ae08745Sheppo 
16851ae08745Sheppo 	return (B_TRUE);
16861ae08745Sheppo }
16871ae08745Sheppo 
16881ae08745Sheppo 
16890a55fbb7Slm66018 /*
16900a55fbb7Slm66018  * Function:
16910a55fbb7Slm66018  *	vdc_terminate_ldc()
16920a55fbb7Slm66018  *
16930a55fbb7Slm66018  * Description:
16940a55fbb7Slm66018  *
16950a55fbb7Slm66018  * Arguments:
16960a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
16970a55fbb7Slm66018  *
16980a55fbb7Slm66018  * Return Code:
16990a55fbb7Slm66018  *	None
17000a55fbb7Slm66018  */
17011ae08745Sheppo static void
17021ae08745Sheppo vdc_terminate_ldc(vdc_t *vdc)
17031ae08745Sheppo {
17041ae08745Sheppo 	int	instance = ddi_get_instance(vdc->dip);
17051ae08745Sheppo 
17061ae08745Sheppo 	ASSERT(vdc != NULL);
17071ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
17081ae08745Sheppo 
1709*e1ebb9ecSlm66018 	DMSG(0, "[%d] initialized=%x\n", instance, vdc->initialized);
17101ae08745Sheppo 
17111ae08745Sheppo 	if (vdc->initialized & VDC_LDC_OPEN) {
1712*e1ebb9ecSlm66018 		DMSG(0, "[%d] ldc_close()\n", instance);
17131ae08745Sheppo 		(void) ldc_close(vdc->ldc_handle);
17141ae08745Sheppo 	}
17151ae08745Sheppo 	if (vdc->initialized & VDC_LDC_CB) {
1716*e1ebb9ecSlm66018 		DMSG(0, "[%d] ldc_unreg_callback()\n", instance);
17171ae08745Sheppo 		(void) ldc_unreg_callback(vdc->ldc_handle);
17181ae08745Sheppo 	}
17191ae08745Sheppo 	if (vdc->initialized & VDC_LDC) {
1720*e1ebb9ecSlm66018 		DMSG(0, "[%d] ldc_fini()\n", instance);
17211ae08745Sheppo 		(void) ldc_fini(vdc->ldc_handle);
17221ae08745Sheppo 		vdc->ldc_handle = NULL;
17231ae08745Sheppo 	}
17241ae08745Sheppo 
17251ae08745Sheppo 	vdc->initialized &= ~(VDC_LDC | VDC_LDC_CB | VDC_LDC_OPEN);
17261ae08745Sheppo }
17271ae08745Sheppo 
17280a55fbb7Slm66018 /*
17290a55fbb7Slm66018  * Function:
17300a55fbb7Slm66018  *	vdc_reset_connection()
17310a55fbb7Slm66018  *
17320a55fbb7Slm66018  * Description:
17330a55fbb7Slm66018  *
17340a55fbb7Slm66018  * Arguments:
17350a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
17360a55fbb7Slm66018  *	reset_ldc - Flag whether or not to reset the LDC connection also.
17370a55fbb7Slm66018  *
17380a55fbb7Slm66018  * Return Code:
17390a55fbb7Slm66018  *	None
17400a55fbb7Slm66018  */
17411ae08745Sheppo static void
17421ae08745Sheppo vdc_reset_connection(vdc_t *vdc, boolean_t reset_ldc)
17431ae08745Sheppo {
17441ae08745Sheppo 	int	status;
17451ae08745Sheppo 
17461ae08745Sheppo 	ASSERT(vdc != NULL);
17471ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
17481ae08745Sheppo 
1749*e1ebb9ecSlm66018 	cmn_err(CE_CONT, "?[%d] Resetting connection to vDisk server\n",
1750*e1ebb9ecSlm66018 			vdc->instance);
17511ae08745Sheppo 
17521ae08745Sheppo 	vdc->state = VD_STATE_INIT;
17531ae08745Sheppo 
17540a55fbb7Slm66018 	if (reset_ldc) {
1755*e1ebb9ecSlm66018 		status = ldc_down(vdc->ldc_handle);
1756*e1ebb9ecSlm66018 		DMSG(0, "[%d]  ldc_down() = %d\n", vdc->instance, status);
17571ae08745Sheppo 	}
17581ae08745Sheppo 
17591ae08745Sheppo 	vdc->initialized &= ~VDC_HANDSHAKE;
1760*e1ebb9ecSlm66018 	DMSG(0, "[%d] initialized=%x\n", vdc->instance, vdc->initialized);
17611ae08745Sheppo }
17621ae08745Sheppo 
17631ae08745Sheppo /* -------------------------------------------------------------------------- */
17641ae08745Sheppo 
17651ae08745Sheppo /*
17661ae08745Sheppo  * Descriptor Ring helper routines
17671ae08745Sheppo  */
17681ae08745Sheppo 
17690a55fbb7Slm66018 /*
17700a55fbb7Slm66018  * Function:
17710a55fbb7Slm66018  *	vdc_init_descriptor_ring()
17720a55fbb7Slm66018  *
17730a55fbb7Slm66018  * Description:
17740a55fbb7Slm66018  *
17750a55fbb7Slm66018  * Arguments:
17760a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
17770a55fbb7Slm66018  *
17780a55fbb7Slm66018  * Return Code:
17790a55fbb7Slm66018  *	0	- Success
17800a55fbb7Slm66018  */
17811ae08745Sheppo static int
17821ae08745Sheppo vdc_init_descriptor_ring(vdc_t *vdc)
17831ae08745Sheppo {
17841ae08745Sheppo 	vd_dring_entry_t	*dep = NULL;	/* DRing Entry pointer */
17850a55fbb7Slm66018 	int	status = 0;
17861ae08745Sheppo 	int	i;
17871ae08745Sheppo 
1788*e1ebb9ecSlm66018 	DMSG(0, "[%d] initialized=%x\n", vdc->instance, vdc->initialized);
17891ae08745Sheppo 
17901ae08745Sheppo 	ASSERT(vdc != NULL);
17911ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
17921ae08745Sheppo 	ASSERT(vdc->ldc_handle != NULL);
17931ae08745Sheppo 
1794*e1ebb9ecSlm66018 	/* ensure we have enough room to store max sized block */
1795*e1ebb9ecSlm66018 	ASSERT(maxphys <= VD_MAX_BLOCK_SIZE);
1796*e1ebb9ecSlm66018 
17970a55fbb7Slm66018 	if ((vdc->initialized & VDC_DRING_INIT) == 0) {
1798*e1ebb9ecSlm66018 		DMSG(0, "[%d] ldc_mem_dring_create\n", vdc->instance);
1799*e1ebb9ecSlm66018 		/*
1800*e1ebb9ecSlm66018 		 * Calculate the maximum block size we can transmit using one
1801*e1ebb9ecSlm66018 		 * Descriptor Ring entry from the attributes returned by the
1802*e1ebb9ecSlm66018 		 * vDisk server. This is subject to a minimum of 'maxphys'
1803*e1ebb9ecSlm66018 		 * as we do not have the capability to split requests over
1804*e1ebb9ecSlm66018 		 * multiple DRing entries.
1805*e1ebb9ecSlm66018 		 */
1806*e1ebb9ecSlm66018 		if ((vdc->max_xfer_sz * vdc->block_size) < maxphys) {
1807*e1ebb9ecSlm66018 			DMSG(0, "[%d] using minimum DRing size\n",
1808*e1ebb9ecSlm66018 					vdc->instance);
1809*e1ebb9ecSlm66018 			vdc->dring_max_cookies = maxphys / PAGESIZE;
1810*e1ebb9ecSlm66018 		} else {
1811*e1ebb9ecSlm66018 			vdc->dring_max_cookies =
1812*e1ebb9ecSlm66018 				(vdc->max_xfer_sz * vdc->block_size) / PAGESIZE;
1813*e1ebb9ecSlm66018 		}
1814*e1ebb9ecSlm66018 		vdc->dring_entry_size = (sizeof (vd_dring_entry_t) +
1815*e1ebb9ecSlm66018 				(sizeof (ldc_mem_cookie_t) *
1816*e1ebb9ecSlm66018 					(vdc->dring_max_cookies - 1)));
1817*e1ebb9ecSlm66018 		vdc->dring_len = VD_DRING_LEN;
1818*e1ebb9ecSlm66018 
1819*e1ebb9ecSlm66018 		status = ldc_mem_dring_create(vdc->dring_len,
1820*e1ebb9ecSlm66018 				vdc->dring_entry_size, &vdc->ldc_dring_hdl);
18211ae08745Sheppo 		if ((vdc->ldc_dring_hdl == NULL) || (status != 0)) {
1822*e1ebb9ecSlm66018 			cmn_err(CE_NOTE, "[%d] Descriptor ring creation failed",
1823*e1ebb9ecSlm66018 					vdc->instance);
18241ae08745Sheppo 			return (status);
18251ae08745Sheppo 		}
18260a55fbb7Slm66018 		vdc->initialized |= VDC_DRING_INIT;
18270a55fbb7Slm66018 	}
18281ae08745Sheppo 
18290a55fbb7Slm66018 	if ((vdc->initialized & VDC_DRING_BOUND) == 0) {
1830*e1ebb9ecSlm66018 		DMSG(0, "[%d] ldc_mem_dring_bind\n", vdc->instance);
18310a55fbb7Slm66018 		vdc->dring_cookie =
18320a55fbb7Slm66018 			kmem_zalloc(sizeof (ldc_mem_cookie_t), KM_SLEEP);
18331ae08745Sheppo 
18341ae08745Sheppo 		status = ldc_mem_dring_bind(vdc->ldc_handle, vdc->ldc_dring_hdl,
18350a55fbb7Slm66018 				LDC_SHADOW_MAP, LDC_MEM_RW,
18360a55fbb7Slm66018 				&vdc->dring_cookie[0],
18371ae08745Sheppo 				&vdc->dring_cookie_count);
18381ae08745Sheppo 		if (status != 0) {
1839*e1ebb9ecSlm66018 			cmn_err(CE_NOTE, "[%d] Failed to bind descriptor ring "
1840*e1ebb9ecSlm66018 				"(%lx) to channel (%lx)\n", vdc->instance,
1841*e1ebb9ecSlm66018 				vdc->ldc_dring_hdl, vdc->ldc_handle);
18421ae08745Sheppo 			return (status);
18431ae08745Sheppo 		}
18441ae08745Sheppo 		ASSERT(vdc->dring_cookie_count == 1);
18451ae08745Sheppo 		vdc->initialized |= VDC_DRING_BOUND;
18460a55fbb7Slm66018 	}
18471ae08745Sheppo 
18481ae08745Sheppo 	status = ldc_mem_dring_info(vdc->ldc_dring_hdl, &vdc->dring_mem_info);
18491ae08745Sheppo 	if (status != 0) {
1850*e1ebb9ecSlm66018 		DMSG(0, "[%d] Failed to get info for descriptor ring (%lx)\n",
1851*e1ebb9ecSlm66018 			vdc->instance, vdc->ldc_dring_hdl);
18521ae08745Sheppo 		return (status);
18531ae08745Sheppo 	}
18541ae08745Sheppo 
18550a55fbb7Slm66018 	if ((vdc->initialized & VDC_DRING_LOCAL) == 0) {
1856*e1ebb9ecSlm66018 		DMSG(0, "[%d] local dring\n", vdc->instance);
18570a55fbb7Slm66018 
18581ae08745Sheppo 		/* Allocate the local copy of this dring */
18590a55fbb7Slm66018 		vdc->local_dring =
1860*e1ebb9ecSlm66018 			kmem_zalloc(vdc->dring_len * sizeof (vdc_local_desc_t),
18611ae08745Sheppo 						KM_SLEEP);
18621ae08745Sheppo 		vdc->initialized |= VDC_DRING_LOCAL;
18630a55fbb7Slm66018 	}
18641ae08745Sheppo 
18651ae08745Sheppo 	/*
18660a55fbb7Slm66018 	 * Mark all DRing entries as free and initialize the private
18670a55fbb7Slm66018 	 * descriptor's memory handles. If any entry is initialized,
18680a55fbb7Slm66018 	 * we need to free it later so we set the bit in 'initialized'
18690a55fbb7Slm66018 	 * at the start.
18701ae08745Sheppo 	 */
18711ae08745Sheppo 	vdc->initialized |= VDC_DRING_ENTRY;
1872*e1ebb9ecSlm66018 	for (i = 0; i < vdc->dring_len; i++) {
18731ae08745Sheppo 		dep = VDC_GET_DRING_ENTRY_PTR(vdc, i);
18741ae08745Sheppo 		dep->hdr.dstate = VIO_DESC_FREE;
18751ae08745Sheppo 
18761ae08745Sheppo 		status = ldc_mem_alloc_handle(vdc->ldc_handle,
18771ae08745Sheppo 				&vdc->local_dring[i].desc_mhdl);
18781ae08745Sheppo 		if (status != 0) {
18791ae08745Sheppo 			cmn_err(CE_NOTE, "![%d] Failed to alloc mem handle for"
18801ae08745Sheppo 					" descriptor %d", vdc->instance, i);
18811ae08745Sheppo 			return (status);
18821ae08745Sheppo 		}
18831ae08745Sheppo 		vdc->local_dring[i].flags = VIO_DESC_FREE;
18841ae08745Sheppo 		vdc->local_dring[i].dep = dep;
18851ae08745Sheppo 
18861ae08745Sheppo 		mutex_init(&vdc->local_dring[i].lock, NULL, MUTEX_DRIVER, NULL);
18871ae08745Sheppo 		cv_init(&vdc->local_dring[i].cv, NULL, CV_DRIVER, NULL);
18881ae08745Sheppo 	}
18891ae08745Sheppo 
18901ae08745Sheppo 	/*
18911ae08745Sheppo 	 * We init the index of the last DRing entry used. Since the code to
18921ae08745Sheppo 	 * get the next available entry increments it before selecting one,
18931ae08745Sheppo 	 * we set it to the last DRing entry so that it wraps around to zero
18941ae08745Sheppo 	 * for the 1st entry to be used.
18951ae08745Sheppo 	 */
1896*e1ebb9ecSlm66018 	vdc->dring_curr_idx = vdc->dring_len - 1;
1897*e1ebb9ecSlm66018 
1898*e1ebb9ecSlm66018 	vdc->dring_notify_server = B_TRUE;
18991ae08745Sheppo 
19001ae08745Sheppo 	return (status);
19011ae08745Sheppo }
19021ae08745Sheppo 
19030a55fbb7Slm66018 /*
19040a55fbb7Slm66018  * Function:
19050a55fbb7Slm66018  *	vdc_destroy_descriptor_ring()
19060a55fbb7Slm66018  *
19070a55fbb7Slm66018  * Description:
19080a55fbb7Slm66018  *
19090a55fbb7Slm66018  * Arguments:
19100a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
19110a55fbb7Slm66018  *
19120a55fbb7Slm66018  * Return Code:
19130a55fbb7Slm66018  *	None
19140a55fbb7Slm66018  */
19151ae08745Sheppo static void
19161ae08745Sheppo vdc_destroy_descriptor_ring(vdc_t *vdc)
19171ae08745Sheppo {
19180a55fbb7Slm66018 	vdc_local_desc_t	*ldep = NULL;	/* Local Dring Entry Pointer */
19191ae08745Sheppo 	ldc_mem_handle_t	mhdl = NULL;
19201ae08745Sheppo 	int			status = -1;
19211ae08745Sheppo 	int			i;	/* loop */
19221ae08745Sheppo 
19231ae08745Sheppo 	ASSERT(vdc != NULL);
19241ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
19251ae08745Sheppo 	ASSERT(vdc->state == VD_STATE_INIT);
19261ae08745Sheppo 
1927*e1ebb9ecSlm66018 	DMSG(0, "[%d] Entered\n", vdc->instance);
19281ae08745Sheppo 
19291ae08745Sheppo 	if (vdc->initialized & VDC_DRING_ENTRY) {
1930*e1ebb9ecSlm66018 		DMSG(0, "[%d] Removing Local DRing entries\n", vdc->instance);
1931*e1ebb9ecSlm66018 		for (i = 0; i < vdc->dring_len; i++) {
19320a55fbb7Slm66018 			ldep = &vdc->local_dring[i];
19330a55fbb7Slm66018 			mhdl = ldep->desc_mhdl;
19341ae08745Sheppo 
19350a55fbb7Slm66018 			if (mhdl == NULL)
19360a55fbb7Slm66018 				continue;
19370a55fbb7Slm66018 
19381ae08745Sheppo 			(void) ldc_mem_free_handle(mhdl);
19390a55fbb7Slm66018 			mutex_destroy(&ldep->lock);
19400a55fbb7Slm66018 			cv_destroy(&ldep->cv);
19411ae08745Sheppo 		}
19421ae08745Sheppo 		vdc->initialized &= ~VDC_DRING_ENTRY;
19431ae08745Sheppo 	}
19441ae08745Sheppo 
19451ae08745Sheppo 	if (vdc->initialized & VDC_DRING_LOCAL) {
1946*e1ebb9ecSlm66018 		DMSG(0, "[%d] Freeing Local DRing\n", vdc->instance);
19471ae08745Sheppo 		kmem_free(vdc->local_dring,
1948*e1ebb9ecSlm66018 				vdc->dring_len * sizeof (vdc_local_desc_t));
19491ae08745Sheppo 		vdc->initialized &= ~VDC_DRING_LOCAL;
19501ae08745Sheppo 	}
19511ae08745Sheppo 
19521ae08745Sheppo 	if (vdc->initialized & VDC_DRING_BOUND) {
1953*e1ebb9ecSlm66018 		DMSG(0, "[%d] Unbinding DRing\n", vdc->instance);
19541ae08745Sheppo 		status = ldc_mem_dring_unbind(vdc->ldc_dring_hdl);
19551ae08745Sheppo 		if (status == 0) {
19561ae08745Sheppo 			vdc->initialized &= ~VDC_DRING_BOUND;
19571ae08745Sheppo 		} else {
1958*e1ebb9ecSlm66018 			cmn_err(CE_NOTE, "[%d] Error %d unbinding DRing %lx",
1959*e1ebb9ecSlm66018 				vdc->instance, status, vdc->ldc_dring_hdl);
19601ae08745Sheppo 		}
19611ae08745Sheppo 	}
19621ae08745Sheppo 
19631ae08745Sheppo 	if (vdc->initialized & VDC_DRING_INIT) {
1964*e1ebb9ecSlm66018 		DMSG(0, "[%d] Destroying DRing\n", vdc->instance);
19651ae08745Sheppo 		status = ldc_mem_dring_destroy(vdc->ldc_dring_hdl);
19661ae08745Sheppo 		if (status == 0) {
19671ae08745Sheppo 			vdc->ldc_dring_hdl = NULL;
19681ae08745Sheppo 			bzero(&vdc->dring_mem_info, sizeof (ldc_mem_info_t));
19691ae08745Sheppo 			vdc->initialized &= ~VDC_DRING_INIT;
19701ae08745Sheppo 		} else {
1971*e1ebb9ecSlm66018 			cmn_err(CE_NOTE, "[%d] Error %d destroying DRing (%lx)",
1972*e1ebb9ecSlm66018 				vdc->instance, status, vdc->ldc_dring_hdl);
19731ae08745Sheppo 		}
19741ae08745Sheppo 	}
19751ae08745Sheppo }
19761ae08745Sheppo 
19771ae08745Sheppo /*
19781ae08745Sheppo  * vdc_get_next_dring_entry_idx()
19791ae08745Sheppo  *
19801ae08745Sheppo  * Description:
19811ae08745Sheppo  *	This function gets the index of the next Descriptor Ring entry available
1982d10e4ef2Snarayan  *	If the ring is full, it will back off and wait for the next entry to be
1983d10e4ef2Snarayan  *	freed (the ACK handler will signal).
19841ae08745Sheppo  *
19851ae08745Sheppo  * Return Value:
1986*e1ebb9ecSlm66018  *	0 <= rv < vdc->dring_len		Next available slot
19871ae08745Sheppo  *	-1 				DRing is full
19881ae08745Sheppo  */
19891ae08745Sheppo static int
19901ae08745Sheppo vdc_get_next_dring_entry_idx(vdc_t *vdc, uint_t num_slots_needed)
19911ae08745Sheppo {
19921ae08745Sheppo 	_NOTE(ARGUNUSED(num_slots_needed))
19931ae08745Sheppo 
1994d10e4ef2Snarayan 	vd_dring_entry_t	*dep = NULL;	/* DRing Entry Pointer */
1995d10e4ef2Snarayan 	vdc_local_desc_t	*ldep = NULL;	/* Local DRing Entry Pointer */
19961ae08745Sheppo 	int			idx = -1;
19971ae08745Sheppo 
19981ae08745Sheppo 	ASSERT(vdc != NULL);
1999*e1ebb9ecSlm66018 	ASSERT(vdc->dring_len == vdc->dring_len);
20001ae08745Sheppo 	ASSERT(vdc->dring_curr_idx >= 0);
2001*e1ebb9ecSlm66018 	ASSERT(vdc->dring_curr_idx < vdc->dring_len);
20021ae08745Sheppo 	ASSERT(mutex_owned(&vdc->dring_lock));
20031ae08745Sheppo 
2004d10e4ef2Snarayan 	/* pick the next descriptor after the last one used */
2005*e1ebb9ecSlm66018 	idx = (vdc->dring_curr_idx + 1) % vdc->dring_len;
2006d10e4ef2Snarayan 	ldep = &vdc->local_dring[idx];
2007d10e4ef2Snarayan 	ASSERT(ldep != NULL);
2008d10e4ef2Snarayan 	dep = ldep->dep;
20091ae08745Sheppo 	ASSERT(dep != NULL);
20101ae08745Sheppo 
2011d10e4ef2Snarayan 	mutex_enter(&ldep->lock);
20121ae08745Sheppo 	if (dep->hdr.dstate == VIO_DESC_FREE) {
20131ae08745Sheppo 		vdc->dring_curr_idx = idx;
20141ae08745Sheppo 	} else {
2015d10e4ef2Snarayan 		DTRACE_PROBE(full);
2016d10e4ef2Snarayan 		(void) cv_timedwait(&ldep->cv, &ldep->lock,
2017*e1ebb9ecSlm66018 					VD_GET_TIMEOUT_HZ(vdc_hz_timeout, 1));
2018d10e4ef2Snarayan 		if (dep->hdr.dstate == VIO_DESC_FREE) {
2019d10e4ef2Snarayan 			vdc->dring_curr_idx = idx;
2020d10e4ef2Snarayan 		} else {
2021*e1ebb9ecSlm66018 			DMSG(0, "[%d] Entry %d unavailable still in state %d\n",
2022d10e4ef2Snarayan 					vdc->instance, idx, dep->hdr.dstate);
2023d10e4ef2Snarayan 			idx = -1; /* indicate that the ring is full */
20241ae08745Sheppo 		}
2025d10e4ef2Snarayan 	}
2026d10e4ef2Snarayan 	mutex_exit(&ldep->lock);
20271ae08745Sheppo 
2028d10e4ef2Snarayan 	return (idx);
20291ae08745Sheppo }
20301ae08745Sheppo 
20311ae08745Sheppo /*
20321ae08745Sheppo  * Function:
20331ae08745Sheppo  *	vdc_populate_descriptor
20341ae08745Sheppo  *
20351ae08745Sheppo  * Description:
20361ae08745Sheppo  *	This routine writes the data to be transmitted to vds into the
20371ae08745Sheppo  *	descriptor, notifies vds that the ring has been updated and
20381ae08745Sheppo  *	then waits for the request to be processed.
20391ae08745Sheppo  *
20401ae08745Sheppo  * Arguments:
20411ae08745Sheppo  *	vdc	- the soft state pointer
2042d10e4ef2Snarayan  *	addr	- address of structure to be written. In the case of block
2043d10e4ef2Snarayan  *		  reads and writes this structure will be a buf_t and the
2044d10e4ef2Snarayan  *		  address of the data to be written will be in the b_un.b_addr
2045d10e4ef2Snarayan  *		  field. Otherwise the value of addr will be the address
2046d10e4ef2Snarayan  *		  to be written.
20471ae08745Sheppo  *	nbytes	- number of bytes to read/write
20481ae08745Sheppo  *	operation - operation we want vds to perform (VD_OP_XXX)
20491ae08745Sheppo  *	arg	- parameter to be sent to server (depends on VD_OP_XXX type)
20501ae08745Sheppo  *			. mode for ioctl(9e)
20511ae08745Sheppo  *			. LP64 diskaddr_t (block I/O)
20521ae08745Sheppo  *	slice	- the disk slice this request is for
20531ae08745Sheppo  *
20541ae08745Sheppo  * Return Codes:
20551ae08745Sheppo  *	0
20561ae08745Sheppo  *	EAGAIN
20571ae08745Sheppo  *		EFAULT
20581ae08745Sheppo  *		ENXIO
20591ae08745Sheppo  *		EIO
20601ae08745Sheppo  */
20611ae08745Sheppo static int
20621ae08745Sheppo vdc_populate_descriptor(vdc_t *vdc, caddr_t addr, size_t nbytes, int operation,
20631ae08745Sheppo 				uint64_t arg, uint64_t slice)
20641ae08745Sheppo {
20651ae08745Sheppo 	vdc_local_desc_t *local_dep = NULL;	/* Local Dring Entry Pointer */
20661ae08745Sheppo 	vd_dring_entry_t *dep = NULL;		/* Dring Entry Pointer */
20671ae08745Sheppo 	int			idx = 0;	/* Index of DRing entry used */
20681ae08745Sheppo 	vio_dring_msg_t		dmsg;
20691ae08745Sheppo 	size_t			msglen = sizeof (dmsg);
20701ae08745Sheppo 	int			retries = 0;
20718e6a2a04Slm66018 	int			rv;
20721ae08745Sheppo 
20731ae08745Sheppo 	ASSERT(vdc != NULL);
20741ae08745Sheppo 	ASSERT(slice < V_NUMPAR);
20751ae08745Sheppo 
20761ae08745Sheppo 	/*
20771ae08745Sheppo 	 * Get next available DRing entry.
20781ae08745Sheppo 	 */
20791ae08745Sheppo 	mutex_enter(&vdc->dring_lock);
20801ae08745Sheppo 	idx = vdc_get_next_dring_entry_idx(vdc, 1);
20811ae08745Sheppo 	if (idx == -1) {
20821ae08745Sheppo 		mutex_exit(&vdc->dring_lock);
2083*e1ebb9ecSlm66018 		DMSG(0, "[%d] no descriptor ring entry avail, last seq=%ld\n",
2084d10e4ef2Snarayan 				vdc->instance, vdc->seq_num - 1);
20851ae08745Sheppo 
20861ae08745Sheppo 		/*
20871ae08745Sheppo 		 * Since strategy should not block we don't wait for the DRing
20881ae08745Sheppo 		 * to empty and instead return
20891ae08745Sheppo 		 */
20901ae08745Sheppo 		return (EAGAIN);
20911ae08745Sheppo 	}
20921ae08745Sheppo 
2093*e1ebb9ecSlm66018 	ASSERT(idx < vdc->dring_len);
20941ae08745Sheppo 	local_dep = &vdc->local_dring[idx];
20951ae08745Sheppo 	dep = local_dep->dep;
20961ae08745Sheppo 	ASSERT(dep != NULL);
20971ae08745Sheppo 
20981ae08745Sheppo 	/*
2099d10e4ef2Snarayan 	 * We now get the lock for this descriptor before dropping the overall
2100d10e4ef2Snarayan 	 * DRing lock. This prevents a race condition where another vdc thread
2101d10e4ef2Snarayan 	 * could grab the descriptor we selected.
21021ae08745Sheppo 	 */
2103*e1ebb9ecSlm66018 	ASSERT(MUTEX_NOT_HELD(&local_dep->lock));
21041ae08745Sheppo 	mutex_enter(&local_dep->lock);
2105d10e4ef2Snarayan 	mutex_exit(&vdc->dring_lock);
21061ae08745Sheppo 
21071ae08745Sheppo 	switch (operation) {
21081ae08745Sheppo 	case VD_OP_BREAD:
21091ae08745Sheppo 	case VD_OP_BWRITE:
2110d10e4ef2Snarayan 		local_dep->buf = (struct buf *)addr;
2111d10e4ef2Snarayan 		local_dep->addr = local_dep->buf->b_un.b_addr;
2112*e1ebb9ecSlm66018 		DMSG(2, "[%d] buf=%p, block=%lx, nbytes=%lu\n",
2113*e1ebb9ecSlm66018 				vdc->instance, (void *)addr, arg, nbytes);
21141ae08745Sheppo 		dep->payload.addr = (diskaddr_t)arg;
2115d10e4ef2Snarayan 		rv = vdc_populate_mem_hdl(vdc, idx, local_dep->addr,
2116d10e4ef2Snarayan 						nbytes, operation);
21171ae08745Sheppo 		break;
21181ae08745Sheppo 
21191ae08745Sheppo 	case VD_OP_GET_VTOC:
21201ae08745Sheppo 	case VD_OP_SET_VTOC:
21211ae08745Sheppo 	case VD_OP_GET_DISKGEOM:
21221ae08745Sheppo 	case VD_OP_SET_DISKGEOM:
21231ae08745Sheppo 	case VD_OP_SCSICMD:
2124d10e4ef2Snarayan 		local_dep->addr = addr;
21251ae08745Sheppo 		if (nbytes > 0) {
21261ae08745Sheppo 			rv = vdc_populate_mem_hdl(vdc, idx, addr, nbytes,
21271ae08745Sheppo 							operation);
21281ae08745Sheppo 		}
21291ae08745Sheppo 		break;
21308e6a2a04Slm66018 
21318e6a2a04Slm66018 	case VD_OP_FLUSH:
21328e6a2a04Slm66018 	case VD_OP_GET_WCE:
21338e6a2a04Slm66018 	case VD_OP_SET_WCE:
21348e6a2a04Slm66018 		rv = 0;		/* nothing to bind */
21358e6a2a04Slm66018 		break;
21368e6a2a04Slm66018 
21371ae08745Sheppo 	default:
2138*e1ebb9ecSlm66018 		cmn_err(CE_CONT, "?[%d] Unsupported vDisk operation [%d]\n",
21391ae08745Sheppo 				vdc->instance, operation);
21401ae08745Sheppo 		rv = EINVAL;
21411ae08745Sheppo 	}
21421ae08745Sheppo 
21431ae08745Sheppo 	if (rv != 0) {
21441ae08745Sheppo 		mutex_exit(&local_dep->lock);
21451ae08745Sheppo 		return (rv);
21461ae08745Sheppo 	}
21471ae08745Sheppo 
21481ae08745Sheppo 	/*
21491ae08745Sheppo 	 * fill in the data details into the DRing
21501ae08745Sheppo 	 */
21511ae08745Sheppo 	dep->payload.req_id = VDC_GET_NEXT_REQ_ID(vdc);
21521ae08745Sheppo 	dep->payload.operation = operation;
21531ae08745Sheppo 	dep->payload.nbytes = nbytes;
2154*e1ebb9ecSlm66018 	dep->payload.status = -1;	/* vds will set valid value */
21551ae08745Sheppo 	dep->payload.slice = slice;
21561ae08745Sheppo 	dep->hdr.dstate = VIO_DESC_READY;
21571ae08745Sheppo 	dep->hdr.ack = 1;		/* request an ACK for every message */
21581ae08745Sheppo 
21591ae08745Sheppo 	local_dep->flags = VIO_DESC_READY;
21601ae08745Sheppo 
21611ae08745Sheppo 	/*
21621ae08745Sheppo 	 * Send a msg with the DRing details to vds
21631ae08745Sheppo 	 */
2164d10e4ef2Snarayan 	mutex_enter(&vdc->lock);
21651ae08745Sheppo 	VIO_INIT_DRING_DATA_TAG(dmsg);
21661ae08745Sheppo 	VDC_INIT_DRING_DATA_MSG_IDS(dmsg, vdc);
21671ae08745Sheppo 	dmsg.dring_ident = vdc->dring_ident;
21681ae08745Sheppo 	dmsg.start_idx = idx;
21691ae08745Sheppo 	dmsg.end_idx = idx;
21701ae08745Sheppo 
2171d10e4ef2Snarayan 	DTRACE_IO2(send, vio_dring_msg_t *, &dmsg, vdc_t *, vdc);
2172d10e4ef2Snarayan 
2173*e1ebb9ecSlm66018 	DMSG(2, "[%d] ident=0x%lx, st=%u, end=%u, seq=%ld req=%ld dep=%p\n",
2174*e1ebb9ecSlm66018 			vdc->instance, vdc->dring_ident,
2175*e1ebb9ecSlm66018 			dmsg.start_idx, dmsg.end_idx,
2176*e1ebb9ecSlm66018 			dmsg.seq_num, dep->payload.req_id, (void *)dep);
21771ae08745Sheppo 
21788e6a2a04Slm66018 	rv = vdc_send(vdc, (caddr_t)&dmsg, &msglen);
2179*e1ebb9ecSlm66018 	DMSG(1, "[%d] send via LDC: rv=%d\n", vdc->instance, rv);
21808e6a2a04Slm66018 	if (rv != 0) {
2181*e1ebb9ecSlm66018 		cmn_err(CE_NOTE, "[%d] err (%d) sending DRing data msg via LDC",
2182*e1ebb9ecSlm66018 				vdc->instance, rv);
2183d10e4ef2Snarayan 
2184d10e4ef2Snarayan 		/* Clear the DRing entry */
2185d10e4ef2Snarayan 		rv = vdc_depopulate_descriptor(vdc, idx);
2186d10e4ef2Snarayan 
2187*e1ebb9ecSlm66018 		mutex_exit(&vdc->lock);
2188*e1ebb9ecSlm66018 		mutex_exit(&local_dep->lock);
2189*e1ebb9ecSlm66018 
2190d10e4ef2Snarayan 		return (rv ? rv : EAGAIN);
21911ae08745Sheppo 	}
21921ae08745Sheppo 
21931ae08745Sheppo 	/*
21940a55fbb7Slm66018 	 * If the message was successfully sent, we increment the sequence
21950a55fbb7Slm66018 	 * number to be used by the next message
21960a55fbb7Slm66018 	 */
21970a55fbb7Slm66018 	vdc->seq_num++;
2198d10e4ef2Snarayan 	mutex_exit(&vdc->lock);
21991ae08745Sheppo 
22001ae08745Sheppo 	/*
22011ae08745Sheppo 	 * When a guest is panicking, the completion of requests needs to be
22021ae08745Sheppo 	 * handled differently because interrupts are disabled and vdc
22031ae08745Sheppo 	 * will not get messages. We have to poll for the messages instead.
22041ae08745Sheppo 	 */
22051ae08745Sheppo 	if (ddi_in_panic()) {
22061ae08745Sheppo 		int start = 0;
22071ae08745Sheppo 		retries = 0;
22081ae08745Sheppo 		for (;;) {
22091ae08745Sheppo 			msglen = sizeof (dmsg);
22108e6a2a04Slm66018 			rv = ldc_read(vdc->ldc_handle, (caddr_t)&dmsg,
22111ae08745Sheppo 					&msglen);
22128e6a2a04Slm66018 			if (rv) {
22138e6a2a04Slm66018 				rv = EINVAL;
22141ae08745Sheppo 				break;
22151ae08745Sheppo 			}
22161ae08745Sheppo 
22171ae08745Sheppo 			/*
22181ae08745Sheppo 			 * if there are no packets wait and check again
22191ae08745Sheppo 			 */
22208e6a2a04Slm66018 			if ((rv == 0) && (msglen == 0)) {
22211ae08745Sheppo 				if (retries++ > vdc_dump_retries) {
2222*e1ebb9ecSlm66018 					DMSG(0, "[%d] Stopping wait, idx %d\n",
22231ae08745Sheppo 							vdc->instance, idx);
22248e6a2a04Slm66018 					rv = EAGAIN;
22251ae08745Sheppo 					break;
22261ae08745Sheppo 				}
22271ae08745Sheppo 
2228*e1ebb9ecSlm66018 				DMSG(1, "Waiting for next packet @ %d\n", idx);
2229d10e4ef2Snarayan 				drv_usecwait(vdc_usec_timeout_dump);
22301ae08745Sheppo 				continue;
22311ae08745Sheppo 			}
22321ae08745Sheppo 
22331ae08745Sheppo 			/*
22341ae08745Sheppo 			 * Ignore all messages that are not ACKs/NACKs to
22351ae08745Sheppo 			 * DRing requests.
22361ae08745Sheppo 			 */
22371ae08745Sheppo 			if ((dmsg.tag.vio_msgtype != VIO_TYPE_DATA) ||
22381ae08745Sheppo 			    (dmsg.tag.vio_subtype_env != VIO_DRING_DATA)) {
2239*e1ebb9ecSlm66018 				DMSG(0, "discard pkt: type=%d sub=%d env=%d\n",
22401ae08745Sheppo 					dmsg.tag.vio_msgtype,
22411ae08745Sheppo 					dmsg.tag.vio_subtype,
22421ae08745Sheppo 					dmsg.tag.vio_subtype_env);
22431ae08745Sheppo 				continue;
22441ae08745Sheppo 			}
22451ae08745Sheppo 
22461ae08745Sheppo 			/*
22471ae08745Sheppo 			 * set the appropriate return value for the
22481ae08745Sheppo 			 * current request.
22491ae08745Sheppo 			 */
22501ae08745Sheppo 			switch (dmsg.tag.vio_subtype) {
22511ae08745Sheppo 			case VIO_SUBTYPE_ACK:
22528e6a2a04Slm66018 				rv = 0;
22531ae08745Sheppo 				break;
22541ae08745Sheppo 			case VIO_SUBTYPE_NACK:
22558e6a2a04Slm66018 				rv = EAGAIN;
22561ae08745Sheppo 				break;
22571ae08745Sheppo 			default:
22581ae08745Sheppo 				continue;
22591ae08745Sheppo 			}
22601ae08745Sheppo 
22611ae08745Sheppo 			start = dmsg.start_idx;
2262*e1ebb9ecSlm66018 			if (start >= vdc->dring_len) {
2263*e1ebb9ecSlm66018 				DMSG(0, "[%d] Bogus ack data : start %d\n",
22641ae08745Sheppo 					vdc->instance, start);
22651ae08745Sheppo 				continue;
22661ae08745Sheppo 			}
22671ae08745Sheppo 
22681ae08745Sheppo 			dep = VDC_GET_DRING_ENTRY_PTR(vdc, start);
22691ae08745Sheppo 
2270*e1ebb9ecSlm66018 			DMSG(1, "[%d] Dumping start=%d idx=%d state=%d\n",
22711ae08745Sheppo 				vdc->instance, start, idx, dep->hdr.dstate);
22721ae08745Sheppo 
22731ae08745Sheppo 			if (dep->hdr.dstate != VIO_DESC_DONE) {
2274*e1ebb9ecSlm66018 				DMSG(0, "[%d] Entry @ %d - state !DONE %d\n",
22751ae08745Sheppo 					vdc->instance, start, dep->hdr.dstate);
22761ae08745Sheppo 				continue;
22771ae08745Sheppo 			}
22781ae08745Sheppo 
22791ae08745Sheppo 			(void) vdc_depopulate_descriptor(vdc, start);
22801ae08745Sheppo 
22811ae08745Sheppo 			/*
22821ae08745Sheppo 			 * We want to process all Dring entries up to
22831ae08745Sheppo 			 * the current one so that we can return an
22841ae08745Sheppo 			 * error with the correct request.
22851ae08745Sheppo 			 */
22861ae08745Sheppo 			if (idx > start) {
2287*e1ebb9ecSlm66018 				DMSG(0, "[%d] Looping: start %d, idx %d\n",
22881ae08745Sheppo 						vdc->instance, idx, start);
22891ae08745Sheppo 				continue;
22901ae08745Sheppo 			}
22911ae08745Sheppo 
22921ae08745Sheppo 			/* exit - all outstanding requests are completed */
22931ae08745Sheppo 			break;
22941ae08745Sheppo 		}
22951ae08745Sheppo 
22961ae08745Sheppo 		mutex_exit(&local_dep->lock);
22971ae08745Sheppo 
22988e6a2a04Slm66018 		return (rv);
22991ae08745Sheppo 	}
23001ae08745Sheppo 
23011ae08745Sheppo 	/*
2302d10e4ef2Snarayan 	 * In the case of calls from strategy and dump (in the non-panic case),
2303d10e4ef2Snarayan 	 * instead of waiting for a response from the vDisk server return now.
2304d10e4ef2Snarayan 	 * They will be processed asynchronously and the vdc ACK handling code
2305d10e4ef2Snarayan 	 * will trigger the biodone(9F)
2306d10e4ef2Snarayan 	 */
2307d10e4ef2Snarayan 	if ((operation == VD_OP_BREAD) || (operation == VD_OP_BWRITE)) {
2308d10e4ef2Snarayan 		mutex_exit(&local_dep->lock);
2309d10e4ef2Snarayan 		return (rv);
2310d10e4ef2Snarayan 	}
2311d10e4ef2Snarayan 
2312d10e4ef2Snarayan 	/*
2313d10e4ef2Snarayan 	 * In the case of synchronous calls we watch the DRing entries we
2314d10e4ef2Snarayan 	 * modified and await the response from vds.
23151ae08745Sheppo 	 */
23168e6a2a04Slm66018 	rv = vdc_wait_for_descriptor_update(vdc, idx, dmsg);
23178e6a2a04Slm66018 	if (rv == ETIMEDOUT) {
23181ae08745Sheppo 		/* debug info when dumping state on vds side */
23191ae08745Sheppo 		dep->payload.status = ECANCELED;
23201ae08745Sheppo 	}
23211ae08745Sheppo 
23228e6a2a04Slm66018 	rv = vdc_depopulate_descriptor(vdc, idx);
2323*e1ebb9ecSlm66018 	DMSG(0, "[%d] Exiting: status=%d\n", vdc->instance, rv);
23241ae08745Sheppo 
23251ae08745Sheppo 	mutex_exit(&local_dep->lock);
23261ae08745Sheppo 
23278e6a2a04Slm66018 	return (rv);
23281ae08745Sheppo }
23291ae08745Sheppo 
23300a55fbb7Slm66018 /*
23310a55fbb7Slm66018  * Function:
23320a55fbb7Slm66018  *	vdc_wait_for_descriptor_update()
23330a55fbb7Slm66018  *
23340a55fbb7Slm66018  * Description:
23350a55fbb7Slm66018  *
23360a55fbb7Slm66018  * Arguments:
23370a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
23380a55fbb7Slm66018  *	idx	- Index of the Descriptor Ring entry being modified
23390a55fbb7Slm66018  *	dmsg	- LDC message sent by vDisk server
23400a55fbb7Slm66018  *
23410a55fbb7Slm66018  * Return Code:
23420a55fbb7Slm66018  *	0	- Success
23430a55fbb7Slm66018  */
23441ae08745Sheppo static int
23451ae08745Sheppo vdc_wait_for_descriptor_update(vdc_t *vdc, uint_t idx, vio_dring_msg_t dmsg)
23461ae08745Sheppo {
23471ae08745Sheppo 	vd_dring_entry_t *dep = NULL;		/* Dring Entry Pointer */
23481ae08745Sheppo 	vdc_local_desc_t *local_dep = NULL;	/* Local Dring Entry Pointer */
23491ae08745Sheppo 	size_t	msglen = sizeof (dmsg);
23501ae08745Sheppo 	int	retries = 0;
23510a55fbb7Slm66018 	int	status = 0;
23521ae08745Sheppo 	int	rv = 0;
23531ae08745Sheppo 
23541ae08745Sheppo 	ASSERT(vdc != NULL);
2355*e1ebb9ecSlm66018 	ASSERT(idx < vdc->dring_len);
23561ae08745Sheppo 	local_dep = &vdc->local_dring[idx];
23571ae08745Sheppo 	ASSERT(local_dep != NULL);
2358*e1ebb9ecSlm66018 	ASSERT(MUTEX_HELD(&local_dep->lock));
23591ae08745Sheppo 	dep = local_dep->dep;
23601ae08745Sheppo 	ASSERT(dep != NULL);
23611ae08745Sheppo 
23621ae08745Sheppo 	while (dep->hdr.dstate != VIO_DESC_DONE) {
23631ae08745Sheppo 		rv = cv_timedwait(&local_dep->cv, &local_dep->lock,
2364*e1ebb9ecSlm66018 			VD_GET_TIMEOUT_HZ(vdc_hz_timeout, retries));
23651ae08745Sheppo 		if (rv == -1) {
23661ae08745Sheppo 			/*
23671ae08745Sheppo 			 * If they persist in ignoring us we'll storm off in a
23681ae08745Sheppo 			 * huff and return ETIMEDOUT to the upper layers.
23691ae08745Sheppo 			 */
23701ae08745Sheppo 			if (retries >= vdc_retries) {
2371*e1ebb9ecSlm66018 				DMSG(0, "[%d] Finished waiting on entry %d\n",
2372*e1ebb9ecSlm66018 					vdc->instance, idx);
23731ae08745Sheppo 				status = ETIMEDOUT;
23741ae08745Sheppo 				break;
23751ae08745Sheppo 			} else {
23761ae08745Sheppo 				retries++;
2377*e1ebb9ecSlm66018 				DMSG(0, "[%d] Timeout #%d on entry %d "
2378*e1ebb9ecSlm66018 				    "[seq %lu][req %lu]\n", vdc->instance,
23791ae08745Sheppo 				    retries, idx, dmsg.seq_num,
23801ae08745Sheppo 				    dep->payload.req_id);
23811ae08745Sheppo 			}
23821ae08745Sheppo 
23831ae08745Sheppo 			if (dep->hdr.dstate & VIO_DESC_ACCEPTED) {
2384*e1ebb9ecSlm66018 				DMSG(0, "[%d] entry %d ACCEPTED [seq %lu]"
2385*e1ebb9ecSlm66018 				    "[req %lu] but not ACK'ed by vds yet\n",
2386*e1ebb9ecSlm66018 				    vdc->instance, idx, dmsg.seq_num,
23871ae08745Sheppo 				    dep->payload.req_id);
23881ae08745Sheppo 				continue;
23891ae08745Sheppo 			}
23901ae08745Sheppo 
23911ae08745Sheppo 			/*
23921ae08745Sheppo 			 * we resend the message as it may have been dropped
23931ae08745Sheppo 			 * and have never made it to the other side (vds).
23941ae08745Sheppo 			 * (We reuse the original message but update seq ID)
23951ae08745Sheppo 			 */
2396d10e4ef2Snarayan 			mutex_enter(&vdc->lock);
23971ae08745Sheppo 			VDC_INIT_DRING_DATA_MSG_IDS(dmsg, vdc);
23981ae08745Sheppo 			retries = 0;
23990a55fbb7Slm66018 			status = vdc_send(vdc, (caddr_t)&dmsg, &msglen);
24001ae08745Sheppo 			if (status != 0) {
2401d10e4ef2Snarayan 				mutex_exit(&vdc->lock);
2402*e1ebb9ecSlm66018 				cmn_err(CE_NOTE, "[%d] Error (%d) while sending"
2403*e1ebb9ecSlm66018 						" after timeout",
2404*e1ebb9ecSlm66018 						vdc->instance, status);
24051ae08745Sheppo 				status = ETIMEDOUT;
24061ae08745Sheppo 				break;
24071ae08745Sheppo 			}
24080a55fbb7Slm66018 			/*
24090a55fbb7Slm66018 			 * If the message was successfully sent, we increment
24100a55fbb7Slm66018 			 * the sequence number to be used by the next message.
24110a55fbb7Slm66018 			 */
24120a55fbb7Slm66018 			vdc->seq_num++;
2413d10e4ef2Snarayan 			mutex_exit(&vdc->lock);
24141ae08745Sheppo 		}
24151ae08745Sheppo 	}
24161ae08745Sheppo 
24171ae08745Sheppo 	return (status);
24181ae08745Sheppo }
24191ae08745Sheppo 
24201ae08745Sheppo 
24210a55fbb7Slm66018 /*
24220a55fbb7Slm66018  * Function:
24230a55fbb7Slm66018  *	vdc_depopulate_descriptor()
24240a55fbb7Slm66018  *
24250a55fbb7Slm66018  * Description:
24260a55fbb7Slm66018  *
24270a55fbb7Slm66018  * Arguments:
24280a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
24290a55fbb7Slm66018  *	idx	- Index of the Descriptor Ring entry being modified
24300a55fbb7Slm66018  *
24310a55fbb7Slm66018  * Return Code:
24320a55fbb7Slm66018  *	0	- Success
24330a55fbb7Slm66018  */
24341ae08745Sheppo static int
24351ae08745Sheppo vdc_depopulate_descriptor(vdc_t *vdc, uint_t idx)
24361ae08745Sheppo {
24371ae08745Sheppo 	vd_dring_entry_t *dep = NULL;		/* Dring Entry Pointer */
24381ae08745Sheppo 	vdc_local_desc_t *ldep = NULL;		/* Local Dring Entry Pointer */
24391ae08745Sheppo 	int		status = ENXIO;
24408e6a2a04Slm66018 	int		operation;
24418e6a2a04Slm66018 	int		rv = 0;
24421ae08745Sheppo 
24431ae08745Sheppo 	ASSERT(vdc != NULL);
2444*e1ebb9ecSlm66018 	ASSERT(idx < vdc->dring_len);
24451ae08745Sheppo 	ldep = &vdc->local_dring[idx];
24461ae08745Sheppo 	ASSERT(ldep != NULL);
2447*e1ebb9ecSlm66018 	ASSERT(MUTEX_HELD(&ldep->lock));
24481ae08745Sheppo 	dep = ldep->dep;
24491ae08745Sheppo 	ASSERT(dep != NULL);
2450*e1ebb9ecSlm66018 	ASSERT((dep->hdr.dstate == VIO_DESC_DONE) ||
2451*e1ebb9ecSlm66018 			(dep->payload.status == ECANCELED));
24521ae08745Sheppo 
2453*e1ebb9ecSlm66018 	VDC_MARK_DRING_ENTRY_FREE(vdc, idx);
2454*e1ebb9ecSlm66018 	VIO_SET_DESC_STATE(ldep->flags, VIO_DESC_FREE);
24551ae08745Sheppo 	status = dep->payload.status;
24568e6a2a04Slm66018 	operation = dep->payload.operation;
24571ae08745Sheppo 
24588e6a2a04Slm66018 	/* the DKIO W$ operations never bind handles so we can return now */
24598e6a2a04Slm66018 	if ((operation == VD_OP_FLUSH) ||
24608e6a2a04Slm66018 	    (operation == VD_OP_GET_WCE) ||
24618e6a2a04Slm66018 	    (operation == VD_OP_SET_WCE))
24628e6a2a04Slm66018 		return (status);
24638e6a2a04Slm66018 
24641ae08745Sheppo 	/*
24651ae08745Sheppo 	 * If the upper layer passed in a misaligned address we copied the
24661ae08745Sheppo 	 * data into an aligned buffer before sending it to LDC - we now
24671ae08745Sheppo 	 * copy it back to the original buffer.
24681ae08745Sheppo 	 */
24691ae08745Sheppo 	if (ldep->align_addr) {
24701ae08745Sheppo 		ASSERT(ldep->addr != NULL);
24711ae08745Sheppo 		ASSERT(dep->payload.nbytes > 0);
24721ae08745Sheppo 
24731ae08745Sheppo 		bcopy(ldep->align_addr, ldep->addr, dep->payload.nbytes);
24741ae08745Sheppo 		kmem_free(ldep->align_addr,
2475d10e4ef2Snarayan 			sizeof (caddr_t) * P2ROUNDUP(dep->payload.nbytes, 8));
24761ae08745Sheppo 		ldep->align_addr = NULL;
24771ae08745Sheppo 	}
24781ae08745Sheppo 
24798e6a2a04Slm66018 	rv = ldc_mem_unbind_handle(ldep->desc_mhdl);
24808e6a2a04Slm66018 	if (rv != 0) {
2481*e1ebb9ecSlm66018 		cmn_err(CE_CONT, "?[%d] unbind mhdl 0x%lx @ idx %d failed (%d)",
24828e6a2a04Slm66018 				vdc->instance, ldep->desc_mhdl, idx, rv);
24838e6a2a04Slm66018 		/*
24848e6a2a04Slm66018 		 * The error returned by the vDisk server is more informative
24858e6a2a04Slm66018 		 * and thus has a higher priority but if it isn't set we ensure
24868e6a2a04Slm66018 		 * that this function returns an error.
24878e6a2a04Slm66018 		 */
24888e6a2a04Slm66018 		if (status == 0)
24898e6a2a04Slm66018 			status = EINVAL;
24901ae08745Sheppo 	}
24911ae08745Sheppo 
24921ae08745Sheppo 	return (status);
24931ae08745Sheppo }
24941ae08745Sheppo 
24950a55fbb7Slm66018 /*
24960a55fbb7Slm66018  * Function:
24970a55fbb7Slm66018  *	vdc_populate_mem_hdl()
24980a55fbb7Slm66018  *
24990a55fbb7Slm66018  * Description:
25000a55fbb7Slm66018  *
25010a55fbb7Slm66018  * Arguments:
25020a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
25030a55fbb7Slm66018  *	idx	- Index of the Descriptor Ring entry being modified
25040a55fbb7Slm66018  *	addr	- virtual address being mapped in
25050a55fbb7Slm66018  *	nybtes	- number of bytes in 'addr'
25060a55fbb7Slm66018  *	operation - the vDisk operation being performed (VD_OP_xxx)
25070a55fbb7Slm66018  *
25080a55fbb7Slm66018  * Return Code:
25090a55fbb7Slm66018  *	0	- Success
25100a55fbb7Slm66018  */
25111ae08745Sheppo static int
25121ae08745Sheppo vdc_populate_mem_hdl(vdc_t *vdc, uint_t idx, caddr_t addr, size_t nbytes,
25131ae08745Sheppo 			int operation)
25141ae08745Sheppo {
25151ae08745Sheppo 	vd_dring_entry_t	*dep = NULL;
25161ae08745Sheppo 	vdc_local_desc_t	*ldep = NULL;
25171ae08745Sheppo 	ldc_mem_handle_t	mhdl;
25181ae08745Sheppo 	caddr_t			vaddr;
25191ae08745Sheppo 	int			perm = LDC_MEM_RW;
25201ae08745Sheppo 	int			rv = 0;
25211ae08745Sheppo 	int			i;
25221ae08745Sheppo 
25231ae08745Sheppo 	ASSERT(vdc != NULL);
2524*e1ebb9ecSlm66018 	ASSERT(idx < vdc->dring_len);
25251ae08745Sheppo 
25261ae08745Sheppo 	dep = VDC_GET_DRING_ENTRY_PTR(vdc, idx);
25271ae08745Sheppo 	ldep = &vdc->local_dring[idx];
25281ae08745Sheppo 	mhdl = ldep->desc_mhdl;
25291ae08745Sheppo 
25301ae08745Sheppo 	switch (operation) {
25311ae08745Sheppo 	case VD_OP_BREAD:
25321ae08745Sheppo 		perm = LDC_MEM_W;
25331ae08745Sheppo 		break;
25341ae08745Sheppo 
25351ae08745Sheppo 	case VD_OP_BWRITE:
25361ae08745Sheppo 		perm = LDC_MEM_R;
25371ae08745Sheppo 		break;
25381ae08745Sheppo 
25391ae08745Sheppo 	case VD_OP_GET_VTOC:
25401ae08745Sheppo 	case VD_OP_SET_VTOC:
25411ae08745Sheppo 	case VD_OP_GET_DISKGEOM:
25421ae08745Sheppo 	case VD_OP_SET_DISKGEOM:
25431ae08745Sheppo 	case VD_OP_SCSICMD:
25441ae08745Sheppo 		perm = LDC_MEM_RW;
25451ae08745Sheppo 		break;
25461ae08745Sheppo 
25471ae08745Sheppo 	default:
25481ae08745Sheppo 		ASSERT(0);	/* catch bad programming in vdc */
25491ae08745Sheppo 	}
25501ae08745Sheppo 
25511ae08745Sheppo 	/*
25521ae08745Sheppo 	 * LDC expects any addresses passed in to be 8-byte aligned. We need
25531ae08745Sheppo 	 * to copy the contents of any misaligned buffers to a newly allocated
25541ae08745Sheppo 	 * buffer and bind it instead (and copy the the contents back to the
25551ae08745Sheppo 	 * original buffer passed in when depopulating the descriptor)
25561ae08745Sheppo 	 */
25571ae08745Sheppo 	vaddr = addr;
25581ae08745Sheppo 	if (((uint64_t)addr & 0x7) != 0) {
2559d10e4ef2Snarayan 		ASSERT(ldep->align_addr == NULL);
25601ae08745Sheppo 		ldep->align_addr =
2561d10e4ef2Snarayan 			kmem_zalloc(sizeof (caddr_t) * P2ROUNDUP(nbytes, 8),
2562d10e4ef2Snarayan 					KM_SLEEP);
2563*e1ebb9ecSlm66018 		DMSG(0, "[%d] Misaligned address %p reallocating "
2564*e1ebb9ecSlm66018 		    "(buf=%p nb=%ld op=%d entry=%d)\n",
2565*e1ebb9ecSlm66018 		    vdc->instance, (void *)addr, (void *)ldep->align_addr,
2566*e1ebb9ecSlm66018 		    nbytes, operation, idx);
25671ae08745Sheppo 		bcopy(addr, ldep->align_addr, nbytes);
25681ae08745Sheppo 		vaddr = ldep->align_addr;
25691ae08745Sheppo 	}
25701ae08745Sheppo 
25711ae08745Sheppo 	rv = ldc_mem_bind_handle(mhdl, vaddr, P2ROUNDUP(nbytes, 8),
2572d10e4ef2Snarayan 		LDC_SHADOW_MAP, perm, &dep->payload.cookie[0],
25731ae08745Sheppo 		&dep->payload.ncookies);
2574*e1ebb9ecSlm66018 	DMSG(2, "[%d] bound mem handle; ncookies=%d\n",
2575*e1ebb9ecSlm66018 			vdc->instance, dep->payload.ncookies);
25761ae08745Sheppo 	if (rv != 0) {
2577*e1ebb9ecSlm66018 		cmn_err(CE_CONT, "?[%d] Failed to bind LDC memory handle "
2578*e1ebb9ecSlm66018 		    "(mhdl=%p, buf=%p entry=%u err=%d)\n",
2579*e1ebb9ecSlm66018 		    vdc->instance, (void *)mhdl, (void *)addr, idx, rv);
25801ae08745Sheppo 		if (ldep->align_addr) {
25811ae08745Sheppo 			kmem_free(ldep->align_addr,
2582d10e4ef2Snarayan 				sizeof (caddr_t) * P2ROUNDUP(nbytes, 8));
25831ae08745Sheppo 			ldep->align_addr = NULL;
25841ae08745Sheppo 		}
25851ae08745Sheppo 		return (EAGAIN);
25861ae08745Sheppo 	}
25871ae08745Sheppo 
25881ae08745Sheppo 	/*
25891ae08745Sheppo 	 * Get the other cookies (if any).
25901ae08745Sheppo 	 */
25911ae08745Sheppo 	for (i = 1; i < dep->payload.ncookies; i++) {
25921ae08745Sheppo 		rv = ldc_mem_nextcookie(mhdl, &dep->payload.cookie[i]);
25931ae08745Sheppo 		if (rv != 0) {
25941ae08745Sheppo 			(void) ldc_mem_unbind_handle(mhdl);
2595*e1ebb9ecSlm66018 			cmn_err(CE_CONT, "?[%d] Failed to get next cookie "
2596*e1ebb9ecSlm66018 					"(mhdl=%lx cnum=%d), err=%d",
2597*e1ebb9ecSlm66018 					vdc->instance, mhdl, i, rv);
25981ae08745Sheppo 			if (ldep->align_addr) {
25991ae08745Sheppo 				kmem_free(ldep->align_addr,
26001ae08745Sheppo 					sizeof (caddr_t) * dep->payload.nbytes);
26011ae08745Sheppo 				ldep->align_addr = NULL;
26021ae08745Sheppo 			}
26031ae08745Sheppo 			return (EAGAIN);
26041ae08745Sheppo 		}
26051ae08745Sheppo 	}
26061ae08745Sheppo 
26071ae08745Sheppo 	return (rv);
26081ae08745Sheppo }
26091ae08745Sheppo 
26101ae08745Sheppo /*
26111ae08745Sheppo  * Interrupt handlers for messages from LDC
26121ae08745Sheppo  */
26131ae08745Sheppo 
26140a55fbb7Slm66018 /*
26150a55fbb7Slm66018  * Function:
26160a55fbb7Slm66018  *	vdc_handle_cb()
26170a55fbb7Slm66018  *
26180a55fbb7Slm66018  * Description:
26190a55fbb7Slm66018  *
26200a55fbb7Slm66018  * Arguments:
26210a55fbb7Slm66018  *	event	- Type of event (LDC_EVT_xxx) that triggered the callback
26220a55fbb7Slm66018  *	arg	- soft state pointer for this instance of the device driver.
26230a55fbb7Slm66018  *
26240a55fbb7Slm66018  * Return Code:
26250a55fbb7Slm66018  *	0	- Success
26260a55fbb7Slm66018  */
26271ae08745Sheppo static uint_t
26281ae08745Sheppo vdc_handle_cb(uint64_t event, caddr_t arg)
26291ae08745Sheppo {
26301ae08745Sheppo 	ldc_status_t	ldc_state;
26311ae08745Sheppo 	int		rv = 0;
26321ae08745Sheppo 
26331ae08745Sheppo 	vdc_t	*vdc = (vdc_t *)(void *)arg;
26341ae08745Sheppo 
26351ae08745Sheppo 	ASSERT(vdc != NULL);
26361ae08745Sheppo 
2637*e1ebb9ecSlm66018 	DMSG(1, "[%d] evt=%lx seqID=%ld\n", vdc->instance, event, vdc->seq_num);
26381ae08745Sheppo 
26391ae08745Sheppo 	/*
26401ae08745Sheppo 	 * Depending on the type of event that triggered this callback,
26411ae08745Sheppo 	 * we modify the handhske state or read the data.
26421ae08745Sheppo 	 *
26431ae08745Sheppo 	 * NOTE: not done as a switch() as event could be triggered by
26441ae08745Sheppo 	 * a state change and a read request. Also the ordering	of the
26451ae08745Sheppo 	 * check for the event types is deliberate.
26461ae08745Sheppo 	 */
26471ae08745Sheppo 	if (event & LDC_EVT_UP) {
2648*e1ebb9ecSlm66018 		DMSG(0, "[%d] Received LDC_EVT_UP\n", vdc->instance);
26491ae08745Sheppo 
26501ae08745Sheppo 		/* get LDC state */
26511ae08745Sheppo 		rv = ldc_status(vdc->ldc_handle, &ldc_state);
26521ae08745Sheppo 		if (rv != 0) {
26531ae08745Sheppo 			cmn_err(CE_NOTE, "[%d] Couldn't get LDC status %d",
26541ae08745Sheppo 					vdc->instance, rv);
26550a55fbb7Slm66018 			mutex_enter(&vdc->lock);
26561ae08745Sheppo 			vdc_reset_connection(vdc, B_TRUE);
26570a55fbb7Slm66018 			mutex_exit(&vdc->lock);
26581ae08745Sheppo 			return (LDC_SUCCESS);
26591ae08745Sheppo 		}
26601ae08745Sheppo 
26611ae08745Sheppo 		/*
26621ae08745Sheppo 		 * Reset the transaction sequence numbers when LDC comes up.
26631ae08745Sheppo 		 * We then kick off the handshake negotiation with the vDisk
26641ae08745Sheppo 		 * server.
26651ae08745Sheppo 		 */
26661ae08745Sheppo 		mutex_enter(&vdc->lock);
26670a55fbb7Slm66018 		vdc->seq_num = 1;
26681ae08745Sheppo 		vdc->seq_num_reply = 0;
26691ae08745Sheppo 		vdc->ldc_state = ldc_state;
26701ae08745Sheppo 		ASSERT(ldc_state == LDC_UP);
26711ae08745Sheppo 		mutex_exit(&vdc->lock);
26721ae08745Sheppo 
26731ae08745Sheppo 		vdc_init_handshake_negotiation(vdc);
26741ae08745Sheppo 
26751ae08745Sheppo 		ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0);
26761ae08745Sheppo 	}
26771ae08745Sheppo 
26781ae08745Sheppo 	if (event & LDC_EVT_READ) {
26791ae08745Sheppo 		/*
26801ae08745Sheppo 		 * Wake up the worker thread to process the message
26811ae08745Sheppo 		 */
26821ae08745Sheppo 		mutex_enter(&vdc->msg_proc_lock);
26831ae08745Sheppo 		vdc->msg_pending = B_TRUE;
26841ae08745Sheppo 		cv_signal(&vdc->msg_proc_cv);
26851ae08745Sheppo 		mutex_exit(&vdc->msg_proc_lock);
26861ae08745Sheppo 
26871ae08745Sheppo 		ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0);
26881ae08745Sheppo 
26891ae08745Sheppo 		/* that's all we have to do - no need to handle DOWN/RESET */
26901ae08745Sheppo 		return (LDC_SUCCESS);
26911ae08745Sheppo 	}
26921ae08745Sheppo 
26931ae08745Sheppo 	if (event & LDC_EVT_RESET) {
2694*e1ebb9ecSlm66018 		DMSG(0, "[%d] Received LDC RESET event\n", vdc->instance);
26950a55fbb7Slm66018 
26960a55fbb7Slm66018 		/* get LDC state */
26970a55fbb7Slm66018 		rv = ldc_status(vdc->ldc_handle, &ldc_state);
26980a55fbb7Slm66018 		if (rv != 0) {
26990a55fbb7Slm66018 			cmn_err(CE_NOTE, "[%d] Couldn't get LDC status %d",
27000a55fbb7Slm66018 					vdc->instance, rv);
27010a55fbb7Slm66018 			ldc_state = LDC_OPEN;
27020a55fbb7Slm66018 		}
27030a55fbb7Slm66018 		mutex_enter(&vdc->lock);
27040a55fbb7Slm66018 		vdc->ldc_state = ldc_state;
2705*e1ebb9ecSlm66018 		vdc_reset_connection(vdc, B_TRUE);
27060a55fbb7Slm66018 		mutex_exit(&vdc->lock);
27070a55fbb7Slm66018 
27080a55fbb7Slm66018 		vdc_init_handshake_negotiation(vdc);
27091ae08745Sheppo 	}
27101ae08745Sheppo 
27111ae08745Sheppo 	if (event & LDC_EVT_DOWN) {
2712*e1ebb9ecSlm66018 		DMSG(0, "[%d] Received LDC DOWN event\n", vdc->instance);
27131ae08745Sheppo 
27141ae08745Sheppo 		/* get LDC state */
27151ae08745Sheppo 		rv = ldc_status(vdc->ldc_handle, &ldc_state);
27161ae08745Sheppo 		if (rv != 0) {
27171ae08745Sheppo 			cmn_err(CE_NOTE, "[%d] Couldn't get LDC status %d",
27181ae08745Sheppo 					vdc->instance, rv);
27191ae08745Sheppo 			ldc_state = LDC_OPEN;
27201ae08745Sheppo 		}
27211ae08745Sheppo 		mutex_enter(&vdc->lock);
27221ae08745Sheppo 		vdc->ldc_state = ldc_state;
27231ae08745Sheppo 		vdc_reset_connection(vdc, B_TRUE);
27240a55fbb7Slm66018 		mutex_exit(&vdc->lock);
27251ae08745Sheppo 	}
27261ae08745Sheppo 
27271ae08745Sheppo 	if (event & ~(LDC_EVT_UP | LDC_EVT_RESET | LDC_EVT_DOWN | LDC_EVT_READ))
27281ae08745Sheppo 		cmn_err(CE_NOTE, "![%d] Unexpected LDC event (%lx) received",
27291ae08745Sheppo 				vdc->instance, event);
27301ae08745Sheppo 
27311ae08745Sheppo 	return (LDC_SUCCESS);
27321ae08745Sheppo }
27331ae08745Sheppo 
27341ae08745Sheppo /* -------------------------------------------------------------------------- */
27351ae08745Sheppo 
27361ae08745Sheppo /*
27371ae08745Sheppo  * The following functions process the incoming messages from vds
27381ae08745Sheppo  */
27391ae08745Sheppo 
27401ae08745Sheppo 
27410a55fbb7Slm66018 /*
27420a55fbb7Slm66018  * Function:
27430a55fbb7Slm66018  *	vdc_process_msg_thread()
27440a55fbb7Slm66018  *
27450a55fbb7Slm66018  * Description:
27460a55fbb7Slm66018  *
27470a55fbb7Slm66018  * Arguments:
27480a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
27490a55fbb7Slm66018  *
27500a55fbb7Slm66018  * Return Code:
27510a55fbb7Slm66018  *	None
27520a55fbb7Slm66018  */
27531ae08745Sheppo static void
27541ae08745Sheppo vdc_process_msg_thread(vdc_t *vdc)
27551ae08745Sheppo {
27561ae08745Sheppo 	int		status = 0;
2757*e1ebb9ecSlm66018 	boolean_t	q_has_pkts = B_FALSE;
27581ae08745Sheppo 
27591ae08745Sheppo 	ASSERT(vdc != NULL);
27601ae08745Sheppo 
27611ae08745Sheppo 	mutex_enter(&vdc->msg_proc_lock);
2762*e1ebb9ecSlm66018 	DMSG(0, "[%d] Starting\n", vdc->instance);
27631ae08745Sheppo 
27641ae08745Sheppo 	vdc->msg_proc_thr_state = VDC_THR_RUNNING;
27651ae08745Sheppo 
27661ae08745Sheppo 	while (vdc->msg_proc_thr_state == VDC_THR_RUNNING) {
27671ae08745Sheppo 
2768*e1ebb9ecSlm66018 		DMSG(2, "[%d] Waiting\n", vdc->instance);
27690a55fbb7Slm66018 		while (!vdc->msg_pending)
27701ae08745Sheppo 			cv_wait(&vdc->msg_proc_cv, &vdc->msg_proc_lock);
27711ae08745Sheppo 
2772*e1ebb9ecSlm66018 		DMSG(2, "[%d] Message Received\n", vdc->instance);
27731ae08745Sheppo 
27741ae08745Sheppo 		/* check if there is data */
2775*e1ebb9ecSlm66018 		status = ldc_chkq(vdc->ldc_handle, &q_has_pkts);
27761ae08745Sheppo 		if ((status != 0) &&
27771ae08745Sheppo 		    (vdc->msg_proc_thr_state == VDC_THR_RUNNING)) {
27781ae08745Sheppo 			cmn_err(CE_NOTE, "[%d] Unable to communicate with vDisk"
27791ae08745Sheppo 					" server. Cannot check LDC queue: %d",
27801ae08745Sheppo 					vdc->instance, status);
27811ae08745Sheppo 			mutex_enter(&vdc->lock);
2782*e1ebb9ecSlm66018 			vdc_reset_connection(vdc, B_TRUE);
27831ae08745Sheppo 			mutex_exit(&vdc->lock);
27841ae08745Sheppo 			vdc->msg_proc_thr_state = VDC_THR_STOP;
27851ae08745Sheppo 			continue;
27861ae08745Sheppo 		}
27871ae08745Sheppo 
2788*e1ebb9ecSlm66018 		if (q_has_pkts) {
2789*e1ebb9ecSlm66018 			DMSG(2, "[%d] new pkt(s) available\n", vdc->instance);
27901ae08745Sheppo 			vdc_process_msg(vdc);
27911ae08745Sheppo 		}
27921ae08745Sheppo 
27931ae08745Sheppo 		vdc->msg_pending = B_FALSE;
27941ae08745Sheppo 	}
27951ae08745Sheppo 
2796*e1ebb9ecSlm66018 	DMSG(0, "[%d] Message processing thread stopped\n", vdc->instance);
27971ae08745Sheppo 	vdc->msg_pending = B_FALSE;
27981ae08745Sheppo 	vdc->msg_proc_thr_state = VDC_THR_DONE;
27991ae08745Sheppo 	cv_signal(&vdc->msg_proc_cv);
28001ae08745Sheppo 	mutex_exit(&vdc->msg_proc_lock);
28011ae08745Sheppo 	thread_exit();
28021ae08745Sheppo }
28031ae08745Sheppo 
28041ae08745Sheppo 
28051ae08745Sheppo /*
28061ae08745Sheppo  * Function:
28071ae08745Sheppo  *	vdc_process_msg()
28081ae08745Sheppo  *
28091ae08745Sheppo  * Description:
28101ae08745Sheppo  *	This function is called by the message processing thread each time it
28111ae08745Sheppo  *	is triggered when LDC sends an interrupt to indicate that there are
28121ae08745Sheppo  *	more packets on the queue. When it is called it will continue to loop
28131ae08745Sheppo  *	and read the messages until there are no more left of the queue. If it
28141ae08745Sheppo  *	encounters an invalid sized message it will drop it and check the next
28151ae08745Sheppo  *	message.
28161ae08745Sheppo  *
28171ae08745Sheppo  * Arguments:
28181ae08745Sheppo  *	arg	- soft state pointer for this instance of the device driver.
28191ae08745Sheppo  *
28201ae08745Sheppo  * Return Code:
28211ae08745Sheppo  *	None.
28221ae08745Sheppo  */
28231ae08745Sheppo static void
28241ae08745Sheppo vdc_process_msg(void *arg)
28251ae08745Sheppo {
28261ae08745Sheppo 	vdc_t		*vdc = (vdc_t *)(void *)arg;
28271ae08745Sheppo 	vio_msg_t	vio_msg;
28281ae08745Sheppo 	size_t		nbytes = sizeof (vio_msg);
28291ae08745Sheppo 	int		status;
28301ae08745Sheppo 
28311ae08745Sheppo 	ASSERT(vdc != NULL);
28321ae08745Sheppo 
28331ae08745Sheppo 	mutex_enter(&vdc->lock);
28341ae08745Sheppo 
2835*e1ebb9ecSlm66018 	DMSG(1, "[%d]\n", vdc->instance);
28361ae08745Sheppo 
28371ae08745Sheppo 	for (;;) {
28381ae08745Sheppo 
28391ae08745Sheppo 		/* read all messages - until no more left */
28401ae08745Sheppo 		status = ldc_read(vdc->ldc_handle, (caddr_t)&vio_msg, &nbytes);
28411ae08745Sheppo 
28421ae08745Sheppo 		if (status) {
2843*e1ebb9ecSlm66018 			cmn_err(CE_CONT, "?[%d] Error %d reading LDC msg\n",
2844*e1ebb9ecSlm66018 					vdc->instance, status);
28451ae08745Sheppo 
28461ae08745Sheppo 			/* if status is ECONNRESET --- reset vdc state */
28471ae08745Sheppo 			if (status == EIO || status == ECONNRESET) {
28480a55fbb7Slm66018 				vdc_reset_connection(vdc, B_TRUE);
28491ae08745Sheppo 			}
28501ae08745Sheppo 
28511ae08745Sheppo 			mutex_exit(&vdc->lock);
28521ae08745Sheppo 			return;
28531ae08745Sheppo 		}
28541ae08745Sheppo 
28551ae08745Sheppo 		if ((nbytes > 0) && (nbytes < sizeof (vio_msg_tag_t))) {
2856*e1ebb9ecSlm66018 			cmn_err(CE_CONT, "?[%d] Expect %lu bytes; recv'd %lu\n",
28571ae08745Sheppo 				vdc->instance, sizeof (vio_msg_tag_t), nbytes);
28581ae08745Sheppo 			mutex_exit(&vdc->lock);
28591ae08745Sheppo 			return;
28601ae08745Sheppo 		}
28611ae08745Sheppo 
28621ae08745Sheppo 		if (nbytes == 0) {
2863*e1ebb9ecSlm66018 			DMSG(3, "[%d] ldc_read() done..\n", vdc->instance);
28641ae08745Sheppo 			mutex_exit(&vdc->lock);
28651ae08745Sheppo 			return;
28661ae08745Sheppo 		}
28671ae08745Sheppo 
2868*e1ebb9ecSlm66018 		DMSG(2, "[%d] (%x/%x/%x)\n", vdc->instance,
28691ae08745Sheppo 		    vio_msg.tag.vio_msgtype,
28701ae08745Sheppo 		    vio_msg.tag.vio_subtype,
28711ae08745Sheppo 		    vio_msg.tag.vio_subtype_env);
28721ae08745Sheppo 
28731ae08745Sheppo 		/*
28741ae08745Sheppo 		 * Verify the Session ID of the message
28751ae08745Sheppo 		 *
28761ae08745Sheppo 		 * Every message after the Version has been negotiated should
28771ae08745Sheppo 		 * have the correct session ID set.
28781ae08745Sheppo 		 */
28791ae08745Sheppo 		if ((vio_msg.tag.vio_sid != vdc->session_id) &&
28801ae08745Sheppo 		    (vio_msg.tag.vio_subtype_env != VIO_VER_INFO)) {
2881*e1ebb9ecSlm66018 			cmn_err(CE_NOTE, "[%d] Invalid SID: received 0x%x, "
2882*e1ebb9ecSlm66018 					"expected 0x%lx [seq num %lx @ %d]",
28830a55fbb7Slm66018 				vdc->instance, vio_msg.tag.vio_sid,
2884*e1ebb9ecSlm66018 				vdc->session_id,
2885*e1ebb9ecSlm66018 				((vio_dring_msg_t *)&vio_msg)->seq_num,
2886*e1ebb9ecSlm66018 				((vio_dring_msg_t *)&vio_msg)->start_idx);
2887*e1ebb9ecSlm66018 			vdc_reset_connection(vdc, B_TRUE);
28881ae08745Sheppo 			mutex_exit(&vdc->lock);
28891ae08745Sheppo 			return;
28901ae08745Sheppo 		}
28911ae08745Sheppo 
28921ae08745Sheppo 		switch (vio_msg.tag.vio_msgtype) {
28931ae08745Sheppo 		case VIO_TYPE_CTRL:
28941ae08745Sheppo 			status = vdc_process_ctrl_msg(vdc, vio_msg);
28951ae08745Sheppo 			break;
28961ae08745Sheppo 		case VIO_TYPE_DATA:
28971ae08745Sheppo 			status = vdc_process_data_msg(vdc, vio_msg);
28981ae08745Sheppo 			break;
28991ae08745Sheppo 		case VIO_TYPE_ERR:
29001ae08745Sheppo 			status = vdc_process_err_msg(vdc, vio_msg);
29011ae08745Sheppo 			break;
29021ae08745Sheppo 		default:
2903*e1ebb9ecSlm66018 			cmn_err(CE_NOTE, "[%d] Unknown VIO message type",
2904*e1ebb9ecSlm66018 					vdc->instance);
29051ae08745Sheppo 			status = EINVAL;
29061ae08745Sheppo 			break;
29071ae08745Sheppo 		}
29081ae08745Sheppo 
29091ae08745Sheppo 		if (status != 0) {
2910*e1ebb9ecSlm66018 			DMSG(0, "[%d] Error (%d) occurred processing req %lu\n",
2911*e1ebb9ecSlm66018 					vdc->instance, status,
2912*e1ebb9ecSlm66018 					vdc->req_id_proc);
2913*e1ebb9ecSlm66018 			vdc_reset_connection(vdc, B_TRUE);
2914*e1ebb9ecSlm66018 
2915*e1ebb9ecSlm66018 			/* we need to drop the lock to trigger the handshake */
2916*e1ebb9ecSlm66018 			mutex_exit(&vdc->lock);
2917*e1ebb9ecSlm66018 			vdc_init_handshake_negotiation(vdc);
2918*e1ebb9ecSlm66018 			mutex_enter(&vdc->lock);
29191ae08745Sheppo 		}
29201ae08745Sheppo 	}
29211ae08745Sheppo 	_NOTE(NOTREACHED)
29221ae08745Sheppo }
29231ae08745Sheppo 
29241ae08745Sheppo /*
29251ae08745Sheppo  * Function:
29261ae08745Sheppo  *	vdc_process_ctrl_msg()
29271ae08745Sheppo  *
29281ae08745Sheppo  * Description:
29291ae08745Sheppo  *	This function is called by the message processing thread each time
29301ae08745Sheppo  *	an LDC message with a msgtype of VIO_TYPE_CTRL is received.
29311ae08745Sheppo  *
29321ae08745Sheppo  * Arguments:
29331ae08745Sheppo  *	vdc	- soft state pointer for this instance of the device driver.
29341ae08745Sheppo  *	msg	- the LDC message sent by vds
29351ae08745Sheppo  *
29361ae08745Sheppo  * Return Codes:
29371ae08745Sheppo  *	0	- Success.
29381ae08745Sheppo  *	EPROTO	- A message was received which shouldn't have happened according
29391ae08745Sheppo  *		  to the protocol
29401ae08745Sheppo  *	ENOTSUP	- An action which is allowed according to the protocol but which
29411ae08745Sheppo  *		  isn't (or doesn't need to be) implemented yet.
29421ae08745Sheppo  *	EINVAL	- An invalid value was returned as part of a message.
29431ae08745Sheppo  */
29441ae08745Sheppo static int
29451ae08745Sheppo vdc_process_ctrl_msg(vdc_t *vdc, vio_msg_t msg)
29461ae08745Sheppo {
29471ae08745Sheppo 	int			status = -1;
29481ae08745Sheppo 
29491ae08745Sheppo 	ASSERT(msg.tag.vio_msgtype == VIO_TYPE_CTRL);
29501ae08745Sheppo 	ASSERT(vdc != NULL);
29511ae08745Sheppo 	ASSERT(mutex_owned(&vdc->lock));
29521ae08745Sheppo 
29531ae08745Sheppo 	/* Depending on which state we are in; process the message */
29541ae08745Sheppo 	switch (vdc->state) {
29551ae08745Sheppo 	case VD_STATE_INIT:
29560a55fbb7Slm66018 		status = vdc_handle_ver_msg(vdc, (vio_ver_msg_t *)&msg);
29570a55fbb7Slm66018 		break;
29580a55fbb7Slm66018 
29590a55fbb7Slm66018 	case VD_STATE_VER:
29600a55fbb7Slm66018 		status = vdc_handle_attr_msg(vdc, (vd_attr_msg_t *)&msg);
29610a55fbb7Slm66018 		break;
29620a55fbb7Slm66018 
29630a55fbb7Slm66018 	case VD_STATE_ATTR:
29640a55fbb7Slm66018 		status = vdc_handle_dring_reg_msg(vdc,
29650a55fbb7Slm66018 				(vio_dring_reg_msg_t *)&msg);
29660a55fbb7Slm66018 		break;
29670a55fbb7Slm66018 
29680a55fbb7Slm66018 	case VD_STATE_RDX:
29690a55fbb7Slm66018 		if (msg.tag.vio_subtype_env != VIO_RDX) {
29701ae08745Sheppo 			status = EPROTO;
29711ae08745Sheppo 			break;
29721ae08745Sheppo 		}
29731ae08745Sheppo 
2974*e1ebb9ecSlm66018 		DMSG(0, "[%d] Received RDX: handshake done\n", vdc->instance);
29751ae08745Sheppo 
29760a55fbb7Slm66018 		vdc->hshake_cnt = 0;	/* reset failed handshake count */
29770a55fbb7Slm66018 		status = 0;
29780a55fbb7Slm66018 		vdc->state = VD_STATE_DATA;
29790a55fbb7Slm66018 
29800a55fbb7Slm66018 		cv_broadcast(&vdc->attach_cv);
29810a55fbb7Slm66018 		break;
29820a55fbb7Slm66018 
29830a55fbb7Slm66018 	case VD_STATE_DATA:
29840a55fbb7Slm66018 	default:
29850a55fbb7Slm66018 		cmn_err(CE_NOTE, "[%d] Unexpected handshake state %d",
29860a55fbb7Slm66018 				vdc->instance, vdc->state);
29871ae08745Sheppo 		status = EPROTO;
29881ae08745Sheppo 		break;
29890a55fbb7Slm66018 	}
29901ae08745Sheppo 
29910a55fbb7Slm66018 	return (status);
29920a55fbb7Slm66018 }
29930a55fbb7Slm66018 
29940a55fbb7Slm66018 
29950a55fbb7Slm66018 /*
29960a55fbb7Slm66018  * Function:
29970a55fbb7Slm66018  *	vdc_process_data_msg()
29980a55fbb7Slm66018  *
29990a55fbb7Slm66018  * Description:
30000a55fbb7Slm66018  *	This function is called by the message processing thread each time
30010a55fbb7Slm66018  *	a message with a msgtype of VIO_TYPE_DATA is received. It will either
30020a55fbb7Slm66018  *	be an ACK or NACK from vds[1] which vdc handles as follows.
30030a55fbb7Slm66018  *		ACK	- wake up the waiting thread
30040a55fbb7Slm66018  *		NACK	- resend any messages necessary
30050a55fbb7Slm66018  *
30060a55fbb7Slm66018  *	[1] Although the message format allows it, vds should not send a
30070a55fbb7Slm66018  *	    VIO_SUBTYPE_INFO message to vdc asking it to read data; if for
30080a55fbb7Slm66018  *	    some bizarre reason it does, vdc will reset the connection.
30090a55fbb7Slm66018  *
30100a55fbb7Slm66018  * Arguments:
30110a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
30120a55fbb7Slm66018  *	msg	- the LDC message sent by vds
30130a55fbb7Slm66018  *
30140a55fbb7Slm66018  * Return Code:
30150a55fbb7Slm66018  *	0	- Success.
30160a55fbb7Slm66018  *	> 0	- error value returned by LDC
30170a55fbb7Slm66018  */
30180a55fbb7Slm66018 static int
30190a55fbb7Slm66018 vdc_process_data_msg(vdc_t *vdc, vio_msg_t msg)
30200a55fbb7Slm66018 {
30210a55fbb7Slm66018 	int			status = 0;
3022d10e4ef2Snarayan 	vdc_local_desc_t	*ldep = NULL;
30230a55fbb7Slm66018 	vio_dring_msg_t		*dring_msg = NULL;
30240a55fbb7Slm66018 	uint_t			start;
3025*e1ebb9ecSlm66018 	int			end;
3026*e1ebb9ecSlm66018 	uint_t			count = 0;
3027*e1ebb9ecSlm66018 	uint_t			operation;
3028*e1ebb9ecSlm66018 	uint_t			idx;
30290a55fbb7Slm66018 
30300a55fbb7Slm66018 	ASSERT(msg.tag.vio_msgtype == VIO_TYPE_DATA);
30310a55fbb7Slm66018 	ASSERT(vdc != NULL);
30320a55fbb7Slm66018 	ASSERT(mutex_owned(&vdc->lock));
30330a55fbb7Slm66018 
30340a55fbb7Slm66018 	dring_msg = (vio_dring_msg_t *)&msg;
30350a55fbb7Slm66018 
30360a55fbb7Slm66018 	/*
30370a55fbb7Slm66018 	 * Check to see if the message has bogus data
30380a55fbb7Slm66018 	 */
3039*e1ebb9ecSlm66018 	idx = start = dring_msg->start_idx;
30400a55fbb7Slm66018 	end = dring_msg->end_idx;
3041*e1ebb9ecSlm66018 	if ((start >= vdc->dring_len) ||
3042*e1ebb9ecSlm66018 	    (end >= vdc->dring_len) || (end < -1)) {
3043*e1ebb9ecSlm66018 		cmn_err(CE_CONT, "?[%d] Bogus ACK data : start %d, end %d\n",
3044*e1ebb9ecSlm66018 			vdc->instance, start, end);
3045*e1ebb9ecSlm66018 		return (EINVAL);
30460a55fbb7Slm66018 	}
30470a55fbb7Slm66018 
3048d10e4ef2Snarayan 	DTRACE_IO2(recv, vio_dring_msg_t, dring_msg, vdc_t *, vdc);
3049d10e4ef2Snarayan 
30500a55fbb7Slm66018 	/*
30510a55fbb7Slm66018 	 * Verify that the sequence number is what vdc expects.
30520a55fbb7Slm66018 	 */
3053*e1ebb9ecSlm66018 	switch (vdc_verify_seq_num(vdc, dring_msg)) {
3054*e1ebb9ecSlm66018 	case VDC_SEQ_NUM_TODO:
3055*e1ebb9ecSlm66018 		break;	/* keep processing this message */
3056*e1ebb9ecSlm66018 	case VDC_SEQ_NUM_SKIP:
3057*e1ebb9ecSlm66018 		return (0);
3058*e1ebb9ecSlm66018 	case VDC_SEQ_NUM_INVALID:
30590a55fbb7Slm66018 		return (ENXIO);
30600a55fbb7Slm66018 	}
30610a55fbb7Slm66018 
3062*e1ebb9ecSlm66018 	if (msg.tag.vio_subtype == VIO_SUBTYPE_NACK) {
3063*e1ebb9ecSlm66018 		DMSG(0, "[%d] DATA NACK\n", vdc->instance);
3064*e1ebb9ecSlm66018 		VDC_DUMP_DRING_MSG(dring_msg);
3065*e1ebb9ecSlm66018 		return (EIO);
30660a55fbb7Slm66018 
3067*e1ebb9ecSlm66018 	} else if (msg.tag.vio_subtype == VIO_SUBTYPE_INFO) {
3068*e1ebb9ecSlm66018 		return (EPROTO);
3069*e1ebb9ecSlm66018 	}
3070*e1ebb9ecSlm66018 
3071*e1ebb9ecSlm66018 	ldep = &vdc->local_dring[start];
3072*e1ebb9ecSlm66018 	if (ldep->dep->hdr.dstate == VIO_DESC_DONE) {
3073d10e4ef2Snarayan 		mutex_enter(&ldep->lock);
3074d10e4ef2Snarayan 		operation = ldep->dep->payload.operation;
3075*e1ebb9ecSlm66018 		vdc->req_id_proc = ldep->dep->payload.req_id;
3076*e1ebb9ecSlm66018 		vdc->dring_proc_idx = idx;
3077*e1ebb9ecSlm66018 		ASSERT(ldep->dep->hdr.dstate == VIO_DESC_DONE);
3078*e1ebb9ecSlm66018 
3079d10e4ef2Snarayan 		if ((operation == VD_OP_BREAD) || (operation == VD_OP_BWRITE)) {
3080d10e4ef2Snarayan 			bioerror(ldep->buf, ldep->dep->payload.status);
3081d10e4ef2Snarayan 			biodone(ldep->buf);
3082d10e4ef2Snarayan 
3083d10e4ef2Snarayan 			DTRACE_IO2(vdone, buf_t *, ldep->buf, vdc_t *, vdc);
3084d10e4ef2Snarayan 
3085d10e4ef2Snarayan 			/* Clear the DRing entry */
3086d10e4ef2Snarayan 			status = vdc_depopulate_descriptor(vdc, idx);
3087d10e4ef2Snarayan 		}
3088d10e4ef2Snarayan 		cv_signal(&ldep->cv);
3089d10e4ef2Snarayan 		mutex_exit(&ldep->lock);
30900a55fbb7Slm66018 	}
30910a55fbb7Slm66018 
3092*e1ebb9ecSlm66018 	/* probe gives the count of how many entries were processed */
3093*e1ebb9ecSlm66018 	DTRACE_IO2(processed, int, count, vdc_t *, vdc);
30940a55fbb7Slm66018 
30950a55fbb7Slm66018 	return (status);
30960a55fbb7Slm66018 }
30970a55fbb7Slm66018 
30980a55fbb7Slm66018 /*
30990a55fbb7Slm66018  * Function:
31000a55fbb7Slm66018  *	vdc_process_err_msg()
31010a55fbb7Slm66018  *
31020a55fbb7Slm66018  * NOTE: No error messages are used as part of the vDisk protocol
31030a55fbb7Slm66018  */
31040a55fbb7Slm66018 static int
31050a55fbb7Slm66018 vdc_process_err_msg(vdc_t *vdc, vio_msg_t msg)
31060a55fbb7Slm66018 {
31070a55fbb7Slm66018 	_NOTE(ARGUNUSED(vdc))
31080a55fbb7Slm66018 	_NOTE(ARGUNUSED(msg))
31090a55fbb7Slm66018 
31100a55fbb7Slm66018 	ASSERT(msg.tag.vio_msgtype == VIO_TYPE_ERR);
31110a55fbb7Slm66018 	cmn_err(CE_NOTE, "[%d] Got an ERR msg", vdc->instance);
31120a55fbb7Slm66018 
31130a55fbb7Slm66018 	return (ENOTSUP);
31140a55fbb7Slm66018 }
31150a55fbb7Slm66018 
31160a55fbb7Slm66018 /*
31170a55fbb7Slm66018  * Function:
31180a55fbb7Slm66018  *	vdc_handle_ver_msg()
31190a55fbb7Slm66018  *
31200a55fbb7Slm66018  * Description:
31210a55fbb7Slm66018  *
31220a55fbb7Slm66018  * Arguments:
31230a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
31240a55fbb7Slm66018  *	ver_msg	- LDC message sent by vDisk server
31250a55fbb7Slm66018  *
31260a55fbb7Slm66018  * Return Code:
31270a55fbb7Slm66018  *	0	- Success
31280a55fbb7Slm66018  */
31290a55fbb7Slm66018 static int
31300a55fbb7Slm66018 vdc_handle_ver_msg(vdc_t *vdc, vio_ver_msg_t *ver_msg)
31310a55fbb7Slm66018 {
31320a55fbb7Slm66018 	int status = 0;
31330a55fbb7Slm66018 
31340a55fbb7Slm66018 	ASSERT(vdc != NULL);
31350a55fbb7Slm66018 	ASSERT(mutex_owned(&vdc->lock));
31360a55fbb7Slm66018 
31370a55fbb7Slm66018 	if (ver_msg->tag.vio_subtype_env != VIO_VER_INFO) {
31380a55fbb7Slm66018 		return (EPROTO);
31390a55fbb7Slm66018 	}
31400a55fbb7Slm66018 
31410a55fbb7Slm66018 	if (ver_msg->dev_class != VDEV_DISK_SERVER) {
31420a55fbb7Slm66018 		return (EINVAL);
31430a55fbb7Slm66018 	}
31440a55fbb7Slm66018 
31450a55fbb7Slm66018 	switch (ver_msg->tag.vio_subtype) {
31460a55fbb7Slm66018 	case VIO_SUBTYPE_ACK:
31470a55fbb7Slm66018 		/*
31480a55fbb7Slm66018 		 * We check to see if the version returned is indeed supported
31490a55fbb7Slm66018 		 * (The server may have also adjusted the minor number downwards
31500a55fbb7Slm66018 		 * and if so 'ver_msg' will contain the actual version agreed)
31510a55fbb7Slm66018 		 */
31520a55fbb7Slm66018 		if (vdc_is_supported_version(ver_msg)) {
31530a55fbb7Slm66018 			vdc->ver.major = ver_msg->ver_major;
31540a55fbb7Slm66018 			vdc->ver.minor = ver_msg->ver_minor;
31550a55fbb7Slm66018 			ASSERT(vdc->ver.major > 0);
31560a55fbb7Slm66018 
31570a55fbb7Slm66018 			vdc->state = VD_STATE_VER;
31580a55fbb7Slm66018 			status = vdc_init_attr_negotiation(vdc);
31590a55fbb7Slm66018 		} else {
31600a55fbb7Slm66018 			status = EPROTO;
31610a55fbb7Slm66018 		}
31620a55fbb7Slm66018 		break;
31630a55fbb7Slm66018 
31640a55fbb7Slm66018 	case VIO_SUBTYPE_NACK:
31650a55fbb7Slm66018 		/*
31660a55fbb7Slm66018 		 * call vdc_is_supported_version() which will return the next
31670a55fbb7Slm66018 		 * supported version (if any) in 'ver_msg'
31680a55fbb7Slm66018 		 */
31690a55fbb7Slm66018 		(void) vdc_is_supported_version(ver_msg);
31700a55fbb7Slm66018 		if (ver_msg->ver_major > 0) {
31710a55fbb7Slm66018 			size_t len = sizeof (*ver_msg);
31720a55fbb7Slm66018 
31730a55fbb7Slm66018 			ASSERT(vdc->ver.major > 0);
31740a55fbb7Slm66018 
31750a55fbb7Slm66018 			/* reset the necessary fields and resend */
31760a55fbb7Slm66018 			ver_msg->tag.vio_subtype = VIO_SUBTYPE_INFO;
31770a55fbb7Slm66018 			ver_msg->dev_class = VDEV_DISK;
31780a55fbb7Slm66018 
31790a55fbb7Slm66018 			status = vdc_send(vdc, (caddr_t)ver_msg, &len);
3180*e1ebb9ecSlm66018 			DMSG(0, "[%d] Resend VER info (LDC status = %d)\n",
31810a55fbb7Slm66018 					vdc->instance, status);
31820a55fbb7Slm66018 			if (len != sizeof (*ver_msg))
31830a55fbb7Slm66018 				status = EBADMSG;
31840a55fbb7Slm66018 		} else {
31850a55fbb7Slm66018 			cmn_err(CE_NOTE, "[%d] No common version with "
31860a55fbb7Slm66018 					"vDisk server", vdc->instance);
31870a55fbb7Slm66018 			status = ENOTSUP;
31880a55fbb7Slm66018 		}
31890a55fbb7Slm66018 
31900a55fbb7Slm66018 		break;
31911ae08745Sheppo 	case VIO_SUBTYPE_INFO:
31921ae08745Sheppo 		/*
31931ae08745Sheppo 		 * Handle the case where vds starts handshake
31941ae08745Sheppo 		 * (for now only vdc is the instigatior)
31951ae08745Sheppo 		 */
31961ae08745Sheppo 		status = ENOTSUP;
31971ae08745Sheppo 		break;
31981ae08745Sheppo 
31991ae08745Sheppo 	default:
32000a55fbb7Slm66018 		status = EINVAL;
32011ae08745Sheppo 		break;
32021ae08745Sheppo 	}
32031ae08745Sheppo 
32040a55fbb7Slm66018 	return (status);
32050a55fbb7Slm66018 }
32060a55fbb7Slm66018 
32070a55fbb7Slm66018 /*
32080a55fbb7Slm66018  * Function:
32090a55fbb7Slm66018  *	vdc_handle_attr_msg()
32100a55fbb7Slm66018  *
32110a55fbb7Slm66018  * Description:
32120a55fbb7Slm66018  *
32130a55fbb7Slm66018  * Arguments:
32140a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
32150a55fbb7Slm66018  *	attr_msg	- LDC message sent by vDisk server
32160a55fbb7Slm66018  *
32170a55fbb7Slm66018  * Return Code:
32180a55fbb7Slm66018  *	0	- Success
32190a55fbb7Slm66018  */
32200a55fbb7Slm66018 static int
32210a55fbb7Slm66018 vdc_handle_attr_msg(vdc_t *vdc, vd_attr_msg_t *attr_msg)
32220a55fbb7Slm66018 {
32230a55fbb7Slm66018 	int status = 0;
32240a55fbb7Slm66018 
32250a55fbb7Slm66018 	ASSERT(vdc != NULL);
32260a55fbb7Slm66018 	ASSERT(mutex_owned(&vdc->lock));
32270a55fbb7Slm66018 
32280a55fbb7Slm66018 	if (attr_msg->tag.vio_subtype_env != VIO_ATTR_INFO) {
32290a55fbb7Slm66018 		return (EPROTO);
32300a55fbb7Slm66018 	}
32310a55fbb7Slm66018 
32320a55fbb7Slm66018 	switch (attr_msg->tag.vio_subtype) {
32331ae08745Sheppo 	case VIO_SUBTYPE_ACK:
32341ae08745Sheppo 		/*
32351ae08745Sheppo 		 * We now verify the attributes sent by vds.
32361ae08745Sheppo 		 */
32371ae08745Sheppo 		vdc->vdisk_size = attr_msg->vdisk_size;
32381ae08745Sheppo 		vdc->vdisk_type = attr_msg->vdisk_type;
32391ae08745Sheppo 
3240*e1ebb9ecSlm66018 		DMSG(0, "[%d] max_xfer_sz: sent %lx acked %lx\n",
3241*e1ebb9ecSlm66018 			vdc->instance, vdc->max_xfer_sz, attr_msg->max_xfer_sz);
3242*e1ebb9ecSlm66018 		DMSG(0, "[%d] vdisk_block_size: sent %lx acked %x\n",
3243*e1ebb9ecSlm66018 			vdc->instance, vdc->block_size,
3244*e1ebb9ecSlm66018 			attr_msg->vdisk_block_size);
3245*e1ebb9ecSlm66018 
32461ae08745Sheppo 		/*
3247*e1ebb9ecSlm66018 		 * We don't know at compile time what the vDisk server will
3248*e1ebb9ecSlm66018 		 * think are good values but we apply an large (arbitrary)
3249*e1ebb9ecSlm66018 		 * upper bound to prevent memory exhaustion in vdc if it was
3250*e1ebb9ecSlm66018 		 * allocating a DRing based of huge values sent by the server.
3251*e1ebb9ecSlm66018 		 * We probably will never exceed this except if the message
3252*e1ebb9ecSlm66018 		 * was garbage.
32531ae08745Sheppo 		 */
3254*e1ebb9ecSlm66018 		if ((attr_msg->max_xfer_sz * attr_msg->vdisk_block_size) <=
3255*e1ebb9ecSlm66018 				(PAGESIZE * DEV_BSIZE)) {
3256*e1ebb9ecSlm66018 			vdc->max_xfer_sz = attr_msg->max_xfer_sz;
3257*e1ebb9ecSlm66018 			vdc->block_size = attr_msg->vdisk_block_size;
3258*e1ebb9ecSlm66018 		} else {
3259*e1ebb9ecSlm66018 			cmn_err(CE_NOTE, "[%d] vds block transfer size too big;"
3260*e1ebb9ecSlm66018 				" using max supported by vdc", vdc->instance);
32611ae08745Sheppo 		}
32621ae08745Sheppo 
32631ae08745Sheppo 		if ((attr_msg->xfer_mode != VIO_DRING_MODE) ||
32641ae08745Sheppo 		    (attr_msg->vdisk_size > INT64_MAX) ||
32651ae08745Sheppo 		    (attr_msg->vdisk_type > VD_DISK_TYPE_DISK)) {
3266*e1ebb9ecSlm66018 			cmn_err(CE_NOTE, "[%d] Invalid attributes from vds",
3267*e1ebb9ecSlm66018 					vdc->instance);
32681ae08745Sheppo 			status = EINVAL;
32691ae08745Sheppo 			break;
32701ae08745Sheppo 		}
32711ae08745Sheppo 
32721ae08745Sheppo 		vdc->state = VD_STATE_ATTR;
32731ae08745Sheppo 		status = vdc_init_dring_negotiate(vdc);
32741ae08745Sheppo 		break;
32751ae08745Sheppo 
32761ae08745Sheppo 	case VIO_SUBTYPE_NACK:
32771ae08745Sheppo 		/*
32781ae08745Sheppo 		 * vds could not handle the attributes we sent so we
32791ae08745Sheppo 		 * stop negotiating.
32801ae08745Sheppo 		 */
32811ae08745Sheppo 		status = EPROTO;
32821ae08745Sheppo 		break;
32831ae08745Sheppo 
32841ae08745Sheppo 	case VIO_SUBTYPE_INFO:
32851ae08745Sheppo 		/*
32861ae08745Sheppo 		 * Handle the case where vds starts the handshake
32871ae08745Sheppo 		 * (for now; vdc is the only supported instigatior)
32881ae08745Sheppo 		 */
32891ae08745Sheppo 		status = ENOTSUP;
32901ae08745Sheppo 		break;
32911ae08745Sheppo 
32921ae08745Sheppo 	default:
32931ae08745Sheppo 		status = ENOTSUP;
32941ae08745Sheppo 		break;
32951ae08745Sheppo 	}
32961ae08745Sheppo 
32970a55fbb7Slm66018 	return (status);
32981ae08745Sheppo }
32991ae08745Sheppo 
33000a55fbb7Slm66018 /*
33010a55fbb7Slm66018  * Function:
33020a55fbb7Slm66018  *	vdc_handle_dring_reg_msg()
33030a55fbb7Slm66018  *
33040a55fbb7Slm66018  * Description:
33050a55fbb7Slm66018  *
33060a55fbb7Slm66018  * Arguments:
33070a55fbb7Slm66018  *	vdc		- soft state pointer for this instance of the driver.
33080a55fbb7Slm66018  *	dring_msg	- LDC message sent by vDisk server
33090a55fbb7Slm66018  *
33100a55fbb7Slm66018  * Return Code:
33110a55fbb7Slm66018  *	0	- Success
33120a55fbb7Slm66018  */
33130a55fbb7Slm66018 static int
33140a55fbb7Slm66018 vdc_handle_dring_reg_msg(vdc_t *vdc, vio_dring_reg_msg_t *dring_msg)
33150a55fbb7Slm66018 {
33160a55fbb7Slm66018 	int		status = 0;
33170a55fbb7Slm66018 	vio_rdx_msg_t	msg = {0};
33180a55fbb7Slm66018 	size_t		msglen = sizeof (msg);
33191ae08745Sheppo 
33200a55fbb7Slm66018 	ASSERT(vdc != NULL);
33210a55fbb7Slm66018 	ASSERT(mutex_owned(&vdc->lock));
33220a55fbb7Slm66018 
33230a55fbb7Slm66018 	if (dring_msg->tag.vio_subtype_env != VIO_DRING_REG) {
33240a55fbb7Slm66018 		return (EPROTO);
33250a55fbb7Slm66018 	}
33260a55fbb7Slm66018 
33270a55fbb7Slm66018 	switch (dring_msg->tag.vio_subtype) {
33280a55fbb7Slm66018 	case VIO_SUBTYPE_ACK:
33291ae08745Sheppo 		/* save the received dring_ident */
33301ae08745Sheppo 		vdc->dring_ident = dring_msg->dring_ident;
3331*e1ebb9ecSlm66018 		DMSG(0, "[%d] Received dring ident=0x%lx\n",
3332*e1ebb9ecSlm66018 			vdc->instance, vdc->dring_ident);
33331ae08745Sheppo 
33341ae08745Sheppo 		/*
33351ae08745Sheppo 		 * Send an RDX message to vds to indicate we are ready
33361ae08745Sheppo 		 * to send data
33371ae08745Sheppo 		 */
33381ae08745Sheppo 		msg.tag.vio_msgtype = VIO_TYPE_CTRL;
33391ae08745Sheppo 		msg.tag.vio_subtype = VIO_SUBTYPE_INFO;
33401ae08745Sheppo 		msg.tag.vio_subtype_env = VIO_RDX;
33411ae08745Sheppo 		msg.tag.vio_sid = vdc->session_id;
33420a55fbb7Slm66018 		status = vdc_send(vdc, (caddr_t)&msg, &msglen);
33431ae08745Sheppo 		if (status != 0) {
33441ae08745Sheppo 			cmn_err(CE_NOTE, "[%d] Failed to send RDX"
33451ae08745Sheppo 				" message (%d)", vdc->instance, status);
33461ae08745Sheppo 			break;
33471ae08745Sheppo 		}
33481ae08745Sheppo 
33491ae08745Sheppo 		vdc->state = VD_STATE_RDX;
33501ae08745Sheppo 		break;
33511ae08745Sheppo 
33521ae08745Sheppo 	case VIO_SUBTYPE_NACK:
33531ae08745Sheppo 		/*
33541ae08745Sheppo 		 * vds could not handle the DRing info we sent so we
33551ae08745Sheppo 		 * stop negotiating.
33561ae08745Sheppo 		 */
33571ae08745Sheppo 		cmn_err(CE_CONT, "server could not register DRing\n");
3358*e1ebb9ecSlm66018 		vdc_reset_connection(vdc, B_TRUE);
33591ae08745Sheppo 		vdc_destroy_descriptor_ring(vdc);
33601ae08745Sheppo 		status = EPROTO;
33611ae08745Sheppo 		break;
33621ae08745Sheppo 
33631ae08745Sheppo 	case VIO_SUBTYPE_INFO:
33641ae08745Sheppo 		/*
33651ae08745Sheppo 		 * Handle the case where vds starts handshake
33661ae08745Sheppo 		 * (for now only vdc is the instigatior)
33671ae08745Sheppo 		 */
33681ae08745Sheppo 		status = ENOTSUP;
33691ae08745Sheppo 		break;
33701ae08745Sheppo 	default:
33711ae08745Sheppo 		status = ENOTSUP;
33721ae08745Sheppo 	}
33731ae08745Sheppo 
33741ae08745Sheppo 	return (status);
33751ae08745Sheppo }
33761ae08745Sheppo 
33771ae08745Sheppo /*
33781ae08745Sheppo  * Function:
33791ae08745Sheppo  *	vdc_verify_seq_num()
33801ae08745Sheppo  *
33811ae08745Sheppo  * Description:
3382*e1ebb9ecSlm66018  *	This functions verifies that the sequence number sent back by the vDisk
3383*e1ebb9ecSlm66018  *	server with the latest message is what is expected (i.e. it is greater
3384*e1ebb9ecSlm66018  *	than the last seq num sent by the vDisk server and less than or equal
3385*e1ebb9ecSlm66018  *	to the last seq num generated by vdc).
3386*e1ebb9ecSlm66018  *
3387*e1ebb9ecSlm66018  *	It then checks the request ID to see if any requests need processing
3388*e1ebb9ecSlm66018  *	in the DRing.
33891ae08745Sheppo  *
33901ae08745Sheppo  * Arguments:
33911ae08745Sheppo  *	vdc		- soft state pointer for this instance of the driver.
33921ae08745Sheppo  *	dring_msg	- pointer to the LDC message sent by vds
33931ae08745Sheppo  *
33941ae08745Sheppo  * Return Code:
3395*e1ebb9ecSlm66018  *	VDC_SEQ_NUM_TODO	- Message needs to be processed
3396*e1ebb9ecSlm66018  *	VDC_SEQ_NUM_SKIP	- Message has already been processed
3397*e1ebb9ecSlm66018  *	VDC_SEQ_NUM_INVALID	- The seq numbers are so out of sync,
3398*e1ebb9ecSlm66018  *				  vdc cannot deal with them
33991ae08745Sheppo  */
3400*e1ebb9ecSlm66018 static int
3401*e1ebb9ecSlm66018 vdc_verify_seq_num(vdc_t *vdc, vio_dring_msg_t *dring_msg)
34021ae08745Sheppo {
34031ae08745Sheppo 	ASSERT(vdc != NULL);
34041ae08745Sheppo 	ASSERT(dring_msg != NULL);
3405d10e4ef2Snarayan 	ASSERT(mutex_owned(&vdc->lock));
34061ae08745Sheppo 
34071ae08745Sheppo 	/*
34081ae08745Sheppo 	 * Check to see if the messages were responded to in the correct
3409*e1ebb9ecSlm66018 	 * order by vds.
34101ae08745Sheppo 	 */
3411*e1ebb9ecSlm66018 	if ((dring_msg->seq_num <= vdc->seq_num_reply) ||
3412*e1ebb9ecSlm66018 	    (dring_msg->seq_num > vdc->seq_num)) {
3413*e1ebb9ecSlm66018 		cmn_err(CE_CONT, "?[%d] Bogus sequence_number %lu: "
3414*e1ebb9ecSlm66018 			"%lu > expected <= %lu (last proc req %lu sent %lu)\n",
3415*e1ebb9ecSlm66018 				vdc->instance, dring_msg->seq_num,
3416*e1ebb9ecSlm66018 				vdc->seq_num_reply, vdc->seq_num,
3417*e1ebb9ecSlm66018 				vdc->req_id_proc, vdc->req_id);
3418*e1ebb9ecSlm66018 		return (VDC_SEQ_NUM_INVALID);
34191ae08745Sheppo 	}
3420*e1ebb9ecSlm66018 	vdc->seq_num_reply = dring_msg->seq_num;
34211ae08745Sheppo 
3422*e1ebb9ecSlm66018 	if (vdc->req_id_proc < vdc->req_id)
3423*e1ebb9ecSlm66018 		return (VDC_SEQ_NUM_TODO);
3424*e1ebb9ecSlm66018 	else
3425*e1ebb9ecSlm66018 		return (VDC_SEQ_NUM_SKIP);
34261ae08745Sheppo }
34271ae08745Sheppo 
34280a55fbb7Slm66018 
34290a55fbb7Slm66018 /*
34300a55fbb7Slm66018  * Function:
34310a55fbb7Slm66018  *	vdc_is_supported_version()
34320a55fbb7Slm66018  *
34330a55fbb7Slm66018  * Description:
34340a55fbb7Slm66018  *	This routine checks if the major/minor version numbers specified in
34350a55fbb7Slm66018  *	'ver_msg' are supported. If not it finds the next version that is
34360a55fbb7Slm66018  *	in the supported version list 'vdc_version[]' and sets the fields in
34370a55fbb7Slm66018  *	'ver_msg' to those values
34380a55fbb7Slm66018  *
34390a55fbb7Slm66018  * Arguments:
34400a55fbb7Slm66018  *	ver_msg	- LDC message sent by vDisk server
34410a55fbb7Slm66018  *
34420a55fbb7Slm66018  * Return Code:
34430a55fbb7Slm66018  *	B_TRUE	- Success
34440a55fbb7Slm66018  *	B_FALSE	- Version not supported
34450a55fbb7Slm66018  */
34460a55fbb7Slm66018 static boolean_t
34470a55fbb7Slm66018 vdc_is_supported_version(vio_ver_msg_t *ver_msg)
34480a55fbb7Slm66018 {
34490a55fbb7Slm66018 	int vdc_num_versions = sizeof (vdc_version) / sizeof (vdc_version[0]);
34500a55fbb7Slm66018 
34510a55fbb7Slm66018 	for (int i = 0; i < vdc_num_versions; i++) {
34520a55fbb7Slm66018 		ASSERT(vdc_version[i].major > 0);
34530a55fbb7Slm66018 		ASSERT((i == 0) ||
34540a55fbb7Slm66018 		    (vdc_version[i].major < vdc_version[i-1].major));
34550a55fbb7Slm66018 
34560a55fbb7Slm66018 		/*
34570a55fbb7Slm66018 		 * If the major versions match, adjust the minor version, if
34580a55fbb7Slm66018 		 * necessary, down to the highest value supported by this
34590a55fbb7Slm66018 		 * client. The server should support all minor versions lower
34600a55fbb7Slm66018 		 * than the value it sent
34610a55fbb7Slm66018 		 */
34620a55fbb7Slm66018 		if (ver_msg->ver_major == vdc_version[i].major) {
34630a55fbb7Slm66018 			if (ver_msg->ver_minor > vdc_version[i].minor) {
3464*e1ebb9ecSlm66018 				DMSG(0, "Adjusting minor version from %u to %u",
34650a55fbb7Slm66018 				    ver_msg->ver_minor, vdc_version[i].minor);
34660a55fbb7Slm66018 				ver_msg->ver_minor = vdc_version[i].minor;
34670a55fbb7Slm66018 			}
34680a55fbb7Slm66018 			return (B_TRUE);
34690a55fbb7Slm66018 		}
34700a55fbb7Slm66018 
34710a55fbb7Slm66018 		/*
34720a55fbb7Slm66018 		 * If the message contains a higher major version number, set
34730a55fbb7Slm66018 		 * the message's major/minor versions to the current values
34740a55fbb7Slm66018 		 * and return false, so this message will get resent with
34750a55fbb7Slm66018 		 * these values, and the server will potentially try again
34760a55fbb7Slm66018 		 * with the same or a lower version
34770a55fbb7Slm66018 		 */
34780a55fbb7Slm66018 		if (ver_msg->ver_major > vdc_version[i].major) {
34790a55fbb7Slm66018 			ver_msg->ver_major = vdc_version[i].major;
34800a55fbb7Slm66018 			ver_msg->ver_minor = vdc_version[i].minor;
3481*e1ebb9ecSlm66018 			DMSG(0, "Suggesting major/minor (0x%x/0x%x)\n",
34820a55fbb7Slm66018 				ver_msg->ver_major, ver_msg->ver_minor);
34830a55fbb7Slm66018 
34840a55fbb7Slm66018 			return (B_FALSE);
34850a55fbb7Slm66018 		}
34860a55fbb7Slm66018 
34870a55fbb7Slm66018 		/*
34880a55fbb7Slm66018 		 * Otherwise, the message's major version is less than the
34890a55fbb7Slm66018 		 * current major version, so continue the loop to the next
34900a55fbb7Slm66018 		 * (lower) supported version
34910a55fbb7Slm66018 		 */
34920a55fbb7Slm66018 	}
34930a55fbb7Slm66018 
34940a55fbb7Slm66018 	/*
34950a55fbb7Slm66018 	 * No common version was found; "ground" the version pair in the
34960a55fbb7Slm66018 	 * message to terminate negotiation
34970a55fbb7Slm66018 	 */
34980a55fbb7Slm66018 	ver_msg->ver_major = 0;
34990a55fbb7Slm66018 	ver_msg->ver_minor = 0;
35000a55fbb7Slm66018 
35010a55fbb7Slm66018 	return (B_FALSE);
35020a55fbb7Slm66018 }
35031ae08745Sheppo /* -------------------------------------------------------------------------- */
35041ae08745Sheppo 
35051ae08745Sheppo /*
35061ae08745Sheppo  * DKIO(7) support
35071ae08745Sheppo  */
35081ae08745Sheppo 
35091ae08745Sheppo typedef struct vdc_dk_arg {
35101ae08745Sheppo 	struct dk_callback	dkc;
35111ae08745Sheppo 	int			mode;
35121ae08745Sheppo 	dev_t			dev;
35131ae08745Sheppo 	vdc_t			*vdc;
35141ae08745Sheppo } vdc_dk_arg_t;
35151ae08745Sheppo 
35161ae08745Sheppo /*
35171ae08745Sheppo  * Function:
35181ae08745Sheppo  * 	vdc_dkio_flush_cb()
35191ae08745Sheppo  *
35201ae08745Sheppo  * Description:
35211ae08745Sheppo  *	This routine is a callback for DKIOCFLUSHWRITECACHE which can be called
35221ae08745Sheppo  *	by kernel code.
35231ae08745Sheppo  *
35241ae08745Sheppo  * Arguments:
35251ae08745Sheppo  *	arg	- a pointer to a vdc_dk_arg_t structure.
35261ae08745Sheppo  */
35271ae08745Sheppo void
35281ae08745Sheppo vdc_dkio_flush_cb(void *arg)
35291ae08745Sheppo {
35301ae08745Sheppo 	struct vdc_dk_arg	*dk_arg = (struct vdc_dk_arg *)arg;
35311ae08745Sheppo 	struct dk_callback	*dkc = NULL;
35321ae08745Sheppo 	vdc_t			*vdc = NULL;
35331ae08745Sheppo 	int			rv;
35341ae08745Sheppo 
35351ae08745Sheppo 	if (dk_arg == NULL) {
3536*e1ebb9ecSlm66018 		cmn_err(CE_CONT, "?[Unk] DKIOCFLUSHWRITECACHE arg is NULL\n");
35371ae08745Sheppo 		return;
35381ae08745Sheppo 	}
35391ae08745Sheppo 	dkc = &dk_arg->dkc;
35401ae08745Sheppo 	vdc = dk_arg->vdc;
35411ae08745Sheppo 	ASSERT(vdc != NULL);
35421ae08745Sheppo 
35431ae08745Sheppo 	rv = vdc_populate_descriptor(vdc, NULL, 0, VD_OP_FLUSH,
35441ae08745Sheppo 		dk_arg->mode, SDPART(getminor(dk_arg->dev)));
35451ae08745Sheppo 	if (rv != 0) {
3546*e1ebb9ecSlm66018 		DMSG(0, "[%d] DKIOCFLUSHWRITECACHE failed %d : model %x\n",
3547*e1ebb9ecSlm66018 			vdc->instance, rv,
35481ae08745Sheppo 			ddi_model_convert_from(dk_arg->mode & FMODELS));
35491ae08745Sheppo 	}
35501ae08745Sheppo 
35511ae08745Sheppo 	/*
35521ae08745Sheppo 	 * Trigger the call back to notify the caller the the ioctl call has
35531ae08745Sheppo 	 * been completed.
35541ae08745Sheppo 	 */
35551ae08745Sheppo 	if ((dk_arg->mode & FKIOCTL) &&
35561ae08745Sheppo 	    (dkc != NULL) &&
35571ae08745Sheppo 	    (dkc->dkc_callback != NULL)) {
35581ae08745Sheppo 		ASSERT(dkc->dkc_cookie != NULL);
35598e6a2a04Slm66018 		(*dkc->dkc_callback)(dkc->dkc_cookie, rv);
35601ae08745Sheppo 	}
35611ae08745Sheppo 
35621ae08745Sheppo 	/* Indicate that one less DKIO write flush is outstanding */
35631ae08745Sheppo 	mutex_enter(&vdc->lock);
35641ae08745Sheppo 	vdc->dkio_flush_pending--;
35651ae08745Sheppo 	ASSERT(vdc->dkio_flush_pending >= 0);
35661ae08745Sheppo 	mutex_exit(&vdc->lock);
35678e6a2a04Slm66018 
35688e6a2a04Slm66018 	/* free the mem that was allocated when the callback was dispatched */
35698e6a2a04Slm66018 	kmem_free(arg, sizeof (vdc_dk_arg_t));
35701ae08745Sheppo }
35711ae08745Sheppo 
35721ae08745Sheppo /*
35731ae08745Sheppo  * This structure is used in the DKIO(7I) array below.
35741ae08745Sheppo  */
35751ae08745Sheppo typedef struct vdc_dk_ioctl {
35761ae08745Sheppo 	uint8_t		op;		/* VD_OP_XXX value */
35771ae08745Sheppo 	int		cmd;		/* Solaris ioctl operation number */
35781ae08745Sheppo 	size_t		nbytes;		/* size of structure to be copied */
35790a55fbb7Slm66018 
35800a55fbb7Slm66018 	/* function to convert between vDisk and Solaris structure formats */
3581d10e4ef2Snarayan 	int	(*convert)(vdc_t *vdc, void *vd_buf, void *ioctl_arg,
3582d10e4ef2Snarayan 	    int mode, int dir);
35831ae08745Sheppo } vdc_dk_ioctl_t;
35841ae08745Sheppo 
35851ae08745Sheppo /*
35861ae08745Sheppo  * Subset of DKIO(7I) operations currently supported
35871ae08745Sheppo  */
35881ae08745Sheppo static vdc_dk_ioctl_t	dk_ioctl[] = {
35890a55fbb7Slm66018 	{VD_OP_FLUSH,		DKIOCFLUSHWRITECACHE,	sizeof (int),
35900a55fbb7Slm66018 		vdc_null_copy_func},
35910a55fbb7Slm66018 	{VD_OP_GET_WCE,		DKIOCGETWCE,		sizeof (int),
35920a55fbb7Slm66018 		vdc_null_copy_func},
35930a55fbb7Slm66018 	{VD_OP_SET_WCE,		DKIOCSETWCE,		sizeof (int),
35940a55fbb7Slm66018 		vdc_null_copy_func},
35950a55fbb7Slm66018 	{VD_OP_GET_VTOC,	DKIOCGVTOC,		sizeof (vd_vtoc_t),
35960a55fbb7Slm66018 		vdc_get_vtoc_convert},
35970a55fbb7Slm66018 	{VD_OP_SET_VTOC,	DKIOCSVTOC,		sizeof (vd_vtoc_t),
35980a55fbb7Slm66018 		vdc_set_vtoc_convert},
35990a55fbb7Slm66018 	{VD_OP_GET_DISKGEOM,	DKIOCGGEOM,		sizeof (vd_geom_t),
36000a55fbb7Slm66018 		vdc_get_geom_convert},
36010a55fbb7Slm66018 	{VD_OP_GET_DISKGEOM,	DKIOCG_PHYGEOM,		sizeof (vd_geom_t),
36020a55fbb7Slm66018 		vdc_get_geom_convert},
36030a55fbb7Slm66018 	{VD_OP_GET_DISKGEOM, 	DKIOCG_VIRTGEOM,	sizeof (vd_geom_t),
36040a55fbb7Slm66018 		vdc_get_geom_convert},
36050a55fbb7Slm66018 	{VD_OP_SET_DISKGEOM,	DKIOCSGEOM,		sizeof (vd_geom_t),
36060a55fbb7Slm66018 		vdc_set_geom_convert},
36070a55fbb7Slm66018 
36080a55fbb7Slm66018 	/*
36090a55fbb7Slm66018 	 * These particular ioctls are not sent to the server - vdc fakes up
36100a55fbb7Slm66018 	 * the necessary info.
36110a55fbb7Slm66018 	 */
36120a55fbb7Slm66018 	{0, DKIOCINFO, sizeof (struct dk_cinfo), vdc_null_copy_func},
36130a55fbb7Slm66018 	{0, DKIOCGMEDIAINFO, sizeof (struct dk_minfo), vdc_null_copy_func},
36140a55fbb7Slm66018 	{0, USCSICMD,	sizeof (struct uscsi_cmd), vdc_null_copy_func},
36150a55fbb7Slm66018 	{0, DKIOCREMOVABLE, 0, vdc_null_copy_func},
36160a55fbb7Slm66018 	{0, CDROMREADOFFSET, 0, vdc_null_copy_func}
36171ae08745Sheppo };
36181ae08745Sheppo 
36191ae08745Sheppo /*
36201ae08745Sheppo  * Function:
36211ae08745Sheppo  *	vd_process_ioctl()
36221ae08745Sheppo  *
36231ae08745Sheppo  * Description:
36240a55fbb7Slm66018  *	This routine processes disk specific ioctl calls
36251ae08745Sheppo  *
36261ae08745Sheppo  * Arguments:
36271ae08745Sheppo  *	dev	- the device number
36281ae08745Sheppo  *	cmd	- the operation [dkio(7I)] to be processed
36291ae08745Sheppo  *	arg	- pointer to user provided structure
36301ae08745Sheppo  *		  (contains data to be set or reference parameter for get)
36311ae08745Sheppo  *	mode	- bit flag, indicating open settings, 32/64 bit type, etc
36321ae08745Sheppo  *
36331ae08745Sheppo  * Return Code:
36341ae08745Sheppo  *	0
36351ae08745Sheppo  *	EFAULT
36361ae08745Sheppo  *	ENXIO
36371ae08745Sheppo  *	EIO
36381ae08745Sheppo  *	ENOTSUP
36391ae08745Sheppo  */
36401ae08745Sheppo static int
36411ae08745Sheppo vd_process_ioctl(dev_t dev, int cmd, caddr_t arg, int mode)
36421ae08745Sheppo {
36431ae08745Sheppo 	int		instance = SDUNIT(getminor(dev));
36441ae08745Sheppo 	vdc_t		*vdc = NULL;
36451ae08745Sheppo 	int		rv = -1;
36461ae08745Sheppo 	int		idx = 0;		/* index into dk_ioctl[] */
36471ae08745Sheppo 	size_t		len = 0;		/* #bytes to send to vds */
36481ae08745Sheppo 	size_t		alloc_len = 0;		/* #bytes to allocate mem for */
36491ae08745Sheppo 	caddr_t		mem_p = NULL;
36501ae08745Sheppo 	size_t		nioctls = (sizeof (dk_ioctl)) / (sizeof (dk_ioctl[0]));
3651d10e4ef2Snarayan 	struct vtoc	vtoc_saved;
36521ae08745Sheppo 
3653*e1ebb9ecSlm66018 	DMSG(0, "[%d] Processing ioctl(%x) for dev %lx : model %x\n",
3654*e1ebb9ecSlm66018 		instance, cmd, dev, ddi_model_convert_from(mode & FMODELS));
36551ae08745Sheppo 
36561ae08745Sheppo 	vdc = ddi_get_soft_state(vdc_state, instance);
36571ae08745Sheppo 	if (vdc == NULL) {
36581ae08745Sheppo 		cmn_err(CE_NOTE, "![%d] Could not get soft state structure",
36591ae08745Sheppo 		    instance);
36601ae08745Sheppo 		return (ENXIO);
36611ae08745Sheppo 	}
36621ae08745Sheppo 
36631ae08745Sheppo 	/*
36641ae08745Sheppo 	 * Check to see if we can communicate with the vDisk server
36651ae08745Sheppo 	 */
36660a55fbb7Slm66018 	if (!vdc_is_able_to_tx_data(vdc, O_NONBLOCK)) {
3667*e1ebb9ecSlm66018 		DMSG(0, "[%d] Not ready to transmit data\n", instance);
36681ae08745Sheppo 		return (ENOLINK);
36691ae08745Sheppo 	}
36701ae08745Sheppo 
36711ae08745Sheppo 	/*
36721ae08745Sheppo 	 * Validate the ioctl operation to be performed.
36731ae08745Sheppo 	 *
36741ae08745Sheppo 	 * If we have looped through the array without finding a match then we
36751ae08745Sheppo 	 * don't support this ioctl.
36761ae08745Sheppo 	 */
36771ae08745Sheppo 	for (idx = 0; idx < nioctls; idx++) {
36781ae08745Sheppo 		if (cmd == dk_ioctl[idx].cmd)
36791ae08745Sheppo 			break;
36801ae08745Sheppo 	}
36811ae08745Sheppo 
36821ae08745Sheppo 	if (idx >= nioctls) {
3683*e1ebb9ecSlm66018 		cmn_err(CE_CONT, "?[%d] Unsupported ioctl (0x%x)\n",
3684*e1ebb9ecSlm66018 				vdc->instance, cmd);
36851ae08745Sheppo 		return (ENOTSUP);
36861ae08745Sheppo 	}
36871ae08745Sheppo 
36880a55fbb7Slm66018 	len = dk_ioctl[idx].nbytes;
36891ae08745Sheppo 
36901ae08745Sheppo 	/*
36910a55fbb7Slm66018 	 * Deal with the ioctls which the server does not provide. vdc can
36920a55fbb7Slm66018 	 * fake these up and return immediately
36931ae08745Sheppo 	 */
36941ae08745Sheppo 	switch (cmd) {
36951ae08745Sheppo 	case CDROMREADOFFSET:
36961ae08745Sheppo 	case DKIOCREMOVABLE:
36970a55fbb7Slm66018 	case USCSICMD:
36981ae08745Sheppo 		return (ENOTTY);
36991ae08745Sheppo 
37001ae08745Sheppo 	case DKIOCINFO:
37011ae08745Sheppo 		{
37021ae08745Sheppo 			struct dk_cinfo	cinfo;
37031ae08745Sheppo 			if (vdc->cinfo == NULL)
37041ae08745Sheppo 				return (ENXIO);
37051ae08745Sheppo 
37061ae08745Sheppo 			bcopy(vdc->cinfo, &cinfo, sizeof (struct dk_cinfo));
37071ae08745Sheppo 			cinfo.dki_partition = SDPART(getminor(dev));
37081ae08745Sheppo 
37091ae08745Sheppo 			rv = ddi_copyout(&cinfo, (void *)arg,
37101ae08745Sheppo 					sizeof (struct dk_cinfo), mode);
37111ae08745Sheppo 			if (rv != 0)
37121ae08745Sheppo 				return (EFAULT);
37131ae08745Sheppo 
37141ae08745Sheppo 			return (0);
37151ae08745Sheppo 		}
37161ae08745Sheppo 
37171ae08745Sheppo 	case DKIOCGMEDIAINFO:
37188e6a2a04Slm66018 		{
37191ae08745Sheppo 			if (vdc->minfo == NULL)
37201ae08745Sheppo 				return (ENXIO);
37211ae08745Sheppo 
37221ae08745Sheppo 			rv = ddi_copyout(vdc->minfo, (void *)arg,
37231ae08745Sheppo 					sizeof (struct dk_minfo), mode);
37241ae08745Sheppo 			if (rv != 0)
37251ae08745Sheppo 				return (EFAULT);
37261ae08745Sheppo 
37271ae08745Sheppo 			return (0);
37281ae08745Sheppo 		}
37291ae08745Sheppo 
37308e6a2a04Slm66018 	case DKIOCFLUSHWRITECACHE:
37318e6a2a04Slm66018 		{
37328e6a2a04Slm66018 			struct dk_callback *dkc = (struct dk_callback *)arg;
37338e6a2a04Slm66018 			vdc_dk_arg_t	*dkarg = NULL;
37348e6a2a04Slm66018 
3735*e1ebb9ecSlm66018 			DMSG(1, "[%d] Flush W$: mode %x\n", instance, mode);
37368e6a2a04Slm66018 
37378e6a2a04Slm66018 			/*
37388e6a2a04Slm66018 			 * If the backing device is not a 'real' disk then the
37398e6a2a04Slm66018 			 * W$ operation request to the vDisk server will fail
37408e6a2a04Slm66018 			 * so we might as well save the cycles and return now.
37418e6a2a04Slm66018 			 */
37428e6a2a04Slm66018 			if (vdc->vdisk_type != VD_DISK_TYPE_DISK)
37438e6a2a04Slm66018 				return (ENOTTY);
37448e6a2a04Slm66018 
37458e6a2a04Slm66018 			/*
37468e6a2a04Slm66018 			 * If arg is NULL, then there is no callback function
37478e6a2a04Slm66018 			 * registered and the call operates synchronously; we
37488e6a2a04Slm66018 			 * break and continue with the rest of the function and
37498e6a2a04Slm66018 			 * wait for vds to return (i.e. after the request to
37508e6a2a04Slm66018 			 * vds returns successfully, all writes completed prior
37518e6a2a04Slm66018 			 * to the ioctl will have been flushed from the disk
37528e6a2a04Slm66018 			 * write cache to persistent media.
37538e6a2a04Slm66018 			 *
37548e6a2a04Slm66018 			 * If a callback function is registered, we dispatch
37558e6a2a04Slm66018 			 * the request on a task queue and return immediately.
37568e6a2a04Slm66018 			 * The callback will deal with informing the calling
37578e6a2a04Slm66018 			 * thread that the flush request is completed.
37588e6a2a04Slm66018 			 */
37598e6a2a04Slm66018 			if (dkc == NULL)
37608e6a2a04Slm66018 				break;
37618e6a2a04Slm66018 
37628e6a2a04Slm66018 			dkarg = kmem_zalloc(sizeof (vdc_dk_arg_t), KM_SLEEP);
37638e6a2a04Slm66018 
37648e6a2a04Slm66018 			dkarg->mode = mode;
37658e6a2a04Slm66018 			dkarg->dev = dev;
37668e6a2a04Slm66018 			bcopy(dkc, &dkarg->dkc, sizeof (*dkc));
37678e6a2a04Slm66018 
37688e6a2a04Slm66018 			mutex_enter(&vdc->lock);
37698e6a2a04Slm66018 			vdc->dkio_flush_pending++;
37708e6a2a04Slm66018 			dkarg->vdc = vdc;
37718e6a2a04Slm66018 			mutex_exit(&vdc->lock);
37728e6a2a04Slm66018 
37738e6a2a04Slm66018 			/* put the request on a task queue */
37748e6a2a04Slm66018 			rv = taskq_dispatch(system_taskq, vdc_dkio_flush_cb,
37758e6a2a04Slm66018 				(void *)dkarg, DDI_SLEEP);
37768e6a2a04Slm66018 
37778e6a2a04Slm66018 			return (rv == NULL ? ENOMEM : 0);
37788e6a2a04Slm66018 		}
37798e6a2a04Slm66018 	}
37808e6a2a04Slm66018 
37811ae08745Sheppo 	/* catch programming error in vdc - should be a VD_OP_XXX ioctl */
37820a55fbb7Slm66018 	ASSERT(dk_ioctl[idx].op != 0);
37831ae08745Sheppo 
37841ae08745Sheppo 	/* LDC requires that the memory being mapped is 8-byte aligned */
37851ae08745Sheppo 	alloc_len = P2ROUNDUP(len, sizeof (uint64_t));
3786*e1ebb9ecSlm66018 	DMSG(1, "[%d] struct size %ld alloc %ld\n", instance, len, alloc_len);
37871ae08745Sheppo 
37880a55fbb7Slm66018 	ASSERT(alloc_len != 0);	/* sanity check */
37891ae08745Sheppo 	mem_p = kmem_zalloc(alloc_len, KM_SLEEP);
37901ae08745Sheppo 
3791d10e4ef2Snarayan 	if (cmd == DKIOCSVTOC) {
3792d10e4ef2Snarayan 		/*
3793d10e4ef2Snarayan 		 * Save a copy of the current VTOC so that we can roll back
3794d10e4ef2Snarayan 		 * if the setting of the new VTOC fails.
3795d10e4ef2Snarayan 		 */
3796d10e4ef2Snarayan 		bcopy(vdc->vtoc, &vtoc_saved, sizeof (struct vtoc));
3797d10e4ef2Snarayan 	}
3798d10e4ef2Snarayan 
37990a55fbb7Slm66018 	/*
38000a55fbb7Slm66018 	 * Call the conversion function for this ioctl whhich if necessary
38010a55fbb7Slm66018 	 * converts from the Solaris format to the format ARC'ed
38020a55fbb7Slm66018 	 * as part of the vDisk protocol (FWARC 2006/195)
38030a55fbb7Slm66018 	 */
38040a55fbb7Slm66018 	ASSERT(dk_ioctl[idx].convert != NULL);
3805d10e4ef2Snarayan 	rv = (dk_ioctl[idx].convert)(vdc, arg, mem_p, mode, VD_COPYIN);
38061ae08745Sheppo 	if (rv != 0) {
3807*e1ebb9ecSlm66018 		DMSG(0, "[%d] convert func returned %d for ioctl 0x%x\n",
3808*e1ebb9ecSlm66018 				instance, rv, cmd);
38091ae08745Sheppo 		if (mem_p != NULL)
38101ae08745Sheppo 			kmem_free(mem_p, alloc_len);
38110a55fbb7Slm66018 		return (rv);
38121ae08745Sheppo 	}
38131ae08745Sheppo 
38141ae08745Sheppo 	/*
38151ae08745Sheppo 	 * send request to vds to service the ioctl.
38161ae08745Sheppo 	 */
38170a55fbb7Slm66018 	rv = vdc_populate_descriptor(vdc, mem_p, alloc_len, dk_ioctl[idx].op,
38180a55fbb7Slm66018 			mode, SDPART((getminor(dev))));
38191ae08745Sheppo 	if (rv != 0) {
38201ae08745Sheppo 		/*
38211ae08745Sheppo 		 * This is not necessarily an error. The ioctl could
38221ae08745Sheppo 		 * be returning a value such as ENOTTY to indicate
38231ae08745Sheppo 		 * that the ioctl is not applicable.
38241ae08745Sheppo 		 */
3825*e1ebb9ecSlm66018 		DMSG(0, "[%d] vds returned %d for ioctl 0x%x\n",
3826*e1ebb9ecSlm66018 			instance, rv, cmd);
38271ae08745Sheppo 		if (mem_p != NULL)
38281ae08745Sheppo 			kmem_free(mem_p, alloc_len);
3829d10e4ef2Snarayan 
3830d10e4ef2Snarayan 		if (cmd == DKIOCSVTOC) {
3831d10e4ef2Snarayan 			/* update of the VTOC has failed, roll back */
3832d10e4ef2Snarayan 			bcopy(&vtoc_saved, vdc->vtoc, sizeof (struct vtoc));
3833d10e4ef2Snarayan 		}
3834d10e4ef2Snarayan 
38351ae08745Sheppo 		return (rv);
38361ae08745Sheppo 	}
38371ae08745Sheppo 
38381ae08745Sheppo 	if (cmd == DKIOCSVTOC) {
3839d10e4ef2Snarayan 		/*
3840d10e4ef2Snarayan 		 * The VTOC has been changed, try and update the device
3841d10e4ef2Snarayan 		 * node properties. Failing to set the properties should
3842d10e4ef2Snarayan 		 * not cause an error to be return the caller though.
3843d10e4ef2Snarayan 		 */
38441ae08745Sheppo 		if (vdc_create_device_nodes_props(vdc)) {
38451ae08745Sheppo 			cmn_err(CE_NOTE, "![%d] Failed to update device nodes"
3846d10e4ef2Snarayan 			    " properties", vdc->instance);
38471ae08745Sheppo 		}
38481ae08745Sheppo 	}
38491ae08745Sheppo 
38501ae08745Sheppo 	/*
38510a55fbb7Slm66018 	 * Call the conversion function (if it exists) for this ioctl
38520a55fbb7Slm66018 	 * which converts from the format ARC'ed as part of the vDisk
38530a55fbb7Slm66018 	 * protocol (FWARC 2006/195) back to a format understood by
38540a55fbb7Slm66018 	 * the rest of Solaris.
38551ae08745Sheppo 	 */
3856d10e4ef2Snarayan 	rv = (dk_ioctl[idx].convert)(vdc, mem_p, arg, mode, VD_COPYOUT);
38570a55fbb7Slm66018 	if (rv != 0) {
3858*e1ebb9ecSlm66018 		DMSG(0, "[%d] convert func returned %d for ioctl 0x%x\n",
3859*e1ebb9ecSlm66018 				instance, rv, cmd);
38601ae08745Sheppo 		if (mem_p != NULL)
38611ae08745Sheppo 			kmem_free(mem_p, alloc_len);
38620a55fbb7Slm66018 		return (rv);
38631ae08745Sheppo 	}
38641ae08745Sheppo 
38651ae08745Sheppo 	if (mem_p != NULL)
38661ae08745Sheppo 		kmem_free(mem_p, alloc_len);
38671ae08745Sheppo 
38681ae08745Sheppo 	return (rv);
38691ae08745Sheppo }
38701ae08745Sheppo 
38711ae08745Sheppo /*
38721ae08745Sheppo  * Function:
38730a55fbb7Slm66018  *
38740a55fbb7Slm66018  * Description:
38750a55fbb7Slm66018  *	This is an empty conversion function used by ioctl calls which
38760a55fbb7Slm66018  *	do not need to convert the data being passed in/out to userland
38770a55fbb7Slm66018  */
38780a55fbb7Slm66018 static int
3879d10e4ef2Snarayan vdc_null_copy_func(vdc_t *vdc, void *from, void *to, int mode, int dir)
38800a55fbb7Slm66018 {
3881d10e4ef2Snarayan 	_NOTE(ARGUNUSED(vdc))
38820a55fbb7Slm66018 	_NOTE(ARGUNUSED(from))
38830a55fbb7Slm66018 	_NOTE(ARGUNUSED(to))
38840a55fbb7Slm66018 	_NOTE(ARGUNUSED(mode))
38850a55fbb7Slm66018 	_NOTE(ARGUNUSED(dir))
38860a55fbb7Slm66018 
38870a55fbb7Slm66018 	return (0);
38880a55fbb7Slm66018 }
38890a55fbb7Slm66018 
38900a55fbb7Slm66018 /*
38910a55fbb7Slm66018  * Function:
38920a55fbb7Slm66018  *	vdc_get_vtoc_convert()
38930a55fbb7Slm66018  *
38940a55fbb7Slm66018  * Description:
3895d10e4ef2Snarayan  *	This routine performs the necessary convertions from the DKIOCGVTOC
3896d10e4ef2Snarayan  *	Solaris structure to the format defined in FWARC 2006/195.
3897d10e4ef2Snarayan  *
3898d10e4ef2Snarayan  *	In the struct vtoc definition, the timestamp field is marked as not
3899d10e4ef2Snarayan  *	supported so it is not part of vDisk protocol (FWARC 2006/195).
3900d10e4ef2Snarayan  *	However SVM uses that field to check it can write into the VTOC,
3901d10e4ef2Snarayan  *	so we fake up the info of that field.
39020a55fbb7Slm66018  *
39030a55fbb7Slm66018  * Arguments:
3904d10e4ef2Snarayan  *	vdc	- the vDisk client
39050a55fbb7Slm66018  *	from	- the buffer containing the data to be copied from
39060a55fbb7Slm66018  *	to	- the buffer to be copied to
39070a55fbb7Slm66018  *	mode	- flags passed to ioctl() call
39080a55fbb7Slm66018  *	dir	- the "direction" of the copy - VD_COPYIN or VD_COPYOUT
39090a55fbb7Slm66018  *
39100a55fbb7Slm66018  * Return Code:
39110a55fbb7Slm66018  *	0	- Success
39120a55fbb7Slm66018  *	ENXIO	- incorrect buffer passed in.
3913d10e4ef2Snarayan  *	EFAULT	- ddi_copyout routine encountered an error.
39140a55fbb7Slm66018  */
39150a55fbb7Slm66018 static int
3916d10e4ef2Snarayan vdc_get_vtoc_convert(vdc_t *vdc, void *from, void *to, int mode, int dir)
39170a55fbb7Slm66018 {
3918d10e4ef2Snarayan 	int		i;
39190a55fbb7Slm66018 	void		*tmp_mem = NULL;
39200a55fbb7Slm66018 	void		*tmp_memp;
39210a55fbb7Slm66018 	struct vtoc	vt;
39220a55fbb7Slm66018 	struct vtoc32	vt32;
39230a55fbb7Slm66018 	int		copy_len = 0;
39240a55fbb7Slm66018 	int		rv = 0;
39250a55fbb7Slm66018 
39260a55fbb7Slm66018 	if (dir != VD_COPYOUT)
39270a55fbb7Slm66018 		return (0);	/* nothing to do */
39280a55fbb7Slm66018 
39290a55fbb7Slm66018 	if ((from == NULL) || (to == NULL))
39300a55fbb7Slm66018 		return (ENXIO);
39310a55fbb7Slm66018 
39320a55fbb7Slm66018 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32)
39330a55fbb7Slm66018 		copy_len = sizeof (struct vtoc32);
39340a55fbb7Slm66018 	else
39350a55fbb7Slm66018 		copy_len = sizeof (struct vtoc);
39360a55fbb7Slm66018 
39370a55fbb7Slm66018 	tmp_mem = kmem_alloc(copy_len, KM_SLEEP);
39380a55fbb7Slm66018 
39390a55fbb7Slm66018 	VD_VTOC2VTOC((vd_vtoc_t *)from, &vt);
3940d10e4ef2Snarayan 
3941d10e4ef2Snarayan 	/* fake the VTOC timestamp field */
3942d10e4ef2Snarayan 	for (i = 0; i < V_NUMPAR; i++) {
3943d10e4ef2Snarayan 		vt.timestamp[i] = vdc->vtoc->timestamp[i];
3944d10e4ef2Snarayan 	}
3945d10e4ef2Snarayan 
39460a55fbb7Slm66018 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
39470a55fbb7Slm66018 		vtoctovtoc32(vt, vt32);
39480a55fbb7Slm66018 		tmp_memp = &vt32;
39490a55fbb7Slm66018 	} else {
39500a55fbb7Slm66018 		tmp_memp = &vt;
39510a55fbb7Slm66018 	}
39520a55fbb7Slm66018 	rv = ddi_copyout(tmp_memp, to, copy_len, mode);
39530a55fbb7Slm66018 	if (rv != 0)
39540a55fbb7Slm66018 		rv = EFAULT;
39550a55fbb7Slm66018 
39560a55fbb7Slm66018 	kmem_free(tmp_mem, copy_len);
39570a55fbb7Slm66018 	return (rv);
39580a55fbb7Slm66018 }
39590a55fbb7Slm66018 
39600a55fbb7Slm66018 /*
39610a55fbb7Slm66018  * Function:
39620a55fbb7Slm66018  *	vdc_set_vtoc_convert()
39630a55fbb7Slm66018  *
39640a55fbb7Slm66018  * Description:
3965d10e4ef2Snarayan  *	This routine performs the necessary convertions from the DKIOCSVTOC
3966d10e4ef2Snarayan  *	Solaris structure to the format defined in FWARC 2006/195.
39670a55fbb7Slm66018  *
39680a55fbb7Slm66018  * Arguments:
3969d10e4ef2Snarayan  *	vdc	- the vDisk client
39700a55fbb7Slm66018  *	from	- Buffer with data
39710a55fbb7Slm66018  *	to	- Buffer where data is to be copied to
39720a55fbb7Slm66018  *	mode	- flags passed to ioctl
39730a55fbb7Slm66018  *	dir	- direction of copy (in or out)
39740a55fbb7Slm66018  *
39750a55fbb7Slm66018  * Return Code:
39760a55fbb7Slm66018  *	0	- Success
39770a55fbb7Slm66018  *	ENXIO	- Invalid buffer passed in
39780a55fbb7Slm66018  *	EFAULT	- ddi_copyin of data failed
39790a55fbb7Slm66018  */
39800a55fbb7Slm66018 static int
3981d10e4ef2Snarayan vdc_set_vtoc_convert(vdc_t *vdc, void *from, void *to, int mode, int dir)
39820a55fbb7Slm66018 {
39830a55fbb7Slm66018 	void		*tmp_mem = NULL;
39840a55fbb7Slm66018 	struct vtoc	vt;
39850a55fbb7Slm66018 	struct vtoc	*vtp = &vt;
39860a55fbb7Slm66018 	vd_vtoc_t	vtvd;
39870a55fbb7Slm66018 	int		copy_len = 0;
39880a55fbb7Slm66018 	int		rv = 0;
39890a55fbb7Slm66018 
39900a55fbb7Slm66018 	if (dir != VD_COPYIN)
39910a55fbb7Slm66018 		return (0);	/* nothing to do */
39920a55fbb7Slm66018 
39930a55fbb7Slm66018 	if ((from == NULL) || (to == NULL))
39940a55fbb7Slm66018 		return (ENXIO);
39950a55fbb7Slm66018 
39960a55fbb7Slm66018 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32)
39970a55fbb7Slm66018 		copy_len = sizeof (struct vtoc32);
39980a55fbb7Slm66018 	else
39990a55fbb7Slm66018 		copy_len = sizeof (struct vtoc);
40000a55fbb7Slm66018 
40010a55fbb7Slm66018 	tmp_mem = kmem_alloc(copy_len, KM_SLEEP);
40020a55fbb7Slm66018 
40030a55fbb7Slm66018 	rv = ddi_copyin(from, tmp_mem, copy_len, mode);
40040a55fbb7Slm66018 	if (rv != 0) {
40050a55fbb7Slm66018 		kmem_free(tmp_mem, copy_len);
40060a55fbb7Slm66018 		return (EFAULT);
40070a55fbb7Slm66018 	}
40080a55fbb7Slm66018 
40090a55fbb7Slm66018 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
40100a55fbb7Slm66018 		vtoc32tovtoc((*(struct vtoc32 *)tmp_mem), vt);
40110a55fbb7Slm66018 	} else {
40120a55fbb7Slm66018 		vtp = tmp_mem;
40130a55fbb7Slm66018 	}
40140a55fbb7Slm66018 
4015d10e4ef2Snarayan 	/*
4016d10e4ef2Snarayan 	 * The VTOC is being changed, then vdc needs to update the copy
4017d10e4ef2Snarayan 	 * it saved in the soft state structure.
4018d10e4ef2Snarayan 	 */
4019d10e4ef2Snarayan 	bcopy(vtp, vdc->vtoc, sizeof (struct vtoc));
4020d10e4ef2Snarayan 
40210a55fbb7Slm66018 	VTOC2VD_VTOC(vtp, &vtvd);
40220a55fbb7Slm66018 	bcopy(&vtvd, to, sizeof (vd_vtoc_t));
40230a55fbb7Slm66018 	kmem_free(tmp_mem, copy_len);
40240a55fbb7Slm66018 
40250a55fbb7Slm66018 	return (0);
40260a55fbb7Slm66018 }
40270a55fbb7Slm66018 
40280a55fbb7Slm66018 /*
40290a55fbb7Slm66018  * Function:
40300a55fbb7Slm66018  *	vdc_get_geom_convert()
40310a55fbb7Slm66018  *
40320a55fbb7Slm66018  * Description:
4033d10e4ef2Snarayan  *	This routine performs the necessary convertions from the DKIOCGGEOM,
4034d10e4ef2Snarayan  *	DKIOCG_PHYSGEOM and DKIOG_VIRTGEOM Solaris structures to the format
4035d10e4ef2Snarayan  *	defined in FWARC 2006/195
40360a55fbb7Slm66018  *
40370a55fbb7Slm66018  * Arguments:
4038d10e4ef2Snarayan  *	vdc	- the vDisk client
40390a55fbb7Slm66018  *	from	- Buffer with data
40400a55fbb7Slm66018  *	to	- Buffer where data is to be copied to
40410a55fbb7Slm66018  *	mode	- flags passed to ioctl
40420a55fbb7Slm66018  *	dir	- direction of copy (in or out)
40430a55fbb7Slm66018  *
40440a55fbb7Slm66018  * Return Code:
40450a55fbb7Slm66018  *	0	- Success
40460a55fbb7Slm66018  *	ENXIO	- Invalid buffer passed in
4047d10e4ef2Snarayan  *	EFAULT	- ddi_copyout of data failed
40480a55fbb7Slm66018  */
40490a55fbb7Slm66018 static int
4050d10e4ef2Snarayan vdc_get_geom_convert(vdc_t *vdc, void *from, void *to, int mode, int dir)
40510a55fbb7Slm66018 {
4052d10e4ef2Snarayan 	_NOTE(ARGUNUSED(vdc))
4053d10e4ef2Snarayan 
40540a55fbb7Slm66018 	struct dk_geom	geom;
40550a55fbb7Slm66018 	int	copy_len = sizeof (struct dk_geom);
40560a55fbb7Slm66018 	int	rv = 0;
40570a55fbb7Slm66018 
40580a55fbb7Slm66018 	if (dir != VD_COPYOUT)
40590a55fbb7Slm66018 		return (0);	/* nothing to do */
40600a55fbb7Slm66018 
40610a55fbb7Slm66018 	if ((from == NULL) || (to == NULL))
40620a55fbb7Slm66018 		return (ENXIO);
40630a55fbb7Slm66018 
40640a55fbb7Slm66018 	VD_GEOM2DK_GEOM((vd_geom_t *)from, &geom);
40650a55fbb7Slm66018 	rv = ddi_copyout(&geom, to, copy_len, mode);
40660a55fbb7Slm66018 	if (rv != 0)
40670a55fbb7Slm66018 		rv = EFAULT;
40680a55fbb7Slm66018 
40690a55fbb7Slm66018 	return (rv);
40700a55fbb7Slm66018 }
40710a55fbb7Slm66018 
40720a55fbb7Slm66018 /*
40730a55fbb7Slm66018  * Function:
40740a55fbb7Slm66018  *	vdc_set_geom_convert()
40750a55fbb7Slm66018  *
40760a55fbb7Slm66018  * Description:
4077d10e4ef2Snarayan  *	This routine performs the necessary convertions from the DKIOCSGEOM
4078d10e4ef2Snarayan  *	Solaris structure to the format defined in FWARC 2006/195.
40790a55fbb7Slm66018  *
40800a55fbb7Slm66018  * Arguments:
4081d10e4ef2Snarayan  *	vdc	- the vDisk client
40820a55fbb7Slm66018  *	from	- Buffer with data
40830a55fbb7Slm66018  *	to	- Buffer where data is to be copied to
40840a55fbb7Slm66018  *	mode	- flags passed to ioctl
40850a55fbb7Slm66018  *	dir	- direction of copy (in or out)
40860a55fbb7Slm66018  *
40870a55fbb7Slm66018  * Return Code:
40880a55fbb7Slm66018  *	0	- Success
40890a55fbb7Slm66018  *	ENXIO	- Invalid buffer passed in
40900a55fbb7Slm66018  *	EFAULT	- ddi_copyin of data failed
40910a55fbb7Slm66018  */
40920a55fbb7Slm66018 static int
4093d10e4ef2Snarayan vdc_set_geom_convert(vdc_t *vdc, void *from, void *to, int mode, int dir)
40940a55fbb7Slm66018 {
4095d10e4ef2Snarayan 	_NOTE(ARGUNUSED(vdc))
4096d10e4ef2Snarayan 
40970a55fbb7Slm66018 	vd_geom_t	vdgeom;
40980a55fbb7Slm66018 	void		*tmp_mem = NULL;
40990a55fbb7Slm66018 	int		copy_len = sizeof (struct dk_geom);
41000a55fbb7Slm66018 	int		rv = 0;
41010a55fbb7Slm66018 
41020a55fbb7Slm66018 	if (dir != VD_COPYIN)
41030a55fbb7Slm66018 		return (0);	/* nothing to do */
41040a55fbb7Slm66018 
41050a55fbb7Slm66018 	if ((from == NULL) || (to == NULL))
41060a55fbb7Slm66018 		return (ENXIO);
41070a55fbb7Slm66018 
41080a55fbb7Slm66018 	tmp_mem = kmem_alloc(copy_len, KM_SLEEP);
41090a55fbb7Slm66018 
41100a55fbb7Slm66018 	rv = ddi_copyin(from, tmp_mem, copy_len, mode);
41110a55fbb7Slm66018 	if (rv != 0) {
41120a55fbb7Slm66018 		kmem_free(tmp_mem, copy_len);
41130a55fbb7Slm66018 		return (EFAULT);
41140a55fbb7Slm66018 	}
41150a55fbb7Slm66018 	DK_GEOM2VD_GEOM((struct dk_geom *)tmp_mem, &vdgeom);
41160a55fbb7Slm66018 	bcopy(&vdgeom, to, sizeof (vdgeom));
41170a55fbb7Slm66018 	kmem_free(tmp_mem, copy_len);
41180a55fbb7Slm66018 
41190a55fbb7Slm66018 	return (0);
41200a55fbb7Slm66018 }
41210a55fbb7Slm66018 
41220a55fbb7Slm66018 /*
41230a55fbb7Slm66018  * Function:
41241ae08745Sheppo  *	vdc_create_fake_geometry()
41251ae08745Sheppo  *
41261ae08745Sheppo  * Description:
41271ae08745Sheppo  *	This routine fakes up the disk info needed for some DKIO ioctls.
41281ae08745Sheppo  *		- DKIOCINFO
41291ae08745Sheppo  *		- DKIOCGMEDIAINFO
41301ae08745Sheppo  *
41311ae08745Sheppo  *	[ just like lofi(7D) and ramdisk(7D) ]
41321ae08745Sheppo  *
41331ae08745Sheppo  * Arguments:
41341ae08745Sheppo  *	vdc	- soft state pointer for this instance of the device driver.
41351ae08745Sheppo  *
41361ae08745Sheppo  * Return Code:
41371ae08745Sheppo  *	0	- Success
41381ae08745Sheppo  */
41391ae08745Sheppo static int
41401ae08745Sheppo vdc_create_fake_geometry(vdc_t *vdc)
41411ae08745Sheppo {
41420a55fbb7Slm66018 	int	rv = 0;
41430a55fbb7Slm66018 
41441ae08745Sheppo 	ASSERT(vdc != NULL);
41451ae08745Sheppo 
41461ae08745Sheppo 	/*
41471ae08745Sheppo 	 * DKIOCINFO support
41481ae08745Sheppo 	 */
41491ae08745Sheppo 	vdc->cinfo = kmem_zalloc(sizeof (struct dk_cinfo), KM_SLEEP);
41501ae08745Sheppo 
41511ae08745Sheppo 	(void) strcpy(vdc->cinfo->dki_cname, VDC_DRIVER_NAME);
41521ae08745Sheppo 	(void) strcpy(vdc->cinfo->dki_dname, VDC_DRIVER_NAME);
41538e6a2a04Slm66018 	/* max_xfer_sz is #blocks so we don't need to divide by DEV_BSIZE */
41548e6a2a04Slm66018 	vdc->cinfo->dki_maxtransfer = vdc->max_xfer_sz;
41551ae08745Sheppo 	vdc->cinfo->dki_ctype = DKC_SCSI_CCS;
41561ae08745Sheppo 	vdc->cinfo->dki_flags = DKI_FMTVOL;
41571ae08745Sheppo 	vdc->cinfo->dki_cnum = 0;
41581ae08745Sheppo 	vdc->cinfo->dki_addr = 0;
41591ae08745Sheppo 	vdc->cinfo->dki_space = 0;
41601ae08745Sheppo 	vdc->cinfo->dki_prio = 0;
41611ae08745Sheppo 	vdc->cinfo->dki_vec = 0;
41621ae08745Sheppo 	vdc->cinfo->dki_unit = vdc->instance;
41631ae08745Sheppo 	vdc->cinfo->dki_slave = 0;
41641ae08745Sheppo 	/*
41651ae08745Sheppo 	 * The partition number will be created on the fly depending on the
41661ae08745Sheppo 	 * actual slice (i.e. minor node) that is used to request the data.
41671ae08745Sheppo 	 */
41681ae08745Sheppo 	vdc->cinfo->dki_partition = 0;
41691ae08745Sheppo 
41701ae08745Sheppo 	/*
41711ae08745Sheppo 	 * DKIOCGMEDIAINFO support
41721ae08745Sheppo 	 */
41730a55fbb7Slm66018 	if (vdc->minfo == NULL)
41741ae08745Sheppo 		vdc->minfo = kmem_zalloc(sizeof (struct dk_minfo), KM_SLEEP);
41751ae08745Sheppo 	vdc->minfo->dki_media_type = DK_FIXED_DISK;
41761ae08745Sheppo 	vdc->minfo->dki_capacity = 1;
41771ae08745Sheppo 	vdc->minfo->dki_lbsize = DEV_BSIZE;
41781ae08745Sheppo 
41790a55fbb7Slm66018 	return (rv);
41800a55fbb7Slm66018 }
41810a55fbb7Slm66018 
41820a55fbb7Slm66018 /*
41830a55fbb7Slm66018  * Function:
41840a55fbb7Slm66018  *	vdc_setup_disk_layout()
41850a55fbb7Slm66018  *
41860a55fbb7Slm66018  * Description:
41870a55fbb7Slm66018  *	This routine discovers all the necessary details about the "disk"
41880a55fbb7Slm66018  *	by requesting the data that is available from the vDisk server and by
41890a55fbb7Slm66018  *	faking up the rest of the data.
41900a55fbb7Slm66018  *
41910a55fbb7Slm66018  * Arguments:
41920a55fbb7Slm66018  *	vdc	- soft state pointer for this instance of the device driver.
41930a55fbb7Slm66018  *
41940a55fbb7Slm66018  * Return Code:
41950a55fbb7Slm66018  *	0	- Success
41960a55fbb7Slm66018  */
41970a55fbb7Slm66018 static int
41980a55fbb7Slm66018 vdc_setup_disk_layout(vdc_t *vdc)
41990a55fbb7Slm66018 {
4200d10e4ef2Snarayan 	buf_t	*buf;	/* BREAD requests need to be in a buf_t structure */
42010a55fbb7Slm66018 	dev_t	dev;
42020a55fbb7Slm66018 	int	slice = 0;
42030a55fbb7Slm66018 	int	rv;
42040a55fbb7Slm66018 
42050a55fbb7Slm66018 	ASSERT(vdc != NULL);
42060a55fbb7Slm66018 
42070a55fbb7Slm66018 	rv = vdc_create_fake_geometry(vdc);
42080a55fbb7Slm66018 	if (rv != 0) {
42090a55fbb7Slm66018 		cmn_err(CE_NOTE, "[%d] Failed to create disk geometry (err%d)",
42100a55fbb7Slm66018 				vdc->instance, rv);
42110a55fbb7Slm66018 	}
42120a55fbb7Slm66018 
42130a55fbb7Slm66018 	if (vdc->vtoc == NULL)
42140a55fbb7Slm66018 		vdc->vtoc = kmem_zalloc(sizeof (struct vtoc), KM_SLEEP);
42150a55fbb7Slm66018 
42160a55fbb7Slm66018 	dev = makedevice(ddi_driver_major(vdc->dip),
42170a55fbb7Slm66018 				VD_MAKE_DEV(vdc->instance, 0));
42180a55fbb7Slm66018 	rv = vd_process_ioctl(dev, DKIOCGVTOC, (caddr_t)vdc->vtoc, FKIOCTL);
42190a55fbb7Slm66018 	if (rv) {
42200a55fbb7Slm66018 		cmn_err(CE_NOTE, "[%d] Failed to get VTOC (err=%d)",
42210a55fbb7Slm66018 				vdc->instance, rv);
42220a55fbb7Slm66018 		return (rv);
42230a55fbb7Slm66018 	}
42240a55fbb7Slm66018 
42250a55fbb7Slm66018 	/*
42260a55fbb7Slm66018 	 * find the slice that represents the entire "disk" and use that to
42270a55fbb7Slm66018 	 * read the disk label. The convention in Solaris is that slice 2
4228d10e4ef2Snarayan 	 * represents the whole disk so we check that it is, otherwise we
42290a55fbb7Slm66018 	 * default to slice 0
42300a55fbb7Slm66018 	 */
42310a55fbb7Slm66018 	if ((vdc->vdisk_type == VD_DISK_TYPE_DISK) &&
42320a55fbb7Slm66018 	    (vdc->vtoc->v_part[2].p_tag == V_BACKUP)) {
42330a55fbb7Slm66018 		slice = 2;
42340a55fbb7Slm66018 	} else {
42350a55fbb7Slm66018 		slice = 0;
42360a55fbb7Slm66018 	}
4237d10e4ef2Snarayan 
4238d10e4ef2Snarayan 	/*
4239d10e4ef2Snarayan 	 * Read disk label from start of disk
4240d10e4ef2Snarayan 	 */
4241d10e4ef2Snarayan 	vdc->label = kmem_zalloc(DK_LABEL_SIZE, KM_SLEEP);
4242d10e4ef2Snarayan 	buf = kmem_alloc(sizeof (buf_t), KM_SLEEP);
4243d10e4ef2Snarayan 	bioinit(buf);
4244d10e4ef2Snarayan 	buf->b_un.b_addr = (caddr_t)vdc->label;
4245d10e4ef2Snarayan 	buf->b_bcount = DK_LABEL_SIZE;
4246d10e4ef2Snarayan 	buf->b_flags = B_BUSY | B_READ;
4247d10e4ef2Snarayan 	buf->b_dev = dev;
4248d10e4ef2Snarayan 	rv = vdc_populate_descriptor(vdc, (caddr_t)buf, DK_LABEL_SIZE,
42490a55fbb7Slm66018 			VD_OP_BREAD, 0, slice);
4250d10e4ef2Snarayan 	rv = biowait(buf);
4251d10e4ef2Snarayan 	biofini(buf);
4252d10e4ef2Snarayan 	kmem_free(buf, sizeof (buf_t));
42530a55fbb7Slm66018 
42540a55fbb7Slm66018 	return (rv);
42551ae08745Sheppo }
4256