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 /* 236567eb0aSlh195018 * Copyright 2007 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 60e1ebb9ecSlm66018 #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/fdisk.h> 8487a7269eSachartre #include <sys/dktp/dadkio.h> 851ae08745Sheppo #include <sys/scsi/generic/sense.h> 861ae08745Sheppo #include <sys/scsi/impl/uscsi.h> /* Needed for defn of USCSICMD ioctl */ 871ae08745Sheppo 881ae08745Sheppo #include <sys/ldoms.h> 891ae08745Sheppo #include <sys/ldc.h> 901ae08745Sheppo #include <sys/vio_common.h> 911ae08745Sheppo #include <sys/vio_mailbox.h> 921ae08745Sheppo #include <sys/vdsk_common.h> 931ae08745Sheppo #include <sys/vdsk_mailbox.h> 941ae08745Sheppo #include <sys/vdc.h> 951ae08745Sheppo 961ae08745Sheppo /* 971ae08745Sheppo * function prototypes 981ae08745Sheppo */ 991ae08745Sheppo 1001ae08745Sheppo /* standard driver functions */ 1011ae08745Sheppo static int vdc_open(dev_t *dev, int flag, int otyp, cred_t *cred); 1021ae08745Sheppo static int vdc_close(dev_t dev, int flag, int otyp, cred_t *cred); 1031ae08745Sheppo static int vdc_strategy(struct buf *buf); 1041ae08745Sheppo static int vdc_print(dev_t dev, char *str); 1051ae08745Sheppo static int vdc_dump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk); 1061ae08745Sheppo static int vdc_read(dev_t dev, struct uio *uio, cred_t *cred); 1071ae08745Sheppo static int vdc_write(dev_t dev, struct uio *uio, cred_t *cred); 1081ae08745Sheppo static int vdc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 1091ae08745Sheppo cred_t *credp, int *rvalp); 1101ae08745Sheppo static int vdc_aread(dev_t dev, struct aio_req *aio, cred_t *cred); 1111ae08745Sheppo static int vdc_awrite(dev_t dev, struct aio_req *aio, cred_t *cred); 1121ae08745Sheppo 1131ae08745Sheppo static int vdc_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, 1141ae08745Sheppo void *arg, void **resultp); 1151ae08745Sheppo static int vdc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 1161ae08745Sheppo static int vdc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 1171ae08745Sheppo 1181ae08745Sheppo /* setup */ 1190d0c8d4bSnarayan static void vdc_min(struct buf *bufp); 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); 1244bac2208Snarayan static int vdc_create_device_nodes_efi(vdc_t *vdc); 1254bac2208Snarayan static int vdc_create_device_nodes_vtoc(vdc_t *vdc); 1261ae08745Sheppo static int vdc_create_device_nodes_props(vdc_t *vdc); 1271ae08745Sheppo static int vdc_get_ldc_id(dev_info_t *dip, uint64_t *ldc_id); 1280a55fbb7Slm66018 static int vdc_do_ldc_up(vdc_t *vdc); 1291ae08745Sheppo static void vdc_terminate_ldc(vdc_t *vdc); 1301ae08745Sheppo static int vdc_init_descriptor_ring(vdc_t *vdc); 1311ae08745Sheppo static void vdc_destroy_descriptor_ring(vdc_t *vdc); 1324bac2208Snarayan static int vdc_setup_devid(vdc_t *vdc); 1334bac2208Snarayan static void vdc_store_efi(vdc_t *vdc, struct dk_gpt *efi); 1341ae08745Sheppo 1351ae08745Sheppo /* handshake with vds */ 1360a55fbb7Slm66018 static int vdc_init_ver_negotiation(vdc_t *vdc, vio_ver_t ver); 1373af08d82Slm66018 static int vdc_ver_negotiation(vdc_t *vdcp); 1381ae08745Sheppo static int vdc_init_attr_negotiation(vdc_t *vdc); 1393af08d82Slm66018 static int vdc_attr_negotiation(vdc_t *vdcp); 1401ae08745Sheppo static int vdc_init_dring_negotiate(vdc_t *vdc); 1413af08d82Slm66018 static int vdc_dring_negotiation(vdc_t *vdcp); 1423af08d82Slm66018 static int vdc_send_rdx(vdc_t *vdcp); 1433af08d82Slm66018 static int vdc_rdx_exchange(vdc_t *vdcp); 1440a55fbb7Slm66018 static boolean_t vdc_is_supported_version(vio_ver_msg_t *ver_msg); 1451ae08745Sheppo 1460a55fbb7Slm66018 /* processing incoming messages from vDisk server */ 1471ae08745Sheppo static void vdc_process_msg_thread(vdc_t *vdc); 1483af08d82Slm66018 static int vdc_recv(vdc_t *vdc, vio_msg_t *msgp, size_t *nbytesp); 1493af08d82Slm66018 1500a55fbb7Slm66018 static uint_t vdc_handle_cb(uint64_t event, caddr_t arg); 1513af08d82Slm66018 static int vdc_process_data_msg(vdc_t *vdc, vio_msg_t *msg); 1521ae08745Sheppo static int vdc_process_err_msg(vdc_t *vdc, vio_msg_t msg); 1530a55fbb7Slm66018 static int vdc_handle_ver_msg(vdc_t *vdc, vio_ver_msg_t *ver_msg); 1540a55fbb7Slm66018 static int vdc_handle_attr_msg(vdc_t *vdc, vd_attr_msg_t *attr_msg); 1550a55fbb7Slm66018 static int vdc_handle_dring_reg_msg(vdc_t *vdc, vio_dring_reg_msg_t *msg); 1563af08d82Slm66018 static int vdc_send_request(vdc_t *vdcp, int operation, 1573af08d82Slm66018 caddr_t addr, size_t nbytes, int slice, diskaddr_t offset, 1583af08d82Slm66018 int cb_type, void *cb_arg, vio_desc_direction_t dir); 1593af08d82Slm66018 static int vdc_map_to_shared_dring(vdc_t *vdcp, int idx); 1603af08d82Slm66018 static int vdc_populate_descriptor(vdc_t *vdcp, int operation, 1613af08d82Slm66018 caddr_t addr, size_t nbytes, int slice, diskaddr_t offset, 1623af08d82Slm66018 int cb_type, void *cb_arg, vio_desc_direction_t dir); 1633af08d82Slm66018 static int vdc_do_sync_op(vdc_t *vdcp, int operation, 1643af08d82Slm66018 caddr_t addr, size_t nbytes, int slice, diskaddr_t offset, 1653af08d82Slm66018 int cb_type, void *cb_arg, vio_desc_direction_t dir); 1663af08d82Slm66018 1673af08d82Slm66018 static int vdc_wait_for_response(vdc_t *vdcp, vio_msg_t *msgp); 1683af08d82Slm66018 static int vdc_drain_response(vdc_t *vdcp); 1691ae08745Sheppo static int vdc_depopulate_descriptor(vdc_t *vdc, uint_t idx); 1703af08d82Slm66018 static int vdc_populate_mem_hdl(vdc_t *vdcp, vdc_local_desc_t *ldep); 171e1ebb9ecSlm66018 static int vdc_verify_seq_num(vdc_t *vdc, vio_dring_msg_t *dring_msg); 1721ae08745Sheppo 1731ae08745Sheppo /* dkio */ 1741ae08745Sheppo static int vd_process_ioctl(dev_t dev, int cmd, caddr_t arg, int mode); 1751ae08745Sheppo static int vdc_create_fake_geometry(vdc_t *vdc); 1760a55fbb7Slm66018 static int vdc_setup_disk_layout(vdc_t *vdc); 177d10e4ef2Snarayan static int vdc_null_copy_func(vdc_t *vdc, void *from, void *to, 178d10e4ef2Snarayan int mode, int dir); 1794bac2208Snarayan static int vdc_get_wce_convert(vdc_t *vdc, void *from, void *to, 1804bac2208Snarayan int mode, int dir); 1814bac2208Snarayan static int vdc_set_wce_convert(vdc_t *vdc, void *from, void *to, 1824bac2208Snarayan int mode, int dir); 183d10e4ef2Snarayan static int vdc_get_vtoc_convert(vdc_t *vdc, void *from, void *to, 184d10e4ef2Snarayan int mode, int dir); 185d10e4ef2Snarayan static int vdc_set_vtoc_convert(vdc_t *vdc, void *from, void *to, 186d10e4ef2Snarayan int mode, int dir); 187d10e4ef2Snarayan static int vdc_get_geom_convert(vdc_t *vdc, void *from, void *to, 188d10e4ef2Snarayan int mode, int dir); 189d10e4ef2Snarayan static int vdc_set_geom_convert(vdc_t *vdc, void *from, void *to, 190d10e4ef2Snarayan int mode, int dir); 191d10e4ef2Snarayan static int vdc_uscsicmd_convert(vdc_t *vdc, void *from, void *to, 192d10e4ef2Snarayan int mode, int dir); 1934bac2208Snarayan static int vdc_get_efi_convert(vdc_t *vdc, void *from, void *to, 1944bac2208Snarayan int mode, int dir); 1954bac2208Snarayan static int vdc_set_efi_convert(vdc_t *vdc, void *from, void *to, 1964bac2208Snarayan int mode, int dir); 1971ae08745Sheppo 1981ae08745Sheppo /* 1991ae08745Sheppo * Module variables 2001ae08745Sheppo */ 201e1ebb9ecSlm66018 202e1ebb9ecSlm66018 /* 203e1ebb9ecSlm66018 * Tunable variables to control how long vdc waits before timing out on 204e1ebb9ecSlm66018 * various operations 205e1ebb9ecSlm66018 */ 206e1ebb9ecSlm66018 static int vdc_retries = 10; 2073c96341aSnarayan static int vdc_hshake_retries = 3; 208e1ebb9ecSlm66018 209e1ebb9ecSlm66018 /* calculated from 'vdc_usec_timeout' during attach */ 210e1ebb9ecSlm66018 static uint64_t vdc_hz_timeout; /* units: Hz */ 211e1ebb9ecSlm66018 static uint64_t vdc_usec_timeout = 30 * MICROSEC; /* 30s units: ns */ 212e1ebb9ecSlm66018 2133af08d82Slm66018 static uint64_t vdc_hz_min_ldc_delay; 2143af08d82Slm66018 static uint64_t vdc_min_timeout_ldc = 1 * MILLISEC; 2153af08d82Slm66018 static uint64_t vdc_hz_max_ldc_delay; 2163af08d82Slm66018 static uint64_t vdc_max_timeout_ldc = 100 * MILLISEC; 2173af08d82Slm66018 2183af08d82Slm66018 static uint64_t vdc_ldc_read_init_delay = 1 * MILLISEC; 2193af08d82Slm66018 static uint64_t vdc_ldc_read_max_delay = 100 * MILLISEC; 220e1ebb9ecSlm66018 221e1ebb9ecSlm66018 /* values for dumping - need to run in a tighter loop */ 222e1ebb9ecSlm66018 static uint64_t vdc_usec_timeout_dump = 100 * MILLISEC; /* 0.1s units: ns */ 223e1ebb9ecSlm66018 static int vdc_dump_retries = 100; 224e1ebb9ecSlm66018 225e1ebb9ecSlm66018 /* Count of the number of vdc instances attached */ 226e1ebb9ecSlm66018 static volatile uint32_t vdc_instance_count = 0; 2271ae08745Sheppo 2281ae08745Sheppo /* Soft state pointer */ 2291ae08745Sheppo static void *vdc_state; 2301ae08745Sheppo 2313af08d82Slm66018 /* 2323af08d82Slm66018 * Controlling the verbosity of the error/debug messages 2333af08d82Slm66018 * 2343af08d82Slm66018 * vdc_msglevel - controls level of messages 2353af08d82Slm66018 * vdc_matchinst - 64-bit variable where each bit corresponds 2363af08d82Slm66018 * to the vdc instance the vdc_msglevel applies. 2373af08d82Slm66018 */ 2383af08d82Slm66018 int vdc_msglevel = 0x0; 2393af08d82Slm66018 uint64_t vdc_matchinst = 0ull; 2401ae08745Sheppo 2410a55fbb7Slm66018 /* 2420a55fbb7Slm66018 * Supported vDisk protocol version pairs. 2430a55fbb7Slm66018 * 2440a55fbb7Slm66018 * The first array entry is the latest and preferred version. 2450a55fbb7Slm66018 */ 2460a55fbb7Slm66018 static const vio_ver_t vdc_version[] = {{1, 0}}; 2471ae08745Sheppo 2481ae08745Sheppo static struct cb_ops vdc_cb_ops = { 2491ae08745Sheppo vdc_open, /* cb_open */ 2501ae08745Sheppo vdc_close, /* cb_close */ 2511ae08745Sheppo vdc_strategy, /* cb_strategy */ 2521ae08745Sheppo vdc_print, /* cb_print */ 2531ae08745Sheppo vdc_dump, /* cb_dump */ 2541ae08745Sheppo vdc_read, /* cb_read */ 2551ae08745Sheppo vdc_write, /* cb_write */ 2561ae08745Sheppo vdc_ioctl, /* cb_ioctl */ 2571ae08745Sheppo nodev, /* cb_devmap */ 2581ae08745Sheppo nodev, /* cb_mmap */ 2591ae08745Sheppo nodev, /* cb_segmap */ 2601ae08745Sheppo nochpoll, /* cb_chpoll */ 2611ae08745Sheppo ddi_prop_op, /* cb_prop_op */ 2621ae08745Sheppo NULL, /* cb_str */ 2631ae08745Sheppo D_MP | D_64BIT, /* cb_flag */ 2641ae08745Sheppo CB_REV, /* cb_rev */ 2651ae08745Sheppo vdc_aread, /* cb_aread */ 2661ae08745Sheppo vdc_awrite /* cb_awrite */ 2671ae08745Sheppo }; 2681ae08745Sheppo 2691ae08745Sheppo static struct dev_ops vdc_ops = { 2701ae08745Sheppo DEVO_REV, /* devo_rev */ 2711ae08745Sheppo 0, /* devo_refcnt */ 2721ae08745Sheppo vdc_getinfo, /* devo_getinfo */ 2731ae08745Sheppo nulldev, /* devo_identify */ 2741ae08745Sheppo nulldev, /* devo_probe */ 2751ae08745Sheppo vdc_attach, /* devo_attach */ 2761ae08745Sheppo vdc_detach, /* devo_detach */ 2771ae08745Sheppo nodev, /* devo_reset */ 2781ae08745Sheppo &vdc_cb_ops, /* devo_cb_ops */ 2791ae08745Sheppo NULL, /* devo_bus_ops */ 2801ae08745Sheppo nulldev /* devo_power */ 2811ae08745Sheppo }; 2821ae08745Sheppo 2831ae08745Sheppo static struct modldrv modldrv = { 2841ae08745Sheppo &mod_driverops, 285*205eeb1aSlm66018 "virtual disk client", 2861ae08745Sheppo &vdc_ops, 2871ae08745Sheppo }; 2881ae08745Sheppo 2891ae08745Sheppo static struct modlinkage modlinkage = { 2901ae08745Sheppo MODREV_1, 2911ae08745Sheppo &modldrv, 2921ae08745Sheppo NULL 2931ae08745Sheppo }; 2941ae08745Sheppo 2951ae08745Sheppo /* -------------------------------------------------------------------------- */ 2961ae08745Sheppo 2971ae08745Sheppo /* 2981ae08745Sheppo * Device Driver housekeeping and setup 2991ae08745Sheppo */ 3001ae08745Sheppo 3011ae08745Sheppo int 3021ae08745Sheppo _init(void) 3031ae08745Sheppo { 3041ae08745Sheppo int status; 3051ae08745Sheppo 3061ae08745Sheppo if ((status = ddi_soft_state_init(&vdc_state, sizeof (vdc_t), 1)) != 0) 3071ae08745Sheppo return (status); 3081ae08745Sheppo if ((status = mod_install(&modlinkage)) != 0) 3091ae08745Sheppo ddi_soft_state_fini(&vdc_state); 3104bac2208Snarayan vdc_efi_init(vd_process_ioctl); 3111ae08745Sheppo return (status); 3121ae08745Sheppo } 3131ae08745Sheppo 3141ae08745Sheppo int 3151ae08745Sheppo _info(struct modinfo *modinfop) 3161ae08745Sheppo { 3171ae08745Sheppo return (mod_info(&modlinkage, modinfop)); 3181ae08745Sheppo } 3191ae08745Sheppo 3201ae08745Sheppo int 3211ae08745Sheppo _fini(void) 3221ae08745Sheppo { 3231ae08745Sheppo int status; 3241ae08745Sheppo 3251ae08745Sheppo if ((status = mod_remove(&modlinkage)) != 0) 3261ae08745Sheppo return (status); 3274bac2208Snarayan vdc_efi_fini(); 3281ae08745Sheppo ddi_soft_state_fini(&vdc_state); 3291ae08745Sheppo return (0); 3301ae08745Sheppo } 3311ae08745Sheppo 3321ae08745Sheppo static int 3331ae08745Sheppo vdc_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp) 3341ae08745Sheppo { 3351ae08745Sheppo _NOTE(ARGUNUSED(dip)) 3361ae08745Sheppo 3370d0c8d4bSnarayan int instance = VDCUNIT((dev_t)arg); 3381ae08745Sheppo vdc_t *vdc = NULL; 3391ae08745Sheppo 3401ae08745Sheppo switch (cmd) { 3411ae08745Sheppo case DDI_INFO_DEVT2DEVINFO: 3421ae08745Sheppo if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) { 3431ae08745Sheppo *resultp = NULL; 3441ae08745Sheppo return (DDI_FAILURE); 3451ae08745Sheppo } 3461ae08745Sheppo *resultp = vdc->dip; 3471ae08745Sheppo return (DDI_SUCCESS); 3481ae08745Sheppo case DDI_INFO_DEVT2INSTANCE: 3491ae08745Sheppo *resultp = (void *)(uintptr_t)instance; 3501ae08745Sheppo return (DDI_SUCCESS); 3511ae08745Sheppo default: 3521ae08745Sheppo *resultp = NULL; 3531ae08745Sheppo return (DDI_FAILURE); 3541ae08745Sheppo } 3551ae08745Sheppo } 3561ae08745Sheppo 3571ae08745Sheppo static int 3581ae08745Sheppo vdc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 3591ae08745Sheppo { 3601ae08745Sheppo int instance; 3611ae08745Sheppo int rv; 3621ae08745Sheppo vdc_t *vdc = NULL; 3631ae08745Sheppo 3641ae08745Sheppo switch (cmd) { 3651ae08745Sheppo case DDI_DETACH: 3661ae08745Sheppo /* the real work happens below */ 3671ae08745Sheppo break; 3681ae08745Sheppo case DDI_SUSPEND: 3691ae08745Sheppo /* nothing to do for this non-device */ 3701ae08745Sheppo return (DDI_SUCCESS); 3711ae08745Sheppo default: 3721ae08745Sheppo return (DDI_FAILURE); 3731ae08745Sheppo } 3741ae08745Sheppo 3751ae08745Sheppo ASSERT(cmd == DDI_DETACH); 3761ae08745Sheppo instance = ddi_get_instance(dip); 3773af08d82Slm66018 DMSGX(1, "[%d] Entered\n", instance); 3781ae08745Sheppo 3791ae08745Sheppo if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) { 380e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't get state structure", instance); 3811ae08745Sheppo return (DDI_FAILURE); 3821ae08745Sheppo } 3831ae08745Sheppo 3843af08d82Slm66018 if (vdc->open_count) { 3853af08d82Slm66018 DMSG(vdc, 0, "[%d] Cannot detach: device is open", instance); 3861ae08745Sheppo return (DDI_FAILURE); 3871ae08745Sheppo } 3881ae08745Sheppo 3893af08d82Slm66018 DMSG(vdc, 0, "[%d] proceeding...\n", instance); 3903af08d82Slm66018 3913af08d82Slm66018 /* mark instance as detaching */ 3923af08d82Slm66018 vdc->lifecycle = VDC_LC_DETACHING; 3931ae08745Sheppo 3941ae08745Sheppo /* 3951ae08745Sheppo * try and disable callbacks to prevent another handshake 3961ae08745Sheppo */ 3971ae08745Sheppo rv = ldc_set_cb_mode(vdc->ldc_handle, LDC_CB_DISABLE); 3983af08d82Slm66018 DMSG(vdc, 0, "callback disabled (rv=%d)\n", rv); 3991ae08745Sheppo 4001ae08745Sheppo if (vdc->initialized & VDC_THREAD) { 4013af08d82Slm66018 mutex_enter(&vdc->read_lock); 4023af08d82Slm66018 if ((vdc->read_state == VDC_READ_WAITING) || 4033af08d82Slm66018 (vdc->read_state == VDC_READ_RESET)) { 4043af08d82Slm66018 vdc->read_state = VDC_READ_RESET; 4053af08d82Slm66018 cv_signal(&vdc->read_cv); 4061ae08745Sheppo } 4073af08d82Slm66018 4083af08d82Slm66018 mutex_exit(&vdc->read_lock); 4093af08d82Slm66018 4103af08d82Slm66018 /* wake up any thread waiting for connection to come online */ 4113af08d82Slm66018 mutex_enter(&vdc->lock); 4123af08d82Slm66018 if (vdc->state == VDC_STATE_INIT_WAITING) { 4133af08d82Slm66018 DMSG(vdc, 0, 4143af08d82Slm66018 "[%d] write reset - move to resetting state...\n", 4153af08d82Slm66018 instance); 4163af08d82Slm66018 vdc->state = VDC_STATE_RESETTING; 4173af08d82Slm66018 cv_signal(&vdc->initwait_cv); 4183af08d82Slm66018 } 4193af08d82Slm66018 mutex_exit(&vdc->lock); 4203af08d82Slm66018 4213af08d82Slm66018 /* now wait until state transitions to VDC_STATE_DETACH */ 4223af08d82Slm66018 thread_join(vdc->msg_proc_thr->t_did); 4233af08d82Slm66018 ASSERT(vdc->state == VDC_STATE_DETACH); 4243af08d82Slm66018 DMSG(vdc, 0, "[%d] Reset thread exit and join ..\n", 4253af08d82Slm66018 vdc->instance); 4261ae08745Sheppo } 4271ae08745Sheppo 4281ae08745Sheppo mutex_enter(&vdc->lock); 4291ae08745Sheppo 4301ae08745Sheppo if (vdc->initialized & VDC_DRING) 4311ae08745Sheppo vdc_destroy_descriptor_ring(vdc); 4321ae08745Sheppo 4331ae08745Sheppo if (vdc->initialized & VDC_LDC) 4341ae08745Sheppo vdc_terminate_ldc(vdc); 4351ae08745Sheppo 4361ae08745Sheppo mutex_exit(&vdc->lock); 4371ae08745Sheppo 4381ae08745Sheppo if (vdc->initialized & VDC_MINOR) { 4391ae08745Sheppo ddi_prop_remove_all(dip); 4401ae08745Sheppo ddi_remove_minor_node(dip, NULL); 4411ae08745Sheppo } 4421ae08745Sheppo 4431ae08745Sheppo if (vdc->initialized & VDC_LOCKS) { 4441ae08745Sheppo mutex_destroy(&vdc->lock); 4453af08d82Slm66018 mutex_destroy(&vdc->read_lock); 4463af08d82Slm66018 cv_destroy(&vdc->initwait_cv); 4473af08d82Slm66018 cv_destroy(&vdc->dring_free_cv); 4483af08d82Slm66018 cv_destroy(&vdc->membind_cv); 4493af08d82Slm66018 cv_destroy(&vdc->sync_pending_cv); 4503af08d82Slm66018 cv_destroy(&vdc->sync_blocked_cv); 4513af08d82Slm66018 cv_destroy(&vdc->read_cv); 4523af08d82Slm66018 cv_destroy(&vdc->running_cv); 4531ae08745Sheppo } 4541ae08745Sheppo 4551ae08745Sheppo if (vdc->minfo) 4561ae08745Sheppo kmem_free(vdc->minfo, sizeof (struct dk_minfo)); 4571ae08745Sheppo 4581ae08745Sheppo if (vdc->cinfo) 4591ae08745Sheppo kmem_free(vdc->cinfo, sizeof (struct dk_cinfo)); 4601ae08745Sheppo 4611ae08745Sheppo if (vdc->vtoc) 4621ae08745Sheppo kmem_free(vdc->vtoc, sizeof (struct vtoc)); 4631ae08745Sheppo 4640a55fbb7Slm66018 if (vdc->label) 4650a55fbb7Slm66018 kmem_free(vdc->label, DK_LABEL_SIZE); 4660a55fbb7Slm66018 4674bac2208Snarayan if (vdc->devid) { 4684bac2208Snarayan ddi_devid_unregister(dip); 4694bac2208Snarayan ddi_devid_free(vdc->devid); 4704bac2208Snarayan } 4714bac2208Snarayan 4721ae08745Sheppo if (vdc->initialized & VDC_SOFT_STATE) 4731ae08745Sheppo ddi_soft_state_free(vdc_state, instance); 4741ae08745Sheppo 4753af08d82Slm66018 DMSG(vdc, 0, "[%d] End %p\n", instance, (void *)vdc); 4761ae08745Sheppo 4771ae08745Sheppo return (DDI_SUCCESS); 4781ae08745Sheppo } 4791ae08745Sheppo 4801ae08745Sheppo 4811ae08745Sheppo static int 4821ae08745Sheppo vdc_do_attach(dev_info_t *dip) 4831ae08745Sheppo { 4841ae08745Sheppo int instance; 4851ae08745Sheppo vdc_t *vdc = NULL; 4861ae08745Sheppo int status; 4871ae08745Sheppo 4881ae08745Sheppo ASSERT(dip != NULL); 4891ae08745Sheppo 4901ae08745Sheppo instance = ddi_get_instance(dip); 4911ae08745Sheppo if (ddi_soft_state_zalloc(vdc_state, instance) != DDI_SUCCESS) { 492e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't alloc state structure", 493e1ebb9ecSlm66018 instance); 4941ae08745Sheppo return (DDI_FAILURE); 4951ae08745Sheppo } 4961ae08745Sheppo 4971ae08745Sheppo if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) { 498e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't get state structure", instance); 4991ae08745Sheppo return (DDI_FAILURE); 5001ae08745Sheppo } 5011ae08745Sheppo 5021ae08745Sheppo /* 5031ae08745Sheppo * We assign the value to initialized in this case to zero out the 5041ae08745Sheppo * variable and then set bits in it to indicate what has been done 5051ae08745Sheppo */ 5061ae08745Sheppo vdc->initialized = VDC_SOFT_STATE; 5071ae08745Sheppo 5081ae08745Sheppo vdc_hz_timeout = drv_usectohz(vdc_usec_timeout); 5093af08d82Slm66018 5103af08d82Slm66018 vdc_hz_min_ldc_delay = drv_usectohz(vdc_min_timeout_ldc); 5113af08d82Slm66018 vdc_hz_max_ldc_delay = drv_usectohz(vdc_max_timeout_ldc); 5121ae08745Sheppo 5131ae08745Sheppo vdc->dip = dip; 5141ae08745Sheppo vdc->instance = instance; 5153af08d82Slm66018 vdc->open_count = 0; 5161ae08745Sheppo vdc->vdisk_type = VD_DISK_TYPE_UNK; 5174bac2208Snarayan vdc->vdisk_label = VD_DISK_LABEL_UNK; 5183af08d82Slm66018 vdc->state = VDC_STATE_INIT; 5193af08d82Slm66018 vdc->lifecycle = VDC_LC_ATTACHING; 5201ae08745Sheppo vdc->ldc_state = 0; 5211ae08745Sheppo vdc->session_id = 0; 5221ae08745Sheppo vdc->block_size = DEV_BSIZE; 5238e6a2a04Slm66018 vdc->max_xfer_sz = maxphys / DEV_BSIZE; 5241ae08745Sheppo 5251ae08745Sheppo vdc->vtoc = NULL; 5261ae08745Sheppo vdc->cinfo = NULL; 5271ae08745Sheppo vdc->minfo = NULL; 5281ae08745Sheppo 5291ae08745Sheppo mutex_init(&vdc->lock, NULL, MUTEX_DRIVER, NULL); 5303af08d82Slm66018 cv_init(&vdc->initwait_cv, NULL, CV_DRIVER, NULL); 5313af08d82Slm66018 cv_init(&vdc->dring_free_cv, NULL, CV_DRIVER, NULL); 5323af08d82Slm66018 cv_init(&vdc->membind_cv, NULL, CV_DRIVER, NULL); 5333af08d82Slm66018 cv_init(&vdc->running_cv, NULL, CV_DRIVER, NULL); 5343af08d82Slm66018 5353af08d82Slm66018 vdc->threads_pending = 0; 5363af08d82Slm66018 vdc->sync_op_pending = B_FALSE; 5373af08d82Slm66018 vdc->sync_op_blocked = B_FALSE; 5383af08d82Slm66018 cv_init(&vdc->sync_pending_cv, NULL, CV_DRIVER, NULL); 5393af08d82Slm66018 cv_init(&vdc->sync_blocked_cv, NULL, CV_DRIVER, NULL); 5403af08d82Slm66018 5413af08d82Slm66018 /* init blocking msg read functionality */ 5423af08d82Slm66018 mutex_init(&vdc->read_lock, NULL, MUTEX_DRIVER, NULL); 5433af08d82Slm66018 cv_init(&vdc->read_cv, NULL, CV_DRIVER, NULL); 5443af08d82Slm66018 vdc->read_state = VDC_READ_IDLE; 5453af08d82Slm66018 5461ae08745Sheppo vdc->initialized |= VDC_LOCKS; 5471ae08745Sheppo 5483af08d82Slm66018 /* initialise LDC channel which will be used to communicate with vds */ 5493af08d82Slm66018 if ((status = vdc_do_ldc_init(vdc)) != 0) { 5503af08d82Slm66018 cmn_err(CE_NOTE, "[%d] Couldn't initialize LDC", instance); 5513af08d82Slm66018 goto return_status; 5523af08d82Slm66018 } 5533af08d82Slm66018 5543af08d82Slm66018 /* initialize the thread responsible for managing state with server */ 5553af08d82Slm66018 vdc->msg_proc_thr = thread_create(NULL, 0, vdc_process_msg_thread, 5561ae08745Sheppo vdc, 0, &p0, TS_RUN, minclsyspri); 5573af08d82Slm66018 if (vdc->msg_proc_thr == NULL) { 5581ae08745Sheppo cmn_err(CE_NOTE, "[%d] Failed to create msg processing thread", 5591ae08745Sheppo instance); 5601ae08745Sheppo return (DDI_FAILURE); 5611ae08745Sheppo } 5623af08d82Slm66018 5631ae08745Sheppo vdc->initialized |= VDC_THREAD; 5641ae08745Sheppo 565e1ebb9ecSlm66018 atomic_inc_32(&vdc_instance_count); 5661ae08745Sheppo 5670a55fbb7Slm66018 /* 5680a55fbb7Slm66018 * Once the handshake is complete, we can use the DRing to send 5690a55fbb7Slm66018 * requests to the vDisk server to calculate the geometry and 5700a55fbb7Slm66018 * VTOC of the "disk" 5710a55fbb7Slm66018 */ 5720a55fbb7Slm66018 status = vdc_setup_disk_layout(vdc); 5730a55fbb7Slm66018 if (status != 0) { 5743af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to discover disk layout (err%d)", 5750a55fbb7Slm66018 vdc->instance, status); 5763af08d82Slm66018 goto return_status; 5771ae08745Sheppo } 5781ae08745Sheppo 5791ae08745Sheppo /* 5801ae08745Sheppo * Now that we have the device info we can create the 5811ae08745Sheppo * device nodes and properties 5821ae08745Sheppo */ 5831ae08745Sheppo status = vdc_create_device_nodes(vdc); 5841ae08745Sheppo if (status) { 5853af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to create device nodes", 5861ae08745Sheppo instance); 5873af08d82Slm66018 goto return_status; 5881ae08745Sheppo } 5891ae08745Sheppo status = vdc_create_device_nodes_props(vdc); 5901ae08745Sheppo if (status) { 5913af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to create device nodes" 5920a55fbb7Slm66018 " properties (%d)", instance, status); 5933af08d82Slm66018 goto return_status; 5941ae08745Sheppo } 5951ae08745Sheppo 5964bac2208Snarayan /* 5974bac2208Snarayan * Setup devid 5984bac2208Snarayan */ 5994bac2208Snarayan if (vdc_setup_devid(vdc)) { 6003af08d82Slm66018 DMSG(vdc, 0, "[%d] No device id available\n", instance); 6014bac2208Snarayan } 6024bac2208Snarayan 6031ae08745Sheppo ddi_report_dev(dip); 6043af08d82Slm66018 vdc->lifecycle = VDC_LC_ONLINE; 6053af08d82Slm66018 DMSG(vdc, 0, "[%d] Attach tasks successful\n", instance); 6061ae08745Sheppo 6073af08d82Slm66018 return_status: 6083af08d82Slm66018 DMSG(vdc, 0, "[%d] Attach completed\n", instance); 6091ae08745Sheppo return (status); 6101ae08745Sheppo } 6111ae08745Sheppo 6121ae08745Sheppo static int 6131ae08745Sheppo vdc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 6141ae08745Sheppo { 6151ae08745Sheppo int status; 6161ae08745Sheppo 6171ae08745Sheppo switch (cmd) { 6181ae08745Sheppo case DDI_ATTACH: 6191ae08745Sheppo if ((status = vdc_do_attach(dip)) != 0) 6201ae08745Sheppo (void) vdc_detach(dip, DDI_DETACH); 6211ae08745Sheppo return (status); 6221ae08745Sheppo case DDI_RESUME: 6231ae08745Sheppo /* nothing to do for this non-device */ 6241ae08745Sheppo return (DDI_SUCCESS); 6251ae08745Sheppo default: 6261ae08745Sheppo return (DDI_FAILURE); 6271ae08745Sheppo } 6281ae08745Sheppo } 6291ae08745Sheppo 6301ae08745Sheppo static int 6311ae08745Sheppo vdc_do_ldc_init(vdc_t *vdc) 6321ae08745Sheppo { 6331ae08745Sheppo int status = 0; 6341ae08745Sheppo ldc_status_t ldc_state; 6351ae08745Sheppo ldc_attr_t ldc_attr; 6361ae08745Sheppo uint64_t ldc_id = 0; 6371ae08745Sheppo dev_info_t *dip = NULL; 6381ae08745Sheppo 6391ae08745Sheppo ASSERT(vdc != NULL); 6401ae08745Sheppo 6411ae08745Sheppo dip = vdc->dip; 6421ae08745Sheppo vdc->initialized |= VDC_LDC; 6431ae08745Sheppo 6441ae08745Sheppo if ((status = vdc_get_ldc_id(dip, &ldc_id)) != 0) { 6453af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to get LDC channel ID property", 646e1ebb9ecSlm66018 vdc->instance); 6471ae08745Sheppo return (EIO); 6481ae08745Sheppo } 6491ae08745Sheppo vdc->ldc_id = ldc_id; 6501ae08745Sheppo 6511ae08745Sheppo ldc_attr.devclass = LDC_DEV_BLK; 6521ae08745Sheppo ldc_attr.instance = vdc->instance; 6531ae08745Sheppo ldc_attr.mode = LDC_MODE_UNRELIABLE; /* unreliable transport */ 654e1ebb9ecSlm66018 ldc_attr.mtu = VD_LDC_MTU; 6551ae08745Sheppo 6561ae08745Sheppo if ((vdc->initialized & VDC_LDC_INIT) == 0) { 6571ae08745Sheppo status = ldc_init(ldc_id, &ldc_attr, &vdc->ldc_handle); 6581ae08745Sheppo if (status != 0) { 6593af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_init(chan %ld) returned %d", 6601ae08745Sheppo vdc->instance, ldc_id, status); 6611ae08745Sheppo return (status); 6621ae08745Sheppo } 6631ae08745Sheppo vdc->initialized |= VDC_LDC_INIT; 6641ae08745Sheppo } 6651ae08745Sheppo status = ldc_status(vdc->ldc_handle, &ldc_state); 6661ae08745Sheppo if (status != 0) { 6673af08d82Slm66018 DMSG(vdc, 0, "[%d] Cannot discover LDC status [err=%d]", 668e1ebb9ecSlm66018 vdc->instance, status); 6691ae08745Sheppo return (status); 6701ae08745Sheppo } 6711ae08745Sheppo vdc->ldc_state = ldc_state; 6721ae08745Sheppo 6731ae08745Sheppo if ((vdc->initialized & VDC_LDC_CB) == 0) { 6741ae08745Sheppo status = ldc_reg_callback(vdc->ldc_handle, vdc_handle_cb, 6751ae08745Sheppo (caddr_t)vdc); 6761ae08745Sheppo if (status != 0) { 6773af08d82Slm66018 DMSG(vdc, 0, "[%d] LDC callback reg. failed (%d)", 678e1ebb9ecSlm66018 vdc->instance, status); 6791ae08745Sheppo return (status); 6801ae08745Sheppo } 6811ae08745Sheppo vdc->initialized |= VDC_LDC_CB; 6821ae08745Sheppo } 6831ae08745Sheppo 6841ae08745Sheppo vdc->initialized |= VDC_LDC; 6851ae08745Sheppo 6861ae08745Sheppo /* 6871ae08745Sheppo * At this stage we have initialised LDC, we will now try and open 6881ae08745Sheppo * the connection. 6891ae08745Sheppo */ 6901ae08745Sheppo if (vdc->ldc_state == LDC_INIT) { 6911ae08745Sheppo status = ldc_open(vdc->ldc_handle); 6921ae08745Sheppo if (status != 0) { 6933af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_open(chan %ld) returned %d", 6941ae08745Sheppo vdc->instance, vdc->ldc_id, status); 6951ae08745Sheppo return (status); 6961ae08745Sheppo } 6971ae08745Sheppo vdc->initialized |= VDC_LDC_OPEN; 6981ae08745Sheppo } 6991ae08745Sheppo 7001ae08745Sheppo return (status); 7011ae08745Sheppo } 7021ae08745Sheppo 7031ae08745Sheppo static int 7041ae08745Sheppo vdc_start_ldc_connection(vdc_t *vdc) 7051ae08745Sheppo { 7061ae08745Sheppo int status = 0; 7071ae08745Sheppo 7081ae08745Sheppo ASSERT(vdc != NULL); 7091ae08745Sheppo 7103af08d82Slm66018 ASSERT(MUTEX_HELD(&vdc->lock)); 7111ae08745Sheppo 7120a55fbb7Slm66018 status = vdc_do_ldc_up(vdc); 7131ae08745Sheppo 7143af08d82Slm66018 DMSG(vdc, 0, "[%d] Finished bringing up LDC\n", vdc->instance); 7151ae08745Sheppo 7163af08d82Slm66018 return (status); 7173af08d82Slm66018 } 7183af08d82Slm66018 7193af08d82Slm66018 static int 7203af08d82Slm66018 vdc_stop_ldc_connection(vdc_t *vdcp) 7213af08d82Slm66018 { 7223af08d82Slm66018 int status; 7233af08d82Slm66018 7243af08d82Slm66018 DMSG(vdcp, 0, ": Resetting connection to vDisk server : state %d\n", 7253af08d82Slm66018 vdcp->state); 7263af08d82Slm66018 7273af08d82Slm66018 status = ldc_down(vdcp->ldc_handle); 7283af08d82Slm66018 DMSG(vdcp, 0, "ldc_down() = %d\n", status); 7293af08d82Slm66018 7303af08d82Slm66018 vdcp->initialized &= ~VDC_HANDSHAKE; 7313af08d82Slm66018 DMSG(vdcp, 0, "initialized=%x\n", vdcp->initialized); 7321ae08745Sheppo 7331ae08745Sheppo return (status); 7341ae08745Sheppo } 7351ae08745Sheppo 7364bac2208Snarayan static int 7374bac2208Snarayan vdc_create_device_nodes_efi(vdc_t *vdc) 7384bac2208Snarayan { 7394bac2208Snarayan ddi_remove_minor_node(vdc->dip, "h"); 7404bac2208Snarayan ddi_remove_minor_node(vdc->dip, "h,raw"); 7414bac2208Snarayan 7424bac2208Snarayan if (ddi_create_minor_node(vdc->dip, "wd", S_IFBLK, 7434bac2208Snarayan VD_MAKE_DEV(vdc->instance, VD_EFI_WD_SLICE), 7444bac2208Snarayan DDI_NT_BLOCK, 0) != DDI_SUCCESS) { 7454bac2208Snarayan cmn_err(CE_NOTE, "[%d] Couldn't add block node 'wd'", 7464bac2208Snarayan vdc->instance); 7474bac2208Snarayan return (EIO); 7484bac2208Snarayan } 7494bac2208Snarayan 7504bac2208Snarayan /* if any device node is created we set this flag */ 7514bac2208Snarayan vdc->initialized |= VDC_MINOR; 7524bac2208Snarayan 7534bac2208Snarayan if (ddi_create_minor_node(vdc->dip, "wd,raw", S_IFCHR, 7544bac2208Snarayan VD_MAKE_DEV(vdc->instance, VD_EFI_WD_SLICE), 7554bac2208Snarayan DDI_NT_BLOCK, 0) != DDI_SUCCESS) { 7564bac2208Snarayan cmn_err(CE_NOTE, "[%d] Couldn't add block node 'wd,raw'", 7574bac2208Snarayan vdc->instance); 7584bac2208Snarayan return (EIO); 7594bac2208Snarayan } 7604bac2208Snarayan 7614bac2208Snarayan return (0); 7624bac2208Snarayan } 7634bac2208Snarayan 7644bac2208Snarayan static int 7654bac2208Snarayan vdc_create_device_nodes_vtoc(vdc_t *vdc) 7664bac2208Snarayan { 7674bac2208Snarayan ddi_remove_minor_node(vdc->dip, "wd"); 7684bac2208Snarayan ddi_remove_minor_node(vdc->dip, "wd,raw"); 7694bac2208Snarayan 7704bac2208Snarayan if (ddi_create_minor_node(vdc->dip, "h", S_IFBLK, 7714bac2208Snarayan VD_MAKE_DEV(vdc->instance, VD_EFI_WD_SLICE), 7724bac2208Snarayan DDI_NT_BLOCK, 0) != DDI_SUCCESS) { 7734bac2208Snarayan cmn_err(CE_NOTE, "[%d] Couldn't add block node 'h'", 7744bac2208Snarayan vdc->instance); 7754bac2208Snarayan return (EIO); 7764bac2208Snarayan } 7774bac2208Snarayan 7784bac2208Snarayan /* if any device node is created we set this flag */ 7794bac2208Snarayan vdc->initialized |= VDC_MINOR; 7804bac2208Snarayan 7814bac2208Snarayan if (ddi_create_minor_node(vdc->dip, "h,raw", S_IFCHR, 7824bac2208Snarayan VD_MAKE_DEV(vdc->instance, VD_EFI_WD_SLICE), 7834bac2208Snarayan DDI_NT_BLOCK, 0) != DDI_SUCCESS) { 7844bac2208Snarayan cmn_err(CE_NOTE, "[%d] Couldn't add block node 'h,raw'", 7854bac2208Snarayan vdc->instance); 7864bac2208Snarayan return (EIO); 7874bac2208Snarayan } 7884bac2208Snarayan 7894bac2208Snarayan return (0); 7904bac2208Snarayan } 7911ae08745Sheppo 7921ae08745Sheppo /* 7931ae08745Sheppo * Function: 7941ae08745Sheppo * vdc_create_device_nodes 7951ae08745Sheppo * 7961ae08745Sheppo * Description: 7971ae08745Sheppo * This function creates the block and character device nodes under 7981ae08745Sheppo * /devices along with the node properties. It is called as part of 7991ae08745Sheppo * the attach(9E) of the instance during the handshake with vds after 8001ae08745Sheppo * vds has sent the attributes to vdc. 8011ae08745Sheppo * 8021ae08745Sheppo * If the device is of type VD_DISK_TYPE_SLICE then the minor node 8031ae08745Sheppo * of 2 is used in keeping with the Solaris convention that slice 2 8041ae08745Sheppo * refers to a whole disk. Slices start at 'a' 8051ae08745Sheppo * 8061ae08745Sheppo * Parameters: 8071ae08745Sheppo * vdc - soft state pointer 8081ae08745Sheppo * 8091ae08745Sheppo * Return Values 8101ae08745Sheppo * 0 - Success 8111ae08745Sheppo * EIO - Failed to create node 8121ae08745Sheppo * EINVAL - Unknown type of disk exported 8131ae08745Sheppo */ 8141ae08745Sheppo static int 8151ae08745Sheppo vdc_create_device_nodes(vdc_t *vdc) 8161ae08745Sheppo { 8174bac2208Snarayan char name[sizeof ("s,raw")]; 8181ae08745Sheppo dev_info_t *dip = NULL; 8194bac2208Snarayan int instance, status; 8201ae08745Sheppo int num_slices = 1; 8211ae08745Sheppo int i; 8221ae08745Sheppo 8231ae08745Sheppo ASSERT(vdc != NULL); 8241ae08745Sheppo 8251ae08745Sheppo instance = vdc->instance; 8261ae08745Sheppo dip = vdc->dip; 8271ae08745Sheppo 8281ae08745Sheppo switch (vdc->vdisk_type) { 8291ae08745Sheppo case VD_DISK_TYPE_DISK: 8301ae08745Sheppo num_slices = V_NUMPAR; 8311ae08745Sheppo break; 8321ae08745Sheppo case VD_DISK_TYPE_SLICE: 8331ae08745Sheppo num_slices = 1; 8341ae08745Sheppo break; 8351ae08745Sheppo case VD_DISK_TYPE_UNK: 8361ae08745Sheppo default: 8371ae08745Sheppo return (EINVAL); 8381ae08745Sheppo } 8391ae08745Sheppo 8404bac2208Snarayan /* 8414bac2208Snarayan * Minor nodes are different for EFI disks: EFI disks do not have 8424bac2208Snarayan * a minor node 'g' for the minor number corresponding to slice 8434bac2208Snarayan * VD_EFI_WD_SLICE (slice 7) instead they have a minor node 'wd' 8444bac2208Snarayan * representing the whole disk. 8454bac2208Snarayan */ 8461ae08745Sheppo for (i = 0; i < num_slices; i++) { 8474bac2208Snarayan 8484bac2208Snarayan if (i == VD_EFI_WD_SLICE) { 8494bac2208Snarayan if (vdc->vdisk_label == VD_DISK_LABEL_EFI) 8504bac2208Snarayan status = vdc_create_device_nodes_efi(vdc); 8514bac2208Snarayan else 8524bac2208Snarayan status = vdc_create_device_nodes_vtoc(vdc); 8534bac2208Snarayan if (status != 0) 8544bac2208Snarayan return (status); 8554bac2208Snarayan continue; 8564bac2208Snarayan } 8574bac2208Snarayan 8581ae08745Sheppo (void) snprintf(name, sizeof (name), "%c", 'a' + i); 8591ae08745Sheppo if (ddi_create_minor_node(dip, name, S_IFBLK, 8601ae08745Sheppo VD_MAKE_DEV(instance, i), DDI_NT_BLOCK, 0) != DDI_SUCCESS) { 861e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't add block node '%s'", 862e1ebb9ecSlm66018 instance, name); 8631ae08745Sheppo return (EIO); 8641ae08745Sheppo } 8651ae08745Sheppo 8661ae08745Sheppo /* if any device node is created we set this flag */ 8671ae08745Sheppo vdc->initialized |= VDC_MINOR; 8681ae08745Sheppo 86987a7269eSachartre (void) snprintf(name, sizeof (name), "%c%s", 'a' + i, ",raw"); 87087a7269eSachartre 8711ae08745Sheppo if (ddi_create_minor_node(dip, name, S_IFCHR, 8721ae08745Sheppo VD_MAKE_DEV(instance, i), DDI_NT_BLOCK, 0) != DDI_SUCCESS) { 873e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't add raw node '%s'", 874e1ebb9ecSlm66018 instance, name); 8751ae08745Sheppo return (EIO); 8761ae08745Sheppo } 8771ae08745Sheppo } 8781ae08745Sheppo 8791ae08745Sheppo return (0); 8801ae08745Sheppo } 8811ae08745Sheppo 8821ae08745Sheppo /* 8831ae08745Sheppo * Function: 8841ae08745Sheppo * vdc_create_device_nodes_props 8851ae08745Sheppo * 8861ae08745Sheppo * Description: 8871ae08745Sheppo * This function creates the block and character device nodes under 8881ae08745Sheppo * /devices along with the node properties. It is called as part of 8891ae08745Sheppo * the attach(9E) of the instance during the handshake with vds after 8901ae08745Sheppo * vds has sent the attributes to vdc. 8911ae08745Sheppo * 8921ae08745Sheppo * Parameters: 8931ae08745Sheppo * vdc - soft state pointer 8941ae08745Sheppo * 8951ae08745Sheppo * Return Values 8961ae08745Sheppo * 0 - Success 8971ae08745Sheppo * EIO - Failed to create device node property 8981ae08745Sheppo * EINVAL - Unknown type of disk exported 8991ae08745Sheppo */ 9001ae08745Sheppo static int 9011ae08745Sheppo vdc_create_device_nodes_props(vdc_t *vdc) 9021ae08745Sheppo { 9031ae08745Sheppo dev_info_t *dip = NULL; 9041ae08745Sheppo int instance; 9051ae08745Sheppo int num_slices = 1; 9061ae08745Sheppo int64_t size = 0; 9071ae08745Sheppo dev_t dev; 9081ae08745Sheppo int rv; 9091ae08745Sheppo int i; 9101ae08745Sheppo 9111ae08745Sheppo ASSERT(vdc != NULL); 9121ae08745Sheppo 9131ae08745Sheppo instance = vdc->instance; 9141ae08745Sheppo dip = vdc->dip; 9151ae08745Sheppo 9161ae08745Sheppo if ((vdc->vtoc == NULL) || (vdc->vtoc->v_sanity != VTOC_SANE)) { 9173af08d82Slm66018 DMSG(vdc, 0, "![%d] Could not create device node property." 9181ae08745Sheppo " No VTOC available", instance); 9191ae08745Sheppo return (ENXIO); 9201ae08745Sheppo } 9211ae08745Sheppo 9221ae08745Sheppo switch (vdc->vdisk_type) { 9231ae08745Sheppo case VD_DISK_TYPE_DISK: 9241ae08745Sheppo num_slices = V_NUMPAR; 9251ae08745Sheppo break; 9261ae08745Sheppo case VD_DISK_TYPE_SLICE: 9271ae08745Sheppo num_slices = 1; 9281ae08745Sheppo break; 9291ae08745Sheppo case VD_DISK_TYPE_UNK: 9301ae08745Sheppo default: 9311ae08745Sheppo return (EINVAL); 9321ae08745Sheppo } 9331ae08745Sheppo 9341ae08745Sheppo for (i = 0; i < num_slices; i++) { 9351ae08745Sheppo dev = makedevice(ddi_driver_major(dip), 9361ae08745Sheppo VD_MAKE_DEV(instance, i)); 9371ae08745Sheppo 9381ae08745Sheppo size = vdc->vtoc->v_part[i].p_size * vdc->vtoc->v_sectorsz; 9393af08d82Slm66018 DMSG(vdc, 0, "[%d] sz %ld (%ld Mb) p_size %lx\n", 940e1ebb9ecSlm66018 instance, size, size / (1024 * 1024), 9411ae08745Sheppo vdc->vtoc->v_part[i].p_size); 9421ae08745Sheppo 9431ae08745Sheppo rv = ddi_prop_update_int64(dev, dip, VDC_SIZE_PROP_NAME, size); 9441ae08745Sheppo if (rv != DDI_PROP_SUCCESS) { 945e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't add '%s' prop of [%ld]", 946e1ebb9ecSlm66018 instance, VDC_SIZE_PROP_NAME, size); 9471ae08745Sheppo return (EIO); 9481ae08745Sheppo } 9491ae08745Sheppo 9501ae08745Sheppo rv = ddi_prop_update_int64(dev, dip, VDC_NBLOCKS_PROP_NAME, 9511ae08745Sheppo lbtodb(size)); 9521ae08745Sheppo if (rv != DDI_PROP_SUCCESS) { 953e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't add '%s' prop [%llu]", 9541ae08745Sheppo instance, VDC_NBLOCKS_PROP_NAME, lbtodb(size)); 9551ae08745Sheppo return (EIO); 9561ae08745Sheppo } 9571ae08745Sheppo } 9581ae08745Sheppo 9591ae08745Sheppo return (0); 9601ae08745Sheppo } 9611ae08745Sheppo 9621ae08745Sheppo static int 9631ae08745Sheppo vdc_open(dev_t *dev, int flag, int otyp, cred_t *cred) 9641ae08745Sheppo { 9651ae08745Sheppo _NOTE(ARGUNUSED(cred)) 9661ae08745Sheppo 9671ae08745Sheppo int instance; 9681ae08745Sheppo vdc_t *vdc; 9691ae08745Sheppo 9701ae08745Sheppo ASSERT(dev != NULL); 9710d0c8d4bSnarayan instance = VDCUNIT(*dev); 9721ae08745Sheppo 9731ae08745Sheppo if ((otyp != OTYP_CHR) && (otyp != OTYP_BLK)) 9741ae08745Sheppo return (EINVAL); 9751ae08745Sheppo 9761ae08745Sheppo if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) { 977e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't get state structure", instance); 9781ae08745Sheppo return (ENXIO); 9791ae08745Sheppo } 9801ae08745Sheppo 9813af08d82Slm66018 DMSG(vdc, 0, "minor = %d flag = %x, otyp = %x\n", 9823af08d82Slm66018 getminor(*dev), flag, otyp); 9831ae08745Sheppo 9841ae08745Sheppo mutex_enter(&vdc->lock); 9853af08d82Slm66018 vdc->open_count++; 9861ae08745Sheppo mutex_exit(&vdc->lock); 9871ae08745Sheppo 9881ae08745Sheppo return (0); 9891ae08745Sheppo } 9901ae08745Sheppo 9911ae08745Sheppo static int 9921ae08745Sheppo vdc_close(dev_t dev, int flag, int otyp, cred_t *cred) 9931ae08745Sheppo { 9941ae08745Sheppo _NOTE(ARGUNUSED(cred)) 9951ae08745Sheppo 9961ae08745Sheppo int instance; 9971ae08745Sheppo vdc_t *vdc; 9981ae08745Sheppo 9990d0c8d4bSnarayan instance = VDCUNIT(dev); 10001ae08745Sheppo 10011ae08745Sheppo if ((otyp != OTYP_CHR) && (otyp != OTYP_BLK)) 10021ae08745Sheppo return (EINVAL); 10031ae08745Sheppo 10041ae08745Sheppo if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) { 1005e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't get state structure", instance); 10061ae08745Sheppo return (ENXIO); 10071ae08745Sheppo } 10081ae08745Sheppo 10093af08d82Slm66018 DMSG(vdc, 0, "[%d] flag = %x, otyp = %x\n", instance, flag, otyp); 10101ae08745Sheppo if (vdc->dkio_flush_pending) { 10113af08d82Slm66018 DMSG(vdc, 0, 10123af08d82Slm66018 "[%d] Cannot detach: %d outstanding DKIO flushes\n", 1013e1ebb9ecSlm66018 instance, vdc->dkio_flush_pending); 10141ae08745Sheppo return (EBUSY); 10151ae08745Sheppo } 10161ae08745Sheppo 10171ae08745Sheppo /* 10181ae08745Sheppo * Should not need the mutex here, since the framework should protect 10191ae08745Sheppo * against more opens on this device, but just in case. 10201ae08745Sheppo */ 10211ae08745Sheppo mutex_enter(&vdc->lock); 10223af08d82Slm66018 vdc->open_count--; 10231ae08745Sheppo mutex_exit(&vdc->lock); 10241ae08745Sheppo 10251ae08745Sheppo return (0); 10261ae08745Sheppo } 10271ae08745Sheppo 10281ae08745Sheppo static int 10291ae08745Sheppo vdc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) 10301ae08745Sheppo { 10311ae08745Sheppo _NOTE(ARGUNUSED(credp)) 10321ae08745Sheppo _NOTE(ARGUNUSED(rvalp)) 10331ae08745Sheppo 10341ae08745Sheppo return (vd_process_ioctl(dev, cmd, (caddr_t)arg, mode)); 10351ae08745Sheppo } 10361ae08745Sheppo 10371ae08745Sheppo static int 10381ae08745Sheppo vdc_print(dev_t dev, char *str) 10391ae08745Sheppo { 10400d0c8d4bSnarayan cmn_err(CE_NOTE, "vdc%d: %s", VDCUNIT(dev), str); 10411ae08745Sheppo return (0); 10421ae08745Sheppo } 10431ae08745Sheppo 10441ae08745Sheppo static int 10451ae08745Sheppo vdc_dump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk) 10461ae08745Sheppo { 1047d10e4ef2Snarayan int rv; 1048d10e4ef2Snarayan size_t nbytes = nblk * DEV_BSIZE; 10490d0c8d4bSnarayan int instance = VDCUNIT(dev); 1050d10e4ef2Snarayan vdc_t *vdc = NULL; 10511ae08745Sheppo 10521ae08745Sheppo if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) { 1053e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't get state structure", instance); 10541ae08745Sheppo return (ENXIO); 10551ae08745Sheppo } 10561ae08745Sheppo 10573af08d82Slm66018 DMSG(vdc, 2, "[%d] dump %ld bytes at block 0x%lx : addr=0x%p\n", 10583af08d82Slm66018 instance, nbytes, blkno, (void *)addr); 10593af08d82Slm66018 rv = vdc_send_request(vdc, VD_OP_BWRITE, addr, nbytes, 10600d0c8d4bSnarayan VDCPART(dev), blkno, CB_STRATEGY, 0, VIO_write_dir); 10613af08d82Slm66018 if (rv) { 10623af08d82Slm66018 DMSG(vdc, 0, "Failed to do a disk dump (err=%d)\n", rv); 10631ae08745Sheppo return (rv); 10641ae08745Sheppo } 10651ae08745Sheppo 10663af08d82Slm66018 if (ddi_in_panic()) 10673af08d82Slm66018 (void) vdc_drain_response(vdc); 10683af08d82Slm66018 10693af08d82Slm66018 DMSG(vdc, 0, "[%d] End\n", instance); 10703af08d82Slm66018 10713af08d82Slm66018 return (0); 10723af08d82Slm66018 } 10733af08d82Slm66018 10741ae08745Sheppo /* -------------------------------------------------------------------------- */ 10751ae08745Sheppo 10761ae08745Sheppo /* 10771ae08745Sheppo * Disk access routines 10781ae08745Sheppo * 10791ae08745Sheppo */ 10801ae08745Sheppo 10811ae08745Sheppo /* 10821ae08745Sheppo * vdc_strategy() 10831ae08745Sheppo * 10841ae08745Sheppo * Return Value: 10851ae08745Sheppo * 0: As per strategy(9E), the strategy() function must return 0 10861ae08745Sheppo * [ bioerror(9f) sets b_flags to the proper error code ] 10871ae08745Sheppo */ 10881ae08745Sheppo static int 10891ae08745Sheppo vdc_strategy(struct buf *buf) 10901ae08745Sheppo { 10911ae08745Sheppo int rv = -1; 10921ae08745Sheppo vdc_t *vdc = NULL; 10930d0c8d4bSnarayan int instance = VDCUNIT(buf->b_edev); 10941ae08745Sheppo int op = (buf->b_flags & B_READ) ? VD_OP_BREAD : VD_OP_BWRITE; 109587a7269eSachartre int slice; 10961ae08745Sheppo 10971ae08745Sheppo if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) { 1098e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't get state structure", instance); 10991ae08745Sheppo bioerror(buf, ENXIO); 11001ae08745Sheppo biodone(buf); 11011ae08745Sheppo return (0); 11021ae08745Sheppo } 11031ae08745Sheppo 11043af08d82Slm66018 DMSG(vdc, 2, "[%d] %s %ld bytes at block %llx : b_addr=0x%p\n", 11053af08d82Slm66018 instance, (buf->b_flags & B_READ) ? "Read" : "Write", 11063af08d82Slm66018 buf->b_bcount, buf->b_lblkno, (void *)buf->b_un.b_addr); 1107d10e4ef2Snarayan DTRACE_IO2(vstart, buf_t *, buf, vdc_t *, vdc); 1108d10e4ef2Snarayan 11091ae08745Sheppo bp_mapin(buf); 11101ae08745Sheppo 111187a7269eSachartre if ((long)buf->b_private == VD_SLICE_NONE) { 111287a7269eSachartre /* I/O using an absolute disk offset */ 111387a7269eSachartre slice = VD_SLICE_NONE; 111487a7269eSachartre } else { 111587a7269eSachartre slice = VDCPART(buf->b_edev); 111687a7269eSachartre } 111787a7269eSachartre 11183af08d82Slm66018 rv = vdc_send_request(vdc, op, (caddr_t)buf->b_un.b_addr, 111987a7269eSachartre buf->b_bcount, slice, buf->b_lblkno, 11203af08d82Slm66018 CB_STRATEGY, buf, (op == VD_OP_BREAD) ? VIO_read_dir : 11213af08d82Slm66018 VIO_write_dir); 11223af08d82Slm66018 1123d10e4ef2Snarayan /* 1124d10e4ef2Snarayan * If the request was successfully sent, the strategy call returns and 1125d10e4ef2Snarayan * the ACK handler calls the bioxxx functions when the vDisk server is 1126d10e4ef2Snarayan * done. 1127d10e4ef2Snarayan */ 1128d10e4ef2Snarayan if (rv) { 11293af08d82Slm66018 DMSG(vdc, 0, "Failed to read/write (err=%d)\n", rv); 11301ae08745Sheppo bioerror(buf, rv); 11311ae08745Sheppo biodone(buf); 1132d10e4ef2Snarayan } 1133d10e4ef2Snarayan 11341ae08745Sheppo return (0); 11351ae08745Sheppo } 11361ae08745Sheppo 11370d0c8d4bSnarayan /* 11380d0c8d4bSnarayan * Function: 11390d0c8d4bSnarayan * vdc_min 11400d0c8d4bSnarayan * 11410d0c8d4bSnarayan * Description: 11420d0c8d4bSnarayan * Routine to limit the size of a data transfer. Used in 11430d0c8d4bSnarayan * conjunction with physio(9F). 11440d0c8d4bSnarayan * 11450d0c8d4bSnarayan * Arguments: 11460d0c8d4bSnarayan * bp - pointer to the indicated buf(9S) struct. 11470d0c8d4bSnarayan * 11480d0c8d4bSnarayan */ 11490d0c8d4bSnarayan static void 11500d0c8d4bSnarayan vdc_min(struct buf *bufp) 11510d0c8d4bSnarayan { 11520d0c8d4bSnarayan vdc_t *vdc = NULL; 11530d0c8d4bSnarayan int instance = VDCUNIT(bufp->b_edev); 11540d0c8d4bSnarayan 11550d0c8d4bSnarayan vdc = ddi_get_soft_state(vdc_state, instance); 11560d0c8d4bSnarayan VERIFY(vdc != NULL); 11570d0c8d4bSnarayan 11580d0c8d4bSnarayan if (bufp->b_bcount > (vdc->max_xfer_sz * vdc->block_size)) { 11590d0c8d4bSnarayan bufp->b_bcount = vdc->max_xfer_sz * vdc->block_size; 11600d0c8d4bSnarayan } 11610d0c8d4bSnarayan } 11621ae08745Sheppo 11631ae08745Sheppo static int 11641ae08745Sheppo vdc_read(dev_t dev, struct uio *uio, cred_t *cred) 11651ae08745Sheppo { 11661ae08745Sheppo _NOTE(ARGUNUSED(cred)) 11671ae08745Sheppo 11680d0c8d4bSnarayan DMSGX(1, "[%d] Entered", VDCUNIT(dev)); 11690d0c8d4bSnarayan return (physio(vdc_strategy, NULL, dev, B_READ, vdc_min, uio)); 11701ae08745Sheppo } 11711ae08745Sheppo 11721ae08745Sheppo static int 11731ae08745Sheppo vdc_write(dev_t dev, struct uio *uio, cred_t *cred) 11741ae08745Sheppo { 11751ae08745Sheppo _NOTE(ARGUNUSED(cred)) 11761ae08745Sheppo 11770d0c8d4bSnarayan DMSGX(1, "[%d] Entered", VDCUNIT(dev)); 11780d0c8d4bSnarayan return (physio(vdc_strategy, NULL, dev, B_WRITE, vdc_min, uio)); 11791ae08745Sheppo } 11801ae08745Sheppo 11811ae08745Sheppo static int 11821ae08745Sheppo vdc_aread(dev_t dev, struct aio_req *aio, cred_t *cred) 11831ae08745Sheppo { 11841ae08745Sheppo _NOTE(ARGUNUSED(cred)) 11851ae08745Sheppo 11860d0c8d4bSnarayan DMSGX(1, "[%d] Entered", VDCUNIT(dev)); 11870d0c8d4bSnarayan return (aphysio(vdc_strategy, anocancel, dev, B_READ, vdc_min, aio)); 11881ae08745Sheppo } 11891ae08745Sheppo 11901ae08745Sheppo static int 11911ae08745Sheppo vdc_awrite(dev_t dev, struct aio_req *aio, cred_t *cred) 11921ae08745Sheppo { 11931ae08745Sheppo _NOTE(ARGUNUSED(cred)) 11941ae08745Sheppo 11950d0c8d4bSnarayan DMSGX(1, "[%d] Entered", VDCUNIT(dev)); 11960d0c8d4bSnarayan return (aphysio(vdc_strategy, anocancel, dev, B_WRITE, vdc_min, aio)); 11971ae08745Sheppo } 11981ae08745Sheppo 11991ae08745Sheppo 12001ae08745Sheppo /* -------------------------------------------------------------------------- */ 12011ae08745Sheppo 12021ae08745Sheppo /* 12031ae08745Sheppo * Handshake support 12041ae08745Sheppo */ 12051ae08745Sheppo 12061ae08745Sheppo 12070a55fbb7Slm66018 /* 12080a55fbb7Slm66018 * Function: 12090a55fbb7Slm66018 * vdc_init_ver_negotiation() 12100a55fbb7Slm66018 * 12110a55fbb7Slm66018 * Description: 12120a55fbb7Slm66018 * 12130a55fbb7Slm66018 * Arguments: 12140a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 12150a55fbb7Slm66018 * 12160a55fbb7Slm66018 * Return Code: 12170a55fbb7Slm66018 * 0 - Success 12180a55fbb7Slm66018 */ 12191ae08745Sheppo static int 12200a55fbb7Slm66018 vdc_init_ver_negotiation(vdc_t *vdc, vio_ver_t ver) 12211ae08745Sheppo { 12221ae08745Sheppo vio_ver_msg_t pkt; 12231ae08745Sheppo size_t msglen = sizeof (pkt); 12241ae08745Sheppo int status = -1; 12251ae08745Sheppo 12261ae08745Sheppo ASSERT(vdc != NULL); 12271ae08745Sheppo ASSERT(mutex_owned(&vdc->lock)); 12281ae08745Sheppo 12293af08d82Slm66018 DMSG(vdc, 0, "[%d] Entered.\n", vdc->instance); 1230e1ebb9ecSlm66018 12311ae08745Sheppo /* 12321ae08745Sheppo * set the Session ID to a unique value 12331ae08745Sheppo * (the lower 32 bits of the clock tick) 12341ae08745Sheppo */ 12351ae08745Sheppo vdc->session_id = ((uint32_t)gettick() & 0xffffffff); 12363af08d82Slm66018 DMSG(vdc, 0, "[%d] Set SID to 0x%lx\n", vdc->instance, vdc->session_id); 12371ae08745Sheppo 12381ae08745Sheppo pkt.tag.vio_msgtype = VIO_TYPE_CTRL; 12391ae08745Sheppo pkt.tag.vio_subtype = VIO_SUBTYPE_INFO; 12401ae08745Sheppo pkt.tag.vio_subtype_env = VIO_VER_INFO; 12411ae08745Sheppo pkt.tag.vio_sid = vdc->session_id; 12421ae08745Sheppo pkt.dev_class = VDEV_DISK; 12430a55fbb7Slm66018 pkt.ver_major = ver.major; 12440a55fbb7Slm66018 pkt.ver_minor = ver.minor; 12451ae08745Sheppo 12460a55fbb7Slm66018 status = vdc_send(vdc, (caddr_t)&pkt, &msglen); 12473af08d82Slm66018 DMSG(vdc, 0, "[%d] Ver info sent (status = %d)\n", 12483af08d82Slm66018 vdc->instance, status); 12491ae08745Sheppo if ((status != 0) || (msglen != sizeof (vio_ver_msg_t))) { 12503af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to send Ver negotiation info: " 125187a7269eSachartre "id(%lx) rv(%d) size(%ld)", vdc->instance, vdc->ldc_handle, 12521ae08745Sheppo status, msglen); 12531ae08745Sheppo if (msglen != sizeof (vio_ver_msg_t)) 12541ae08745Sheppo status = ENOMSG; 12551ae08745Sheppo } 12561ae08745Sheppo 12571ae08745Sheppo return (status); 12581ae08745Sheppo } 12591ae08745Sheppo 12600a55fbb7Slm66018 /* 12610a55fbb7Slm66018 * Function: 12623af08d82Slm66018 * vdc_ver_negotiation() 12633af08d82Slm66018 * 12643af08d82Slm66018 * Description: 12653af08d82Slm66018 * 12663af08d82Slm66018 * Arguments: 12673af08d82Slm66018 * vdcp - soft state pointer for this instance of the device driver. 12683af08d82Slm66018 * 12693af08d82Slm66018 * Return Code: 12703af08d82Slm66018 * 0 - Success 12713af08d82Slm66018 */ 12723af08d82Slm66018 static int 12733af08d82Slm66018 vdc_ver_negotiation(vdc_t *vdcp) 12743af08d82Slm66018 { 12753af08d82Slm66018 vio_msg_t vio_msg; 12763af08d82Slm66018 int status; 12773af08d82Slm66018 12783af08d82Slm66018 if (status = vdc_init_ver_negotiation(vdcp, vdc_version[0])) 12793af08d82Slm66018 return (status); 12803af08d82Slm66018 12813af08d82Slm66018 /* release lock and wait for response */ 12823af08d82Slm66018 mutex_exit(&vdcp->lock); 12833af08d82Slm66018 status = vdc_wait_for_response(vdcp, &vio_msg); 12843af08d82Slm66018 mutex_enter(&vdcp->lock); 12853af08d82Slm66018 if (status) { 12863af08d82Slm66018 DMSG(vdcp, 0, 12873af08d82Slm66018 "[%d] Failed waiting for Ver negotiation response, rv(%d)", 12883af08d82Slm66018 vdcp->instance, status); 12893af08d82Slm66018 return (status); 12903af08d82Slm66018 } 12913af08d82Slm66018 12923af08d82Slm66018 /* check type and sub_type ... */ 12933af08d82Slm66018 if (vio_msg.tag.vio_msgtype != VIO_TYPE_CTRL || 12943af08d82Slm66018 vio_msg.tag.vio_subtype == VIO_SUBTYPE_INFO) { 12953af08d82Slm66018 DMSG(vdcp, 0, "[%d] Invalid ver negotiation response\n", 12963af08d82Slm66018 vdcp->instance); 12973af08d82Slm66018 return (EPROTO); 12983af08d82Slm66018 } 12993af08d82Slm66018 13003af08d82Slm66018 return (vdc_handle_ver_msg(vdcp, (vio_ver_msg_t *)&vio_msg)); 13013af08d82Slm66018 } 13023af08d82Slm66018 13033af08d82Slm66018 /* 13043af08d82Slm66018 * Function: 13050a55fbb7Slm66018 * vdc_init_attr_negotiation() 13060a55fbb7Slm66018 * 13070a55fbb7Slm66018 * Description: 13080a55fbb7Slm66018 * 13090a55fbb7Slm66018 * Arguments: 13100a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 13110a55fbb7Slm66018 * 13120a55fbb7Slm66018 * Return Code: 13130a55fbb7Slm66018 * 0 - Success 13140a55fbb7Slm66018 */ 13151ae08745Sheppo static int 13161ae08745Sheppo vdc_init_attr_negotiation(vdc_t *vdc) 13171ae08745Sheppo { 13181ae08745Sheppo vd_attr_msg_t pkt; 13191ae08745Sheppo size_t msglen = sizeof (pkt); 13201ae08745Sheppo int status; 13211ae08745Sheppo 13221ae08745Sheppo ASSERT(vdc != NULL); 13231ae08745Sheppo ASSERT(mutex_owned(&vdc->lock)); 13241ae08745Sheppo 13253af08d82Slm66018 DMSG(vdc, 0, "[%d] entered\n", vdc->instance); 13261ae08745Sheppo 13271ae08745Sheppo /* fill in tag */ 13281ae08745Sheppo pkt.tag.vio_msgtype = VIO_TYPE_CTRL; 13291ae08745Sheppo pkt.tag.vio_subtype = VIO_SUBTYPE_INFO; 13301ae08745Sheppo pkt.tag.vio_subtype_env = VIO_ATTR_INFO; 13311ae08745Sheppo pkt.tag.vio_sid = vdc->session_id; 13321ae08745Sheppo /* fill in payload */ 13331ae08745Sheppo pkt.max_xfer_sz = vdc->max_xfer_sz; 13341ae08745Sheppo pkt.vdisk_block_size = vdc->block_size; 13351ae08745Sheppo pkt.xfer_mode = VIO_DRING_MODE; 13361ae08745Sheppo pkt.operations = 0; /* server will set bits of valid operations */ 13371ae08745Sheppo pkt.vdisk_type = 0; /* server will set to valid device type */ 13381ae08745Sheppo pkt.vdisk_size = 0; /* server will set to valid size */ 13391ae08745Sheppo 13400a55fbb7Slm66018 status = vdc_send(vdc, (caddr_t)&pkt, &msglen); 13413af08d82Slm66018 DMSG(vdc, 0, "Attr info sent (status = %d)\n", status); 13421ae08745Sheppo 13431ae08745Sheppo if ((status != 0) || (msglen != sizeof (vio_ver_msg_t))) { 13443af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to send Attr negotiation info: " 134587a7269eSachartre "id(%lx) rv(%d) size(%ld)", vdc->instance, vdc->ldc_handle, 13461ae08745Sheppo status, msglen); 13471ae08745Sheppo if (msglen != sizeof (vio_ver_msg_t)) 13481ae08745Sheppo status = ENOMSG; 13491ae08745Sheppo } 13501ae08745Sheppo 13511ae08745Sheppo return (status); 13521ae08745Sheppo } 13531ae08745Sheppo 13540a55fbb7Slm66018 /* 13550a55fbb7Slm66018 * Function: 13563af08d82Slm66018 * vdc_attr_negotiation() 13573af08d82Slm66018 * 13583af08d82Slm66018 * Description: 13593af08d82Slm66018 * 13603af08d82Slm66018 * Arguments: 13613af08d82Slm66018 * vdc - soft state pointer for this instance of the device driver. 13623af08d82Slm66018 * 13633af08d82Slm66018 * Return Code: 13643af08d82Slm66018 * 0 - Success 13653af08d82Slm66018 */ 13663af08d82Slm66018 static int 13673af08d82Slm66018 vdc_attr_negotiation(vdc_t *vdcp) 13683af08d82Slm66018 { 13693af08d82Slm66018 int status; 13703af08d82Slm66018 vio_msg_t vio_msg; 13713af08d82Slm66018 13723af08d82Slm66018 if (status = vdc_init_attr_negotiation(vdcp)) 13733af08d82Slm66018 return (status); 13743af08d82Slm66018 13753af08d82Slm66018 /* release lock and wait for response */ 13763af08d82Slm66018 mutex_exit(&vdcp->lock); 13773af08d82Slm66018 status = vdc_wait_for_response(vdcp, &vio_msg); 13783af08d82Slm66018 mutex_enter(&vdcp->lock); 13793af08d82Slm66018 if (status) { 13803af08d82Slm66018 DMSG(vdcp, 0, 13813af08d82Slm66018 "[%d] Failed waiting for Attr negotiation response, rv(%d)", 13823af08d82Slm66018 vdcp->instance, status); 13833af08d82Slm66018 return (status); 13843af08d82Slm66018 } 13853af08d82Slm66018 13863af08d82Slm66018 /* check type and sub_type ... */ 13873af08d82Slm66018 if (vio_msg.tag.vio_msgtype != VIO_TYPE_CTRL || 13883af08d82Slm66018 vio_msg.tag.vio_subtype == VIO_SUBTYPE_INFO) { 13893af08d82Slm66018 DMSG(vdcp, 0, "[%d] Invalid attr negotiation response\n", 13903af08d82Slm66018 vdcp->instance); 13913af08d82Slm66018 return (EPROTO); 13923af08d82Slm66018 } 13933af08d82Slm66018 13943af08d82Slm66018 return (vdc_handle_attr_msg(vdcp, (vd_attr_msg_t *)&vio_msg)); 13953af08d82Slm66018 } 13963af08d82Slm66018 13973af08d82Slm66018 13983af08d82Slm66018 /* 13993af08d82Slm66018 * Function: 14000a55fbb7Slm66018 * vdc_init_dring_negotiate() 14010a55fbb7Slm66018 * 14020a55fbb7Slm66018 * Description: 14030a55fbb7Slm66018 * 14040a55fbb7Slm66018 * Arguments: 14050a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 14060a55fbb7Slm66018 * 14070a55fbb7Slm66018 * Return Code: 14080a55fbb7Slm66018 * 0 - Success 14090a55fbb7Slm66018 */ 14101ae08745Sheppo static int 14111ae08745Sheppo vdc_init_dring_negotiate(vdc_t *vdc) 14121ae08745Sheppo { 14131ae08745Sheppo vio_dring_reg_msg_t pkt; 14141ae08745Sheppo size_t msglen = sizeof (pkt); 14151ae08745Sheppo int status = -1; 14163af08d82Slm66018 int retry; 14173af08d82Slm66018 int nretries = 10; 14181ae08745Sheppo 14191ae08745Sheppo ASSERT(vdc != NULL); 14201ae08745Sheppo ASSERT(mutex_owned(&vdc->lock)); 14211ae08745Sheppo 14223af08d82Slm66018 for (retry = 0; retry < nretries; retry++) { 14231ae08745Sheppo status = vdc_init_descriptor_ring(vdc); 14243af08d82Slm66018 if (status != EAGAIN) 14253af08d82Slm66018 break; 14263af08d82Slm66018 drv_usecwait(vdc_min_timeout_ldc); 14273af08d82Slm66018 } 14283af08d82Slm66018 14291ae08745Sheppo if (status != 0) { 14303af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to init DRing (status = %d)\n", 14311ae08745Sheppo vdc->instance, status); 14321ae08745Sheppo return (status); 14331ae08745Sheppo } 14343af08d82Slm66018 14353af08d82Slm66018 DMSG(vdc, 0, "[%d] Init of descriptor ring completed (status = %d)\n", 1436e1ebb9ecSlm66018 vdc->instance, status); 14371ae08745Sheppo 14381ae08745Sheppo /* fill in tag */ 14391ae08745Sheppo pkt.tag.vio_msgtype = VIO_TYPE_CTRL; 14401ae08745Sheppo pkt.tag.vio_subtype = VIO_SUBTYPE_INFO; 14411ae08745Sheppo pkt.tag.vio_subtype_env = VIO_DRING_REG; 14421ae08745Sheppo pkt.tag.vio_sid = vdc->session_id; 14431ae08745Sheppo /* fill in payload */ 14441ae08745Sheppo pkt.dring_ident = 0; 1445e1ebb9ecSlm66018 pkt.num_descriptors = vdc->dring_len; 1446e1ebb9ecSlm66018 pkt.descriptor_size = vdc->dring_entry_size; 14471ae08745Sheppo pkt.options = (VIO_TX_DRING | VIO_RX_DRING); 14481ae08745Sheppo pkt.ncookies = vdc->dring_cookie_count; 14491ae08745Sheppo pkt.cookie[0] = vdc->dring_cookie[0]; /* for now just one cookie */ 14501ae08745Sheppo 14510a55fbb7Slm66018 status = vdc_send(vdc, (caddr_t)&pkt, &msglen); 14521ae08745Sheppo if (status != 0) { 14533af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to register DRing (err = %d)", 1454e1ebb9ecSlm66018 vdc->instance, status); 14551ae08745Sheppo } 14561ae08745Sheppo 14571ae08745Sheppo return (status); 14581ae08745Sheppo } 14591ae08745Sheppo 14601ae08745Sheppo 14613af08d82Slm66018 /* 14623af08d82Slm66018 * Function: 14633af08d82Slm66018 * vdc_dring_negotiation() 14643af08d82Slm66018 * 14653af08d82Slm66018 * Description: 14663af08d82Slm66018 * 14673af08d82Slm66018 * Arguments: 14683af08d82Slm66018 * vdc - soft state pointer for this instance of the device driver. 14693af08d82Slm66018 * 14703af08d82Slm66018 * Return Code: 14713af08d82Slm66018 * 0 - Success 14723af08d82Slm66018 */ 14733af08d82Slm66018 static int 14743af08d82Slm66018 vdc_dring_negotiation(vdc_t *vdcp) 14753af08d82Slm66018 { 14763af08d82Slm66018 int status; 14773af08d82Slm66018 vio_msg_t vio_msg; 14783af08d82Slm66018 14793af08d82Slm66018 if (status = vdc_init_dring_negotiate(vdcp)) 14803af08d82Slm66018 return (status); 14813af08d82Slm66018 14823af08d82Slm66018 /* release lock and wait for response */ 14833af08d82Slm66018 mutex_exit(&vdcp->lock); 14843af08d82Slm66018 status = vdc_wait_for_response(vdcp, &vio_msg); 14853af08d82Slm66018 mutex_enter(&vdcp->lock); 14863af08d82Slm66018 if (status) { 14873af08d82Slm66018 DMSG(vdcp, 0, 14883af08d82Slm66018 "[%d] Failed waiting for Dring negotiation response," 14893af08d82Slm66018 " rv(%d)", vdcp->instance, status); 14903af08d82Slm66018 return (status); 14913af08d82Slm66018 } 14923af08d82Slm66018 14933af08d82Slm66018 /* check type and sub_type ... */ 14943af08d82Slm66018 if (vio_msg.tag.vio_msgtype != VIO_TYPE_CTRL || 14953af08d82Slm66018 vio_msg.tag.vio_subtype == VIO_SUBTYPE_INFO) { 14963af08d82Slm66018 DMSG(vdcp, 0, "[%d] Invalid Dring negotiation response\n", 14973af08d82Slm66018 vdcp->instance); 14983af08d82Slm66018 return (EPROTO); 14993af08d82Slm66018 } 15003af08d82Slm66018 15013af08d82Slm66018 return (vdc_handle_dring_reg_msg(vdcp, 15023af08d82Slm66018 (vio_dring_reg_msg_t *)&vio_msg)); 15033af08d82Slm66018 } 15043af08d82Slm66018 15053af08d82Slm66018 15063af08d82Slm66018 /* 15073af08d82Slm66018 * Function: 15083af08d82Slm66018 * vdc_send_rdx() 15093af08d82Slm66018 * 15103af08d82Slm66018 * Description: 15113af08d82Slm66018 * 15123af08d82Slm66018 * Arguments: 15133af08d82Slm66018 * vdc - soft state pointer for this instance of the device driver. 15143af08d82Slm66018 * 15153af08d82Slm66018 * Return Code: 15163af08d82Slm66018 * 0 - Success 15173af08d82Slm66018 */ 15183af08d82Slm66018 static int 15193af08d82Slm66018 vdc_send_rdx(vdc_t *vdcp) 15203af08d82Slm66018 { 15213af08d82Slm66018 vio_msg_t msg; 15223af08d82Slm66018 size_t msglen = sizeof (vio_msg_t); 15233af08d82Slm66018 int status; 15243af08d82Slm66018 15253af08d82Slm66018 /* 15263af08d82Slm66018 * Send an RDX message to vds to indicate we are ready 15273af08d82Slm66018 * to send data 15283af08d82Slm66018 */ 15293af08d82Slm66018 msg.tag.vio_msgtype = VIO_TYPE_CTRL; 15303af08d82Slm66018 msg.tag.vio_subtype = VIO_SUBTYPE_INFO; 15313af08d82Slm66018 msg.tag.vio_subtype_env = VIO_RDX; 15323af08d82Slm66018 msg.tag.vio_sid = vdcp->session_id; 15333af08d82Slm66018 status = vdc_send(vdcp, (caddr_t)&msg, &msglen); 15343af08d82Slm66018 if (status != 0) { 15353af08d82Slm66018 DMSG(vdcp, 0, "[%d] Failed to send RDX message (%d)", 15363af08d82Slm66018 vdcp->instance, status); 15373af08d82Slm66018 } 15383af08d82Slm66018 15393af08d82Slm66018 return (status); 15403af08d82Slm66018 } 15413af08d82Slm66018 15423af08d82Slm66018 /* 15433af08d82Slm66018 * Function: 15443af08d82Slm66018 * vdc_handle_rdx() 15453af08d82Slm66018 * 15463af08d82Slm66018 * Description: 15473af08d82Slm66018 * 15483af08d82Slm66018 * Arguments: 15493af08d82Slm66018 * vdc - soft state pointer for this instance of the device driver. 15503af08d82Slm66018 * msgp - received msg 15513af08d82Slm66018 * 15523af08d82Slm66018 * Return Code: 15533af08d82Slm66018 * 0 - Success 15543af08d82Slm66018 */ 15553af08d82Slm66018 static int 15563af08d82Slm66018 vdc_handle_rdx(vdc_t *vdcp, vio_rdx_msg_t *msgp) 15573af08d82Slm66018 { 15583af08d82Slm66018 _NOTE(ARGUNUSED(vdcp)) 15593af08d82Slm66018 _NOTE(ARGUNUSED(msgp)) 15603af08d82Slm66018 15613af08d82Slm66018 ASSERT(msgp->tag.vio_msgtype == VIO_TYPE_CTRL); 15623af08d82Slm66018 ASSERT(msgp->tag.vio_subtype == VIO_SUBTYPE_ACK); 15633af08d82Slm66018 ASSERT(msgp->tag.vio_subtype_env == VIO_RDX); 15643af08d82Slm66018 15653af08d82Slm66018 DMSG(vdcp, 1, "[%d] Got an RDX msg", vdcp->instance); 15663af08d82Slm66018 15673af08d82Slm66018 return (0); 15683af08d82Slm66018 } 15693af08d82Slm66018 15703af08d82Slm66018 /* 15713af08d82Slm66018 * Function: 15723af08d82Slm66018 * vdc_rdx_exchange() 15733af08d82Slm66018 * 15743af08d82Slm66018 * Description: 15753af08d82Slm66018 * 15763af08d82Slm66018 * Arguments: 15773af08d82Slm66018 * vdc - soft state pointer for this instance of the device driver. 15783af08d82Slm66018 * 15793af08d82Slm66018 * Return Code: 15803af08d82Slm66018 * 0 - Success 15813af08d82Slm66018 */ 15823af08d82Slm66018 static int 15833af08d82Slm66018 vdc_rdx_exchange(vdc_t *vdcp) 15843af08d82Slm66018 { 15853af08d82Slm66018 int status; 15863af08d82Slm66018 vio_msg_t vio_msg; 15873af08d82Slm66018 15883af08d82Slm66018 if (status = vdc_send_rdx(vdcp)) 15893af08d82Slm66018 return (status); 15903af08d82Slm66018 15913af08d82Slm66018 /* release lock and wait for response */ 15923af08d82Slm66018 mutex_exit(&vdcp->lock); 15933af08d82Slm66018 status = vdc_wait_for_response(vdcp, &vio_msg); 15943af08d82Slm66018 mutex_enter(&vdcp->lock); 15953af08d82Slm66018 if (status) { 159687a7269eSachartre DMSG(vdcp, 0, "[%d] Failed waiting for RDX response, rv(%d)", 159787a7269eSachartre vdcp->instance, status); 15983af08d82Slm66018 return (status); 15993af08d82Slm66018 } 16003af08d82Slm66018 16013af08d82Slm66018 /* check type and sub_type ... */ 16023af08d82Slm66018 if (vio_msg.tag.vio_msgtype != VIO_TYPE_CTRL || 16033af08d82Slm66018 vio_msg.tag.vio_subtype != VIO_SUBTYPE_ACK) { 160487a7269eSachartre DMSG(vdcp, 0, "[%d] Invalid RDX response\n", vdcp->instance); 16053af08d82Slm66018 return (EPROTO); 16063af08d82Slm66018 } 16073af08d82Slm66018 16083af08d82Slm66018 return (vdc_handle_rdx(vdcp, (vio_rdx_msg_t *)&vio_msg)); 16093af08d82Slm66018 } 16103af08d82Slm66018 16113af08d82Slm66018 16121ae08745Sheppo /* -------------------------------------------------------------------------- */ 16131ae08745Sheppo 16141ae08745Sheppo /* 16151ae08745Sheppo * LDC helper routines 16161ae08745Sheppo */ 16171ae08745Sheppo 16183af08d82Slm66018 static int 16193af08d82Slm66018 vdc_recv(vdc_t *vdc, vio_msg_t *msgp, size_t *nbytesp) 16203af08d82Slm66018 { 16213af08d82Slm66018 int status; 16223af08d82Slm66018 boolean_t q_has_pkts = B_FALSE; 16233af08d82Slm66018 int delay_time; 16243af08d82Slm66018 size_t len; 16253af08d82Slm66018 16263af08d82Slm66018 mutex_enter(&vdc->read_lock); 16273af08d82Slm66018 16283af08d82Slm66018 if (vdc->read_state == VDC_READ_IDLE) 16293af08d82Slm66018 vdc->read_state = VDC_READ_WAITING; 16303af08d82Slm66018 16313af08d82Slm66018 while (vdc->read_state != VDC_READ_PENDING) { 16323af08d82Slm66018 16333af08d82Slm66018 /* detect if the connection has been reset */ 16343af08d82Slm66018 if (vdc->read_state == VDC_READ_RESET) { 16353af08d82Slm66018 status = ECONNRESET; 16363af08d82Slm66018 goto done; 16373af08d82Slm66018 } 16383af08d82Slm66018 16393af08d82Slm66018 cv_wait(&vdc->read_cv, &vdc->read_lock); 16403af08d82Slm66018 } 16413af08d82Slm66018 16423af08d82Slm66018 /* 16433af08d82Slm66018 * Until we get a blocking ldc read we have to retry 16443af08d82Slm66018 * until the entire LDC message has arrived before 16453af08d82Slm66018 * ldc_read() will succeed. Note we also bail out if 1646eff7243fSlm66018 * the channel is reset or goes away. 16473af08d82Slm66018 */ 16483af08d82Slm66018 delay_time = vdc_ldc_read_init_delay; 16493af08d82Slm66018 loop: 16503af08d82Slm66018 len = *nbytesp; 16513af08d82Slm66018 status = ldc_read(vdc->ldc_handle, (caddr_t)msgp, &len); 16523af08d82Slm66018 switch (status) { 16533af08d82Slm66018 case EAGAIN: 16543af08d82Slm66018 delay_time *= 2; 16553af08d82Slm66018 if (delay_time >= vdc_ldc_read_max_delay) 16563af08d82Slm66018 delay_time = vdc_ldc_read_max_delay; 16573af08d82Slm66018 delay(delay_time); 16583af08d82Slm66018 goto loop; 16593af08d82Slm66018 16603af08d82Slm66018 case 0: 16613af08d82Slm66018 if (len == 0) { 16623af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_read returned 0 bytes with " 16633af08d82Slm66018 "no error!\n", vdc->instance); 16643af08d82Slm66018 goto loop; 16653af08d82Slm66018 } 16663af08d82Slm66018 16673af08d82Slm66018 *nbytesp = len; 16683af08d82Slm66018 16693af08d82Slm66018 /* 16703af08d82Slm66018 * If there are pending messages, leave the 16713af08d82Slm66018 * read state as pending. Otherwise, set the state 16723af08d82Slm66018 * back to idle. 16733af08d82Slm66018 */ 16743af08d82Slm66018 status = ldc_chkq(vdc->ldc_handle, &q_has_pkts); 16753af08d82Slm66018 if (status == 0 && !q_has_pkts) 16763af08d82Slm66018 vdc->read_state = VDC_READ_IDLE; 16773af08d82Slm66018 16783af08d82Slm66018 break; 16793af08d82Slm66018 default: 16803af08d82Slm66018 DMSG(vdc, 0, "ldc_read returned %d\n", status); 16813af08d82Slm66018 break; 16823af08d82Slm66018 } 16833af08d82Slm66018 16843af08d82Slm66018 done: 16853af08d82Slm66018 mutex_exit(&vdc->read_lock); 16863af08d82Slm66018 16873af08d82Slm66018 return (status); 16883af08d82Slm66018 } 16893af08d82Slm66018 16903af08d82Slm66018 16913af08d82Slm66018 16923af08d82Slm66018 #ifdef DEBUG 16933af08d82Slm66018 void 16943af08d82Slm66018 vdc_decode_tag(vdc_t *vdcp, vio_msg_t *msg) 16953af08d82Slm66018 { 16963af08d82Slm66018 char *ms, *ss, *ses; 16973af08d82Slm66018 switch (msg->tag.vio_msgtype) { 16983af08d82Slm66018 #define Q(_s) case _s : ms = #_s; break; 16993af08d82Slm66018 Q(VIO_TYPE_CTRL) 17003af08d82Slm66018 Q(VIO_TYPE_DATA) 17013af08d82Slm66018 Q(VIO_TYPE_ERR) 17023af08d82Slm66018 #undef Q 17033af08d82Slm66018 default: ms = "unknown"; break; 17043af08d82Slm66018 } 17053af08d82Slm66018 17063af08d82Slm66018 switch (msg->tag.vio_subtype) { 17073af08d82Slm66018 #define Q(_s) case _s : ss = #_s; break; 17083af08d82Slm66018 Q(VIO_SUBTYPE_INFO) 17093af08d82Slm66018 Q(VIO_SUBTYPE_ACK) 17103af08d82Slm66018 Q(VIO_SUBTYPE_NACK) 17113af08d82Slm66018 #undef Q 17123af08d82Slm66018 default: ss = "unknown"; break; 17133af08d82Slm66018 } 17143af08d82Slm66018 17153af08d82Slm66018 switch (msg->tag.vio_subtype_env) { 17163af08d82Slm66018 #define Q(_s) case _s : ses = #_s; break; 17173af08d82Slm66018 Q(VIO_VER_INFO) 17183af08d82Slm66018 Q(VIO_ATTR_INFO) 17193af08d82Slm66018 Q(VIO_DRING_REG) 17203af08d82Slm66018 Q(VIO_DRING_UNREG) 17213af08d82Slm66018 Q(VIO_RDX) 17223af08d82Slm66018 Q(VIO_PKT_DATA) 17233af08d82Slm66018 Q(VIO_DESC_DATA) 17243af08d82Slm66018 Q(VIO_DRING_DATA) 17253af08d82Slm66018 #undef Q 17263af08d82Slm66018 default: ses = "unknown"; break; 17273af08d82Slm66018 } 17283af08d82Slm66018 17293af08d82Slm66018 DMSG(vdcp, 3, "(%x/%x/%x) message : (%s/%s/%s)\n", 17303af08d82Slm66018 msg->tag.vio_msgtype, msg->tag.vio_subtype, 17313af08d82Slm66018 msg->tag.vio_subtype_env, ms, ss, ses); 17323af08d82Slm66018 } 17333af08d82Slm66018 #endif 17343af08d82Slm66018 17351ae08745Sheppo /* 17361ae08745Sheppo * Function: 17371ae08745Sheppo * vdc_send() 17381ae08745Sheppo * 17391ae08745Sheppo * Description: 17401ae08745Sheppo * The function encapsulates the call to write a message using LDC. 17411ae08745Sheppo * If LDC indicates that the call failed due to the queue being full, 17421ae08745Sheppo * we retry the ldc_write() [ up to 'vdc_retries' time ], otherwise 17431ae08745Sheppo * we return the error returned by LDC. 17441ae08745Sheppo * 17451ae08745Sheppo * Arguments: 17461ae08745Sheppo * ldc_handle - LDC handle for the channel this instance of vdc uses 17471ae08745Sheppo * pkt - address of LDC message to be sent 17481ae08745Sheppo * msglen - the size of the message being sent. When the function 17491ae08745Sheppo * returns, this contains the number of bytes written. 17501ae08745Sheppo * 17511ae08745Sheppo * Return Code: 17521ae08745Sheppo * 0 - Success. 17531ae08745Sheppo * EINVAL - pkt or msglen were NULL 17541ae08745Sheppo * ECONNRESET - The connection was not up. 17551ae08745Sheppo * EWOULDBLOCK - LDC queue is full 17561ae08745Sheppo * xxx - other error codes returned by ldc_write 17571ae08745Sheppo */ 17581ae08745Sheppo static int 17590a55fbb7Slm66018 vdc_send(vdc_t *vdc, caddr_t pkt, size_t *msglen) 17601ae08745Sheppo { 17611ae08745Sheppo size_t size = 0; 17621ae08745Sheppo int status = 0; 17633af08d82Slm66018 clock_t delay_ticks; 17641ae08745Sheppo 17650a55fbb7Slm66018 ASSERT(vdc != NULL); 17660a55fbb7Slm66018 ASSERT(mutex_owned(&vdc->lock)); 17671ae08745Sheppo ASSERT(msglen != NULL); 17681ae08745Sheppo ASSERT(*msglen != 0); 17691ae08745Sheppo 17703af08d82Slm66018 #ifdef DEBUG 17713af08d82Slm66018 vdc_decode_tag(vdc, (vio_msg_t *)pkt); 17723af08d82Slm66018 #endif 17733af08d82Slm66018 /* 17743af08d82Slm66018 * Wait indefinitely to send if channel 17753af08d82Slm66018 * is busy, but bail out if we succeed or 17763af08d82Slm66018 * if the channel closes or is reset. 17773af08d82Slm66018 */ 17783af08d82Slm66018 delay_ticks = vdc_hz_min_ldc_delay; 17791ae08745Sheppo do { 17801ae08745Sheppo size = *msglen; 17810a55fbb7Slm66018 status = ldc_write(vdc->ldc_handle, pkt, &size); 17823af08d82Slm66018 if (status == EWOULDBLOCK) { 17833af08d82Slm66018 delay(delay_ticks); 17843af08d82Slm66018 /* geometric backoff */ 17853af08d82Slm66018 delay_ticks *= 2; 17863af08d82Slm66018 if (delay_ticks > vdc_hz_max_ldc_delay) 17873af08d82Slm66018 delay_ticks = vdc_hz_max_ldc_delay; 17883af08d82Slm66018 } 17893af08d82Slm66018 } while (status == EWOULDBLOCK); 17901ae08745Sheppo 17910a55fbb7Slm66018 /* if LDC had serious issues --- reset vdc state */ 17920a55fbb7Slm66018 if (status == EIO || status == ECONNRESET) { 17933af08d82Slm66018 /* LDC had serious issues --- reset vdc state */ 17943af08d82Slm66018 mutex_enter(&vdc->read_lock); 17953af08d82Slm66018 if ((vdc->read_state == VDC_READ_WAITING) || 17963af08d82Slm66018 (vdc->read_state == VDC_READ_RESET)) 17973af08d82Slm66018 cv_signal(&vdc->read_cv); 17983af08d82Slm66018 vdc->read_state = VDC_READ_RESET; 17993af08d82Slm66018 mutex_exit(&vdc->read_lock); 18003af08d82Slm66018 18013af08d82Slm66018 /* wake up any waiters in the reset thread */ 18023af08d82Slm66018 if (vdc->state == VDC_STATE_INIT_WAITING) { 18033af08d82Slm66018 DMSG(vdc, 0, "[%d] write reset - " 18043af08d82Slm66018 "vdc is resetting ..\n", vdc->instance); 18053af08d82Slm66018 vdc->state = VDC_STATE_RESETTING; 18063af08d82Slm66018 cv_signal(&vdc->initwait_cv); 18073af08d82Slm66018 } 18083af08d82Slm66018 18093af08d82Slm66018 return (ECONNRESET); 18100a55fbb7Slm66018 } 18110a55fbb7Slm66018 18121ae08745Sheppo /* return the last size written */ 18131ae08745Sheppo *msglen = size; 18141ae08745Sheppo 18151ae08745Sheppo return (status); 18161ae08745Sheppo } 18171ae08745Sheppo 18181ae08745Sheppo /* 18191ae08745Sheppo * Function: 18201ae08745Sheppo * vdc_get_ldc_id() 18211ae08745Sheppo * 18221ae08745Sheppo * Description: 18231ae08745Sheppo * This function gets the 'ldc-id' for this particular instance of vdc. 18241ae08745Sheppo * The id returned is the guest domain channel endpoint LDC uses for 18251ae08745Sheppo * communication with vds. 18261ae08745Sheppo * 18271ae08745Sheppo * Arguments: 18281ae08745Sheppo * dip - dev info pointer for this instance of the device driver. 18291ae08745Sheppo * ldc_id - pointer to variable used to return the 'ldc-id' found. 18301ae08745Sheppo * 18311ae08745Sheppo * Return Code: 18321ae08745Sheppo * 0 - Success. 18331ae08745Sheppo * ENOENT - Expected node or property did not exist. 18341ae08745Sheppo * ENXIO - Unexpected error communicating with MD framework 18351ae08745Sheppo */ 18361ae08745Sheppo static int 18371ae08745Sheppo vdc_get_ldc_id(dev_info_t *dip, uint64_t *ldc_id) 18381ae08745Sheppo { 18391ae08745Sheppo int status = ENOENT; 18401ae08745Sheppo char *node_name = NULL; 18411ae08745Sheppo md_t *mdp = NULL; 18421ae08745Sheppo int num_nodes; 18431ae08745Sheppo int num_vdevs; 18441ae08745Sheppo int num_chans; 18451ae08745Sheppo mde_cookie_t rootnode; 18461ae08745Sheppo mde_cookie_t *listp = NULL; 18471ae08745Sheppo mde_cookie_t *chanp = NULL; 18481ae08745Sheppo boolean_t found_inst = B_FALSE; 18491ae08745Sheppo int listsz; 18501ae08745Sheppo int idx; 18511ae08745Sheppo uint64_t md_inst; 18521ae08745Sheppo int obp_inst; 18531ae08745Sheppo int instance = ddi_get_instance(dip); 18541ae08745Sheppo 18551ae08745Sheppo ASSERT(ldc_id != NULL); 18561ae08745Sheppo *ldc_id = 0; 18571ae08745Sheppo 18581ae08745Sheppo /* 18591ae08745Sheppo * Get the OBP instance number for comparison with the MD instance 18601ae08745Sheppo * 18611ae08745Sheppo * The "cfg-handle" property of a vdc node in an MD contains the MD's 18621ae08745Sheppo * notion of "instance", or unique identifier, for that node; OBP 18631ae08745Sheppo * stores the value of the "cfg-handle" MD property as the value of 18641ae08745Sheppo * the "reg" property on the node in the device tree it builds from 18651ae08745Sheppo * the MD and passes to Solaris. Thus, we look up the devinfo node's 18661ae08745Sheppo * "reg" property value to uniquely identify this device instance. 18671ae08745Sheppo * If the "reg" property cannot be found, the device tree state is 18681ae08745Sheppo * presumably so broken that there is no point in continuing. 18691ae08745Sheppo */ 18701ae08745Sheppo if (!ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, OBP_REG)) { 18711ae08745Sheppo cmn_err(CE_WARN, "'%s' property does not exist", OBP_REG); 18721ae08745Sheppo return (ENOENT); 18731ae08745Sheppo } 18741ae08745Sheppo obp_inst = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 18751ae08745Sheppo OBP_REG, -1); 18763af08d82Slm66018 DMSGX(1, "[%d] OBP inst=%d\n", instance, obp_inst); 18771ae08745Sheppo 18781ae08745Sheppo /* 18791ae08745Sheppo * We now walk the MD nodes and if an instance of a vdc node matches 18801ae08745Sheppo * the instance got from OBP we get the ldc-id property. 18811ae08745Sheppo */ 18821ae08745Sheppo if ((mdp = md_get_handle()) == NULL) { 18831ae08745Sheppo cmn_err(CE_WARN, "unable to init machine description"); 18841ae08745Sheppo return (ENXIO); 18851ae08745Sheppo } 18861ae08745Sheppo 18871ae08745Sheppo num_nodes = md_node_count(mdp); 18881ae08745Sheppo ASSERT(num_nodes > 0); 18891ae08745Sheppo 18901ae08745Sheppo listsz = num_nodes * sizeof (mde_cookie_t); 18911ae08745Sheppo 18921ae08745Sheppo /* allocate memory for nodes */ 18931ae08745Sheppo listp = kmem_zalloc(listsz, KM_SLEEP); 18941ae08745Sheppo chanp = kmem_zalloc(listsz, KM_SLEEP); 18951ae08745Sheppo 18961ae08745Sheppo rootnode = md_root_node(mdp); 18971ae08745Sheppo ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE); 18981ae08745Sheppo 18991ae08745Sheppo /* 19001ae08745Sheppo * Search for all the virtual devices, we will then check to see which 19011ae08745Sheppo * ones are disk nodes. 19021ae08745Sheppo */ 19031ae08745Sheppo num_vdevs = md_scan_dag(mdp, rootnode, 19041ae08745Sheppo md_find_name(mdp, VDC_MD_VDEV_NAME), 19051ae08745Sheppo md_find_name(mdp, "fwd"), listp); 19061ae08745Sheppo 19071ae08745Sheppo if (num_vdevs <= 0) { 19081ae08745Sheppo cmn_err(CE_NOTE, "No '%s' node found", VDC_MD_VDEV_NAME); 19091ae08745Sheppo status = ENOENT; 19101ae08745Sheppo goto done; 19111ae08745Sheppo } 19121ae08745Sheppo 19133af08d82Slm66018 DMSGX(1, "[%d] num_vdevs=%d\n", instance, num_vdevs); 19141ae08745Sheppo for (idx = 0; idx < num_vdevs; idx++) { 19151ae08745Sheppo status = md_get_prop_str(mdp, listp[idx], "name", &node_name); 19161ae08745Sheppo if ((status != 0) || (node_name == NULL)) { 19171ae08745Sheppo cmn_err(CE_NOTE, "Unable to get name of node type '%s'" 19181ae08745Sheppo ": err %d", VDC_MD_VDEV_NAME, status); 19191ae08745Sheppo continue; 19201ae08745Sheppo } 19211ae08745Sheppo 19223af08d82Slm66018 DMSGX(1, "[%d] Found node '%s'\n", instance, node_name); 19231ae08745Sheppo if (strcmp(VDC_MD_DISK_NAME, node_name) == 0) { 19241ae08745Sheppo status = md_get_prop_val(mdp, listp[idx], 19251ae08745Sheppo VDC_MD_CFG_HDL, &md_inst); 19263af08d82Slm66018 DMSGX(1, "[%d] vdc inst in MD=%lx\n", 19273af08d82Slm66018 instance, md_inst); 19281ae08745Sheppo if ((status == 0) && (md_inst == obp_inst)) { 19291ae08745Sheppo found_inst = B_TRUE; 19301ae08745Sheppo break; 19311ae08745Sheppo } 19321ae08745Sheppo } 19331ae08745Sheppo } 19341ae08745Sheppo 19350a55fbb7Slm66018 if (!found_inst) { 19363af08d82Slm66018 DMSGX(0, "Unable to find correct '%s' node", VDC_MD_DISK_NAME); 19371ae08745Sheppo status = ENOENT; 19381ae08745Sheppo goto done; 19391ae08745Sheppo } 19403af08d82Slm66018 DMSGX(0, "[%d] MD inst=%lx\n", instance, md_inst); 19411ae08745Sheppo 19421ae08745Sheppo /* get the channels for this node */ 19431ae08745Sheppo num_chans = md_scan_dag(mdp, listp[idx], 19441ae08745Sheppo md_find_name(mdp, VDC_MD_CHAN_NAME), 19451ae08745Sheppo md_find_name(mdp, "fwd"), chanp); 19461ae08745Sheppo 19471ae08745Sheppo /* expecting at least one channel */ 19481ae08745Sheppo if (num_chans <= 0) { 19491ae08745Sheppo cmn_err(CE_NOTE, "No '%s' node for '%s' port", 19501ae08745Sheppo VDC_MD_CHAN_NAME, VDC_MD_VDEV_NAME); 19511ae08745Sheppo status = ENOENT; 19521ae08745Sheppo goto done; 19531ae08745Sheppo 19541ae08745Sheppo } else if (num_chans != 1) { 19553af08d82Slm66018 DMSGX(0, "[%d] Expected 1 '%s' node for '%s' port, found %d\n", 1956e1ebb9ecSlm66018 instance, VDC_MD_CHAN_NAME, VDC_MD_VDEV_NAME, 19571ae08745Sheppo num_chans); 19581ae08745Sheppo } 19591ae08745Sheppo 19601ae08745Sheppo /* 19611ae08745Sheppo * We use the first channel found (index 0), irrespective of how 19621ae08745Sheppo * many are there in total. 19631ae08745Sheppo */ 19641ae08745Sheppo if (md_get_prop_val(mdp, chanp[0], VDC_ID_PROP, ldc_id) != 0) { 19651ae08745Sheppo cmn_err(CE_NOTE, "Channel '%s' property not found", 19661ae08745Sheppo VDC_ID_PROP); 19671ae08745Sheppo status = ENOENT; 19681ae08745Sheppo } 19691ae08745Sheppo 19703af08d82Slm66018 DMSGX(0, "[%d] LDC id is 0x%lx\n", instance, *ldc_id); 19711ae08745Sheppo 19721ae08745Sheppo done: 19731ae08745Sheppo if (chanp) 19741ae08745Sheppo kmem_free(chanp, listsz); 19751ae08745Sheppo if (listp) 19761ae08745Sheppo kmem_free(listp, listsz); 19771ae08745Sheppo 19781ae08745Sheppo (void) md_fini_handle(mdp); 19791ae08745Sheppo 19801ae08745Sheppo return (status); 19811ae08745Sheppo } 19821ae08745Sheppo 19830a55fbb7Slm66018 static int 19840a55fbb7Slm66018 vdc_do_ldc_up(vdc_t *vdc) 19850a55fbb7Slm66018 { 19860a55fbb7Slm66018 int status; 19873af08d82Slm66018 ldc_status_t ldc_state; 19880a55fbb7Slm66018 19893af08d82Slm66018 DMSG(vdc, 0, "[%d] Bringing up channel %lx\n", 19903af08d82Slm66018 vdc->instance, vdc->ldc_id); 19913af08d82Slm66018 19923af08d82Slm66018 if (vdc->lifecycle == VDC_LC_DETACHING) 19933af08d82Slm66018 return (EINVAL); 19940a55fbb7Slm66018 19950a55fbb7Slm66018 if ((status = ldc_up(vdc->ldc_handle)) != 0) { 19960a55fbb7Slm66018 switch (status) { 19970a55fbb7Slm66018 case ECONNREFUSED: /* listener not ready at other end */ 19983af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_up(%lx,...) return %d\n", 1999e1ebb9ecSlm66018 vdc->instance, vdc->ldc_id, status); 20000a55fbb7Slm66018 status = 0; 20010a55fbb7Slm66018 break; 20020a55fbb7Slm66018 default: 20033af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to bring up LDC: " 20043af08d82Slm66018 "channel=%ld, err=%d", vdc->instance, vdc->ldc_id, 20053af08d82Slm66018 status); 20063af08d82Slm66018 break; 20073af08d82Slm66018 } 20083af08d82Slm66018 } 20093af08d82Slm66018 20103af08d82Slm66018 if (ldc_status(vdc->ldc_handle, &ldc_state) == 0) { 20113af08d82Slm66018 vdc->ldc_state = ldc_state; 20123af08d82Slm66018 if (ldc_state == LDC_UP) { 20133af08d82Slm66018 DMSG(vdc, 0, "[%d] LDC channel already up\n", 20143af08d82Slm66018 vdc->instance); 20153af08d82Slm66018 vdc->seq_num = 1; 20163af08d82Slm66018 vdc->seq_num_reply = 0; 20170a55fbb7Slm66018 } 20180a55fbb7Slm66018 } 20190a55fbb7Slm66018 20200a55fbb7Slm66018 return (status); 20210a55fbb7Slm66018 } 20220a55fbb7Slm66018 20230a55fbb7Slm66018 /* 20240a55fbb7Slm66018 * Function: 20250a55fbb7Slm66018 * vdc_terminate_ldc() 20260a55fbb7Slm66018 * 20270a55fbb7Slm66018 * Description: 20280a55fbb7Slm66018 * 20290a55fbb7Slm66018 * Arguments: 20300a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 20310a55fbb7Slm66018 * 20320a55fbb7Slm66018 * Return Code: 20330a55fbb7Slm66018 * None 20340a55fbb7Slm66018 */ 20351ae08745Sheppo static void 20361ae08745Sheppo vdc_terminate_ldc(vdc_t *vdc) 20371ae08745Sheppo { 20381ae08745Sheppo int instance = ddi_get_instance(vdc->dip); 20391ae08745Sheppo 20401ae08745Sheppo ASSERT(vdc != NULL); 20411ae08745Sheppo ASSERT(mutex_owned(&vdc->lock)); 20421ae08745Sheppo 20433af08d82Slm66018 DMSG(vdc, 0, "[%d] initialized=%x\n", instance, vdc->initialized); 20441ae08745Sheppo 20451ae08745Sheppo if (vdc->initialized & VDC_LDC_OPEN) { 20463af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_close()\n", instance); 20471ae08745Sheppo (void) ldc_close(vdc->ldc_handle); 20481ae08745Sheppo } 20491ae08745Sheppo if (vdc->initialized & VDC_LDC_CB) { 20503af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_unreg_callback()\n", instance); 20511ae08745Sheppo (void) ldc_unreg_callback(vdc->ldc_handle); 20521ae08745Sheppo } 20531ae08745Sheppo if (vdc->initialized & VDC_LDC) { 20543af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_fini()\n", instance); 20551ae08745Sheppo (void) ldc_fini(vdc->ldc_handle); 20561ae08745Sheppo vdc->ldc_handle = NULL; 20571ae08745Sheppo } 20581ae08745Sheppo 20591ae08745Sheppo vdc->initialized &= ~(VDC_LDC | VDC_LDC_CB | VDC_LDC_OPEN); 20601ae08745Sheppo } 20611ae08745Sheppo 20621ae08745Sheppo /* -------------------------------------------------------------------------- */ 20631ae08745Sheppo 20641ae08745Sheppo /* 20651ae08745Sheppo * Descriptor Ring helper routines 20661ae08745Sheppo */ 20671ae08745Sheppo 20680a55fbb7Slm66018 /* 20690a55fbb7Slm66018 * Function: 20700a55fbb7Slm66018 * vdc_init_descriptor_ring() 20710a55fbb7Slm66018 * 20720a55fbb7Slm66018 * Description: 20730a55fbb7Slm66018 * 20740a55fbb7Slm66018 * Arguments: 20750a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 20760a55fbb7Slm66018 * 20770a55fbb7Slm66018 * Return Code: 20780a55fbb7Slm66018 * 0 - Success 20790a55fbb7Slm66018 */ 20801ae08745Sheppo static int 20811ae08745Sheppo vdc_init_descriptor_ring(vdc_t *vdc) 20821ae08745Sheppo { 20831ae08745Sheppo vd_dring_entry_t *dep = NULL; /* DRing Entry pointer */ 20840a55fbb7Slm66018 int status = 0; 20851ae08745Sheppo int i; 20861ae08745Sheppo 20873af08d82Slm66018 DMSG(vdc, 0, "[%d] initialized=%x\n", vdc->instance, vdc->initialized); 20881ae08745Sheppo 20891ae08745Sheppo ASSERT(vdc != NULL); 20901ae08745Sheppo ASSERT(mutex_owned(&vdc->lock)); 20911ae08745Sheppo ASSERT(vdc->ldc_handle != NULL); 20921ae08745Sheppo 2093e1ebb9ecSlm66018 /* ensure we have enough room to store max sized block */ 2094e1ebb9ecSlm66018 ASSERT(maxphys <= VD_MAX_BLOCK_SIZE); 2095e1ebb9ecSlm66018 20960a55fbb7Slm66018 if ((vdc->initialized & VDC_DRING_INIT) == 0) { 20973af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_mem_dring_create\n", vdc->instance); 2098e1ebb9ecSlm66018 /* 2099e1ebb9ecSlm66018 * Calculate the maximum block size we can transmit using one 2100e1ebb9ecSlm66018 * Descriptor Ring entry from the attributes returned by the 2101e1ebb9ecSlm66018 * vDisk server. This is subject to a minimum of 'maxphys' 2102e1ebb9ecSlm66018 * as we do not have the capability to split requests over 2103e1ebb9ecSlm66018 * multiple DRing entries. 2104e1ebb9ecSlm66018 */ 2105e1ebb9ecSlm66018 if ((vdc->max_xfer_sz * vdc->block_size) < maxphys) { 21063af08d82Slm66018 DMSG(vdc, 0, "[%d] using minimum DRing size\n", 2107e1ebb9ecSlm66018 vdc->instance); 2108e1ebb9ecSlm66018 vdc->dring_max_cookies = maxphys / PAGESIZE; 2109e1ebb9ecSlm66018 } else { 2110e1ebb9ecSlm66018 vdc->dring_max_cookies = 2111e1ebb9ecSlm66018 (vdc->max_xfer_sz * vdc->block_size) / PAGESIZE; 2112e1ebb9ecSlm66018 } 2113e1ebb9ecSlm66018 vdc->dring_entry_size = (sizeof (vd_dring_entry_t) + 2114e1ebb9ecSlm66018 (sizeof (ldc_mem_cookie_t) * 2115e1ebb9ecSlm66018 (vdc->dring_max_cookies - 1))); 2116e1ebb9ecSlm66018 vdc->dring_len = VD_DRING_LEN; 2117e1ebb9ecSlm66018 2118e1ebb9ecSlm66018 status = ldc_mem_dring_create(vdc->dring_len, 2119e1ebb9ecSlm66018 vdc->dring_entry_size, &vdc->ldc_dring_hdl); 21201ae08745Sheppo if ((vdc->ldc_dring_hdl == NULL) || (status != 0)) { 21213af08d82Slm66018 DMSG(vdc, 0, "[%d] Descriptor ring creation failed", 2122e1ebb9ecSlm66018 vdc->instance); 21231ae08745Sheppo return (status); 21241ae08745Sheppo } 21250a55fbb7Slm66018 vdc->initialized |= VDC_DRING_INIT; 21260a55fbb7Slm66018 } 21271ae08745Sheppo 21280a55fbb7Slm66018 if ((vdc->initialized & VDC_DRING_BOUND) == 0) { 21293af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_mem_dring_bind\n", vdc->instance); 21300a55fbb7Slm66018 vdc->dring_cookie = 21310a55fbb7Slm66018 kmem_zalloc(sizeof (ldc_mem_cookie_t), KM_SLEEP); 21321ae08745Sheppo 21331ae08745Sheppo status = ldc_mem_dring_bind(vdc->ldc_handle, vdc->ldc_dring_hdl, 21344bac2208Snarayan LDC_SHADOW_MAP|LDC_DIRECT_MAP, LDC_MEM_RW, 21350a55fbb7Slm66018 &vdc->dring_cookie[0], 21361ae08745Sheppo &vdc->dring_cookie_count); 21371ae08745Sheppo if (status != 0) { 21383af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to bind descriptor ring " 21393af08d82Slm66018 "(%lx) to channel (%lx) status=%d\n", 21403af08d82Slm66018 vdc->instance, vdc->ldc_dring_hdl, 21413af08d82Slm66018 vdc->ldc_handle, status); 21421ae08745Sheppo return (status); 21431ae08745Sheppo } 21441ae08745Sheppo ASSERT(vdc->dring_cookie_count == 1); 21451ae08745Sheppo vdc->initialized |= VDC_DRING_BOUND; 21460a55fbb7Slm66018 } 21471ae08745Sheppo 21481ae08745Sheppo status = ldc_mem_dring_info(vdc->ldc_dring_hdl, &vdc->dring_mem_info); 21491ae08745Sheppo if (status != 0) { 21503af08d82Slm66018 DMSG(vdc, 0, 21513af08d82Slm66018 "[%d] Failed to get info for descriptor ring (%lx)\n", 2152e1ebb9ecSlm66018 vdc->instance, vdc->ldc_dring_hdl); 21531ae08745Sheppo return (status); 21541ae08745Sheppo } 21551ae08745Sheppo 21560a55fbb7Slm66018 if ((vdc->initialized & VDC_DRING_LOCAL) == 0) { 21573af08d82Slm66018 DMSG(vdc, 0, "[%d] local dring\n", vdc->instance); 21580a55fbb7Slm66018 21591ae08745Sheppo /* Allocate the local copy of this dring */ 21600a55fbb7Slm66018 vdc->local_dring = 2161e1ebb9ecSlm66018 kmem_zalloc(vdc->dring_len * sizeof (vdc_local_desc_t), 21621ae08745Sheppo KM_SLEEP); 21631ae08745Sheppo vdc->initialized |= VDC_DRING_LOCAL; 21640a55fbb7Slm66018 } 21651ae08745Sheppo 21661ae08745Sheppo /* 21670a55fbb7Slm66018 * Mark all DRing entries as free and initialize the private 21680a55fbb7Slm66018 * descriptor's memory handles. If any entry is initialized, 21690a55fbb7Slm66018 * we need to free it later so we set the bit in 'initialized' 21700a55fbb7Slm66018 * at the start. 21711ae08745Sheppo */ 21721ae08745Sheppo vdc->initialized |= VDC_DRING_ENTRY; 2173e1ebb9ecSlm66018 for (i = 0; i < vdc->dring_len; i++) { 21741ae08745Sheppo dep = VDC_GET_DRING_ENTRY_PTR(vdc, i); 21751ae08745Sheppo dep->hdr.dstate = VIO_DESC_FREE; 21761ae08745Sheppo 21771ae08745Sheppo status = ldc_mem_alloc_handle(vdc->ldc_handle, 21781ae08745Sheppo &vdc->local_dring[i].desc_mhdl); 21791ae08745Sheppo if (status != 0) { 21803af08d82Slm66018 DMSG(vdc, 0, "![%d] Failed to alloc mem handle for" 21811ae08745Sheppo " descriptor %d", vdc->instance, i); 21821ae08745Sheppo return (status); 21831ae08745Sheppo } 21843af08d82Slm66018 vdc->local_dring[i].is_free = B_TRUE; 21851ae08745Sheppo vdc->local_dring[i].dep = dep; 21861ae08745Sheppo } 21871ae08745Sheppo 21883af08d82Slm66018 /* Initialize the starting index */ 21893af08d82Slm66018 vdc->dring_curr_idx = 0; 21901ae08745Sheppo 21911ae08745Sheppo return (status); 21921ae08745Sheppo } 21931ae08745Sheppo 21940a55fbb7Slm66018 /* 21950a55fbb7Slm66018 * Function: 21960a55fbb7Slm66018 * vdc_destroy_descriptor_ring() 21970a55fbb7Slm66018 * 21980a55fbb7Slm66018 * Description: 21990a55fbb7Slm66018 * 22000a55fbb7Slm66018 * Arguments: 22010a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 22020a55fbb7Slm66018 * 22030a55fbb7Slm66018 * Return Code: 22040a55fbb7Slm66018 * None 22050a55fbb7Slm66018 */ 22061ae08745Sheppo static void 22071ae08745Sheppo vdc_destroy_descriptor_ring(vdc_t *vdc) 22081ae08745Sheppo { 22090a55fbb7Slm66018 vdc_local_desc_t *ldep = NULL; /* Local Dring Entry Pointer */ 22101ae08745Sheppo ldc_mem_handle_t mhdl = NULL; 22113af08d82Slm66018 ldc_mem_info_t minfo; 22121ae08745Sheppo int status = -1; 22131ae08745Sheppo int i; /* loop */ 22141ae08745Sheppo 22151ae08745Sheppo ASSERT(vdc != NULL); 22161ae08745Sheppo ASSERT(mutex_owned(&vdc->lock)); 22171ae08745Sheppo 22183af08d82Slm66018 DMSG(vdc, 0, "[%d] Entered\n", vdc->instance); 22191ae08745Sheppo 22201ae08745Sheppo if (vdc->initialized & VDC_DRING_ENTRY) { 22213af08d82Slm66018 DMSG(vdc, 0, 22223af08d82Slm66018 "[%d] Removing Local DRing entries\n", vdc->instance); 2223e1ebb9ecSlm66018 for (i = 0; i < vdc->dring_len; i++) { 22240a55fbb7Slm66018 ldep = &vdc->local_dring[i]; 22250a55fbb7Slm66018 mhdl = ldep->desc_mhdl; 22261ae08745Sheppo 22270a55fbb7Slm66018 if (mhdl == NULL) 22280a55fbb7Slm66018 continue; 22290a55fbb7Slm66018 22303af08d82Slm66018 if ((status = ldc_mem_info(mhdl, &minfo)) != 0) { 22313af08d82Slm66018 DMSG(vdc, 0, 22323af08d82Slm66018 "ldc_mem_info returned an error: %d\n", 22333af08d82Slm66018 status); 22343af08d82Slm66018 22353af08d82Slm66018 /* 22363af08d82Slm66018 * This must mean that the mem handle 22373af08d82Slm66018 * is not valid. Clear it out so that 22383af08d82Slm66018 * no one tries to use it. 22393af08d82Slm66018 */ 22403af08d82Slm66018 ldep->desc_mhdl = NULL; 22413af08d82Slm66018 continue; 22423af08d82Slm66018 } 22433af08d82Slm66018 22443af08d82Slm66018 if (minfo.status == LDC_BOUND) { 22453af08d82Slm66018 (void) ldc_mem_unbind_handle(mhdl); 22463af08d82Slm66018 } 22473af08d82Slm66018 22481ae08745Sheppo (void) ldc_mem_free_handle(mhdl); 22493af08d82Slm66018 22503af08d82Slm66018 ldep->desc_mhdl = NULL; 22511ae08745Sheppo } 22521ae08745Sheppo vdc->initialized &= ~VDC_DRING_ENTRY; 22531ae08745Sheppo } 22541ae08745Sheppo 22551ae08745Sheppo if (vdc->initialized & VDC_DRING_LOCAL) { 22563af08d82Slm66018 DMSG(vdc, 0, "[%d] Freeing Local DRing\n", vdc->instance); 22571ae08745Sheppo kmem_free(vdc->local_dring, 2258e1ebb9ecSlm66018 vdc->dring_len * sizeof (vdc_local_desc_t)); 22591ae08745Sheppo vdc->initialized &= ~VDC_DRING_LOCAL; 22601ae08745Sheppo } 22611ae08745Sheppo 22621ae08745Sheppo if (vdc->initialized & VDC_DRING_BOUND) { 22633af08d82Slm66018 DMSG(vdc, 0, "[%d] Unbinding DRing\n", vdc->instance); 22641ae08745Sheppo status = ldc_mem_dring_unbind(vdc->ldc_dring_hdl); 22651ae08745Sheppo if (status == 0) { 22661ae08745Sheppo vdc->initialized &= ~VDC_DRING_BOUND; 22671ae08745Sheppo } else { 22683af08d82Slm66018 DMSG(vdc, 0, "[%d] Error %d unbinding DRing %lx", 2269e1ebb9ecSlm66018 vdc->instance, status, vdc->ldc_dring_hdl); 22701ae08745Sheppo } 22713af08d82Slm66018 kmem_free(vdc->dring_cookie, sizeof (ldc_mem_cookie_t)); 22721ae08745Sheppo } 22731ae08745Sheppo 22741ae08745Sheppo if (vdc->initialized & VDC_DRING_INIT) { 22753af08d82Slm66018 DMSG(vdc, 0, "[%d] Destroying DRing\n", vdc->instance); 22761ae08745Sheppo status = ldc_mem_dring_destroy(vdc->ldc_dring_hdl); 22771ae08745Sheppo if (status == 0) { 22781ae08745Sheppo vdc->ldc_dring_hdl = NULL; 22791ae08745Sheppo bzero(&vdc->dring_mem_info, sizeof (ldc_mem_info_t)); 22801ae08745Sheppo vdc->initialized &= ~VDC_DRING_INIT; 22811ae08745Sheppo } else { 22823af08d82Slm66018 DMSG(vdc, 0, "[%d] Error %d destroying DRing (%lx)", 2283e1ebb9ecSlm66018 vdc->instance, status, vdc->ldc_dring_hdl); 22841ae08745Sheppo } 22851ae08745Sheppo } 22861ae08745Sheppo } 22871ae08745Sheppo 22881ae08745Sheppo /* 22893af08d82Slm66018 * Function: 22903af08d82Slm66018 * vdc_map_to_shared_ring() 22911ae08745Sheppo * 22921ae08745Sheppo * Description: 22933af08d82Slm66018 * Copy contents of the local descriptor to the shared 22943af08d82Slm66018 * memory descriptor. 22951ae08745Sheppo * 22963af08d82Slm66018 * Arguments: 22973af08d82Slm66018 * vdcp - soft state pointer for this instance of the device driver. 22983af08d82Slm66018 * idx - descriptor ring index 22993af08d82Slm66018 * 23003af08d82Slm66018 * Return Code: 23013af08d82Slm66018 * None 23021ae08745Sheppo */ 23031ae08745Sheppo static int 23043af08d82Slm66018 vdc_map_to_shared_dring(vdc_t *vdcp, int idx) 23051ae08745Sheppo { 23063af08d82Slm66018 vdc_local_desc_t *ldep; 23073af08d82Slm66018 vd_dring_entry_t *dep; 23083af08d82Slm66018 int rv; 23091ae08745Sheppo 23103af08d82Slm66018 ldep = &(vdcp->local_dring[idx]); 23111ae08745Sheppo 23123af08d82Slm66018 /* for now leave in the old pop_mem_hdl stuff */ 23133af08d82Slm66018 if (ldep->nbytes > 0) { 23143af08d82Slm66018 rv = vdc_populate_mem_hdl(vdcp, ldep); 23153af08d82Slm66018 if (rv) { 23163af08d82Slm66018 DMSG(vdcp, 0, "[%d] Cannot populate mem handle\n", 23173af08d82Slm66018 vdcp->instance); 23183af08d82Slm66018 return (rv); 23193af08d82Slm66018 } 23203af08d82Slm66018 } 23211ae08745Sheppo 23223af08d82Slm66018 /* 23233af08d82Slm66018 * fill in the data details into the DRing 23243af08d82Slm66018 */ 2325d10e4ef2Snarayan dep = ldep->dep; 23261ae08745Sheppo ASSERT(dep != NULL); 23271ae08745Sheppo 23283af08d82Slm66018 dep->payload.req_id = VDC_GET_NEXT_REQ_ID(vdcp); 23293af08d82Slm66018 dep->payload.operation = ldep->operation; 23303af08d82Slm66018 dep->payload.addr = ldep->offset; 23313af08d82Slm66018 dep->payload.nbytes = ldep->nbytes; 2332055d7c80Scarlsonj dep->payload.status = (uint32_t)-1; /* vds will set valid value */ 23333af08d82Slm66018 dep->payload.slice = ldep->slice; 23343af08d82Slm66018 dep->hdr.dstate = VIO_DESC_READY; 23353af08d82Slm66018 dep->hdr.ack = 1; /* request an ACK for every message */ 23361ae08745Sheppo 23373af08d82Slm66018 return (0); 23381ae08745Sheppo } 23391ae08745Sheppo 23401ae08745Sheppo /* 23411ae08745Sheppo * Function: 23423af08d82Slm66018 * vdc_send_request 23433af08d82Slm66018 * 23443af08d82Slm66018 * Description: 23453af08d82Slm66018 * This routine writes the data to be transmitted to vds into the 23463af08d82Slm66018 * descriptor, notifies vds that the ring has been updated and 23473af08d82Slm66018 * then waits for the request to be processed. 23483af08d82Slm66018 * 23493af08d82Slm66018 * Arguments: 23503af08d82Slm66018 * vdcp - the soft state pointer 23513af08d82Slm66018 * operation - operation we want vds to perform (VD_OP_XXX) 23523af08d82Slm66018 * addr - address of data buf to be read/written. 23533af08d82Slm66018 * nbytes - number of bytes to read/write 23543af08d82Slm66018 * slice - the disk slice this request is for 23553af08d82Slm66018 * offset - relative disk offset 23563af08d82Slm66018 * cb_type - type of call - STRATEGY or SYNC 23573af08d82Slm66018 * cb_arg - parameter to be sent to server (depends on VD_OP_XXX type) 23583af08d82Slm66018 * . mode for ioctl(9e) 23593af08d82Slm66018 * . LP64 diskaddr_t (block I/O) 23603af08d82Slm66018 * dir - direction of operation (READ/WRITE/BOTH) 23613af08d82Slm66018 * 23623af08d82Slm66018 * Return Codes: 23633af08d82Slm66018 * 0 23643af08d82Slm66018 * ENXIO 23653af08d82Slm66018 */ 23663af08d82Slm66018 static int 23673af08d82Slm66018 vdc_send_request(vdc_t *vdcp, int operation, caddr_t addr, 23683af08d82Slm66018 size_t nbytes, int slice, diskaddr_t offset, int cb_type, 23693af08d82Slm66018 void *cb_arg, vio_desc_direction_t dir) 23703af08d82Slm66018 { 23713af08d82Slm66018 ASSERT(vdcp != NULL); 237287a7269eSachartre ASSERT(slice == VD_SLICE_NONE || slice < V_NUMPAR); 23733af08d82Slm66018 23743af08d82Slm66018 mutex_enter(&vdcp->lock); 23753af08d82Slm66018 23763af08d82Slm66018 do { 23773c96341aSnarayan while (vdcp->state != VDC_STATE_RUNNING) { 23783af08d82Slm66018 cv_wait(&vdcp->running_cv, &vdcp->lock); 23793af08d82Slm66018 23803c96341aSnarayan /* return error if detaching */ 23813c96341aSnarayan if (vdcp->state == VDC_STATE_DETACH) { 23823c96341aSnarayan mutex_exit(&vdcp->lock); 23833c96341aSnarayan return (ENXIO); 23843c96341aSnarayan } 23853c96341aSnarayan } 23863c96341aSnarayan 23873af08d82Slm66018 } while (vdc_populate_descriptor(vdcp, operation, addr, 23883af08d82Slm66018 nbytes, slice, offset, cb_type, cb_arg, dir)); 23893af08d82Slm66018 23903af08d82Slm66018 mutex_exit(&vdcp->lock); 23913af08d82Slm66018 return (0); 23923af08d82Slm66018 } 23933af08d82Slm66018 23943af08d82Slm66018 23953af08d82Slm66018 /* 23963af08d82Slm66018 * Function: 23971ae08745Sheppo * vdc_populate_descriptor 23981ae08745Sheppo * 23991ae08745Sheppo * Description: 24001ae08745Sheppo * This routine writes the data to be transmitted to vds into the 24011ae08745Sheppo * descriptor, notifies vds that the ring has been updated and 24021ae08745Sheppo * then waits for the request to be processed. 24031ae08745Sheppo * 24041ae08745Sheppo * Arguments: 24053af08d82Slm66018 * vdcp - the soft state pointer 24061ae08745Sheppo * operation - operation we want vds to perform (VD_OP_XXX) 24073af08d82Slm66018 * addr - address of data buf to be read/written. 24083af08d82Slm66018 * nbytes - number of bytes to read/write 24093af08d82Slm66018 * slice - the disk slice this request is for 24103af08d82Slm66018 * offset - relative disk offset 24113af08d82Slm66018 * cb_type - type of call - STRATEGY or SYNC 24123af08d82Slm66018 * cb_arg - parameter to be sent to server (depends on VD_OP_XXX type) 24131ae08745Sheppo * . mode for ioctl(9e) 24141ae08745Sheppo * . LP64 diskaddr_t (block I/O) 24153af08d82Slm66018 * dir - direction of operation (READ/WRITE/BOTH) 24161ae08745Sheppo * 24171ae08745Sheppo * Return Codes: 24181ae08745Sheppo * 0 24191ae08745Sheppo * EAGAIN 24201ae08745Sheppo * EFAULT 24211ae08745Sheppo * ENXIO 24221ae08745Sheppo * EIO 24231ae08745Sheppo */ 24241ae08745Sheppo static int 24253af08d82Slm66018 vdc_populate_descriptor(vdc_t *vdcp, int operation, caddr_t addr, 24263af08d82Slm66018 size_t nbytes, int slice, diskaddr_t offset, int cb_type, 24273af08d82Slm66018 void *cb_arg, vio_desc_direction_t dir) 24281ae08745Sheppo { 24293af08d82Slm66018 vdc_local_desc_t *local_dep = NULL; /* Local Dring Pointer */ 24303af08d82Slm66018 int idx; /* Index of DRing entry used */ 24313af08d82Slm66018 int next_idx; 24321ae08745Sheppo vio_dring_msg_t dmsg; 24333af08d82Slm66018 size_t msglen; 24348e6a2a04Slm66018 int rv; 24351ae08745Sheppo 24363af08d82Slm66018 ASSERT(MUTEX_HELD(&vdcp->lock)); 24373af08d82Slm66018 vdcp->threads_pending++; 24383af08d82Slm66018 loop: 24393af08d82Slm66018 DMSG(vdcp, 2, ": dring_curr_idx = %d\n", vdcp->dring_curr_idx); 24401ae08745Sheppo 24413af08d82Slm66018 /* Get next available D-Ring entry */ 24423af08d82Slm66018 idx = vdcp->dring_curr_idx; 24433af08d82Slm66018 local_dep = &(vdcp->local_dring[idx]); 24441ae08745Sheppo 24453af08d82Slm66018 if (!local_dep->is_free) { 24463af08d82Slm66018 DMSG(vdcp, 2, "[%d]: dring full - waiting for space\n", 24473af08d82Slm66018 vdcp->instance); 24483af08d82Slm66018 cv_wait(&vdcp->dring_free_cv, &vdcp->lock); 24493af08d82Slm66018 if (vdcp->state == VDC_STATE_RUNNING || 24503af08d82Slm66018 vdcp->state == VDC_STATE_HANDLE_PENDING) { 24513af08d82Slm66018 goto loop; 24523af08d82Slm66018 } 24533af08d82Slm66018 vdcp->threads_pending--; 24543af08d82Slm66018 return (ECONNRESET); 24551ae08745Sheppo } 24561ae08745Sheppo 24573af08d82Slm66018 next_idx = idx + 1; 24583af08d82Slm66018 if (next_idx >= vdcp->dring_len) 24593af08d82Slm66018 next_idx = 0; 24603af08d82Slm66018 vdcp->dring_curr_idx = next_idx; 24611ae08745Sheppo 24623af08d82Slm66018 ASSERT(local_dep->is_free); 24631ae08745Sheppo 24643af08d82Slm66018 local_dep->operation = operation; 2465d10e4ef2Snarayan local_dep->addr = addr; 24663af08d82Slm66018 local_dep->nbytes = nbytes; 24673af08d82Slm66018 local_dep->slice = slice; 24683af08d82Slm66018 local_dep->offset = offset; 24693af08d82Slm66018 local_dep->cb_type = cb_type; 24703af08d82Slm66018 local_dep->cb_arg = cb_arg; 24713af08d82Slm66018 local_dep->dir = dir; 24723af08d82Slm66018 24733af08d82Slm66018 local_dep->is_free = B_FALSE; 24743af08d82Slm66018 24753af08d82Slm66018 rv = vdc_map_to_shared_dring(vdcp, idx); 24763af08d82Slm66018 if (rv) { 24773af08d82Slm66018 DMSG(vdcp, 0, "[%d]: cannot bind memory - waiting ..\n", 24783af08d82Slm66018 vdcp->instance); 24793af08d82Slm66018 /* free the descriptor */ 24803af08d82Slm66018 local_dep->is_free = B_TRUE; 24813af08d82Slm66018 vdcp->dring_curr_idx = idx; 24823af08d82Slm66018 cv_wait(&vdcp->membind_cv, &vdcp->lock); 24833af08d82Slm66018 if (vdcp->state == VDC_STATE_RUNNING || 24843af08d82Slm66018 vdcp->state == VDC_STATE_HANDLE_PENDING) { 24853af08d82Slm66018 goto loop; 24861ae08745Sheppo } 24873af08d82Slm66018 vdcp->threads_pending--; 24883af08d82Slm66018 return (ECONNRESET); 24891ae08745Sheppo } 24901ae08745Sheppo 24911ae08745Sheppo /* 24921ae08745Sheppo * Send a msg with the DRing details to vds 24931ae08745Sheppo */ 24941ae08745Sheppo VIO_INIT_DRING_DATA_TAG(dmsg); 24953af08d82Slm66018 VDC_INIT_DRING_DATA_MSG_IDS(dmsg, vdcp); 24963af08d82Slm66018 dmsg.dring_ident = vdcp->dring_ident; 24971ae08745Sheppo dmsg.start_idx = idx; 24981ae08745Sheppo dmsg.end_idx = idx; 24993af08d82Slm66018 vdcp->seq_num++; 25001ae08745Sheppo 25013af08d82Slm66018 DTRACE_IO2(send, vio_dring_msg_t *, &dmsg, vdc_t *, vdcp); 2502d10e4ef2Snarayan 25033af08d82Slm66018 DMSG(vdcp, 2, "ident=0x%lx, st=%u, end=%u, seq=%ld\n", 25043af08d82Slm66018 vdcp->dring_ident, dmsg.start_idx, dmsg.end_idx, dmsg.seq_num); 25051ae08745Sheppo 25063af08d82Slm66018 /* 25073af08d82Slm66018 * note we're still holding the lock here to 25083af08d82Slm66018 * make sure the message goes out in order !!!... 25093af08d82Slm66018 */ 25103af08d82Slm66018 msglen = sizeof (dmsg); 25113af08d82Slm66018 rv = vdc_send(vdcp, (caddr_t)&dmsg, &msglen); 25123af08d82Slm66018 switch (rv) { 25133af08d82Slm66018 case ECONNRESET: 25143af08d82Slm66018 /* 25153af08d82Slm66018 * vdc_send initiates the reset on failure. 25163af08d82Slm66018 * Since the transaction has already been put 25173af08d82Slm66018 * on the local dring, it will automatically get 25183af08d82Slm66018 * retried when the channel is reset. Given that, 25193af08d82Slm66018 * it is ok to just return success even though the 25203af08d82Slm66018 * send failed. 25213af08d82Slm66018 */ 25223af08d82Slm66018 rv = 0; 25233af08d82Slm66018 break; 2524d10e4ef2Snarayan 25253af08d82Slm66018 case 0: /* EOK */ 25263af08d82Slm66018 DMSG(vdcp, 1, "sent via LDC: rv=%d\n", rv); 25273af08d82Slm66018 break; 2528d10e4ef2Snarayan 25293af08d82Slm66018 default: 25303af08d82Slm66018 goto cleanup_and_exit; 25313af08d82Slm66018 } 2532e1ebb9ecSlm66018 25333af08d82Slm66018 vdcp->threads_pending--; 25343af08d82Slm66018 return (rv); 25353af08d82Slm66018 25363af08d82Slm66018 cleanup_and_exit: 25373af08d82Slm66018 DMSG(vdcp, 0, "unexpected error, rv=%d\n", rv); 25383af08d82Slm66018 return (ENXIO); 25391ae08745Sheppo } 25401ae08745Sheppo 25411ae08745Sheppo /* 25423af08d82Slm66018 * Function: 25433af08d82Slm66018 * vdc_do_sync_op 25443af08d82Slm66018 * 25453af08d82Slm66018 * Description: 25463af08d82Slm66018 * Wrapper around vdc_populate_descriptor that blocks until the 25473af08d82Slm66018 * response to the message is available. 25483af08d82Slm66018 * 25493af08d82Slm66018 * Arguments: 25503af08d82Slm66018 * vdcp - the soft state pointer 25513af08d82Slm66018 * operation - operation we want vds to perform (VD_OP_XXX) 25523af08d82Slm66018 * addr - address of data buf to be read/written. 25533af08d82Slm66018 * nbytes - number of bytes to read/write 25543af08d82Slm66018 * slice - the disk slice this request is for 25553af08d82Slm66018 * offset - relative disk offset 25563af08d82Slm66018 * cb_type - type of call - STRATEGY or SYNC 25573af08d82Slm66018 * cb_arg - parameter to be sent to server (depends on VD_OP_XXX type) 25583af08d82Slm66018 * . mode for ioctl(9e) 25593af08d82Slm66018 * . LP64 diskaddr_t (block I/O) 25603af08d82Slm66018 * dir - direction of operation (READ/WRITE/BOTH) 25613af08d82Slm66018 * 25623af08d82Slm66018 * Return Codes: 25633af08d82Slm66018 * 0 25643af08d82Slm66018 * EAGAIN 25653af08d82Slm66018 * EFAULT 25663af08d82Slm66018 * ENXIO 25673af08d82Slm66018 * EIO 25680a55fbb7Slm66018 */ 25693af08d82Slm66018 static int 25703af08d82Slm66018 vdc_do_sync_op(vdc_t *vdcp, int operation, caddr_t addr, size_t nbytes, 25713af08d82Slm66018 int slice, diskaddr_t offset, int cb_type, void *cb_arg, 25723af08d82Slm66018 vio_desc_direction_t dir) 25733af08d82Slm66018 { 25743af08d82Slm66018 int status; 25753af08d82Slm66018 25763af08d82Slm66018 ASSERT(cb_type == CB_SYNC); 25771ae08745Sheppo 25781ae08745Sheppo /* 25793af08d82Slm66018 * Grab the lock, if blocked wait until the server 25803af08d82Slm66018 * response causes us to wake up again. 25813af08d82Slm66018 */ 25823af08d82Slm66018 mutex_enter(&vdcp->lock); 25833af08d82Slm66018 vdcp->sync_op_cnt++; 25843af08d82Slm66018 while (vdcp->sync_op_blocked && vdcp->state != VDC_STATE_DETACH) 25853af08d82Slm66018 cv_wait(&vdcp->sync_blocked_cv, &vdcp->lock); 25863af08d82Slm66018 25873af08d82Slm66018 if (vdcp->state == VDC_STATE_DETACH) { 25883af08d82Slm66018 cv_broadcast(&vdcp->sync_blocked_cv); 25893af08d82Slm66018 vdcp->sync_op_cnt--; 25903af08d82Slm66018 mutex_exit(&vdcp->lock); 25913af08d82Slm66018 return (ENXIO); 25923af08d82Slm66018 } 25933af08d82Slm66018 25943af08d82Slm66018 /* now block anyone other thread entering after us */ 25953af08d82Slm66018 vdcp->sync_op_blocked = B_TRUE; 25963af08d82Slm66018 vdcp->sync_op_pending = B_TRUE; 25973af08d82Slm66018 mutex_exit(&vdcp->lock); 25983af08d82Slm66018 25993af08d82Slm66018 /* 26003af08d82Slm66018 * No need to check return value - will return error only 26013af08d82Slm66018 * in the DETACH case and we can fall through 26023af08d82Slm66018 */ 26033af08d82Slm66018 (void) vdc_send_request(vdcp, operation, addr, 26043af08d82Slm66018 nbytes, slice, offset, cb_type, cb_arg, dir); 26053af08d82Slm66018 26063af08d82Slm66018 /* 26073af08d82Slm66018 * block until our transaction completes. 26083af08d82Slm66018 * Also anyone else waiting also gets to go next. 26093af08d82Slm66018 */ 26103af08d82Slm66018 mutex_enter(&vdcp->lock); 26113af08d82Slm66018 while (vdcp->sync_op_pending && vdcp->state != VDC_STATE_DETACH) 26123af08d82Slm66018 cv_wait(&vdcp->sync_pending_cv, &vdcp->lock); 26133af08d82Slm66018 26143af08d82Slm66018 DMSG(vdcp, 2, ": operation returned %d\n", vdcp->sync_op_status); 26153c96341aSnarayan if (vdcp->state == VDC_STATE_DETACH) { 26163c96341aSnarayan vdcp->sync_op_pending = B_FALSE; 26173af08d82Slm66018 status = ENXIO; 26183c96341aSnarayan } else { 26193af08d82Slm66018 status = vdcp->sync_op_status; 26203c96341aSnarayan } 26213c96341aSnarayan 26223af08d82Slm66018 vdcp->sync_op_status = 0; 26233af08d82Slm66018 vdcp->sync_op_blocked = B_FALSE; 26243af08d82Slm66018 vdcp->sync_op_cnt--; 26253af08d82Slm66018 26263af08d82Slm66018 /* signal the next waiting thread */ 26273af08d82Slm66018 cv_signal(&vdcp->sync_blocked_cv); 26283af08d82Slm66018 mutex_exit(&vdcp->lock); 26293af08d82Slm66018 26303af08d82Slm66018 return (status); 26313af08d82Slm66018 } 26323af08d82Slm66018 26333af08d82Slm66018 26343af08d82Slm66018 /* 26353af08d82Slm66018 * Function: 26363af08d82Slm66018 * vdc_drain_response() 26373af08d82Slm66018 * 26383af08d82Slm66018 * Description: 26391ae08745Sheppo * When a guest is panicking, the completion of requests needs to be 26401ae08745Sheppo * handled differently because interrupts are disabled and vdc 26411ae08745Sheppo * will not get messages. We have to poll for the messages instead. 26423af08d82Slm66018 * 26433af08d82Slm66018 * Arguments: 26443af08d82Slm66018 * vdc - soft state pointer for this instance of the device driver. 26453af08d82Slm66018 * 26463af08d82Slm66018 * Return Code: 26473af08d82Slm66018 * 0 - Success 26481ae08745Sheppo */ 26493af08d82Slm66018 static int 26503af08d82Slm66018 vdc_drain_response(vdc_t *vdc) 26513af08d82Slm66018 { 26523af08d82Slm66018 int rv, idx, retries; 26533af08d82Slm66018 size_t msglen; 26543af08d82Slm66018 vdc_local_desc_t *ldep = NULL; /* Local Dring Entry Pointer */ 26553af08d82Slm66018 vio_dring_msg_t dmsg; 26563af08d82Slm66018 26573af08d82Slm66018 mutex_enter(&vdc->lock); 26583af08d82Slm66018 26591ae08745Sheppo retries = 0; 26601ae08745Sheppo for (;;) { 26611ae08745Sheppo msglen = sizeof (dmsg); 26623af08d82Slm66018 rv = ldc_read(vdc->ldc_handle, (caddr_t)&dmsg, &msglen); 26638e6a2a04Slm66018 if (rv) { 26648e6a2a04Slm66018 rv = EINVAL; 26651ae08745Sheppo break; 26661ae08745Sheppo } 26671ae08745Sheppo 26681ae08745Sheppo /* 26691ae08745Sheppo * if there are no packets wait and check again 26701ae08745Sheppo */ 26718e6a2a04Slm66018 if ((rv == 0) && (msglen == 0)) { 26721ae08745Sheppo if (retries++ > vdc_dump_retries) { 26738e6a2a04Slm66018 rv = EAGAIN; 26741ae08745Sheppo break; 26751ae08745Sheppo } 26761ae08745Sheppo 2677d10e4ef2Snarayan drv_usecwait(vdc_usec_timeout_dump); 26781ae08745Sheppo continue; 26791ae08745Sheppo } 26801ae08745Sheppo 26811ae08745Sheppo /* 26821ae08745Sheppo * Ignore all messages that are not ACKs/NACKs to 26831ae08745Sheppo * DRing requests. 26841ae08745Sheppo */ 26851ae08745Sheppo if ((dmsg.tag.vio_msgtype != VIO_TYPE_DATA) || 26861ae08745Sheppo (dmsg.tag.vio_subtype_env != VIO_DRING_DATA)) { 26873af08d82Slm66018 DMSG(vdc, 0, "discard pkt: type=%d sub=%d env=%d\n", 26881ae08745Sheppo dmsg.tag.vio_msgtype, 26891ae08745Sheppo dmsg.tag.vio_subtype, 26901ae08745Sheppo dmsg.tag.vio_subtype_env); 26911ae08745Sheppo continue; 26921ae08745Sheppo } 26931ae08745Sheppo 26941ae08745Sheppo /* 26953af08d82Slm66018 * set the appropriate return value for the current request. 26961ae08745Sheppo */ 26971ae08745Sheppo switch (dmsg.tag.vio_subtype) { 26981ae08745Sheppo case VIO_SUBTYPE_ACK: 26998e6a2a04Slm66018 rv = 0; 27001ae08745Sheppo break; 27011ae08745Sheppo case VIO_SUBTYPE_NACK: 27028e6a2a04Slm66018 rv = EAGAIN; 27031ae08745Sheppo break; 27041ae08745Sheppo default: 27051ae08745Sheppo continue; 27061ae08745Sheppo } 27071ae08745Sheppo 27083af08d82Slm66018 idx = dmsg.start_idx; 27093af08d82Slm66018 if (idx >= vdc->dring_len) { 27103af08d82Slm66018 DMSG(vdc, 0, "[%d] Bogus ack data : start %d\n", 2711e1ebb9ecSlm66018 vdc->instance, idx); 27123af08d82Slm66018 continue; 27131ae08745Sheppo } 27143af08d82Slm66018 ldep = &vdc->local_dring[idx]; 27153af08d82Slm66018 if (ldep->dep->hdr.dstate != VIO_DESC_DONE) { 27163af08d82Slm66018 DMSG(vdc, 0, "[%d] Entry @ %d - state !DONE %d\n", 27173af08d82Slm66018 vdc->instance, idx, ldep->dep->hdr.dstate); 27181ae08745Sheppo continue; 27191ae08745Sheppo } 27201ae08745Sheppo 27213af08d82Slm66018 DMSG(vdc, 1, "[%d] Depopulating idx=%d state=%d\n", 27223af08d82Slm66018 vdc->instance, idx, ldep->dep->hdr.dstate); 27233af08d82Slm66018 rv = vdc_depopulate_descriptor(vdc, idx); 27243af08d82Slm66018 if (rv) { 27253af08d82Slm66018 DMSG(vdc, 0, 27263af08d82Slm66018 "[%d] Entry @ %d - depopulate failed ..\n", 27273af08d82Slm66018 vdc->instance, idx); 27281ae08745Sheppo } 27291ae08745Sheppo 27303af08d82Slm66018 /* if this is the last descriptor - break out of loop */ 27313af08d82Slm66018 if ((idx + 1) % vdc->dring_len == vdc->dring_curr_idx) 27323af08d82Slm66018 break; 27333af08d82Slm66018 } 27343af08d82Slm66018 27353af08d82Slm66018 mutex_exit(&vdc->lock); 27363af08d82Slm66018 DMSG(vdc, 0, "End idx=%d\n", idx); 27373af08d82Slm66018 27383af08d82Slm66018 return (rv); 27391ae08745Sheppo } 27401ae08745Sheppo 27411ae08745Sheppo 27420a55fbb7Slm66018 /* 27430a55fbb7Slm66018 * Function: 27440a55fbb7Slm66018 * vdc_depopulate_descriptor() 27450a55fbb7Slm66018 * 27460a55fbb7Slm66018 * Description: 27470a55fbb7Slm66018 * 27480a55fbb7Slm66018 * Arguments: 27490a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 27500a55fbb7Slm66018 * idx - Index of the Descriptor Ring entry being modified 27510a55fbb7Slm66018 * 27520a55fbb7Slm66018 * Return Code: 27530a55fbb7Slm66018 * 0 - Success 27540a55fbb7Slm66018 */ 27551ae08745Sheppo static int 27561ae08745Sheppo vdc_depopulate_descriptor(vdc_t *vdc, uint_t idx) 27571ae08745Sheppo { 27581ae08745Sheppo vd_dring_entry_t *dep = NULL; /* Dring Entry Pointer */ 27591ae08745Sheppo vdc_local_desc_t *ldep = NULL; /* Local Dring Entry Pointer */ 27601ae08745Sheppo int status = ENXIO; 27618e6a2a04Slm66018 int rv = 0; 27621ae08745Sheppo 27631ae08745Sheppo ASSERT(vdc != NULL); 2764e1ebb9ecSlm66018 ASSERT(idx < vdc->dring_len); 27651ae08745Sheppo ldep = &vdc->local_dring[idx]; 27661ae08745Sheppo ASSERT(ldep != NULL); 27673af08d82Slm66018 ASSERT(MUTEX_HELD(&vdc->lock)); 27683af08d82Slm66018 27693af08d82Slm66018 DMSG(vdc, 2, ": idx = %d\n", idx); 27701ae08745Sheppo dep = ldep->dep; 27711ae08745Sheppo ASSERT(dep != NULL); 2772e1ebb9ecSlm66018 ASSERT((dep->hdr.dstate == VIO_DESC_DONE) || 2773e1ebb9ecSlm66018 (dep->payload.status == ECANCELED)); 27741ae08745Sheppo 2775e1ebb9ecSlm66018 VDC_MARK_DRING_ENTRY_FREE(vdc, idx); 27763af08d82Slm66018 27773af08d82Slm66018 ldep->is_free = B_TRUE; 27781ae08745Sheppo status = dep->payload.status; 2779*205eeb1aSlm66018 DMSG(vdc, 2, ": is_free = %d : status = %d\n", ldep->is_free, status); 27801ae08745Sheppo 2781eff7243fSlm66018 /* 2782eff7243fSlm66018 * If no buffers were used to transfer information to the server when 2783eff7243fSlm66018 * populating the descriptor then no memory handles need to be unbound 2784eff7243fSlm66018 * and we can return now. 2785eff7243fSlm66018 */ 2786eff7243fSlm66018 if (ldep->nbytes == 0) { 2787eff7243fSlm66018 cv_signal(&vdc->dring_free_cv); 27888e6a2a04Slm66018 return (status); 2789eff7243fSlm66018 } 27908e6a2a04Slm66018 27911ae08745Sheppo /* 27921ae08745Sheppo * If the upper layer passed in a misaligned address we copied the 27931ae08745Sheppo * data into an aligned buffer before sending it to LDC - we now 27941ae08745Sheppo * copy it back to the original buffer. 27951ae08745Sheppo */ 27961ae08745Sheppo if (ldep->align_addr) { 27971ae08745Sheppo ASSERT(ldep->addr != NULL); 27981ae08745Sheppo 27993c96341aSnarayan if (dep->payload.nbytes > 0) 28003c96341aSnarayan bcopy(ldep->align_addr, ldep->addr, 28013c96341aSnarayan dep->payload.nbytes); 28021ae08745Sheppo kmem_free(ldep->align_addr, 28033c96341aSnarayan sizeof (caddr_t) * P2ROUNDUP(ldep->nbytes, 8)); 28041ae08745Sheppo ldep->align_addr = NULL; 28051ae08745Sheppo } 28061ae08745Sheppo 28078e6a2a04Slm66018 rv = ldc_mem_unbind_handle(ldep->desc_mhdl); 28088e6a2a04Slm66018 if (rv != 0) { 28093af08d82Slm66018 DMSG(vdc, 0, "?[%d] unbind mhdl 0x%lx @ idx %d failed (%d)", 28108e6a2a04Slm66018 vdc->instance, ldep->desc_mhdl, idx, rv); 28118e6a2a04Slm66018 /* 28128e6a2a04Slm66018 * The error returned by the vDisk server is more informative 28138e6a2a04Slm66018 * and thus has a higher priority but if it isn't set we ensure 28148e6a2a04Slm66018 * that this function returns an error. 28158e6a2a04Slm66018 */ 28168e6a2a04Slm66018 if (status == 0) 28178e6a2a04Slm66018 status = EINVAL; 28181ae08745Sheppo } 28191ae08745Sheppo 28203af08d82Slm66018 cv_signal(&vdc->membind_cv); 28213af08d82Slm66018 cv_signal(&vdc->dring_free_cv); 28223af08d82Slm66018 28231ae08745Sheppo return (status); 28241ae08745Sheppo } 28251ae08745Sheppo 28260a55fbb7Slm66018 /* 28270a55fbb7Slm66018 * Function: 28280a55fbb7Slm66018 * vdc_populate_mem_hdl() 28290a55fbb7Slm66018 * 28300a55fbb7Slm66018 * Description: 28310a55fbb7Slm66018 * 28320a55fbb7Slm66018 * Arguments: 28330a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 28340a55fbb7Slm66018 * idx - Index of the Descriptor Ring entry being modified 28350a55fbb7Slm66018 * addr - virtual address being mapped in 28360a55fbb7Slm66018 * nybtes - number of bytes in 'addr' 28370a55fbb7Slm66018 * operation - the vDisk operation being performed (VD_OP_xxx) 28380a55fbb7Slm66018 * 28390a55fbb7Slm66018 * Return Code: 28400a55fbb7Slm66018 * 0 - Success 28410a55fbb7Slm66018 */ 28421ae08745Sheppo static int 28433af08d82Slm66018 vdc_populate_mem_hdl(vdc_t *vdcp, vdc_local_desc_t *ldep) 28441ae08745Sheppo { 28451ae08745Sheppo vd_dring_entry_t *dep = NULL; 28461ae08745Sheppo ldc_mem_handle_t mhdl; 28471ae08745Sheppo caddr_t vaddr; 28483af08d82Slm66018 size_t nbytes; 28494bac2208Snarayan uint8_t perm = LDC_MEM_RW; 28504bac2208Snarayan uint8_t maptype; 28511ae08745Sheppo int rv = 0; 28521ae08745Sheppo int i; 28531ae08745Sheppo 28543af08d82Slm66018 ASSERT(vdcp != NULL); 28551ae08745Sheppo 28563af08d82Slm66018 dep = ldep->dep; 28571ae08745Sheppo mhdl = ldep->desc_mhdl; 28581ae08745Sheppo 28593af08d82Slm66018 switch (ldep->dir) { 28603af08d82Slm66018 case VIO_read_dir: 28611ae08745Sheppo perm = LDC_MEM_W; 28621ae08745Sheppo break; 28631ae08745Sheppo 28643af08d82Slm66018 case VIO_write_dir: 28651ae08745Sheppo perm = LDC_MEM_R; 28661ae08745Sheppo break; 28671ae08745Sheppo 28683af08d82Slm66018 case VIO_both_dir: 28691ae08745Sheppo perm = LDC_MEM_RW; 28701ae08745Sheppo break; 28711ae08745Sheppo 28721ae08745Sheppo default: 28731ae08745Sheppo ASSERT(0); /* catch bad programming in vdc */ 28741ae08745Sheppo } 28751ae08745Sheppo 28761ae08745Sheppo /* 28771ae08745Sheppo * LDC expects any addresses passed in to be 8-byte aligned. We need 28781ae08745Sheppo * to copy the contents of any misaligned buffers to a newly allocated 28791ae08745Sheppo * buffer and bind it instead (and copy the the contents back to the 28801ae08745Sheppo * original buffer passed in when depopulating the descriptor) 28811ae08745Sheppo */ 28823af08d82Slm66018 vaddr = ldep->addr; 28833af08d82Slm66018 nbytes = ldep->nbytes; 28843af08d82Slm66018 if (((uint64_t)vaddr & 0x7) != 0) { 2885d10e4ef2Snarayan ASSERT(ldep->align_addr == NULL); 28861ae08745Sheppo ldep->align_addr = 28873af08d82Slm66018 kmem_alloc(sizeof (caddr_t) * 28883af08d82Slm66018 P2ROUNDUP(nbytes, 8), KM_SLEEP); 28893af08d82Slm66018 DMSG(vdcp, 0, "[%d] Misaligned address %p reallocating " 28903af08d82Slm66018 "(buf=%p nb=%ld op=%d)\n", 28913af08d82Slm66018 vdcp->instance, (void *)vaddr, (void *)ldep->align_addr, 28923af08d82Slm66018 nbytes, ldep->operation); 28933af08d82Slm66018 if (perm != LDC_MEM_W) 28943af08d82Slm66018 bcopy(vaddr, ldep->align_addr, nbytes); 28951ae08745Sheppo vaddr = ldep->align_addr; 28961ae08745Sheppo } 28971ae08745Sheppo 28984bac2208Snarayan maptype = LDC_IO_MAP|LDC_SHADOW_MAP|LDC_DIRECT_MAP; 28991ae08745Sheppo rv = ldc_mem_bind_handle(mhdl, vaddr, P2ROUNDUP(nbytes, 8), 290087a7269eSachartre maptype, perm, &dep->payload.cookie[0], &dep->payload.ncookies); 29013af08d82Slm66018 DMSG(vdcp, 2, "[%d] bound mem handle; ncookies=%d\n", 29023af08d82Slm66018 vdcp->instance, dep->payload.ncookies); 29031ae08745Sheppo if (rv != 0) { 29043af08d82Slm66018 DMSG(vdcp, 0, "[%d] Failed to bind LDC memory handle " 29053af08d82Slm66018 "(mhdl=%p, buf=%p, err=%d)\n", 29063af08d82Slm66018 vdcp->instance, (void *)mhdl, (void *)vaddr, rv); 29071ae08745Sheppo if (ldep->align_addr) { 29081ae08745Sheppo kmem_free(ldep->align_addr, 2909d10e4ef2Snarayan sizeof (caddr_t) * P2ROUNDUP(nbytes, 8)); 29101ae08745Sheppo ldep->align_addr = NULL; 29111ae08745Sheppo } 29121ae08745Sheppo return (EAGAIN); 29131ae08745Sheppo } 29141ae08745Sheppo 29151ae08745Sheppo /* 29161ae08745Sheppo * Get the other cookies (if any). 29171ae08745Sheppo */ 29181ae08745Sheppo for (i = 1; i < dep->payload.ncookies; i++) { 29191ae08745Sheppo rv = ldc_mem_nextcookie(mhdl, &dep->payload.cookie[i]); 29201ae08745Sheppo if (rv != 0) { 29211ae08745Sheppo (void) ldc_mem_unbind_handle(mhdl); 29223af08d82Slm66018 DMSG(vdcp, 0, "?[%d] Failed to get next cookie " 2923e1ebb9ecSlm66018 "(mhdl=%lx cnum=%d), err=%d", 29243af08d82Slm66018 vdcp->instance, mhdl, i, rv); 29251ae08745Sheppo if (ldep->align_addr) { 29261ae08745Sheppo kmem_free(ldep->align_addr, 29273c96341aSnarayan sizeof (caddr_t) * ldep->nbytes); 29281ae08745Sheppo ldep->align_addr = NULL; 29291ae08745Sheppo } 29301ae08745Sheppo return (EAGAIN); 29311ae08745Sheppo } 29321ae08745Sheppo } 29331ae08745Sheppo 29341ae08745Sheppo return (rv); 29351ae08745Sheppo } 29361ae08745Sheppo 29371ae08745Sheppo /* 29381ae08745Sheppo * Interrupt handlers for messages from LDC 29391ae08745Sheppo */ 29401ae08745Sheppo 29410a55fbb7Slm66018 /* 29420a55fbb7Slm66018 * Function: 29430a55fbb7Slm66018 * vdc_handle_cb() 29440a55fbb7Slm66018 * 29450a55fbb7Slm66018 * Description: 29460a55fbb7Slm66018 * 29470a55fbb7Slm66018 * Arguments: 29480a55fbb7Slm66018 * event - Type of event (LDC_EVT_xxx) that triggered the callback 29490a55fbb7Slm66018 * arg - soft state pointer for this instance of the device driver. 29500a55fbb7Slm66018 * 29510a55fbb7Slm66018 * Return Code: 29520a55fbb7Slm66018 * 0 - Success 29530a55fbb7Slm66018 */ 29541ae08745Sheppo static uint_t 29551ae08745Sheppo vdc_handle_cb(uint64_t event, caddr_t arg) 29561ae08745Sheppo { 29571ae08745Sheppo ldc_status_t ldc_state; 29581ae08745Sheppo int rv = 0; 29591ae08745Sheppo 29601ae08745Sheppo vdc_t *vdc = (vdc_t *)(void *)arg; 29611ae08745Sheppo 29621ae08745Sheppo ASSERT(vdc != NULL); 29631ae08745Sheppo 29643af08d82Slm66018 DMSG(vdc, 1, "evt=%lx seqID=%ld\n", event, vdc->seq_num); 29651ae08745Sheppo 29661ae08745Sheppo /* 29671ae08745Sheppo * Depending on the type of event that triggered this callback, 29683af08d82Slm66018 * we modify the handshake state or read the data. 29691ae08745Sheppo * 29701ae08745Sheppo * NOTE: not done as a switch() as event could be triggered by 29711ae08745Sheppo * a state change and a read request. Also the ordering of the 29721ae08745Sheppo * check for the event types is deliberate. 29731ae08745Sheppo */ 29741ae08745Sheppo if (event & LDC_EVT_UP) { 29753af08d82Slm66018 DMSG(vdc, 0, "[%d] Received LDC_EVT_UP\n", vdc->instance); 29763af08d82Slm66018 29773af08d82Slm66018 mutex_enter(&vdc->lock); 29781ae08745Sheppo 29791ae08745Sheppo /* get LDC state */ 29801ae08745Sheppo rv = ldc_status(vdc->ldc_handle, &ldc_state); 29811ae08745Sheppo if (rv != 0) { 29823af08d82Slm66018 DMSG(vdc, 0, "[%d] Couldn't get LDC status %d", 29831ae08745Sheppo vdc->instance, rv); 29841ae08745Sheppo return (LDC_SUCCESS); 29851ae08745Sheppo } 29863af08d82Slm66018 if (vdc->ldc_state != LDC_UP && ldc_state == LDC_UP) { 29871ae08745Sheppo /* 29883af08d82Slm66018 * Reset the transaction sequence numbers when 29893af08d82Slm66018 * LDC comes up. We then kick off the handshake 29903af08d82Slm66018 * negotiation with the vDisk server. 29911ae08745Sheppo */ 29920a55fbb7Slm66018 vdc->seq_num = 1; 29931ae08745Sheppo vdc->seq_num_reply = 0; 29941ae08745Sheppo vdc->ldc_state = ldc_state; 29953af08d82Slm66018 cv_signal(&vdc->initwait_cv); 29963af08d82Slm66018 } 29973af08d82Slm66018 29981ae08745Sheppo mutex_exit(&vdc->lock); 29991ae08745Sheppo } 30001ae08745Sheppo 30011ae08745Sheppo if (event & LDC_EVT_READ) { 30023af08d82Slm66018 DMSG(vdc, 0, "[%d] Received LDC_EVT_READ\n", vdc->instance); 30033af08d82Slm66018 mutex_enter(&vdc->read_lock); 30043af08d82Slm66018 cv_signal(&vdc->read_cv); 30053af08d82Slm66018 vdc->read_state = VDC_READ_PENDING; 30063af08d82Slm66018 mutex_exit(&vdc->read_lock); 30071ae08745Sheppo 30081ae08745Sheppo /* that's all we have to do - no need to handle DOWN/RESET */ 30091ae08745Sheppo return (LDC_SUCCESS); 30101ae08745Sheppo } 30111ae08745Sheppo 30123af08d82Slm66018 if (event & (LDC_EVT_RESET|LDC_EVT_DOWN)) { 30130a55fbb7Slm66018 30143af08d82Slm66018 DMSG(vdc, 0, "[%d] Received LDC RESET event\n", vdc->instance); 30153af08d82Slm66018 30160a55fbb7Slm66018 mutex_enter(&vdc->lock); 30173af08d82Slm66018 /* 30183af08d82Slm66018 * Need to wake up any readers so they will 30193af08d82Slm66018 * detect that a reset has occurred. 30203af08d82Slm66018 */ 30213af08d82Slm66018 mutex_enter(&vdc->read_lock); 30223af08d82Slm66018 if ((vdc->read_state == VDC_READ_WAITING) || 30233af08d82Slm66018 (vdc->read_state == VDC_READ_RESET)) 30243af08d82Slm66018 cv_signal(&vdc->read_cv); 30253af08d82Slm66018 vdc->read_state = VDC_READ_RESET; 30263af08d82Slm66018 mutex_exit(&vdc->read_lock); 30270a55fbb7Slm66018 30283af08d82Slm66018 /* wake up any threads waiting for connection to come up */ 30293af08d82Slm66018 if (vdc->state == VDC_STATE_INIT_WAITING) { 30303af08d82Slm66018 vdc->state = VDC_STATE_RESETTING; 30313af08d82Slm66018 cv_signal(&vdc->initwait_cv); 30321ae08745Sheppo } 30331ae08745Sheppo 30340a55fbb7Slm66018 mutex_exit(&vdc->lock); 30351ae08745Sheppo } 30361ae08745Sheppo 30371ae08745Sheppo if (event & ~(LDC_EVT_UP | LDC_EVT_RESET | LDC_EVT_DOWN | LDC_EVT_READ)) 30383af08d82Slm66018 DMSG(vdc, 0, "![%d] Unexpected LDC event (%lx) received", 30391ae08745Sheppo vdc->instance, event); 30401ae08745Sheppo 30411ae08745Sheppo return (LDC_SUCCESS); 30421ae08745Sheppo } 30431ae08745Sheppo 30443af08d82Slm66018 /* 30453af08d82Slm66018 * Function: 30463af08d82Slm66018 * vdc_wait_for_response() 30473af08d82Slm66018 * 30483af08d82Slm66018 * Description: 30493af08d82Slm66018 * Block waiting for a response from the server. If there is 30503af08d82Slm66018 * no data the thread block on the read_cv that is signalled 30513af08d82Slm66018 * by the callback when an EVT_READ occurs. 30523af08d82Slm66018 * 30533af08d82Slm66018 * Arguments: 30543af08d82Slm66018 * vdcp - soft state pointer for this instance of the device driver. 30553af08d82Slm66018 * 30563af08d82Slm66018 * Return Code: 30573af08d82Slm66018 * 0 - Success 30583af08d82Slm66018 */ 30593af08d82Slm66018 static int 30603af08d82Slm66018 vdc_wait_for_response(vdc_t *vdcp, vio_msg_t *msgp) 30613af08d82Slm66018 { 30623af08d82Slm66018 size_t nbytes = sizeof (*msgp); 30633af08d82Slm66018 int status; 30643af08d82Slm66018 30653af08d82Slm66018 ASSERT(vdcp != NULL); 30663af08d82Slm66018 30673af08d82Slm66018 DMSG(vdcp, 1, "[%d] Entered\n", vdcp->instance); 30683af08d82Slm66018 30693af08d82Slm66018 status = vdc_recv(vdcp, msgp, &nbytes); 30703af08d82Slm66018 DMSG(vdcp, 3, "vdc_read() done.. status=0x%x size=0x%x\n", 30713af08d82Slm66018 status, (int)nbytes); 30723af08d82Slm66018 if (status) { 30733af08d82Slm66018 DMSG(vdcp, 0, "?[%d] Error %d reading LDC msg\n", 30743af08d82Slm66018 vdcp->instance, status); 30753af08d82Slm66018 return (status); 30763af08d82Slm66018 } 30773af08d82Slm66018 30783af08d82Slm66018 if (nbytes < sizeof (vio_msg_tag_t)) { 30793af08d82Slm66018 DMSG(vdcp, 0, "?[%d] Expect %lu bytes; recv'd %lu\n", 30803af08d82Slm66018 vdcp->instance, sizeof (vio_msg_tag_t), nbytes); 30813af08d82Slm66018 return (ENOMSG); 30823af08d82Slm66018 } 30833af08d82Slm66018 30843af08d82Slm66018 DMSG(vdcp, 2, "[%d] (%x/%x/%x)\n", vdcp->instance, 30853af08d82Slm66018 msgp->tag.vio_msgtype, 30863af08d82Slm66018 msgp->tag.vio_subtype, 30873af08d82Slm66018 msgp->tag.vio_subtype_env); 30883af08d82Slm66018 30893af08d82Slm66018 /* 30903af08d82Slm66018 * Verify the Session ID of the message 30913af08d82Slm66018 * 30923af08d82Slm66018 * Every message after the Version has been negotiated should 30933af08d82Slm66018 * have the correct session ID set. 30943af08d82Slm66018 */ 30953af08d82Slm66018 if ((msgp->tag.vio_sid != vdcp->session_id) && 30963af08d82Slm66018 (msgp->tag.vio_subtype_env != VIO_VER_INFO)) { 30973af08d82Slm66018 DMSG(vdcp, 0, "[%d] Invalid SID: received 0x%x, " 30983af08d82Slm66018 "expected 0x%lx [seq num %lx @ %d]", 30993af08d82Slm66018 vdcp->instance, msgp->tag.vio_sid, 31003af08d82Slm66018 vdcp->session_id, 31013af08d82Slm66018 ((vio_dring_msg_t *)msgp)->seq_num, 31023af08d82Slm66018 ((vio_dring_msg_t *)msgp)->start_idx); 31033af08d82Slm66018 return (ENOMSG); 31043af08d82Slm66018 } 31053af08d82Slm66018 return (0); 31063af08d82Slm66018 } 31073af08d82Slm66018 31083af08d82Slm66018 31093af08d82Slm66018 /* 31103af08d82Slm66018 * Function: 31113af08d82Slm66018 * vdc_resubmit_backup_dring() 31123af08d82Slm66018 * 31133af08d82Slm66018 * Description: 31143af08d82Slm66018 * Resubmit each descriptor in the backed up dring to 31153af08d82Slm66018 * vDisk server. The Dring was backed up during connection 31163af08d82Slm66018 * reset. 31173af08d82Slm66018 * 31183af08d82Slm66018 * Arguments: 31193af08d82Slm66018 * vdcp - soft state pointer for this instance of the device driver. 31203af08d82Slm66018 * 31213af08d82Slm66018 * Return Code: 31223af08d82Slm66018 * 0 - Success 31233af08d82Slm66018 */ 31243af08d82Slm66018 static int 31253af08d82Slm66018 vdc_resubmit_backup_dring(vdc_t *vdcp) 31263af08d82Slm66018 { 31273af08d82Slm66018 int count; 31283af08d82Slm66018 int b_idx; 31293af08d82Slm66018 int rv; 31303af08d82Slm66018 int dring_size; 31313af08d82Slm66018 int status; 31323af08d82Slm66018 vio_msg_t vio_msg; 31333af08d82Slm66018 vdc_local_desc_t *curr_ldep; 31343af08d82Slm66018 31353af08d82Slm66018 ASSERT(MUTEX_NOT_HELD(&vdcp->lock)); 31363af08d82Slm66018 ASSERT(vdcp->state == VDC_STATE_HANDLE_PENDING); 31373af08d82Slm66018 31383af08d82Slm66018 DMSG(vdcp, 1, "restoring pending dring entries (len=%d, tail=%d)\n", 31393af08d82Slm66018 vdcp->local_dring_backup_len, vdcp->local_dring_backup_tail); 31403af08d82Slm66018 31413af08d82Slm66018 /* 31423af08d82Slm66018 * Walk the backup copy of the local descriptor ring and 31433af08d82Slm66018 * resubmit all the outstanding transactions. 31443af08d82Slm66018 */ 31453af08d82Slm66018 b_idx = vdcp->local_dring_backup_tail; 31463af08d82Slm66018 for (count = 0; count < vdcp->local_dring_backup_len; count++) { 31473af08d82Slm66018 31483af08d82Slm66018 curr_ldep = &(vdcp->local_dring_backup[b_idx]); 31493af08d82Slm66018 3150eff7243fSlm66018 /* only resubmit outstanding transactions */ 31513af08d82Slm66018 if (!curr_ldep->is_free) { 31523af08d82Slm66018 31533af08d82Slm66018 DMSG(vdcp, 1, "resubmitting entry idx=%x\n", b_idx); 31543af08d82Slm66018 mutex_enter(&vdcp->lock); 31553af08d82Slm66018 rv = vdc_populate_descriptor(vdcp, curr_ldep->operation, 31563af08d82Slm66018 curr_ldep->addr, curr_ldep->nbytes, 31573af08d82Slm66018 curr_ldep->slice, curr_ldep->offset, 31583af08d82Slm66018 curr_ldep->cb_type, curr_ldep->cb_arg, 31593af08d82Slm66018 curr_ldep->dir); 31603af08d82Slm66018 mutex_exit(&vdcp->lock); 31613af08d82Slm66018 if (rv) { 31623af08d82Slm66018 DMSG(vdcp, 1, "[%d] cannot resubmit entry %d\n", 31633af08d82Slm66018 vdcp->instance, b_idx); 31643af08d82Slm66018 return (rv); 31653af08d82Slm66018 } 31663af08d82Slm66018 31673af08d82Slm66018 /* Wait for the response message. */ 31683af08d82Slm66018 DMSG(vdcp, 1, "waiting for response to idx=%x\n", 31693af08d82Slm66018 b_idx); 31703af08d82Slm66018 status = vdc_wait_for_response(vdcp, &vio_msg); 31713af08d82Slm66018 if (status) { 31723af08d82Slm66018 DMSG(vdcp, 1, "[%d] wait_for_response " 31733af08d82Slm66018 "returned err=%d\n", vdcp->instance, 31743af08d82Slm66018 status); 31753af08d82Slm66018 return (status); 31763af08d82Slm66018 } 31773af08d82Slm66018 31783af08d82Slm66018 DMSG(vdcp, 1, "processing msg for idx=%x\n", b_idx); 31793af08d82Slm66018 status = vdc_process_data_msg(vdcp, &vio_msg); 31803af08d82Slm66018 if (status) { 31813af08d82Slm66018 DMSG(vdcp, 1, "[%d] process_data_msg " 31823af08d82Slm66018 "returned err=%d\n", vdcp->instance, 31833af08d82Slm66018 status); 31843af08d82Slm66018 return (status); 31853af08d82Slm66018 } 31863af08d82Slm66018 } 31873af08d82Slm66018 31883af08d82Slm66018 /* get the next element to submit */ 31893af08d82Slm66018 if (++b_idx >= vdcp->local_dring_backup_len) 31903af08d82Slm66018 b_idx = 0; 31913af08d82Slm66018 } 31923af08d82Slm66018 31933af08d82Slm66018 /* all done - now clear up pending dring copy */ 31943af08d82Slm66018 dring_size = vdcp->local_dring_backup_len * 31953af08d82Slm66018 sizeof (vdcp->local_dring_backup[0]); 31963af08d82Slm66018 31973af08d82Slm66018 (void) kmem_free(vdcp->local_dring_backup, dring_size); 31983af08d82Slm66018 31993af08d82Slm66018 vdcp->local_dring_backup = NULL; 32003af08d82Slm66018 32013af08d82Slm66018 return (0); 32023af08d82Slm66018 } 32033af08d82Slm66018 32043af08d82Slm66018 /* 32053af08d82Slm66018 * Function: 32063af08d82Slm66018 * vdc_backup_local_dring() 32073af08d82Slm66018 * 32083af08d82Slm66018 * Description: 32093af08d82Slm66018 * Backup the current dring in the event of a reset. The Dring 32103af08d82Slm66018 * transactions will be resubmitted to the server when the 32113af08d82Slm66018 * connection is restored. 32123af08d82Slm66018 * 32133af08d82Slm66018 * Arguments: 32143af08d82Slm66018 * vdcp - soft state pointer for this instance of the device driver. 32153af08d82Slm66018 * 32163af08d82Slm66018 * Return Code: 32173af08d82Slm66018 * NONE 32183af08d82Slm66018 */ 32193af08d82Slm66018 static void 32203af08d82Slm66018 vdc_backup_local_dring(vdc_t *vdcp) 32213af08d82Slm66018 { 32223af08d82Slm66018 int dring_size; 32233af08d82Slm66018 32243af08d82Slm66018 ASSERT(vdcp->state == VDC_STATE_RESETTING); 32253af08d82Slm66018 32263af08d82Slm66018 /* 32273af08d82Slm66018 * If the backup dring is stil around, it means 32283af08d82Slm66018 * that the last restore did not complete. However, 32293af08d82Slm66018 * since we never got back into the running state, 32303af08d82Slm66018 * the backup copy we have is still valid. 32313af08d82Slm66018 */ 32323af08d82Slm66018 if (vdcp->local_dring_backup != NULL) { 32333af08d82Slm66018 DMSG(vdcp, 1, "reusing local descriptor ring backup " 32343af08d82Slm66018 "(len=%d, tail=%d)\n", vdcp->local_dring_backup_len, 32353af08d82Slm66018 vdcp->local_dring_backup_tail); 32363af08d82Slm66018 return; 32373af08d82Slm66018 } 32383af08d82Slm66018 32393af08d82Slm66018 DMSG(vdcp, 1, "backing up the local descriptor ring (len=%d, " 32403af08d82Slm66018 "tail=%d)\n", vdcp->dring_len, vdcp->dring_curr_idx); 32413af08d82Slm66018 32423af08d82Slm66018 dring_size = vdcp->dring_len * sizeof (vdcp->local_dring[0]); 32433af08d82Slm66018 32443af08d82Slm66018 vdcp->local_dring_backup = kmem_alloc(dring_size, KM_SLEEP); 32453af08d82Slm66018 bcopy(vdcp->local_dring, vdcp->local_dring_backup, dring_size); 32463af08d82Slm66018 32473af08d82Slm66018 vdcp->local_dring_backup_tail = vdcp->dring_curr_idx; 32483af08d82Slm66018 vdcp->local_dring_backup_len = vdcp->dring_len; 32493af08d82Slm66018 } 32503af08d82Slm66018 32511ae08745Sheppo /* -------------------------------------------------------------------------- */ 32521ae08745Sheppo 32531ae08745Sheppo /* 32541ae08745Sheppo * The following functions process the incoming messages from vds 32551ae08745Sheppo */ 32561ae08745Sheppo 32570a55fbb7Slm66018 /* 32580a55fbb7Slm66018 * Function: 32590a55fbb7Slm66018 * vdc_process_msg_thread() 32600a55fbb7Slm66018 * 32610a55fbb7Slm66018 * Description: 32620a55fbb7Slm66018 * 32633af08d82Slm66018 * Main VDC message processing thread. Each vDisk instance 32643af08d82Slm66018 * consists of a copy of this thread. This thread triggers 32653af08d82Slm66018 * all the handshakes and data exchange with the server. It 32663af08d82Slm66018 * also handles all channel resets 32673af08d82Slm66018 * 32680a55fbb7Slm66018 * Arguments: 32690a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 32700a55fbb7Slm66018 * 32710a55fbb7Slm66018 * Return Code: 32720a55fbb7Slm66018 * None 32730a55fbb7Slm66018 */ 32741ae08745Sheppo static void 32753af08d82Slm66018 vdc_process_msg_thread(vdc_t *vdcp) 32761ae08745Sheppo { 32771ae08745Sheppo int status; 32781ae08745Sheppo 32793af08d82Slm66018 mutex_enter(&vdcp->lock); 32801ae08745Sheppo 32811ae08745Sheppo for (;;) { 32821ae08745Sheppo 32833af08d82Slm66018 #define Q(_s) (vdcp->state == _s) ? #_s : 32843af08d82Slm66018 DMSG(vdcp, 3, "state = %d (%s)\n", vdcp->state, 32853af08d82Slm66018 Q(VDC_STATE_INIT) 32863af08d82Slm66018 Q(VDC_STATE_INIT_WAITING) 32873af08d82Slm66018 Q(VDC_STATE_NEGOTIATE) 32883af08d82Slm66018 Q(VDC_STATE_HANDLE_PENDING) 32893af08d82Slm66018 Q(VDC_STATE_RUNNING) 32903af08d82Slm66018 Q(VDC_STATE_RESETTING) 32913af08d82Slm66018 Q(VDC_STATE_DETACH) 32923af08d82Slm66018 "UNKNOWN"); 32931ae08745Sheppo 32943af08d82Slm66018 switch (vdcp->state) { 32953af08d82Slm66018 case VDC_STATE_INIT: 32963af08d82Slm66018 32973af08d82Slm66018 /* Check if have re-initializing repeatedly */ 32983c96341aSnarayan if (vdcp->hshake_cnt++ > vdc_hshake_retries) { 32993c96341aSnarayan cmn_err(CE_NOTE, "[%d] disk access failed.\n", 33003c96341aSnarayan vdcp->instance); 33013af08d82Slm66018 vdcp->state = VDC_STATE_DETACH; 33023af08d82Slm66018 break; 33033af08d82Slm66018 } 33043af08d82Slm66018 33053af08d82Slm66018 /* Bring up connection with vds via LDC */ 33063af08d82Slm66018 status = vdc_start_ldc_connection(vdcp); 33073af08d82Slm66018 switch (status) { 33083af08d82Slm66018 case EINVAL: 33093af08d82Slm66018 DMSG(vdcp, 0, "[%d] Could not start LDC", 33103af08d82Slm66018 vdcp->instance); 33113af08d82Slm66018 vdcp->state = VDC_STATE_DETACH; 33123af08d82Slm66018 break; 33133af08d82Slm66018 case 0: 33143af08d82Slm66018 vdcp->state = VDC_STATE_INIT_WAITING; 33153af08d82Slm66018 break; 33163af08d82Slm66018 default: 33173af08d82Slm66018 vdcp->state = VDC_STATE_INIT_WAITING; 33183af08d82Slm66018 break; 33193af08d82Slm66018 } 33203af08d82Slm66018 break; 33213af08d82Slm66018 33223af08d82Slm66018 case VDC_STATE_INIT_WAITING: 33233af08d82Slm66018 33243af08d82Slm66018 /* 33253af08d82Slm66018 * Let the callback event move us on 33263af08d82Slm66018 * when channel is open to server 33273af08d82Slm66018 */ 33283af08d82Slm66018 while (vdcp->ldc_state != LDC_UP) { 33293af08d82Slm66018 cv_wait(&vdcp->initwait_cv, &vdcp->lock); 33303af08d82Slm66018 if (vdcp->state != VDC_STATE_INIT_WAITING) { 33313af08d82Slm66018 DMSG(vdcp, 0, 33323af08d82Slm66018 "state moved to %d out from under us...\n", 33333af08d82Slm66018 vdcp->state); 33343af08d82Slm66018 33353af08d82Slm66018 break; 33363af08d82Slm66018 } 33373af08d82Slm66018 } 33383af08d82Slm66018 if (vdcp->state == VDC_STATE_INIT_WAITING && 33393af08d82Slm66018 vdcp->ldc_state == LDC_UP) { 33403af08d82Slm66018 vdcp->state = VDC_STATE_NEGOTIATE; 33413af08d82Slm66018 } 33423af08d82Slm66018 break; 33433af08d82Slm66018 33443af08d82Slm66018 case VDC_STATE_NEGOTIATE: 33453af08d82Slm66018 switch (status = vdc_ver_negotiation(vdcp)) { 33463af08d82Slm66018 case 0: 33473af08d82Slm66018 break; 33483af08d82Slm66018 default: 33493af08d82Slm66018 DMSG(vdcp, 0, "ver negotiate failed (%d)..\n", 33503af08d82Slm66018 status); 33513af08d82Slm66018 goto reset; 33523af08d82Slm66018 } 33533af08d82Slm66018 33543af08d82Slm66018 switch (status = vdc_attr_negotiation(vdcp)) { 33553af08d82Slm66018 case 0: 33563af08d82Slm66018 break; 33573af08d82Slm66018 default: 33583af08d82Slm66018 DMSG(vdcp, 0, "attr negotiate failed (%d)..\n", 33593af08d82Slm66018 status); 33603af08d82Slm66018 goto reset; 33613af08d82Slm66018 } 33623af08d82Slm66018 33633af08d82Slm66018 switch (status = vdc_dring_negotiation(vdcp)) { 33643af08d82Slm66018 case 0: 33653af08d82Slm66018 break; 33663af08d82Slm66018 default: 33673af08d82Slm66018 DMSG(vdcp, 0, "dring negotiate failed (%d)..\n", 33683af08d82Slm66018 status); 33693af08d82Slm66018 goto reset; 33703af08d82Slm66018 } 33713af08d82Slm66018 33723af08d82Slm66018 switch (status = vdc_rdx_exchange(vdcp)) { 33733af08d82Slm66018 case 0: 33743af08d82Slm66018 vdcp->state = VDC_STATE_HANDLE_PENDING; 33753af08d82Slm66018 goto done; 33763af08d82Slm66018 default: 33773af08d82Slm66018 DMSG(vdcp, 0, "RDX xchg failed ..(%d)\n", 33783af08d82Slm66018 status); 33793af08d82Slm66018 goto reset; 33803af08d82Slm66018 } 33813af08d82Slm66018 reset: 33823af08d82Slm66018 DMSG(vdcp, 0, "negotiation failed: resetting (%d)\n", 33833af08d82Slm66018 status); 33843af08d82Slm66018 vdcp->state = VDC_STATE_RESETTING; 33853af08d82Slm66018 done: 33863af08d82Slm66018 DMSG(vdcp, 0, "negotiation complete (state=0x%x)...\n", 33873af08d82Slm66018 vdcp->state); 33883af08d82Slm66018 break; 33893af08d82Slm66018 33903af08d82Slm66018 case VDC_STATE_HANDLE_PENDING: 33913af08d82Slm66018 33923af08d82Slm66018 mutex_exit(&vdcp->lock); 33933af08d82Slm66018 status = vdc_resubmit_backup_dring(vdcp); 33943af08d82Slm66018 mutex_enter(&vdcp->lock); 33953af08d82Slm66018 33963af08d82Slm66018 if (status) 33973af08d82Slm66018 vdcp->state = VDC_STATE_RESETTING; 33983af08d82Slm66018 else 33993af08d82Slm66018 vdcp->state = VDC_STATE_RUNNING; 34003af08d82Slm66018 34013af08d82Slm66018 break; 34023af08d82Slm66018 34033af08d82Slm66018 /* enter running state */ 34043af08d82Slm66018 case VDC_STATE_RUNNING: 34053af08d82Slm66018 /* 34063af08d82Slm66018 * Signal anyone waiting for the connection 34073af08d82Slm66018 * to come on line. 34083af08d82Slm66018 */ 34093af08d82Slm66018 vdcp->hshake_cnt = 0; 34103af08d82Slm66018 cv_broadcast(&vdcp->running_cv); 34113af08d82Slm66018 mutex_exit(&vdcp->lock); 34123af08d82Slm66018 34133af08d82Slm66018 for (;;) { 34143af08d82Slm66018 vio_msg_t msg; 34153af08d82Slm66018 status = vdc_wait_for_response(vdcp, &msg); 34163af08d82Slm66018 if (status) break; 34173af08d82Slm66018 34183af08d82Slm66018 DMSG(vdcp, 1, "[%d] new pkt(s) available\n", 34193af08d82Slm66018 vdcp->instance); 34203af08d82Slm66018 status = vdc_process_data_msg(vdcp, &msg); 34211ae08745Sheppo if (status) { 34223af08d82Slm66018 DMSG(vdcp, 1, "[%d] process_data_msg " 34233af08d82Slm66018 "returned err=%d\n", vdcp->instance, 34243af08d82Slm66018 status); 34251ae08745Sheppo break; 34261ae08745Sheppo } 34271ae08745Sheppo 34283af08d82Slm66018 } 3429e1ebb9ecSlm66018 34303af08d82Slm66018 mutex_enter(&vdcp->lock); 34313af08d82Slm66018 34323af08d82Slm66018 vdcp->state = VDC_STATE_RESETTING; 3433690555a1Sachartre vdcp->self_reset = B_TRUE; 34343af08d82Slm66018 break; 34353af08d82Slm66018 34363af08d82Slm66018 case VDC_STATE_RESETTING: 34373af08d82Slm66018 DMSG(vdcp, 0, "Initiating channel reset " 34383af08d82Slm66018 "(pending = %d)\n", (int)vdcp->threads_pending); 34393af08d82Slm66018 34403af08d82Slm66018 if (vdcp->self_reset) { 34413af08d82Slm66018 DMSG(vdcp, 0, 34423af08d82Slm66018 "[%d] calling stop_ldc_connection.\n", 34433af08d82Slm66018 vdcp->instance); 34443af08d82Slm66018 status = vdc_stop_ldc_connection(vdcp); 34453af08d82Slm66018 vdcp->self_reset = B_FALSE; 34461ae08745Sheppo } 34471ae08745Sheppo 34481ae08745Sheppo /* 34493af08d82Slm66018 * Wait for all threads currently waiting 34503af08d82Slm66018 * for a free dring entry to use. 34511ae08745Sheppo */ 34523af08d82Slm66018 while (vdcp->threads_pending) { 34533af08d82Slm66018 cv_broadcast(&vdcp->membind_cv); 34543af08d82Slm66018 cv_broadcast(&vdcp->dring_free_cv); 34553af08d82Slm66018 mutex_exit(&vdcp->lock); 3456*205eeb1aSlm66018 /* give the waiters enough time to wake up */ 3457*205eeb1aSlm66018 delay(vdc_hz_min_ldc_delay); 34583af08d82Slm66018 mutex_enter(&vdcp->lock); 34591ae08745Sheppo } 34601ae08745Sheppo 34613af08d82Slm66018 ASSERT(vdcp->threads_pending == 0); 34621ae08745Sheppo 34633af08d82Slm66018 /* Sanity check that no thread is receiving */ 34643af08d82Slm66018 ASSERT(vdcp->read_state != VDC_READ_WAITING); 34650a55fbb7Slm66018 34663af08d82Slm66018 vdcp->read_state = VDC_READ_IDLE; 34673af08d82Slm66018 34683af08d82Slm66018 vdc_backup_local_dring(vdcp); 34693af08d82Slm66018 34703af08d82Slm66018 /* cleanup the old d-ring */ 34713af08d82Slm66018 vdc_destroy_descriptor_ring(vdcp); 34723af08d82Slm66018 34733af08d82Slm66018 /* go and start again */ 34743af08d82Slm66018 vdcp->state = VDC_STATE_INIT; 34753af08d82Slm66018 34760a55fbb7Slm66018 break; 34770a55fbb7Slm66018 34783af08d82Slm66018 case VDC_STATE_DETACH: 34793af08d82Slm66018 DMSG(vdcp, 0, "[%d] Reset thread exit cleanup ..\n", 34803af08d82Slm66018 vdcp->instance); 34813af08d82Slm66018 34823c96341aSnarayan /* 34833c96341aSnarayan * Signal anyone waiting for connection 34843c96341aSnarayan * to come online 34853c96341aSnarayan */ 34863c96341aSnarayan cv_broadcast(&vdcp->running_cv); 34873c96341aSnarayan 34883af08d82Slm66018 while (vdcp->sync_op_pending) { 34893af08d82Slm66018 cv_signal(&vdcp->sync_pending_cv); 34903af08d82Slm66018 cv_signal(&vdcp->sync_blocked_cv); 34913af08d82Slm66018 mutex_exit(&vdcp->lock); 3492*205eeb1aSlm66018 /* give the waiters enough time to wake up */ 3493*205eeb1aSlm66018 delay(vdc_hz_min_ldc_delay); 34943af08d82Slm66018 mutex_enter(&vdcp->lock); 34950a55fbb7Slm66018 } 34961ae08745Sheppo 34973af08d82Slm66018 mutex_exit(&vdcp->lock); 34983af08d82Slm66018 34993af08d82Slm66018 DMSG(vdcp, 0, "[%d] Msg processing thread exiting ..\n", 35003af08d82Slm66018 vdcp->instance); 35013af08d82Slm66018 thread_exit(); 35023af08d82Slm66018 break; 35033af08d82Slm66018 } 35043af08d82Slm66018 } 35050a55fbb7Slm66018 } 35060a55fbb7Slm66018 35070a55fbb7Slm66018 35080a55fbb7Slm66018 /* 35090a55fbb7Slm66018 * Function: 35100a55fbb7Slm66018 * vdc_process_data_msg() 35110a55fbb7Slm66018 * 35120a55fbb7Slm66018 * Description: 35130a55fbb7Slm66018 * This function is called by the message processing thread each time 35140a55fbb7Slm66018 * a message with a msgtype of VIO_TYPE_DATA is received. It will either 35150a55fbb7Slm66018 * be an ACK or NACK from vds[1] which vdc handles as follows. 35160a55fbb7Slm66018 * ACK - wake up the waiting thread 35170a55fbb7Slm66018 * NACK - resend any messages necessary 35180a55fbb7Slm66018 * 35190a55fbb7Slm66018 * [1] Although the message format allows it, vds should not send a 35200a55fbb7Slm66018 * VIO_SUBTYPE_INFO message to vdc asking it to read data; if for 35210a55fbb7Slm66018 * some bizarre reason it does, vdc will reset the connection. 35220a55fbb7Slm66018 * 35230a55fbb7Slm66018 * Arguments: 35240a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 35250a55fbb7Slm66018 * msg - the LDC message sent by vds 35260a55fbb7Slm66018 * 35270a55fbb7Slm66018 * Return Code: 35280a55fbb7Slm66018 * 0 - Success. 35290a55fbb7Slm66018 * > 0 - error value returned by LDC 35300a55fbb7Slm66018 */ 35310a55fbb7Slm66018 static int 35323af08d82Slm66018 vdc_process_data_msg(vdc_t *vdcp, vio_msg_t *msg) 35330a55fbb7Slm66018 { 35340a55fbb7Slm66018 int status = 0; 35353af08d82Slm66018 vio_dring_msg_t *dring_msg; 3536d10e4ef2Snarayan vdc_local_desc_t *ldep = NULL; 35373af08d82Slm66018 int start, end; 35383af08d82Slm66018 int idx; 35390a55fbb7Slm66018 35403af08d82Slm66018 dring_msg = (vio_dring_msg_t *)msg; 35410a55fbb7Slm66018 35423af08d82Slm66018 ASSERT(msg->tag.vio_msgtype == VIO_TYPE_DATA); 35433af08d82Slm66018 ASSERT(vdcp != NULL); 35443af08d82Slm66018 35453af08d82Slm66018 mutex_enter(&vdcp->lock); 35460a55fbb7Slm66018 35470a55fbb7Slm66018 /* 35480a55fbb7Slm66018 * Check to see if the message has bogus data 35490a55fbb7Slm66018 */ 3550e1ebb9ecSlm66018 idx = start = dring_msg->start_idx; 35510a55fbb7Slm66018 end = dring_msg->end_idx; 35523af08d82Slm66018 if ((start >= vdcp->dring_len) || 35533af08d82Slm66018 (end >= vdcp->dring_len) || (end < -1)) { 35543af08d82Slm66018 DMSG(vdcp, 0, "[%d] Bogus ACK data : start %d, end %d\n", 35553af08d82Slm66018 vdcp->instance, start, end); 35563af08d82Slm66018 mutex_exit(&vdcp->lock); 3557e1ebb9ecSlm66018 return (EINVAL); 35580a55fbb7Slm66018 } 35590a55fbb7Slm66018 35600a55fbb7Slm66018 /* 35610a55fbb7Slm66018 * Verify that the sequence number is what vdc expects. 35620a55fbb7Slm66018 */ 35633af08d82Slm66018 switch (vdc_verify_seq_num(vdcp, dring_msg)) { 3564e1ebb9ecSlm66018 case VDC_SEQ_NUM_TODO: 3565e1ebb9ecSlm66018 break; /* keep processing this message */ 3566e1ebb9ecSlm66018 case VDC_SEQ_NUM_SKIP: 35673af08d82Slm66018 mutex_exit(&vdcp->lock); 3568e1ebb9ecSlm66018 return (0); 3569e1ebb9ecSlm66018 case VDC_SEQ_NUM_INVALID: 35703af08d82Slm66018 mutex_exit(&vdcp->lock); 35713af08d82Slm66018 DMSG(vdcp, 0, "[%d] invalid seqno\n", vdcp->instance); 35720a55fbb7Slm66018 return (ENXIO); 35730a55fbb7Slm66018 } 35740a55fbb7Slm66018 35753af08d82Slm66018 if (msg->tag.vio_subtype == VIO_SUBTYPE_NACK) { 35763af08d82Slm66018 DMSG(vdcp, 0, "[%d] DATA NACK\n", vdcp->instance); 3577e1ebb9ecSlm66018 VDC_DUMP_DRING_MSG(dring_msg); 35783af08d82Slm66018 mutex_exit(&vdcp->lock); 3579e1ebb9ecSlm66018 return (EIO); 35800a55fbb7Slm66018 35813af08d82Slm66018 } else if (msg->tag.vio_subtype == VIO_SUBTYPE_INFO) { 35823af08d82Slm66018 mutex_exit(&vdcp->lock); 3583e1ebb9ecSlm66018 return (EPROTO); 3584e1ebb9ecSlm66018 } 3585e1ebb9ecSlm66018 35863af08d82Slm66018 DTRACE_IO2(recv, vio_dring_msg_t, dring_msg, vdc_t *, vdcp); 35873af08d82Slm66018 DMSG(vdcp, 1, ": start %d end %d\n", start, end); 35883af08d82Slm66018 ASSERT(start == end); 35893af08d82Slm66018 35903af08d82Slm66018 ldep = &vdcp->local_dring[idx]; 35913af08d82Slm66018 35923af08d82Slm66018 DMSG(vdcp, 1, ": state 0x%x - cb_type 0x%x\n", 35933af08d82Slm66018 ldep->dep->hdr.dstate, ldep->cb_type); 35943af08d82Slm66018 3595e1ebb9ecSlm66018 if (ldep->dep->hdr.dstate == VIO_DESC_DONE) { 35963af08d82Slm66018 struct buf *bufp; 3597e1ebb9ecSlm66018 35983af08d82Slm66018 switch (ldep->cb_type) { 35993af08d82Slm66018 case CB_SYNC: 36003af08d82Slm66018 ASSERT(vdcp->sync_op_pending); 3601d10e4ef2Snarayan 36023af08d82Slm66018 status = vdc_depopulate_descriptor(vdcp, idx); 36033af08d82Slm66018 vdcp->sync_op_status = status; 36043af08d82Slm66018 vdcp->sync_op_pending = B_FALSE; 36053af08d82Slm66018 cv_signal(&vdcp->sync_pending_cv); 36063af08d82Slm66018 break; 36074bac2208Snarayan 36083af08d82Slm66018 case CB_STRATEGY: 36093af08d82Slm66018 bufp = ldep->cb_arg; 36103af08d82Slm66018 ASSERT(bufp != NULL); 36113c96341aSnarayan bufp->b_resid = 36123c96341aSnarayan bufp->b_bcount - ldep->dep->payload.nbytes; 36133af08d82Slm66018 status = ldep->dep->payload.status; /* Future:ntoh */ 36143af08d82Slm66018 if (status != 0) { 36153af08d82Slm66018 DMSG(vdcp, 1, "strategy status=%d\n", status); 36163af08d82Slm66018 bioerror(bufp, status); 3617d10e4ef2Snarayan } 36183af08d82Slm66018 status = vdc_depopulate_descriptor(vdcp, idx); 36193af08d82Slm66018 biodone(bufp); 36203c96341aSnarayan 36213c96341aSnarayan DMSG(vdcp, 1, 36223c96341aSnarayan "strategy complete req=%ld bytes resp=%ld bytes\n", 36233c96341aSnarayan bufp->b_bcount, ldep->dep->payload.nbytes); 36243af08d82Slm66018 break; 36253af08d82Slm66018 36263af08d82Slm66018 default: 36273af08d82Slm66018 ASSERT(0); 36280a55fbb7Slm66018 } 36293af08d82Slm66018 } 36303af08d82Slm66018 36313af08d82Slm66018 /* let the arrival signal propogate */ 36323af08d82Slm66018 mutex_exit(&vdcp->lock); 36330a55fbb7Slm66018 3634e1ebb9ecSlm66018 /* probe gives the count of how many entries were processed */ 36353af08d82Slm66018 DTRACE_IO2(processed, int, 1, vdc_t *, vdcp); 36360a55fbb7Slm66018 36373af08d82Slm66018 return (0); 36380a55fbb7Slm66018 } 36390a55fbb7Slm66018 36400a55fbb7Slm66018 /* 36410a55fbb7Slm66018 * Function: 36420a55fbb7Slm66018 * vdc_process_err_msg() 36430a55fbb7Slm66018 * 36440a55fbb7Slm66018 * NOTE: No error messages are used as part of the vDisk protocol 36450a55fbb7Slm66018 */ 36460a55fbb7Slm66018 static int 36470a55fbb7Slm66018 vdc_process_err_msg(vdc_t *vdc, vio_msg_t msg) 36480a55fbb7Slm66018 { 36490a55fbb7Slm66018 _NOTE(ARGUNUSED(vdc)) 36500a55fbb7Slm66018 _NOTE(ARGUNUSED(msg)) 36510a55fbb7Slm66018 36520a55fbb7Slm66018 ASSERT(msg.tag.vio_msgtype == VIO_TYPE_ERR); 36533af08d82Slm66018 DMSG(vdc, 1, "[%d] Got an ERR msg", vdc->instance); 36540a55fbb7Slm66018 36550a55fbb7Slm66018 return (ENOTSUP); 36560a55fbb7Slm66018 } 36570a55fbb7Slm66018 36580a55fbb7Slm66018 /* 36590a55fbb7Slm66018 * Function: 36600a55fbb7Slm66018 * vdc_handle_ver_msg() 36610a55fbb7Slm66018 * 36620a55fbb7Slm66018 * Description: 36630a55fbb7Slm66018 * 36640a55fbb7Slm66018 * Arguments: 36650a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 36660a55fbb7Slm66018 * ver_msg - LDC message sent by vDisk server 36670a55fbb7Slm66018 * 36680a55fbb7Slm66018 * Return Code: 36690a55fbb7Slm66018 * 0 - Success 36700a55fbb7Slm66018 */ 36710a55fbb7Slm66018 static int 36720a55fbb7Slm66018 vdc_handle_ver_msg(vdc_t *vdc, vio_ver_msg_t *ver_msg) 36730a55fbb7Slm66018 { 36740a55fbb7Slm66018 int status = 0; 36750a55fbb7Slm66018 36760a55fbb7Slm66018 ASSERT(vdc != NULL); 36770a55fbb7Slm66018 ASSERT(mutex_owned(&vdc->lock)); 36780a55fbb7Slm66018 36790a55fbb7Slm66018 if (ver_msg->tag.vio_subtype_env != VIO_VER_INFO) { 36800a55fbb7Slm66018 return (EPROTO); 36810a55fbb7Slm66018 } 36820a55fbb7Slm66018 36830a55fbb7Slm66018 if (ver_msg->dev_class != VDEV_DISK_SERVER) { 36840a55fbb7Slm66018 return (EINVAL); 36850a55fbb7Slm66018 } 36860a55fbb7Slm66018 36870a55fbb7Slm66018 switch (ver_msg->tag.vio_subtype) { 36880a55fbb7Slm66018 case VIO_SUBTYPE_ACK: 36890a55fbb7Slm66018 /* 36900a55fbb7Slm66018 * We check to see if the version returned is indeed supported 36910a55fbb7Slm66018 * (The server may have also adjusted the minor number downwards 36920a55fbb7Slm66018 * and if so 'ver_msg' will contain the actual version agreed) 36930a55fbb7Slm66018 */ 36940a55fbb7Slm66018 if (vdc_is_supported_version(ver_msg)) { 36950a55fbb7Slm66018 vdc->ver.major = ver_msg->ver_major; 36960a55fbb7Slm66018 vdc->ver.minor = ver_msg->ver_minor; 36970a55fbb7Slm66018 ASSERT(vdc->ver.major > 0); 36980a55fbb7Slm66018 } else { 36990a55fbb7Slm66018 status = EPROTO; 37000a55fbb7Slm66018 } 37010a55fbb7Slm66018 break; 37020a55fbb7Slm66018 37030a55fbb7Slm66018 case VIO_SUBTYPE_NACK: 37040a55fbb7Slm66018 /* 37050a55fbb7Slm66018 * call vdc_is_supported_version() which will return the next 37060a55fbb7Slm66018 * supported version (if any) in 'ver_msg' 37070a55fbb7Slm66018 */ 37080a55fbb7Slm66018 (void) vdc_is_supported_version(ver_msg); 37090a55fbb7Slm66018 if (ver_msg->ver_major > 0) { 37100a55fbb7Slm66018 size_t len = sizeof (*ver_msg); 37110a55fbb7Slm66018 37120a55fbb7Slm66018 ASSERT(vdc->ver.major > 0); 37130a55fbb7Slm66018 37140a55fbb7Slm66018 /* reset the necessary fields and resend */ 37150a55fbb7Slm66018 ver_msg->tag.vio_subtype = VIO_SUBTYPE_INFO; 37160a55fbb7Slm66018 ver_msg->dev_class = VDEV_DISK; 37170a55fbb7Slm66018 37180a55fbb7Slm66018 status = vdc_send(vdc, (caddr_t)ver_msg, &len); 37193af08d82Slm66018 DMSG(vdc, 0, "[%d] Resend VER info (LDC status = %d)\n", 37200a55fbb7Slm66018 vdc->instance, status); 37210a55fbb7Slm66018 if (len != sizeof (*ver_msg)) 37220a55fbb7Slm66018 status = EBADMSG; 37230a55fbb7Slm66018 } else { 372487a7269eSachartre DMSG(vdc, 0, "[%d] No common version with vDisk server", 372587a7269eSachartre vdc->instance); 37260a55fbb7Slm66018 status = ENOTSUP; 37270a55fbb7Slm66018 } 37280a55fbb7Slm66018 37290a55fbb7Slm66018 break; 37301ae08745Sheppo case VIO_SUBTYPE_INFO: 37311ae08745Sheppo /* 37321ae08745Sheppo * Handle the case where vds starts handshake 3733eff7243fSlm66018 * (for now only vdc is the instigator) 37341ae08745Sheppo */ 37351ae08745Sheppo status = ENOTSUP; 37361ae08745Sheppo break; 37371ae08745Sheppo 37381ae08745Sheppo default: 37390a55fbb7Slm66018 status = EINVAL; 37401ae08745Sheppo break; 37411ae08745Sheppo } 37421ae08745Sheppo 37430a55fbb7Slm66018 return (status); 37440a55fbb7Slm66018 } 37450a55fbb7Slm66018 37460a55fbb7Slm66018 /* 37470a55fbb7Slm66018 * Function: 37480a55fbb7Slm66018 * vdc_handle_attr_msg() 37490a55fbb7Slm66018 * 37500a55fbb7Slm66018 * Description: 37510a55fbb7Slm66018 * 37520a55fbb7Slm66018 * Arguments: 37530a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 37540a55fbb7Slm66018 * attr_msg - LDC message sent by vDisk server 37550a55fbb7Slm66018 * 37560a55fbb7Slm66018 * Return Code: 37570a55fbb7Slm66018 * 0 - Success 37580a55fbb7Slm66018 */ 37590a55fbb7Slm66018 static int 37600a55fbb7Slm66018 vdc_handle_attr_msg(vdc_t *vdc, vd_attr_msg_t *attr_msg) 37610a55fbb7Slm66018 { 37620a55fbb7Slm66018 int status = 0; 37630a55fbb7Slm66018 37640a55fbb7Slm66018 ASSERT(vdc != NULL); 37650a55fbb7Slm66018 ASSERT(mutex_owned(&vdc->lock)); 37660a55fbb7Slm66018 37670a55fbb7Slm66018 if (attr_msg->tag.vio_subtype_env != VIO_ATTR_INFO) { 37680a55fbb7Slm66018 return (EPROTO); 37690a55fbb7Slm66018 } 37700a55fbb7Slm66018 37710a55fbb7Slm66018 switch (attr_msg->tag.vio_subtype) { 37721ae08745Sheppo case VIO_SUBTYPE_ACK: 37731ae08745Sheppo /* 37741ae08745Sheppo * We now verify the attributes sent by vds. 37751ae08745Sheppo */ 37761ae08745Sheppo vdc->vdisk_size = attr_msg->vdisk_size; 37771ae08745Sheppo vdc->vdisk_type = attr_msg->vdisk_type; 37781ae08745Sheppo 37793af08d82Slm66018 DMSG(vdc, 0, "[%d] max_xfer_sz: sent %lx acked %lx\n", 3780e1ebb9ecSlm66018 vdc->instance, vdc->max_xfer_sz, attr_msg->max_xfer_sz); 37813af08d82Slm66018 DMSG(vdc, 0, "[%d] vdisk_block_size: sent %lx acked %x\n", 3782e1ebb9ecSlm66018 vdc->instance, vdc->block_size, 3783e1ebb9ecSlm66018 attr_msg->vdisk_block_size); 3784e1ebb9ecSlm66018 37851ae08745Sheppo /* 3786e1ebb9ecSlm66018 * We don't know at compile time what the vDisk server will 3787e1ebb9ecSlm66018 * think are good values but we apply an large (arbitrary) 3788e1ebb9ecSlm66018 * upper bound to prevent memory exhaustion in vdc if it was 3789e1ebb9ecSlm66018 * allocating a DRing based of huge values sent by the server. 3790e1ebb9ecSlm66018 * We probably will never exceed this except if the message 3791e1ebb9ecSlm66018 * was garbage. 37921ae08745Sheppo */ 3793e1ebb9ecSlm66018 if ((attr_msg->max_xfer_sz * attr_msg->vdisk_block_size) <= 3794e1ebb9ecSlm66018 (PAGESIZE * DEV_BSIZE)) { 3795e1ebb9ecSlm66018 vdc->max_xfer_sz = attr_msg->max_xfer_sz; 3796e1ebb9ecSlm66018 vdc->block_size = attr_msg->vdisk_block_size; 3797e1ebb9ecSlm66018 } else { 37983af08d82Slm66018 DMSG(vdc, 0, "[%d] vds block transfer size too big;" 3799e1ebb9ecSlm66018 " using max supported by vdc", vdc->instance); 38001ae08745Sheppo } 38011ae08745Sheppo 38021ae08745Sheppo if ((attr_msg->xfer_mode != VIO_DRING_MODE) || 38031ae08745Sheppo (attr_msg->vdisk_size > INT64_MAX) || 38041ae08745Sheppo (attr_msg->vdisk_type > VD_DISK_TYPE_DISK)) { 38053af08d82Slm66018 DMSG(vdc, 0, "[%d] Invalid attributes from vds", 3806e1ebb9ecSlm66018 vdc->instance); 38071ae08745Sheppo status = EINVAL; 38081ae08745Sheppo break; 38091ae08745Sheppo } 38101ae08745Sheppo 38111ae08745Sheppo break; 38121ae08745Sheppo 38131ae08745Sheppo case VIO_SUBTYPE_NACK: 38141ae08745Sheppo /* 38151ae08745Sheppo * vds could not handle the attributes we sent so we 38161ae08745Sheppo * stop negotiating. 38171ae08745Sheppo */ 38181ae08745Sheppo status = EPROTO; 38191ae08745Sheppo break; 38201ae08745Sheppo 38211ae08745Sheppo case VIO_SUBTYPE_INFO: 38221ae08745Sheppo /* 38231ae08745Sheppo * Handle the case where vds starts the handshake 38241ae08745Sheppo * (for now; vdc is the only supported instigatior) 38251ae08745Sheppo */ 38261ae08745Sheppo status = ENOTSUP; 38271ae08745Sheppo break; 38281ae08745Sheppo 38291ae08745Sheppo default: 38301ae08745Sheppo status = ENOTSUP; 38311ae08745Sheppo break; 38321ae08745Sheppo } 38331ae08745Sheppo 38340a55fbb7Slm66018 return (status); 38351ae08745Sheppo } 38361ae08745Sheppo 38370a55fbb7Slm66018 /* 38380a55fbb7Slm66018 * Function: 38390a55fbb7Slm66018 * vdc_handle_dring_reg_msg() 38400a55fbb7Slm66018 * 38410a55fbb7Slm66018 * Description: 38420a55fbb7Slm66018 * 38430a55fbb7Slm66018 * Arguments: 38440a55fbb7Slm66018 * vdc - soft state pointer for this instance of the driver. 38450a55fbb7Slm66018 * dring_msg - LDC message sent by vDisk server 38460a55fbb7Slm66018 * 38470a55fbb7Slm66018 * Return Code: 38480a55fbb7Slm66018 * 0 - Success 38490a55fbb7Slm66018 */ 38500a55fbb7Slm66018 static int 38510a55fbb7Slm66018 vdc_handle_dring_reg_msg(vdc_t *vdc, vio_dring_reg_msg_t *dring_msg) 38520a55fbb7Slm66018 { 38530a55fbb7Slm66018 int status = 0; 38541ae08745Sheppo 38550a55fbb7Slm66018 ASSERT(vdc != NULL); 38560a55fbb7Slm66018 ASSERT(mutex_owned(&vdc->lock)); 38570a55fbb7Slm66018 38580a55fbb7Slm66018 if (dring_msg->tag.vio_subtype_env != VIO_DRING_REG) { 38590a55fbb7Slm66018 return (EPROTO); 38600a55fbb7Slm66018 } 38610a55fbb7Slm66018 38620a55fbb7Slm66018 switch (dring_msg->tag.vio_subtype) { 38630a55fbb7Slm66018 case VIO_SUBTYPE_ACK: 38641ae08745Sheppo /* save the received dring_ident */ 38651ae08745Sheppo vdc->dring_ident = dring_msg->dring_ident; 38663af08d82Slm66018 DMSG(vdc, 0, "[%d] Received dring ident=0x%lx\n", 3867e1ebb9ecSlm66018 vdc->instance, vdc->dring_ident); 38681ae08745Sheppo break; 38691ae08745Sheppo 38701ae08745Sheppo case VIO_SUBTYPE_NACK: 38711ae08745Sheppo /* 38721ae08745Sheppo * vds could not handle the DRing info we sent so we 38731ae08745Sheppo * stop negotiating. 38741ae08745Sheppo */ 38753af08d82Slm66018 DMSG(vdc, 0, "[%d] server could not register DRing\n", 38763af08d82Slm66018 vdc->instance); 38771ae08745Sheppo status = EPROTO; 38781ae08745Sheppo break; 38791ae08745Sheppo 38801ae08745Sheppo case VIO_SUBTYPE_INFO: 38811ae08745Sheppo /* 38821ae08745Sheppo * Handle the case where vds starts handshake 38831ae08745Sheppo * (for now only vdc is the instigatior) 38841ae08745Sheppo */ 38851ae08745Sheppo status = ENOTSUP; 38861ae08745Sheppo break; 38871ae08745Sheppo default: 38881ae08745Sheppo status = ENOTSUP; 38891ae08745Sheppo } 38901ae08745Sheppo 38911ae08745Sheppo return (status); 38921ae08745Sheppo } 38931ae08745Sheppo 38941ae08745Sheppo /* 38951ae08745Sheppo * Function: 38961ae08745Sheppo * vdc_verify_seq_num() 38971ae08745Sheppo * 38981ae08745Sheppo * Description: 3899e1ebb9ecSlm66018 * This functions verifies that the sequence number sent back by the vDisk 3900e1ebb9ecSlm66018 * server with the latest message is what is expected (i.e. it is greater 3901e1ebb9ecSlm66018 * than the last seq num sent by the vDisk server and less than or equal 3902e1ebb9ecSlm66018 * to the last seq num generated by vdc). 3903e1ebb9ecSlm66018 * 3904e1ebb9ecSlm66018 * It then checks the request ID to see if any requests need processing 3905e1ebb9ecSlm66018 * in the DRing. 39061ae08745Sheppo * 39071ae08745Sheppo * Arguments: 39081ae08745Sheppo * vdc - soft state pointer for this instance of the driver. 39091ae08745Sheppo * dring_msg - pointer to the LDC message sent by vds 39101ae08745Sheppo * 39111ae08745Sheppo * Return Code: 3912e1ebb9ecSlm66018 * VDC_SEQ_NUM_TODO - Message needs to be processed 3913e1ebb9ecSlm66018 * VDC_SEQ_NUM_SKIP - Message has already been processed 3914e1ebb9ecSlm66018 * VDC_SEQ_NUM_INVALID - The seq numbers are so out of sync, 3915e1ebb9ecSlm66018 * vdc cannot deal with them 39161ae08745Sheppo */ 3917e1ebb9ecSlm66018 static int 3918e1ebb9ecSlm66018 vdc_verify_seq_num(vdc_t *vdc, vio_dring_msg_t *dring_msg) 39191ae08745Sheppo { 39201ae08745Sheppo ASSERT(vdc != NULL); 39211ae08745Sheppo ASSERT(dring_msg != NULL); 3922d10e4ef2Snarayan ASSERT(mutex_owned(&vdc->lock)); 39231ae08745Sheppo 39241ae08745Sheppo /* 39251ae08745Sheppo * Check to see if the messages were responded to in the correct 3926e1ebb9ecSlm66018 * order by vds. 39271ae08745Sheppo */ 3928e1ebb9ecSlm66018 if ((dring_msg->seq_num <= vdc->seq_num_reply) || 3929e1ebb9ecSlm66018 (dring_msg->seq_num > vdc->seq_num)) { 39303af08d82Slm66018 DMSG(vdc, 0, "?[%d] Bogus sequence_number %lu: " 3931e1ebb9ecSlm66018 "%lu > expected <= %lu (last proc req %lu sent %lu)\n", 3932e1ebb9ecSlm66018 vdc->instance, dring_msg->seq_num, 3933e1ebb9ecSlm66018 vdc->seq_num_reply, vdc->seq_num, 3934e1ebb9ecSlm66018 vdc->req_id_proc, vdc->req_id); 3935e1ebb9ecSlm66018 return (VDC_SEQ_NUM_INVALID); 39361ae08745Sheppo } 3937e1ebb9ecSlm66018 vdc->seq_num_reply = dring_msg->seq_num; 39381ae08745Sheppo 3939e1ebb9ecSlm66018 if (vdc->req_id_proc < vdc->req_id) 3940e1ebb9ecSlm66018 return (VDC_SEQ_NUM_TODO); 3941e1ebb9ecSlm66018 else 3942e1ebb9ecSlm66018 return (VDC_SEQ_NUM_SKIP); 39431ae08745Sheppo } 39441ae08745Sheppo 39450a55fbb7Slm66018 39460a55fbb7Slm66018 /* 39470a55fbb7Slm66018 * Function: 39480a55fbb7Slm66018 * vdc_is_supported_version() 39490a55fbb7Slm66018 * 39500a55fbb7Slm66018 * Description: 39510a55fbb7Slm66018 * This routine checks if the major/minor version numbers specified in 39520a55fbb7Slm66018 * 'ver_msg' are supported. If not it finds the next version that is 39530a55fbb7Slm66018 * in the supported version list 'vdc_version[]' and sets the fields in 39540a55fbb7Slm66018 * 'ver_msg' to those values 39550a55fbb7Slm66018 * 39560a55fbb7Slm66018 * Arguments: 39570a55fbb7Slm66018 * ver_msg - LDC message sent by vDisk server 39580a55fbb7Slm66018 * 39590a55fbb7Slm66018 * Return Code: 39600a55fbb7Slm66018 * B_TRUE - Success 39610a55fbb7Slm66018 * B_FALSE - Version not supported 39620a55fbb7Slm66018 */ 39630a55fbb7Slm66018 static boolean_t 39640a55fbb7Slm66018 vdc_is_supported_version(vio_ver_msg_t *ver_msg) 39650a55fbb7Slm66018 { 39660a55fbb7Slm66018 int vdc_num_versions = sizeof (vdc_version) / sizeof (vdc_version[0]); 39670a55fbb7Slm66018 39680a55fbb7Slm66018 for (int i = 0; i < vdc_num_versions; i++) { 39690a55fbb7Slm66018 ASSERT(vdc_version[i].major > 0); 39700a55fbb7Slm66018 ASSERT((i == 0) || 39710a55fbb7Slm66018 (vdc_version[i].major < vdc_version[i-1].major)); 39720a55fbb7Slm66018 39730a55fbb7Slm66018 /* 39740a55fbb7Slm66018 * If the major versions match, adjust the minor version, if 39750a55fbb7Slm66018 * necessary, down to the highest value supported by this 39760a55fbb7Slm66018 * client. The server should support all minor versions lower 39770a55fbb7Slm66018 * than the value it sent 39780a55fbb7Slm66018 */ 39790a55fbb7Slm66018 if (ver_msg->ver_major == vdc_version[i].major) { 39800a55fbb7Slm66018 if (ver_msg->ver_minor > vdc_version[i].minor) { 39813af08d82Slm66018 DMSGX(0, 39823af08d82Slm66018 "Adjusting minor version from %u to %u", 39830a55fbb7Slm66018 ver_msg->ver_minor, vdc_version[i].minor); 39840a55fbb7Slm66018 ver_msg->ver_minor = vdc_version[i].minor; 39850a55fbb7Slm66018 } 39860a55fbb7Slm66018 return (B_TRUE); 39870a55fbb7Slm66018 } 39880a55fbb7Slm66018 39890a55fbb7Slm66018 /* 39900a55fbb7Slm66018 * If the message contains a higher major version number, set 39910a55fbb7Slm66018 * the message's major/minor versions to the current values 39920a55fbb7Slm66018 * and return false, so this message will get resent with 39930a55fbb7Slm66018 * these values, and the server will potentially try again 39940a55fbb7Slm66018 * with the same or a lower version 39950a55fbb7Slm66018 */ 39960a55fbb7Slm66018 if (ver_msg->ver_major > vdc_version[i].major) { 39970a55fbb7Slm66018 ver_msg->ver_major = vdc_version[i].major; 39980a55fbb7Slm66018 ver_msg->ver_minor = vdc_version[i].minor; 39993af08d82Slm66018 DMSGX(0, "Suggesting major/minor (0x%x/0x%x)\n", 40000a55fbb7Slm66018 ver_msg->ver_major, ver_msg->ver_minor); 40010a55fbb7Slm66018 40020a55fbb7Slm66018 return (B_FALSE); 40030a55fbb7Slm66018 } 40040a55fbb7Slm66018 40050a55fbb7Slm66018 /* 40060a55fbb7Slm66018 * Otherwise, the message's major version is less than the 40070a55fbb7Slm66018 * current major version, so continue the loop to the next 40080a55fbb7Slm66018 * (lower) supported version 40090a55fbb7Slm66018 */ 40100a55fbb7Slm66018 } 40110a55fbb7Slm66018 40120a55fbb7Slm66018 /* 40130a55fbb7Slm66018 * No common version was found; "ground" the version pair in the 40140a55fbb7Slm66018 * message to terminate negotiation 40150a55fbb7Slm66018 */ 40160a55fbb7Slm66018 ver_msg->ver_major = 0; 40170a55fbb7Slm66018 ver_msg->ver_minor = 0; 40180a55fbb7Slm66018 40190a55fbb7Slm66018 return (B_FALSE); 40200a55fbb7Slm66018 } 40211ae08745Sheppo /* -------------------------------------------------------------------------- */ 40221ae08745Sheppo 40231ae08745Sheppo /* 40241ae08745Sheppo * DKIO(7) support 40251ae08745Sheppo */ 40261ae08745Sheppo 40271ae08745Sheppo typedef struct vdc_dk_arg { 40281ae08745Sheppo struct dk_callback dkc; 40291ae08745Sheppo int mode; 40301ae08745Sheppo dev_t dev; 40311ae08745Sheppo vdc_t *vdc; 40321ae08745Sheppo } vdc_dk_arg_t; 40331ae08745Sheppo 40341ae08745Sheppo /* 40351ae08745Sheppo * Function: 40361ae08745Sheppo * vdc_dkio_flush_cb() 40371ae08745Sheppo * 40381ae08745Sheppo * Description: 40391ae08745Sheppo * This routine is a callback for DKIOCFLUSHWRITECACHE which can be called 40401ae08745Sheppo * by kernel code. 40411ae08745Sheppo * 40421ae08745Sheppo * Arguments: 40431ae08745Sheppo * arg - a pointer to a vdc_dk_arg_t structure. 40441ae08745Sheppo */ 40451ae08745Sheppo void 40461ae08745Sheppo vdc_dkio_flush_cb(void *arg) 40471ae08745Sheppo { 40481ae08745Sheppo struct vdc_dk_arg *dk_arg = (struct vdc_dk_arg *)arg; 40491ae08745Sheppo struct dk_callback *dkc = NULL; 40501ae08745Sheppo vdc_t *vdc = NULL; 40511ae08745Sheppo int rv; 40521ae08745Sheppo 40531ae08745Sheppo if (dk_arg == NULL) { 40543af08d82Slm66018 cmn_err(CE_NOTE, "?[Unk] DKIOCFLUSHWRITECACHE arg is NULL\n"); 40551ae08745Sheppo return; 40561ae08745Sheppo } 40571ae08745Sheppo dkc = &dk_arg->dkc; 40581ae08745Sheppo vdc = dk_arg->vdc; 40591ae08745Sheppo ASSERT(vdc != NULL); 40601ae08745Sheppo 40613af08d82Slm66018 rv = vdc_do_sync_op(vdc, VD_OP_FLUSH, NULL, 0, 40620d0c8d4bSnarayan VDCPART(dk_arg->dev), 0, CB_SYNC, 0, VIO_both_dir); 40631ae08745Sheppo if (rv != 0) { 40643af08d82Slm66018 DMSG(vdc, 0, "[%d] DKIOCFLUSHWRITECACHE failed %d : model %x\n", 4065e1ebb9ecSlm66018 vdc->instance, rv, 40661ae08745Sheppo ddi_model_convert_from(dk_arg->mode & FMODELS)); 40671ae08745Sheppo } 40681ae08745Sheppo 40691ae08745Sheppo /* 40701ae08745Sheppo * Trigger the call back to notify the caller the the ioctl call has 40711ae08745Sheppo * been completed. 40721ae08745Sheppo */ 40731ae08745Sheppo if ((dk_arg->mode & FKIOCTL) && 40741ae08745Sheppo (dkc != NULL) && 40751ae08745Sheppo (dkc->dkc_callback != NULL)) { 40761ae08745Sheppo ASSERT(dkc->dkc_cookie != NULL); 40778e6a2a04Slm66018 (*dkc->dkc_callback)(dkc->dkc_cookie, rv); 40781ae08745Sheppo } 40791ae08745Sheppo 40801ae08745Sheppo /* Indicate that one less DKIO write flush is outstanding */ 40811ae08745Sheppo mutex_enter(&vdc->lock); 40821ae08745Sheppo vdc->dkio_flush_pending--; 40831ae08745Sheppo ASSERT(vdc->dkio_flush_pending >= 0); 40841ae08745Sheppo mutex_exit(&vdc->lock); 40858e6a2a04Slm66018 40868e6a2a04Slm66018 /* free the mem that was allocated when the callback was dispatched */ 40878e6a2a04Slm66018 kmem_free(arg, sizeof (vdc_dk_arg_t)); 40881ae08745Sheppo } 40891ae08745Sheppo 40901ae08745Sheppo /* 409187a7269eSachartre * Function: 409287a7269eSachartre * vdc_dkio_get_partition() 409387a7269eSachartre * 409487a7269eSachartre * Description: 409587a7269eSachartre * This function implements the DKIOCGAPART ioctl. 409687a7269eSachartre * 409787a7269eSachartre * Arguments: 409887a7269eSachartre * dev - device 409987a7269eSachartre * arg - a pointer to a dk_map[NDKMAP] or dk_map32[NDKMAP] structure 410087a7269eSachartre * flag - ioctl flags 410187a7269eSachartre */ 410287a7269eSachartre static int 410387a7269eSachartre vdc_dkio_get_partition(dev_t dev, caddr_t arg, int flag) 410487a7269eSachartre { 410587a7269eSachartre struct dk_geom geom; 410687a7269eSachartre struct vtoc vtoc; 410787a7269eSachartre union { 410887a7269eSachartre struct dk_map map[NDKMAP]; 410987a7269eSachartre struct dk_map32 map32[NDKMAP]; 411087a7269eSachartre } data; 411187a7269eSachartre int i, rv, size; 411287a7269eSachartre 411387a7269eSachartre rv = vd_process_ioctl(dev, DKIOCGGEOM, (caddr_t)&geom, FKIOCTL); 411487a7269eSachartre if (rv != 0) 411587a7269eSachartre return (rv); 411687a7269eSachartre 411787a7269eSachartre rv = vd_process_ioctl(dev, DKIOCGVTOC, (caddr_t)&vtoc, FKIOCTL); 411887a7269eSachartre if (rv != 0) 411987a7269eSachartre return (rv); 412087a7269eSachartre 412187a7269eSachartre if (vtoc.v_nparts != NDKMAP || 412287a7269eSachartre geom.dkg_nhead == 0 || geom.dkg_nsect == 0) 412387a7269eSachartre return (EINVAL); 412487a7269eSachartre 412587a7269eSachartre if (ddi_model_convert_from(flag & FMODELS) == DDI_MODEL_ILP32) { 412687a7269eSachartre 412787a7269eSachartre for (i = 0; i < NDKMAP; i++) { 412887a7269eSachartre data.map32[i].dkl_cylno = vtoc.v_part[i].p_start / 412987a7269eSachartre (geom.dkg_nhead * geom.dkg_nsect); 413087a7269eSachartre data.map32[i].dkl_nblk = vtoc.v_part[i].p_size; 413187a7269eSachartre } 413287a7269eSachartre size = NDKMAP * sizeof (struct dk_map32); 413387a7269eSachartre 413487a7269eSachartre } else { 413587a7269eSachartre 413687a7269eSachartre for (i = 0; i < NDKMAP; i++) { 413787a7269eSachartre data.map[i].dkl_cylno = vtoc.v_part[i].p_start / 413887a7269eSachartre (geom.dkg_nhead * geom.dkg_nsect); 413987a7269eSachartre data.map[i].dkl_nblk = vtoc.v_part[i].p_size; 414087a7269eSachartre } 414187a7269eSachartre size = NDKMAP * sizeof (struct dk_map); 414287a7269eSachartre 414387a7269eSachartre } 414487a7269eSachartre 414587a7269eSachartre if (ddi_copyout(&data, arg, size, flag) != 0) 414687a7269eSachartre return (EFAULT); 414787a7269eSachartre 414887a7269eSachartre return (0); 414987a7269eSachartre } 415087a7269eSachartre 415187a7269eSachartre /* 415287a7269eSachartre * Function: 415387a7269eSachartre * vdc_dioctl_rwcmd() 415487a7269eSachartre * 415587a7269eSachartre * Description: 415687a7269eSachartre * This function implements the DIOCTL_RWCMD ioctl. This ioctl is used 415787a7269eSachartre * for DKC_DIRECT disks to read or write at an absolute disk offset. 415887a7269eSachartre * 415987a7269eSachartre * Arguments: 416087a7269eSachartre * dev - device 416187a7269eSachartre * arg - a pointer to a dadkio_rwcmd or dadkio_rwcmd32 structure 416287a7269eSachartre * flag - ioctl flags 416387a7269eSachartre */ 416487a7269eSachartre static int 416587a7269eSachartre vdc_dioctl_rwcmd(dev_t dev, caddr_t arg, int flag) 416687a7269eSachartre { 416787a7269eSachartre struct dadkio_rwcmd32 rwcmd32; 416887a7269eSachartre struct dadkio_rwcmd rwcmd; 416987a7269eSachartre struct iovec aiov; 417087a7269eSachartre struct uio auio; 417187a7269eSachartre int rw, status; 417287a7269eSachartre struct buf *buf; 417387a7269eSachartre 417487a7269eSachartre if (ddi_model_convert_from(flag & FMODELS) == DDI_MODEL_ILP32) { 417587a7269eSachartre if (ddi_copyin((caddr_t)arg, (caddr_t)&rwcmd32, 417687a7269eSachartre sizeof (struct dadkio_rwcmd32), flag)) { 417787a7269eSachartre return (EFAULT); 417887a7269eSachartre } 417987a7269eSachartre rwcmd.cmd = rwcmd32.cmd; 418087a7269eSachartre rwcmd.flags = rwcmd32.flags; 418187a7269eSachartre rwcmd.blkaddr = (daddr_t)rwcmd32.blkaddr; 418287a7269eSachartre rwcmd.buflen = rwcmd32.buflen; 418387a7269eSachartre rwcmd.bufaddr = (caddr_t)(uintptr_t)rwcmd32.bufaddr; 418487a7269eSachartre } else { 418587a7269eSachartre if (ddi_copyin((caddr_t)arg, (caddr_t)&rwcmd, 418687a7269eSachartre sizeof (struct dadkio_rwcmd), flag)) { 418787a7269eSachartre return (EFAULT); 418887a7269eSachartre } 418987a7269eSachartre } 419087a7269eSachartre 419187a7269eSachartre switch (rwcmd.cmd) { 419287a7269eSachartre case DADKIO_RWCMD_READ: 419387a7269eSachartre rw = B_READ; 419487a7269eSachartre break; 419587a7269eSachartre case DADKIO_RWCMD_WRITE: 419687a7269eSachartre rw = B_WRITE; 419787a7269eSachartre break; 419887a7269eSachartre default: 419987a7269eSachartre return (EINVAL); 420087a7269eSachartre } 420187a7269eSachartre 420287a7269eSachartre bzero((caddr_t)&aiov, sizeof (struct iovec)); 420387a7269eSachartre aiov.iov_base = rwcmd.bufaddr; 420487a7269eSachartre aiov.iov_len = rwcmd.buflen; 420587a7269eSachartre 420687a7269eSachartre bzero((caddr_t)&auio, sizeof (struct uio)); 420787a7269eSachartre auio.uio_iov = &aiov; 420887a7269eSachartre auio.uio_iovcnt = 1; 420987a7269eSachartre auio.uio_loffset = rwcmd.blkaddr * DEV_BSIZE; 421087a7269eSachartre auio.uio_resid = rwcmd.buflen; 421187a7269eSachartre auio.uio_segflg = flag & FKIOCTL ? UIO_SYSSPACE : UIO_USERSPACE; 421287a7269eSachartre 421387a7269eSachartre buf = kmem_alloc(sizeof (buf_t), KM_SLEEP); 421487a7269eSachartre bioinit(buf); 421587a7269eSachartre /* 421687a7269eSachartre * We use the private field of buf to specify that this is an 421787a7269eSachartre * I/O using an absolute offset. 421887a7269eSachartre */ 421987a7269eSachartre buf->b_private = (void *)VD_SLICE_NONE; 422087a7269eSachartre 422187a7269eSachartre status = physio(vdc_strategy, buf, dev, rw, vdc_min, &auio); 422287a7269eSachartre 422387a7269eSachartre biofini(buf); 422487a7269eSachartre kmem_free(buf, sizeof (buf_t)); 422587a7269eSachartre 422687a7269eSachartre return (status); 422787a7269eSachartre } 422887a7269eSachartre 422987a7269eSachartre /* 42301ae08745Sheppo * This structure is used in the DKIO(7I) array below. 42311ae08745Sheppo */ 42321ae08745Sheppo typedef struct vdc_dk_ioctl { 42331ae08745Sheppo uint8_t op; /* VD_OP_XXX value */ 42341ae08745Sheppo int cmd; /* Solaris ioctl operation number */ 42351ae08745Sheppo size_t nbytes; /* size of structure to be copied */ 42360a55fbb7Slm66018 42370a55fbb7Slm66018 /* function to convert between vDisk and Solaris structure formats */ 4238d10e4ef2Snarayan int (*convert)(vdc_t *vdc, void *vd_buf, void *ioctl_arg, 4239d10e4ef2Snarayan int mode, int dir); 42401ae08745Sheppo } vdc_dk_ioctl_t; 42411ae08745Sheppo 42421ae08745Sheppo /* 42431ae08745Sheppo * Subset of DKIO(7I) operations currently supported 42441ae08745Sheppo */ 42451ae08745Sheppo static vdc_dk_ioctl_t dk_ioctl[] = { 4246eff7243fSlm66018 {VD_OP_FLUSH, DKIOCFLUSHWRITECACHE, 0, 42470a55fbb7Slm66018 vdc_null_copy_func}, 42480a55fbb7Slm66018 {VD_OP_GET_WCE, DKIOCGETWCE, sizeof (int), 42494bac2208Snarayan vdc_get_wce_convert}, 42500a55fbb7Slm66018 {VD_OP_SET_WCE, DKIOCSETWCE, sizeof (int), 42514bac2208Snarayan vdc_set_wce_convert}, 42520a55fbb7Slm66018 {VD_OP_GET_VTOC, DKIOCGVTOC, sizeof (vd_vtoc_t), 42530a55fbb7Slm66018 vdc_get_vtoc_convert}, 42540a55fbb7Slm66018 {VD_OP_SET_VTOC, DKIOCSVTOC, sizeof (vd_vtoc_t), 42550a55fbb7Slm66018 vdc_set_vtoc_convert}, 42560a55fbb7Slm66018 {VD_OP_GET_DISKGEOM, DKIOCGGEOM, sizeof (vd_geom_t), 42570a55fbb7Slm66018 vdc_get_geom_convert}, 42580a55fbb7Slm66018 {VD_OP_GET_DISKGEOM, DKIOCG_PHYGEOM, sizeof (vd_geom_t), 42590a55fbb7Slm66018 vdc_get_geom_convert}, 42600a55fbb7Slm66018 {VD_OP_GET_DISKGEOM, DKIOCG_VIRTGEOM, sizeof (vd_geom_t), 42610a55fbb7Slm66018 vdc_get_geom_convert}, 42620a55fbb7Slm66018 {VD_OP_SET_DISKGEOM, DKIOCSGEOM, sizeof (vd_geom_t), 42630a55fbb7Slm66018 vdc_set_geom_convert}, 42644bac2208Snarayan {VD_OP_GET_EFI, DKIOCGETEFI, 0, 42654bac2208Snarayan vdc_get_efi_convert}, 42664bac2208Snarayan {VD_OP_SET_EFI, DKIOCSETEFI, 0, 42674bac2208Snarayan vdc_set_efi_convert}, 42680a55fbb7Slm66018 426987a7269eSachartre /* DIOCTL_RWCMD is converted to a read or a write */ 427087a7269eSachartre {0, DIOCTL_RWCMD, sizeof (struct dadkio_rwcmd), NULL}, 427187a7269eSachartre 42720a55fbb7Slm66018 /* 42730a55fbb7Slm66018 * These particular ioctls are not sent to the server - vdc fakes up 42740a55fbb7Slm66018 * the necessary info. 42750a55fbb7Slm66018 */ 42760a55fbb7Slm66018 {0, DKIOCINFO, sizeof (struct dk_cinfo), vdc_null_copy_func}, 42770a55fbb7Slm66018 {0, DKIOCGMEDIAINFO, sizeof (struct dk_minfo), vdc_null_copy_func}, 42780a55fbb7Slm66018 {0, USCSICMD, sizeof (struct uscsi_cmd), vdc_null_copy_func}, 427987a7269eSachartre {0, DKIOCGAPART, 0, vdc_null_copy_func }, 42800a55fbb7Slm66018 {0, DKIOCREMOVABLE, 0, vdc_null_copy_func}, 42810a55fbb7Slm66018 {0, CDROMREADOFFSET, 0, vdc_null_copy_func} 42821ae08745Sheppo }; 42831ae08745Sheppo 42841ae08745Sheppo /* 42851ae08745Sheppo * Function: 42861ae08745Sheppo * vd_process_ioctl() 42871ae08745Sheppo * 42881ae08745Sheppo * Description: 42890a55fbb7Slm66018 * This routine processes disk specific ioctl calls 42901ae08745Sheppo * 42911ae08745Sheppo * Arguments: 42921ae08745Sheppo * dev - the device number 42931ae08745Sheppo * cmd - the operation [dkio(7I)] to be processed 42941ae08745Sheppo * arg - pointer to user provided structure 42951ae08745Sheppo * (contains data to be set or reference parameter for get) 42961ae08745Sheppo * mode - bit flag, indicating open settings, 32/64 bit type, etc 42971ae08745Sheppo * 42981ae08745Sheppo * Return Code: 42991ae08745Sheppo * 0 43001ae08745Sheppo * EFAULT 43011ae08745Sheppo * ENXIO 43021ae08745Sheppo * EIO 43031ae08745Sheppo * ENOTSUP 43041ae08745Sheppo */ 43051ae08745Sheppo static int 43061ae08745Sheppo vd_process_ioctl(dev_t dev, int cmd, caddr_t arg, int mode) 43071ae08745Sheppo { 43080d0c8d4bSnarayan int instance = VDCUNIT(dev); 43091ae08745Sheppo vdc_t *vdc = NULL; 43101ae08745Sheppo int rv = -1; 43111ae08745Sheppo int idx = 0; /* index into dk_ioctl[] */ 43121ae08745Sheppo size_t len = 0; /* #bytes to send to vds */ 43131ae08745Sheppo size_t alloc_len = 0; /* #bytes to allocate mem for */ 43141ae08745Sheppo caddr_t mem_p = NULL; 43151ae08745Sheppo size_t nioctls = (sizeof (dk_ioctl)) / (sizeof (dk_ioctl[0])); 4316d10e4ef2Snarayan struct vtoc vtoc_saved; 43173af08d82Slm66018 vdc_dk_ioctl_t *iop; 43181ae08745Sheppo 43191ae08745Sheppo vdc = ddi_get_soft_state(vdc_state, instance); 43201ae08745Sheppo if (vdc == NULL) { 43211ae08745Sheppo cmn_err(CE_NOTE, "![%d] Could not get soft state structure", 43221ae08745Sheppo instance); 43231ae08745Sheppo return (ENXIO); 43241ae08745Sheppo } 43251ae08745Sheppo 43263af08d82Slm66018 DMSG(vdc, 0, "[%d] Processing ioctl(%x) for dev %lx : model %x\n", 43273af08d82Slm66018 instance, cmd, dev, ddi_model_convert_from(mode & FMODELS)); 43281ae08745Sheppo 43291ae08745Sheppo /* 43301ae08745Sheppo * Validate the ioctl operation to be performed. 43311ae08745Sheppo * 43321ae08745Sheppo * If we have looped through the array without finding a match then we 43331ae08745Sheppo * don't support this ioctl. 43341ae08745Sheppo */ 43351ae08745Sheppo for (idx = 0; idx < nioctls; idx++) { 43361ae08745Sheppo if (cmd == dk_ioctl[idx].cmd) 43371ae08745Sheppo break; 43381ae08745Sheppo } 43391ae08745Sheppo 43401ae08745Sheppo if (idx >= nioctls) { 43413af08d82Slm66018 DMSG(vdc, 0, "[%d] Unsupported ioctl (0x%x)\n", 4342e1ebb9ecSlm66018 vdc->instance, cmd); 43431ae08745Sheppo return (ENOTSUP); 43441ae08745Sheppo } 43451ae08745Sheppo 43463af08d82Slm66018 iop = &(dk_ioctl[idx]); 43473af08d82Slm66018 43484bac2208Snarayan if (cmd == DKIOCGETEFI || cmd == DKIOCSETEFI) { 43494bac2208Snarayan /* size is not fixed for EFI ioctls, it depends on ioctl arg */ 43504bac2208Snarayan dk_efi_t dk_efi; 43514bac2208Snarayan 43524bac2208Snarayan rv = ddi_copyin(arg, &dk_efi, sizeof (dk_efi_t), mode); 43534bac2208Snarayan if (rv != 0) 43544bac2208Snarayan return (EFAULT); 43554bac2208Snarayan 43564bac2208Snarayan len = sizeof (vd_efi_t) - 1 + dk_efi.dki_length; 43574bac2208Snarayan } else { 43583af08d82Slm66018 len = iop->nbytes; 43594bac2208Snarayan } 43601ae08745Sheppo 43611ae08745Sheppo /* 43620a55fbb7Slm66018 * Deal with the ioctls which the server does not provide. vdc can 43630a55fbb7Slm66018 * fake these up and return immediately 43641ae08745Sheppo */ 43651ae08745Sheppo switch (cmd) { 43661ae08745Sheppo case CDROMREADOFFSET: 43671ae08745Sheppo case DKIOCREMOVABLE: 43680a55fbb7Slm66018 case USCSICMD: 43691ae08745Sheppo return (ENOTTY); 43701ae08745Sheppo 437187a7269eSachartre case DIOCTL_RWCMD: 437287a7269eSachartre { 437387a7269eSachartre if (vdc->cinfo->dki_ctype != DKC_DIRECT) 437487a7269eSachartre return (ENOTTY); 437587a7269eSachartre 437687a7269eSachartre return (vdc_dioctl_rwcmd(dev, arg, mode)); 437787a7269eSachartre } 437887a7269eSachartre 437987a7269eSachartre case DKIOCGAPART: 438087a7269eSachartre { 438187a7269eSachartre if (vdc->vdisk_label != VD_DISK_LABEL_VTOC) 438287a7269eSachartre return (ENOTSUP); 438387a7269eSachartre 438487a7269eSachartre return (vdc_dkio_get_partition(dev, arg, mode)); 438587a7269eSachartre } 438687a7269eSachartre 43871ae08745Sheppo case DKIOCINFO: 43881ae08745Sheppo { 43891ae08745Sheppo struct dk_cinfo cinfo; 43901ae08745Sheppo if (vdc->cinfo == NULL) 43911ae08745Sheppo return (ENXIO); 43921ae08745Sheppo 43931ae08745Sheppo bcopy(vdc->cinfo, &cinfo, sizeof (struct dk_cinfo)); 43940d0c8d4bSnarayan cinfo.dki_partition = VDCPART(dev); 43951ae08745Sheppo 43961ae08745Sheppo rv = ddi_copyout(&cinfo, (void *)arg, 43971ae08745Sheppo sizeof (struct dk_cinfo), mode); 43981ae08745Sheppo if (rv != 0) 43991ae08745Sheppo return (EFAULT); 44001ae08745Sheppo 44011ae08745Sheppo return (0); 44021ae08745Sheppo } 44031ae08745Sheppo 44041ae08745Sheppo case DKIOCGMEDIAINFO: 44058e6a2a04Slm66018 { 44061ae08745Sheppo if (vdc->minfo == NULL) 44071ae08745Sheppo return (ENXIO); 44081ae08745Sheppo 44091ae08745Sheppo rv = ddi_copyout(vdc->minfo, (void *)arg, 44101ae08745Sheppo sizeof (struct dk_minfo), mode); 44111ae08745Sheppo if (rv != 0) 44121ae08745Sheppo return (EFAULT); 44131ae08745Sheppo 44141ae08745Sheppo return (0); 44151ae08745Sheppo } 44161ae08745Sheppo 44178e6a2a04Slm66018 case DKIOCFLUSHWRITECACHE: 44188e6a2a04Slm66018 { 44198e6a2a04Slm66018 struct dk_callback *dkc = (struct dk_callback *)arg; 44208e6a2a04Slm66018 vdc_dk_arg_t *dkarg = NULL; 44218e6a2a04Slm66018 44223af08d82Slm66018 DMSG(vdc, 1, "[%d] Flush W$: mode %x\n", 44233af08d82Slm66018 instance, mode); 44248e6a2a04Slm66018 44258e6a2a04Slm66018 /* 44268e6a2a04Slm66018 * If the backing device is not a 'real' disk then the 44278e6a2a04Slm66018 * W$ operation request to the vDisk server will fail 44288e6a2a04Slm66018 * so we might as well save the cycles and return now. 44298e6a2a04Slm66018 */ 44308e6a2a04Slm66018 if (vdc->vdisk_type != VD_DISK_TYPE_DISK) 44318e6a2a04Slm66018 return (ENOTTY); 44328e6a2a04Slm66018 44338e6a2a04Slm66018 /* 44348e6a2a04Slm66018 * If arg is NULL, then there is no callback function 44358e6a2a04Slm66018 * registered and the call operates synchronously; we 44368e6a2a04Slm66018 * break and continue with the rest of the function and 44378e6a2a04Slm66018 * wait for vds to return (i.e. after the request to 44388e6a2a04Slm66018 * vds returns successfully, all writes completed prior 44398e6a2a04Slm66018 * to the ioctl will have been flushed from the disk 44408e6a2a04Slm66018 * write cache to persistent media. 44418e6a2a04Slm66018 * 44428e6a2a04Slm66018 * If a callback function is registered, we dispatch 44438e6a2a04Slm66018 * the request on a task queue and return immediately. 44448e6a2a04Slm66018 * The callback will deal with informing the calling 44458e6a2a04Slm66018 * thread that the flush request is completed. 44468e6a2a04Slm66018 */ 44478e6a2a04Slm66018 if (dkc == NULL) 44488e6a2a04Slm66018 break; 44498e6a2a04Slm66018 4450eff7243fSlm66018 /* 4451eff7243fSlm66018 * the asynchronous callback is only supported if 4452eff7243fSlm66018 * invoked from within the kernel 4453eff7243fSlm66018 */ 4454eff7243fSlm66018 if ((mode & FKIOCTL) == 0) 4455eff7243fSlm66018 return (ENOTSUP); 4456eff7243fSlm66018 44578e6a2a04Slm66018 dkarg = kmem_zalloc(sizeof (vdc_dk_arg_t), KM_SLEEP); 44588e6a2a04Slm66018 44598e6a2a04Slm66018 dkarg->mode = mode; 44608e6a2a04Slm66018 dkarg->dev = dev; 44618e6a2a04Slm66018 bcopy(dkc, &dkarg->dkc, sizeof (*dkc)); 44628e6a2a04Slm66018 44638e6a2a04Slm66018 mutex_enter(&vdc->lock); 44648e6a2a04Slm66018 vdc->dkio_flush_pending++; 44658e6a2a04Slm66018 dkarg->vdc = vdc; 44668e6a2a04Slm66018 mutex_exit(&vdc->lock); 44678e6a2a04Slm66018 44688e6a2a04Slm66018 /* put the request on a task queue */ 44698e6a2a04Slm66018 rv = taskq_dispatch(system_taskq, vdc_dkio_flush_cb, 44708e6a2a04Slm66018 (void *)dkarg, DDI_SLEEP); 44713af08d82Slm66018 if (rv == NULL) { 44723af08d82Slm66018 /* clean up if dispatch fails */ 44733af08d82Slm66018 mutex_enter(&vdc->lock); 44743af08d82Slm66018 vdc->dkio_flush_pending--; 44753af08d82Slm66018 kmem_free(dkarg, sizeof (vdc_dk_arg_t)); 44763af08d82Slm66018 } 44778e6a2a04Slm66018 44788e6a2a04Slm66018 return (rv == NULL ? ENOMEM : 0); 44798e6a2a04Slm66018 } 44808e6a2a04Slm66018 } 44818e6a2a04Slm66018 44821ae08745Sheppo /* catch programming error in vdc - should be a VD_OP_XXX ioctl */ 44833af08d82Slm66018 ASSERT(iop->op != 0); 44841ae08745Sheppo 44851ae08745Sheppo /* LDC requires that the memory being mapped is 8-byte aligned */ 44861ae08745Sheppo alloc_len = P2ROUNDUP(len, sizeof (uint64_t)); 44873af08d82Slm66018 DMSG(vdc, 1, "[%d] struct size %ld alloc %ld\n", 44883af08d82Slm66018 instance, len, alloc_len); 44891ae08745Sheppo 4490eff7243fSlm66018 ASSERT(alloc_len >= 0); /* sanity check */ 4491eff7243fSlm66018 if (alloc_len > 0) 44921ae08745Sheppo mem_p = kmem_zalloc(alloc_len, KM_SLEEP); 44931ae08745Sheppo 4494d10e4ef2Snarayan if (cmd == DKIOCSVTOC) { 4495d10e4ef2Snarayan /* 4496d10e4ef2Snarayan * Save a copy of the current VTOC so that we can roll back 4497d10e4ef2Snarayan * if the setting of the new VTOC fails. 4498d10e4ef2Snarayan */ 4499d10e4ef2Snarayan bcopy(vdc->vtoc, &vtoc_saved, sizeof (struct vtoc)); 4500d10e4ef2Snarayan } 4501d10e4ef2Snarayan 45020a55fbb7Slm66018 /* 4503eff7243fSlm66018 * Call the conversion function for this ioctl which, if necessary, 45040a55fbb7Slm66018 * converts from the Solaris format to the format ARC'ed 45050a55fbb7Slm66018 * as part of the vDisk protocol (FWARC 2006/195) 45060a55fbb7Slm66018 */ 45073af08d82Slm66018 ASSERT(iop->convert != NULL); 45083af08d82Slm66018 rv = (iop->convert)(vdc, arg, mem_p, mode, VD_COPYIN); 45091ae08745Sheppo if (rv != 0) { 45103af08d82Slm66018 DMSG(vdc, 0, "[%d] convert func returned %d for ioctl 0x%x\n", 4511e1ebb9ecSlm66018 instance, rv, cmd); 45121ae08745Sheppo if (mem_p != NULL) 45131ae08745Sheppo kmem_free(mem_p, alloc_len); 45140a55fbb7Slm66018 return (rv); 45151ae08745Sheppo } 45161ae08745Sheppo 45171ae08745Sheppo /* 45181ae08745Sheppo * send request to vds to service the ioctl. 45191ae08745Sheppo */ 45203af08d82Slm66018 rv = vdc_do_sync_op(vdc, iop->op, mem_p, alloc_len, 45210d0c8d4bSnarayan VDCPART(dev), 0, CB_SYNC, (void *)(uint64_t)mode, 45223af08d82Slm66018 VIO_both_dir); 45233af08d82Slm66018 45241ae08745Sheppo if (rv != 0) { 45251ae08745Sheppo /* 45261ae08745Sheppo * This is not necessarily an error. The ioctl could 45271ae08745Sheppo * be returning a value such as ENOTTY to indicate 45281ae08745Sheppo * that the ioctl is not applicable. 45291ae08745Sheppo */ 45303af08d82Slm66018 DMSG(vdc, 0, "[%d] vds returned %d for ioctl 0x%x\n", 4531e1ebb9ecSlm66018 instance, rv, cmd); 45321ae08745Sheppo if (mem_p != NULL) 45331ae08745Sheppo kmem_free(mem_p, alloc_len); 4534d10e4ef2Snarayan 4535d10e4ef2Snarayan if (cmd == DKIOCSVTOC) { 4536d10e4ef2Snarayan /* update of the VTOC has failed, roll back */ 4537d10e4ef2Snarayan bcopy(&vtoc_saved, vdc->vtoc, sizeof (struct vtoc)); 4538d10e4ef2Snarayan } 4539d10e4ef2Snarayan 45401ae08745Sheppo return (rv); 45411ae08745Sheppo } 45421ae08745Sheppo 45431ae08745Sheppo if (cmd == DKIOCSVTOC) { 4544d10e4ef2Snarayan /* 45454bac2208Snarayan * The VTOC has been changed. We need to update the device 45464bac2208Snarayan * nodes to handle the case where an EFI label has been 45474bac2208Snarayan * changed to a VTOC label. We also try and update the device 4548d10e4ef2Snarayan * node properties. Failing to set the properties should 4549d10e4ef2Snarayan * not cause an error to be return the caller though. 4550d10e4ef2Snarayan */ 45514bac2208Snarayan vdc->vdisk_label = VD_DISK_LABEL_VTOC; 45524bac2208Snarayan (void) vdc_create_device_nodes_vtoc(vdc); 45534bac2208Snarayan 45541ae08745Sheppo if (vdc_create_device_nodes_props(vdc)) { 45553af08d82Slm66018 DMSG(vdc, 0, "![%d] Failed to update device nodes" 4556d10e4ef2Snarayan " properties", vdc->instance); 45571ae08745Sheppo } 45584bac2208Snarayan 45594bac2208Snarayan } else if (cmd == DKIOCSETEFI) { 45604bac2208Snarayan /* 45614bac2208Snarayan * The EFI has been changed. We need to update the device 45624bac2208Snarayan * nodes to handle the case where a VTOC label has been 45634bac2208Snarayan * changed to an EFI label. We also try and update the device 45644bac2208Snarayan * node properties. Failing to set the properties should 45654bac2208Snarayan * not cause an error to be return the caller though. 45664bac2208Snarayan */ 45674bac2208Snarayan struct dk_gpt *efi; 45684bac2208Snarayan size_t efi_len; 45694bac2208Snarayan 45704bac2208Snarayan vdc->vdisk_label = VD_DISK_LABEL_EFI; 45714bac2208Snarayan (void) vdc_create_device_nodes_efi(vdc); 45724bac2208Snarayan 45734bac2208Snarayan rv = vdc_efi_alloc_and_read(dev, &efi, &efi_len); 45744bac2208Snarayan 45754bac2208Snarayan if (rv == 0) { 45764bac2208Snarayan vdc_store_efi(vdc, efi); 45774bac2208Snarayan rv = vdc_create_device_nodes_props(vdc); 45784bac2208Snarayan vd_efi_free(efi, efi_len); 45794bac2208Snarayan } 45804bac2208Snarayan 45814bac2208Snarayan if (rv) { 45823af08d82Slm66018 DMSG(vdc, 0, "![%d] Failed to update device nodes" 45834bac2208Snarayan " properties", vdc->instance); 45844bac2208Snarayan } 45851ae08745Sheppo } 45861ae08745Sheppo 45871ae08745Sheppo /* 45880a55fbb7Slm66018 * Call the conversion function (if it exists) for this ioctl 45890a55fbb7Slm66018 * which converts from the format ARC'ed as part of the vDisk 45900a55fbb7Slm66018 * protocol (FWARC 2006/195) back to a format understood by 45910a55fbb7Slm66018 * the rest of Solaris. 45921ae08745Sheppo */ 45933af08d82Slm66018 rv = (iop->convert)(vdc, mem_p, arg, mode, VD_COPYOUT); 45940a55fbb7Slm66018 if (rv != 0) { 45953af08d82Slm66018 DMSG(vdc, 0, "[%d] convert func returned %d for ioctl 0x%x\n", 4596e1ebb9ecSlm66018 instance, rv, cmd); 45971ae08745Sheppo if (mem_p != NULL) 45981ae08745Sheppo kmem_free(mem_p, alloc_len); 45990a55fbb7Slm66018 return (rv); 46001ae08745Sheppo } 46011ae08745Sheppo 46021ae08745Sheppo if (mem_p != NULL) 46031ae08745Sheppo kmem_free(mem_p, alloc_len); 46041ae08745Sheppo 46051ae08745Sheppo return (rv); 46061ae08745Sheppo } 46071ae08745Sheppo 46081ae08745Sheppo /* 46091ae08745Sheppo * Function: 46100a55fbb7Slm66018 * 46110a55fbb7Slm66018 * Description: 46120a55fbb7Slm66018 * This is an empty conversion function used by ioctl calls which 46130a55fbb7Slm66018 * do not need to convert the data being passed in/out to userland 46140a55fbb7Slm66018 */ 46150a55fbb7Slm66018 static int 4616d10e4ef2Snarayan vdc_null_copy_func(vdc_t *vdc, void *from, void *to, int mode, int dir) 46170a55fbb7Slm66018 { 4618d10e4ef2Snarayan _NOTE(ARGUNUSED(vdc)) 46190a55fbb7Slm66018 _NOTE(ARGUNUSED(from)) 46200a55fbb7Slm66018 _NOTE(ARGUNUSED(to)) 46210a55fbb7Slm66018 _NOTE(ARGUNUSED(mode)) 46220a55fbb7Slm66018 _NOTE(ARGUNUSED(dir)) 46230a55fbb7Slm66018 46240a55fbb7Slm66018 return (0); 46250a55fbb7Slm66018 } 46260a55fbb7Slm66018 46274bac2208Snarayan static int 46284bac2208Snarayan vdc_get_wce_convert(vdc_t *vdc, void *from, void *to, 46294bac2208Snarayan int mode, int dir) 46304bac2208Snarayan { 46314bac2208Snarayan _NOTE(ARGUNUSED(vdc)) 46324bac2208Snarayan 46334bac2208Snarayan if (dir == VD_COPYIN) 46344bac2208Snarayan return (0); /* nothing to do */ 46354bac2208Snarayan 46364bac2208Snarayan if (ddi_copyout(from, to, sizeof (int), mode) != 0) 46374bac2208Snarayan return (EFAULT); 46384bac2208Snarayan 46394bac2208Snarayan return (0); 46404bac2208Snarayan } 46414bac2208Snarayan 46424bac2208Snarayan static int 46434bac2208Snarayan vdc_set_wce_convert(vdc_t *vdc, void *from, void *to, 46444bac2208Snarayan int mode, int dir) 46454bac2208Snarayan { 46464bac2208Snarayan _NOTE(ARGUNUSED(vdc)) 46474bac2208Snarayan 46484bac2208Snarayan if (dir == VD_COPYOUT) 46494bac2208Snarayan return (0); /* nothing to do */ 46504bac2208Snarayan 46514bac2208Snarayan if (ddi_copyin(from, to, sizeof (int), mode) != 0) 46524bac2208Snarayan return (EFAULT); 46534bac2208Snarayan 46544bac2208Snarayan return (0); 46554bac2208Snarayan } 46564bac2208Snarayan 46570a55fbb7Slm66018 /* 46580a55fbb7Slm66018 * Function: 46590a55fbb7Slm66018 * vdc_get_vtoc_convert() 46600a55fbb7Slm66018 * 46610a55fbb7Slm66018 * Description: 4662d10e4ef2Snarayan * This routine performs the necessary convertions from the DKIOCGVTOC 4663d10e4ef2Snarayan * Solaris structure to the format defined in FWARC 2006/195. 4664d10e4ef2Snarayan * 4665d10e4ef2Snarayan * In the struct vtoc definition, the timestamp field is marked as not 4666d10e4ef2Snarayan * supported so it is not part of vDisk protocol (FWARC 2006/195). 4667d10e4ef2Snarayan * However SVM uses that field to check it can write into the VTOC, 4668d10e4ef2Snarayan * so we fake up the info of that field. 46690a55fbb7Slm66018 * 46700a55fbb7Slm66018 * Arguments: 4671d10e4ef2Snarayan * vdc - the vDisk client 46720a55fbb7Slm66018 * from - the buffer containing the data to be copied from 46730a55fbb7Slm66018 * to - the buffer to be copied to 46740a55fbb7Slm66018 * mode - flags passed to ioctl() call 46750a55fbb7Slm66018 * dir - the "direction" of the copy - VD_COPYIN or VD_COPYOUT 46760a55fbb7Slm66018 * 46770a55fbb7Slm66018 * Return Code: 46780a55fbb7Slm66018 * 0 - Success 46790a55fbb7Slm66018 * ENXIO - incorrect buffer passed in. 4680d10e4ef2Snarayan * EFAULT - ddi_copyout routine encountered an error. 46810a55fbb7Slm66018 */ 46820a55fbb7Slm66018 static int 4683d10e4ef2Snarayan vdc_get_vtoc_convert(vdc_t *vdc, void *from, void *to, int mode, int dir) 46840a55fbb7Slm66018 { 4685d10e4ef2Snarayan int i; 46860a55fbb7Slm66018 void *tmp_mem = NULL; 46870a55fbb7Slm66018 void *tmp_memp; 46880a55fbb7Slm66018 struct vtoc vt; 46890a55fbb7Slm66018 struct vtoc32 vt32; 46900a55fbb7Slm66018 int copy_len = 0; 46910a55fbb7Slm66018 int rv = 0; 46920a55fbb7Slm66018 46930a55fbb7Slm66018 if (dir != VD_COPYOUT) 46940a55fbb7Slm66018 return (0); /* nothing to do */ 46950a55fbb7Slm66018 46960a55fbb7Slm66018 if ((from == NULL) || (to == NULL)) 46970a55fbb7Slm66018 return (ENXIO); 46980a55fbb7Slm66018 46990a55fbb7Slm66018 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) 47000a55fbb7Slm66018 copy_len = sizeof (struct vtoc32); 47010a55fbb7Slm66018 else 47020a55fbb7Slm66018 copy_len = sizeof (struct vtoc); 47030a55fbb7Slm66018 47040a55fbb7Slm66018 tmp_mem = kmem_alloc(copy_len, KM_SLEEP); 47050a55fbb7Slm66018 47060a55fbb7Slm66018 VD_VTOC2VTOC((vd_vtoc_t *)from, &vt); 4707d10e4ef2Snarayan 4708d10e4ef2Snarayan /* fake the VTOC timestamp field */ 4709d10e4ef2Snarayan for (i = 0; i < V_NUMPAR; i++) { 4710d10e4ef2Snarayan vt.timestamp[i] = vdc->vtoc->timestamp[i]; 4711d10e4ef2Snarayan } 4712d10e4ef2Snarayan 47130a55fbb7Slm66018 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 47140a55fbb7Slm66018 vtoctovtoc32(vt, vt32); 47150a55fbb7Slm66018 tmp_memp = &vt32; 47160a55fbb7Slm66018 } else { 47170a55fbb7Slm66018 tmp_memp = &vt; 47180a55fbb7Slm66018 } 47190a55fbb7Slm66018 rv = ddi_copyout(tmp_memp, to, copy_len, mode); 47200a55fbb7Slm66018 if (rv != 0) 47210a55fbb7Slm66018 rv = EFAULT; 47220a55fbb7Slm66018 47230a55fbb7Slm66018 kmem_free(tmp_mem, copy_len); 47240a55fbb7Slm66018 return (rv); 47250a55fbb7Slm66018 } 47260a55fbb7Slm66018 47270a55fbb7Slm66018 /* 47280a55fbb7Slm66018 * Function: 47290a55fbb7Slm66018 * vdc_set_vtoc_convert() 47300a55fbb7Slm66018 * 47310a55fbb7Slm66018 * Description: 4732d10e4ef2Snarayan * This routine performs the necessary convertions from the DKIOCSVTOC 4733d10e4ef2Snarayan * Solaris structure to the format defined in FWARC 2006/195. 47340a55fbb7Slm66018 * 47350a55fbb7Slm66018 * Arguments: 4736d10e4ef2Snarayan * vdc - the vDisk client 47370a55fbb7Slm66018 * from - Buffer with data 47380a55fbb7Slm66018 * to - Buffer where data is to be copied to 47390a55fbb7Slm66018 * mode - flags passed to ioctl 47400a55fbb7Slm66018 * dir - direction of copy (in or out) 47410a55fbb7Slm66018 * 47420a55fbb7Slm66018 * Return Code: 47430a55fbb7Slm66018 * 0 - Success 47440a55fbb7Slm66018 * ENXIO - Invalid buffer passed in 47450a55fbb7Slm66018 * EFAULT - ddi_copyin of data failed 47460a55fbb7Slm66018 */ 47470a55fbb7Slm66018 static int 4748d10e4ef2Snarayan vdc_set_vtoc_convert(vdc_t *vdc, void *from, void *to, int mode, int dir) 47490a55fbb7Slm66018 { 47500a55fbb7Slm66018 void *tmp_mem = NULL; 47510a55fbb7Slm66018 struct vtoc vt; 47520a55fbb7Slm66018 struct vtoc *vtp = &vt; 47530a55fbb7Slm66018 vd_vtoc_t vtvd; 47540a55fbb7Slm66018 int copy_len = 0; 47550a55fbb7Slm66018 int rv = 0; 47560a55fbb7Slm66018 47570a55fbb7Slm66018 if (dir != VD_COPYIN) 47580a55fbb7Slm66018 return (0); /* nothing to do */ 47590a55fbb7Slm66018 47600a55fbb7Slm66018 if ((from == NULL) || (to == NULL)) 47610a55fbb7Slm66018 return (ENXIO); 47620a55fbb7Slm66018 47630a55fbb7Slm66018 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) 47640a55fbb7Slm66018 copy_len = sizeof (struct vtoc32); 47650a55fbb7Slm66018 else 47660a55fbb7Slm66018 copy_len = sizeof (struct vtoc); 47670a55fbb7Slm66018 47680a55fbb7Slm66018 tmp_mem = kmem_alloc(copy_len, KM_SLEEP); 47690a55fbb7Slm66018 47700a55fbb7Slm66018 rv = ddi_copyin(from, tmp_mem, copy_len, mode); 47710a55fbb7Slm66018 if (rv != 0) { 47720a55fbb7Slm66018 kmem_free(tmp_mem, copy_len); 47730a55fbb7Slm66018 return (EFAULT); 47740a55fbb7Slm66018 } 47750a55fbb7Slm66018 47760a55fbb7Slm66018 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 47770a55fbb7Slm66018 vtoc32tovtoc((*(struct vtoc32 *)tmp_mem), vt); 47780a55fbb7Slm66018 } else { 47790a55fbb7Slm66018 vtp = tmp_mem; 47800a55fbb7Slm66018 } 47810a55fbb7Slm66018 4782d10e4ef2Snarayan /* 4783d10e4ef2Snarayan * The VTOC is being changed, then vdc needs to update the copy 4784d10e4ef2Snarayan * it saved in the soft state structure. 4785d10e4ef2Snarayan */ 4786d10e4ef2Snarayan bcopy(vtp, vdc->vtoc, sizeof (struct vtoc)); 4787d10e4ef2Snarayan 47880a55fbb7Slm66018 VTOC2VD_VTOC(vtp, &vtvd); 47890a55fbb7Slm66018 bcopy(&vtvd, to, sizeof (vd_vtoc_t)); 47900a55fbb7Slm66018 kmem_free(tmp_mem, copy_len); 47910a55fbb7Slm66018 47920a55fbb7Slm66018 return (0); 47930a55fbb7Slm66018 } 47940a55fbb7Slm66018 47950a55fbb7Slm66018 /* 47960a55fbb7Slm66018 * Function: 47970a55fbb7Slm66018 * vdc_get_geom_convert() 47980a55fbb7Slm66018 * 47990a55fbb7Slm66018 * Description: 4800d10e4ef2Snarayan * This routine performs the necessary convertions from the DKIOCGGEOM, 4801d10e4ef2Snarayan * DKIOCG_PHYSGEOM and DKIOG_VIRTGEOM Solaris structures to the format 4802d10e4ef2Snarayan * defined in FWARC 2006/195 48030a55fbb7Slm66018 * 48040a55fbb7Slm66018 * Arguments: 4805d10e4ef2Snarayan * vdc - the vDisk client 48060a55fbb7Slm66018 * from - Buffer with data 48070a55fbb7Slm66018 * to - Buffer where data is to be copied to 48080a55fbb7Slm66018 * mode - flags passed to ioctl 48090a55fbb7Slm66018 * dir - direction of copy (in or out) 48100a55fbb7Slm66018 * 48110a55fbb7Slm66018 * Return Code: 48120a55fbb7Slm66018 * 0 - Success 48130a55fbb7Slm66018 * ENXIO - Invalid buffer passed in 4814d10e4ef2Snarayan * EFAULT - ddi_copyout of data failed 48150a55fbb7Slm66018 */ 48160a55fbb7Slm66018 static int 4817d10e4ef2Snarayan vdc_get_geom_convert(vdc_t *vdc, void *from, void *to, int mode, int dir) 48180a55fbb7Slm66018 { 4819d10e4ef2Snarayan _NOTE(ARGUNUSED(vdc)) 4820d10e4ef2Snarayan 48210a55fbb7Slm66018 struct dk_geom geom; 48220a55fbb7Slm66018 int copy_len = sizeof (struct dk_geom); 48230a55fbb7Slm66018 int rv = 0; 48240a55fbb7Slm66018 48250a55fbb7Slm66018 if (dir != VD_COPYOUT) 48260a55fbb7Slm66018 return (0); /* nothing to do */ 48270a55fbb7Slm66018 48280a55fbb7Slm66018 if ((from == NULL) || (to == NULL)) 48290a55fbb7Slm66018 return (ENXIO); 48300a55fbb7Slm66018 48310a55fbb7Slm66018 VD_GEOM2DK_GEOM((vd_geom_t *)from, &geom); 48320a55fbb7Slm66018 rv = ddi_copyout(&geom, to, copy_len, mode); 48330a55fbb7Slm66018 if (rv != 0) 48340a55fbb7Slm66018 rv = EFAULT; 48350a55fbb7Slm66018 48360a55fbb7Slm66018 return (rv); 48370a55fbb7Slm66018 } 48380a55fbb7Slm66018 48390a55fbb7Slm66018 /* 48400a55fbb7Slm66018 * Function: 48410a55fbb7Slm66018 * vdc_set_geom_convert() 48420a55fbb7Slm66018 * 48430a55fbb7Slm66018 * Description: 4844d10e4ef2Snarayan * This routine performs the necessary convertions from the DKIOCSGEOM 4845d10e4ef2Snarayan * Solaris structure to the format defined in FWARC 2006/195. 48460a55fbb7Slm66018 * 48470a55fbb7Slm66018 * Arguments: 4848d10e4ef2Snarayan * vdc - the vDisk client 48490a55fbb7Slm66018 * from - Buffer with data 48500a55fbb7Slm66018 * to - Buffer where data is to be copied to 48510a55fbb7Slm66018 * mode - flags passed to ioctl 48520a55fbb7Slm66018 * dir - direction of copy (in or out) 48530a55fbb7Slm66018 * 48540a55fbb7Slm66018 * Return Code: 48550a55fbb7Slm66018 * 0 - Success 48560a55fbb7Slm66018 * ENXIO - Invalid buffer passed in 48570a55fbb7Slm66018 * EFAULT - ddi_copyin of data failed 48580a55fbb7Slm66018 */ 48590a55fbb7Slm66018 static int 4860d10e4ef2Snarayan vdc_set_geom_convert(vdc_t *vdc, void *from, void *to, int mode, int dir) 48610a55fbb7Slm66018 { 4862d10e4ef2Snarayan _NOTE(ARGUNUSED(vdc)) 4863d10e4ef2Snarayan 48640a55fbb7Slm66018 vd_geom_t vdgeom; 48650a55fbb7Slm66018 void *tmp_mem = NULL; 48660a55fbb7Slm66018 int copy_len = sizeof (struct dk_geom); 48670a55fbb7Slm66018 int rv = 0; 48680a55fbb7Slm66018 48690a55fbb7Slm66018 if (dir != VD_COPYIN) 48700a55fbb7Slm66018 return (0); /* nothing to do */ 48710a55fbb7Slm66018 48720a55fbb7Slm66018 if ((from == NULL) || (to == NULL)) 48730a55fbb7Slm66018 return (ENXIO); 48740a55fbb7Slm66018 48750a55fbb7Slm66018 tmp_mem = kmem_alloc(copy_len, KM_SLEEP); 48760a55fbb7Slm66018 48770a55fbb7Slm66018 rv = ddi_copyin(from, tmp_mem, copy_len, mode); 48780a55fbb7Slm66018 if (rv != 0) { 48790a55fbb7Slm66018 kmem_free(tmp_mem, copy_len); 48800a55fbb7Slm66018 return (EFAULT); 48810a55fbb7Slm66018 } 48820a55fbb7Slm66018 DK_GEOM2VD_GEOM((struct dk_geom *)tmp_mem, &vdgeom); 48830a55fbb7Slm66018 bcopy(&vdgeom, to, sizeof (vdgeom)); 48840a55fbb7Slm66018 kmem_free(tmp_mem, copy_len); 48850a55fbb7Slm66018 48860a55fbb7Slm66018 return (0); 48870a55fbb7Slm66018 } 48880a55fbb7Slm66018 48894bac2208Snarayan static int 48904bac2208Snarayan vdc_get_efi_convert(vdc_t *vdc, void *from, void *to, int mode, int dir) 48914bac2208Snarayan { 48924bac2208Snarayan _NOTE(ARGUNUSED(vdc)) 48934bac2208Snarayan 48944bac2208Snarayan vd_efi_t *vd_efi; 48954bac2208Snarayan dk_efi_t dk_efi; 48964bac2208Snarayan int rv = 0; 48974bac2208Snarayan void *uaddr; 48984bac2208Snarayan 48994bac2208Snarayan if ((from == NULL) || (to == NULL)) 49004bac2208Snarayan return (ENXIO); 49014bac2208Snarayan 49024bac2208Snarayan if (dir == VD_COPYIN) { 49034bac2208Snarayan 49044bac2208Snarayan vd_efi = (vd_efi_t *)to; 49054bac2208Snarayan 49064bac2208Snarayan rv = ddi_copyin(from, &dk_efi, sizeof (dk_efi_t), mode); 49074bac2208Snarayan if (rv != 0) 49084bac2208Snarayan return (EFAULT); 49094bac2208Snarayan 49104bac2208Snarayan vd_efi->lba = dk_efi.dki_lba; 49114bac2208Snarayan vd_efi->length = dk_efi.dki_length; 49124bac2208Snarayan bzero(vd_efi->data, vd_efi->length); 49134bac2208Snarayan 49144bac2208Snarayan } else { 49154bac2208Snarayan 49164bac2208Snarayan rv = ddi_copyin(to, &dk_efi, sizeof (dk_efi_t), mode); 49174bac2208Snarayan if (rv != 0) 49184bac2208Snarayan return (EFAULT); 49194bac2208Snarayan 49204bac2208Snarayan uaddr = dk_efi.dki_data; 49214bac2208Snarayan 49224bac2208Snarayan dk_efi.dki_data = kmem_alloc(dk_efi.dki_length, KM_SLEEP); 49234bac2208Snarayan 49244bac2208Snarayan VD_EFI2DK_EFI((vd_efi_t *)from, &dk_efi); 49254bac2208Snarayan 49264bac2208Snarayan rv = ddi_copyout(dk_efi.dki_data, uaddr, dk_efi.dki_length, 49274bac2208Snarayan mode); 49284bac2208Snarayan if (rv != 0) 49294bac2208Snarayan return (EFAULT); 49304bac2208Snarayan 49314bac2208Snarayan kmem_free(dk_efi.dki_data, dk_efi.dki_length); 49324bac2208Snarayan } 49334bac2208Snarayan 49344bac2208Snarayan return (0); 49354bac2208Snarayan } 49364bac2208Snarayan 49374bac2208Snarayan static int 49384bac2208Snarayan vdc_set_efi_convert(vdc_t *vdc, void *from, void *to, int mode, int dir) 49394bac2208Snarayan { 49404bac2208Snarayan _NOTE(ARGUNUSED(vdc)) 49414bac2208Snarayan 49424bac2208Snarayan dk_efi_t dk_efi; 49434bac2208Snarayan void *uaddr; 49444bac2208Snarayan 49454bac2208Snarayan if (dir == VD_COPYOUT) 49464bac2208Snarayan return (0); /* nothing to do */ 49474bac2208Snarayan 49484bac2208Snarayan if ((from == NULL) || (to == NULL)) 49494bac2208Snarayan return (ENXIO); 49504bac2208Snarayan 49514bac2208Snarayan if (ddi_copyin(from, &dk_efi, sizeof (dk_efi_t), mode) != 0) 49524bac2208Snarayan return (EFAULT); 49534bac2208Snarayan 49544bac2208Snarayan uaddr = dk_efi.dki_data; 49554bac2208Snarayan 49564bac2208Snarayan dk_efi.dki_data = kmem_alloc(dk_efi.dki_length, KM_SLEEP); 49574bac2208Snarayan 49584bac2208Snarayan if (ddi_copyin(uaddr, dk_efi.dki_data, dk_efi.dki_length, mode) != 0) 49594bac2208Snarayan return (EFAULT); 49604bac2208Snarayan 49614bac2208Snarayan DK_EFI2VD_EFI(&dk_efi, (vd_efi_t *)to); 49624bac2208Snarayan 49634bac2208Snarayan kmem_free(dk_efi.dki_data, dk_efi.dki_length); 49644bac2208Snarayan 49654bac2208Snarayan return (0); 49664bac2208Snarayan } 49674bac2208Snarayan 49680a55fbb7Slm66018 /* 49690a55fbb7Slm66018 * Function: 49701ae08745Sheppo * vdc_create_fake_geometry() 49711ae08745Sheppo * 49721ae08745Sheppo * Description: 49731ae08745Sheppo * This routine fakes up the disk info needed for some DKIO ioctls. 49741ae08745Sheppo * - DKIOCINFO 49751ae08745Sheppo * - DKIOCGMEDIAINFO 49761ae08745Sheppo * 49771ae08745Sheppo * [ just like lofi(7D) and ramdisk(7D) ] 49781ae08745Sheppo * 49791ae08745Sheppo * Arguments: 49801ae08745Sheppo * vdc - soft state pointer for this instance of the device driver. 49811ae08745Sheppo * 49821ae08745Sheppo * Return Code: 49831ae08745Sheppo * 0 - Success 49841ae08745Sheppo */ 49851ae08745Sheppo static int 49861ae08745Sheppo vdc_create_fake_geometry(vdc_t *vdc) 49871ae08745Sheppo { 49881ae08745Sheppo ASSERT(vdc != NULL); 49891ae08745Sheppo 49901ae08745Sheppo /* 49910d0c8d4bSnarayan * Check if max_xfer_sz and vdisk_size are valid 49920d0c8d4bSnarayan */ 49930d0c8d4bSnarayan if (vdc->vdisk_size == 0 || vdc->max_xfer_sz == 0) 49940d0c8d4bSnarayan return (EIO); 49950d0c8d4bSnarayan 49960d0c8d4bSnarayan /* 49971ae08745Sheppo * DKIOCINFO support 49981ae08745Sheppo */ 49991ae08745Sheppo vdc->cinfo = kmem_zalloc(sizeof (struct dk_cinfo), KM_SLEEP); 50001ae08745Sheppo 50011ae08745Sheppo (void) strcpy(vdc->cinfo->dki_cname, VDC_DRIVER_NAME); 50021ae08745Sheppo (void) strcpy(vdc->cinfo->dki_dname, VDC_DRIVER_NAME); 50038e6a2a04Slm66018 /* max_xfer_sz is #blocks so we don't need to divide by DEV_BSIZE */ 50048e6a2a04Slm66018 vdc->cinfo->dki_maxtransfer = vdc->max_xfer_sz; 500587a7269eSachartre /* 500687a7269eSachartre * We currently set the controller type to DKC_DIRECT for any disk. 500787a7269eSachartre * When SCSI support is implemented, we will eventually change this 500887a7269eSachartre * type to DKC_SCSI_CCS for disks supporting the SCSI protocol. 500987a7269eSachartre */ 501087a7269eSachartre vdc->cinfo->dki_ctype = DKC_DIRECT; 50111ae08745Sheppo vdc->cinfo->dki_flags = DKI_FMTVOL; 50121ae08745Sheppo vdc->cinfo->dki_cnum = 0; 50131ae08745Sheppo vdc->cinfo->dki_addr = 0; 50141ae08745Sheppo vdc->cinfo->dki_space = 0; 50151ae08745Sheppo vdc->cinfo->dki_prio = 0; 50161ae08745Sheppo vdc->cinfo->dki_vec = 0; 50171ae08745Sheppo vdc->cinfo->dki_unit = vdc->instance; 50181ae08745Sheppo vdc->cinfo->dki_slave = 0; 50191ae08745Sheppo /* 50201ae08745Sheppo * The partition number will be created on the fly depending on the 50211ae08745Sheppo * actual slice (i.e. minor node) that is used to request the data. 50221ae08745Sheppo */ 50231ae08745Sheppo vdc->cinfo->dki_partition = 0; 50241ae08745Sheppo 50251ae08745Sheppo /* 50261ae08745Sheppo * DKIOCGMEDIAINFO support 50271ae08745Sheppo */ 50280a55fbb7Slm66018 if (vdc->minfo == NULL) 50291ae08745Sheppo vdc->minfo = kmem_zalloc(sizeof (struct dk_minfo), KM_SLEEP); 50301ae08745Sheppo vdc->minfo->dki_media_type = DK_FIXED_DISK; 50314bac2208Snarayan vdc->minfo->dki_capacity = vdc->vdisk_size; 50321ae08745Sheppo vdc->minfo->dki_lbsize = DEV_BSIZE; 50331ae08745Sheppo 50340d0c8d4bSnarayan return (0); 50350a55fbb7Slm66018 } 50360a55fbb7Slm66018 50370a55fbb7Slm66018 /* 50380a55fbb7Slm66018 * Function: 50390a55fbb7Slm66018 * vdc_setup_disk_layout() 50400a55fbb7Slm66018 * 50410a55fbb7Slm66018 * Description: 50420a55fbb7Slm66018 * This routine discovers all the necessary details about the "disk" 50430a55fbb7Slm66018 * by requesting the data that is available from the vDisk server and by 50440a55fbb7Slm66018 * faking up the rest of the data. 50450a55fbb7Slm66018 * 50460a55fbb7Slm66018 * Arguments: 50470a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 50480a55fbb7Slm66018 * 50490a55fbb7Slm66018 * Return Code: 50500a55fbb7Slm66018 * 0 - Success 50510a55fbb7Slm66018 */ 50520a55fbb7Slm66018 static int 50530a55fbb7Slm66018 vdc_setup_disk_layout(vdc_t *vdc) 50540a55fbb7Slm66018 { 5055d10e4ef2Snarayan buf_t *buf; /* BREAD requests need to be in a buf_t structure */ 50560a55fbb7Slm66018 dev_t dev; 50570a55fbb7Slm66018 int slice = 0; 50580d0c8d4bSnarayan int rv, error; 50590a55fbb7Slm66018 50600a55fbb7Slm66018 ASSERT(vdc != NULL); 50610a55fbb7Slm66018 50620a55fbb7Slm66018 if (vdc->vtoc == NULL) 50630a55fbb7Slm66018 vdc->vtoc = kmem_zalloc(sizeof (struct vtoc), KM_SLEEP); 50640a55fbb7Slm66018 50650a55fbb7Slm66018 dev = makedevice(ddi_driver_major(vdc->dip), 50660a55fbb7Slm66018 VD_MAKE_DEV(vdc->instance, 0)); 50670a55fbb7Slm66018 rv = vd_process_ioctl(dev, DKIOCGVTOC, (caddr_t)vdc->vtoc, FKIOCTL); 50684bac2208Snarayan 50694bac2208Snarayan if (rv && rv != ENOTSUP) { 50703af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to get VTOC (err=%d)", 50710a55fbb7Slm66018 vdc->instance, rv); 50720a55fbb7Slm66018 return (rv); 50730a55fbb7Slm66018 } 50740a55fbb7Slm66018 50750d0c8d4bSnarayan /* 50760d0c8d4bSnarayan * The process of attempting to read VTOC will initiate 50770d0c8d4bSnarayan * the handshake and establish a connection. Following 50780d0c8d4bSnarayan * handshake, go ahead and create geometry. 50790d0c8d4bSnarayan */ 50800d0c8d4bSnarayan error = vdc_create_fake_geometry(vdc); 50810d0c8d4bSnarayan if (error != 0) { 50820d0c8d4bSnarayan DMSG(vdc, 0, "[%d] Failed to create disk geometry (err%d)", 50830d0c8d4bSnarayan vdc->instance, error); 50840d0c8d4bSnarayan return (error); 50850d0c8d4bSnarayan } 50860d0c8d4bSnarayan 50874bac2208Snarayan if (rv == ENOTSUP) { 50884bac2208Snarayan /* 50894bac2208Snarayan * If the device does not support VTOC then we try 50904bac2208Snarayan * to read an EFI label. 50914bac2208Snarayan */ 50924bac2208Snarayan struct dk_gpt *efi; 50934bac2208Snarayan size_t efi_len; 50944bac2208Snarayan 50954bac2208Snarayan rv = vdc_efi_alloc_and_read(dev, &efi, &efi_len); 50964bac2208Snarayan 50974bac2208Snarayan if (rv) { 50983af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to get EFI (err=%d)", 50994bac2208Snarayan vdc->instance, rv); 51004bac2208Snarayan return (rv); 51014bac2208Snarayan } 51024bac2208Snarayan 51034bac2208Snarayan vdc->vdisk_label = VD_DISK_LABEL_EFI; 51044bac2208Snarayan vdc_store_efi(vdc, efi); 51054bac2208Snarayan vd_efi_free(efi, efi_len); 51064bac2208Snarayan 51074bac2208Snarayan return (0); 51084bac2208Snarayan } 51094bac2208Snarayan 51104bac2208Snarayan vdc->vdisk_label = VD_DISK_LABEL_VTOC; 51114bac2208Snarayan 51120a55fbb7Slm66018 /* 51133af08d82Slm66018 * FUTURE: This could be default way for reading the VTOC 51143af08d82Slm66018 * from the disk as supposed to sending the VD_OP_GET_VTOC 51153af08d82Slm66018 * to the server. Currently this is a sanity check. 51163af08d82Slm66018 * 51170a55fbb7Slm66018 * find the slice that represents the entire "disk" and use that to 51180a55fbb7Slm66018 * read the disk label. The convention in Solaris is that slice 2 5119d10e4ef2Snarayan * represents the whole disk so we check that it is, otherwise we 51200a55fbb7Slm66018 * default to slice 0 51210a55fbb7Slm66018 */ 51220a55fbb7Slm66018 if ((vdc->vdisk_type == VD_DISK_TYPE_DISK) && 51230a55fbb7Slm66018 (vdc->vtoc->v_part[2].p_tag == V_BACKUP)) { 51240a55fbb7Slm66018 slice = 2; 51250a55fbb7Slm66018 } else { 51260a55fbb7Slm66018 slice = 0; 51270a55fbb7Slm66018 } 5128d10e4ef2Snarayan 5129d10e4ef2Snarayan /* 5130d10e4ef2Snarayan * Read disk label from start of disk 5131d10e4ef2Snarayan */ 5132d10e4ef2Snarayan vdc->label = kmem_zalloc(DK_LABEL_SIZE, KM_SLEEP); 5133d10e4ef2Snarayan buf = kmem_alloc(sizeof (buf_t), KM_SLEEP); 5134d10e4ef2Snarayan bioinit(buf); 5135d10e4ef2Snarayan buf->b_un.b_addr = (caddr_t)vdc->label; 5136d10e4ef2Snarayan buf->b_bcount = DK_LABEL_SIZE; 5137d10e4ef2Snarayan buf->b_flags = B_BUSY | B_READ; 5138d10e4ef2Snarayan buf->b_dev = dev; 51393af08d82Slm66018 rv = vdc_send_request(vdc, VD_OP_BREAD, (caddr_t)vdc->label, 51403af08d82Slm66018 DK_LABEL_SIZE, slice, 0, CB_STRATEGY, buf, VIO_read_dir); 51413af08d82Slm66018 if (rv) { 51423af08d82Slm66018 DMSG(vdc, 1, "[%d] Failed to read disk block 0\n", 51433af08d82Slm66018 vdc->instance); 51443af08d82Slm66018 kmem_free(buf, sizeof (buf_t)); 51453af08d82Slm66018 return (rv); 51463af08d82Slm66018 } 5147d10e4ef2Snarayan rv = biowait(buf); 5148d10e4ef2Snarayan biofini(buf); 5149d10e4ef2Snarayan kmem_free(buf, sizeof (buf_t)); 51500a55fbb7Slm66018 51510a55fbb7Slm66018 return (rv); 51521ae08745Sheppo } 51534bac2208Snarayan 51544bac2208Snarayan /* 51554bac2208Snarayan * Function: 51564bac2208Snarayan * vdc_setup_devid() 51574bac2208Snarayan * 51584bac2208Snarayan * Description: 51594bac2208Snarayan * This routine discovers the devid of a vDisk. It requests the devid of 51604bac2208Snarayan * the underlying device from the vDisk server, builds an encapsulated 51614bac2208Snarayan * devid based on the retrieved devid and registers that new devid to 51624bac2208Snarayan * the vDisk. 51634bac2208Snarayan * 51644bac2208Snarayan * Arguments: 51654bac2208Snarayan * vdc - soft state pointer for this instance of the device driver. 51664bac2208Snarayan * 51674bac2208Snarayan * Return Code: 51684bac2208Snarayan * 0 - A devid was succesfully registered for the vDisk 51694bac2208Snarayan */ 51704bac2208Snarayan static int 51714bac2208Snarayan vdc_setup_devid(vdc_t *vdc) 51724bac2208Snarayan { 51734bac2208Snarayan int rv; 51744bac2208Snarayan vd_devid_t *vd_devid; 51754bac2208Snarayan size_t bufsize, bufid_len; 51764bac2208Snarayan 51774bac2208Snarayan /* 51784bac2208Snarayan * At first sight, we don't know the size of the devid that the 51794bac2208Snarayan * server will return but this size will be encoded into the 51804bac2208Snarayan * reply. So we do a first request using a default size then we 51814bac2208Snarayan * check if this size was large enough. If not then we do a second 51824bac2208Snarayan * request with the correct size returned by the server. Note that 51834bac2208Snarayan * ldc requires size to be 8-byte aligned. 51844bac2208Snarayan */ 51854bac2208Snarayan bufsize = P2ROUNDUP(VD_DEVID_SIZE(VD_DEVID_DEFAULT_LEN), 51864bac2208Snarayan sizeof (uint64_t)); 51874bac2208Snarayan vd_devid = kmem_zalloc(bufsize, KM_SLEEP); 51884bac2208Snarayan bufid_len = bufsize - sizeof (vd_efi_t) - 1; 51894bac2208Snarayan 51903af08d82Slm66018 rv = vdc_do_sync_op(vdc, VD_OP_GET_DEVID, (caddr_t)vd_devid, 51913af08d82Slm66018 bufsize, 0, 0, CB_SYNC, 0, VIO_both_dir); 51923af08d82Slm66018 51933af08d82Slm66018 DMSG(vdc, 2, "sync_op returned %d\n", rv); 51943af08d82Slm66018 51954bac2208Snarayan if (rv) { 51964bac2208Snarayan kmem_free(vd_devid, bufsize); 51974bac2208Snarayan return (rv); 51984bac2208Snarayan } 51994bac2208Snarayan 52004bac2208Snarayan if (vd_devid->length > bufid_len) { 52014bac2208Snarayan /* 52024bac2208Snarayan * The returned devid is larger than the buffer used. Try again 52034bac2208Snarayan * with a buffer with the right size. 52044bac2208Snarayan */ 52054bac2208Snarayan kmem_free(vd_devid, bufsize); 52064bac2208Snarayan bufsize = P2ROUNDUP(VD_DEVID_SIZE(vd_devid->length), 52074bac2208Snarayan sizeof (uint64_t)); 52084bac2208Snarayan vd_devid = kmem_zalloc(bufsize, KM_SLEEP); 52094bac2208Snarayan bufid_len = bufsize - sizeof (vd_efi_t) - 1; 52104bac2208Snarayan 52113af08d82Slm66018 rv = vdc_do_sync_op(vdc, VD_OP_GET_DEVID, 52123af08d82Slm66018 (caddr_t)vd_devid, bufsize, 0, 0, CB_SYNC, 0, 52133af08d82Slm66018 VIO_both_dir); 52143af08d82Slm66018 52154bac2208Snarayan if (rv) { 52164bac2208Snarayan kmem_free(vd_devid, bufsize); 52174bac2208Snarayan return (rv); 52184bac2208Snarayan } 52194bac2208Snarayan } 52204bac2208Snarayan 52214bac2208Snarayan /* 52224bac2208Snarayan * The virtual disk should have the same device id as the one associated 52234bac2208Snarayan * with the physical disk it is mapped on, otherwise sharing a disk 52244bac2208Snarayan * between a LDom and a non-LDom may not work (for example for a shared 52254bac2208Snarayan * SVM disk set). 52264bac2208Snarayan * 52274bac2208Snarayan * The DDI framework does not allow creating a device id with any 52284bac2208Snarayan * type so we first create a device id of type DEVID_ENCAP and then 52294bac2208Snarayan * we restore the orignal type of the physical device. 52304bac2208Snarayan */ 52314bac2208Snarayan 52323af08d82Slm66018 DMSG(vdc, 2, ": devid length = %d\n", vd_devid->length); 52333af08d82Slm66018 52344bac2208Snarayan /* build an encapsulated devid based on the returned devid */ 52354bac2208Snarayan if (ddi_devid_init(vdc->dip, DEVID_ENCAP, vd_devid->length, 52364bac2208Snarayan vd_devid->id, &vdc->devid) != DDI_SUCCESS) { 52373af08d82Slm66018 DMSG(vdc, 1, "[%d] Fail to created devid\n", vdc->instance); 52384bac2208Snarayan kmem_free(vd_devid, bufsize); 52394bac2208Snarayan return (1); 52404bac2208Snarayan } 52414bac2208Snarayan 52424bac2208Snarayan DEVID_FORMTYPE((impl_devid_t *)vdc->devid, vd_devid->type); 52434bac2208Snarayan 52444bac2208Snarayan ASSERT(ddi_devid_valid(vdc->devid) == DDI_SUCCESS); 52454bac2208Snarayan 52464bac2208Snarayan kmem_free(vd_devid, bufsize); 52474bac2208Snarayan 52484bac2208Snarayan if (ddi_devid_register(vdc->dip, vdc->devid) != DDI_SUCCESS) { 52493af08d82Slm66018 DMSG(vdc, 1, "[%d] Fail to register devid\n", vdc->instance); 52504bac2208Snarayan return (1); 52514bac2208Snarayan } 52524bac2208Snarayan 52534bac2208Snarayan return (0); 52544bac2208Snarayan } 52554bac2208Snarayan 52564bac2208Snarayan static void 52574bac2208Snarayan vdc_store_efi(vdc_t *vdc, struct dk_gpt *efi) 52584bac2208Snarayan { 52594bac2208Snarayan struct vtoc *vtoc = vdc->vtoc; 52604bac2208Snarayan 52614bac2208Snarayan vd_efi_to_vtoc(efi, vtoc); 52624bac2208Snarayan if (vdc->vdisk_type == VD_DISK_TYPE_SLICE) { 52634bac2208Snarayan /* 52644bac2208Snarayan * vd_efi_to_vtoc() will store information about the EFI Sun 52654bac2208Snarayan * reserved partition (representing the entire disk) into 52664bac2208Snarayan * partition 7. However single-slice device will only have 52674bac2208Snarayan * that single partition and the vdc driver expects to find 52684bac2208Snarayan * information about that partition in slice 0. So we need 52694bac2208Snarayan * to copy information from slice 7 to slice 0. 52704bac2208Snarayan */ 52714bac2208Snarayan vtoc->v_part[0].p_tag = vtoc->v_part[VD_EFI_WD_SLICE].p_tag; 52724bac2208Snarayan vtoc->v_part[0].p_flag = vtoc->v_part[VD_EFI_WD_SLICE].p_flag; 52734bac2208Snarayan vtoc->v_part[0].p_start = vtoc->v_part[VD_EFI_WD_SLICE].p_start; 52744bac2208Snarayan vtoc->v_part[0].p_size = vtoc->v_part[VD_EFI_WD_SLICE].p_size; 52754bac2208Snarayan } 52764bac2208Snarayan } 5277