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