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