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); 121655fd6a9Sachartre static int vdc_do_ldc_init(vdc_t *vdc, md_t *mdp, mde_cookie_t vd_node); 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); 127655fd6a9Sachartre static int vdc_get_md_node(dev_info_t *dip, md_t **mdpp, 128655fd6a9Sachartre mde_cookie_t *vd_nodep, mde_cookie_t *vd_portp); 129655fd6a9Sachartre static int vdc_get_ldc_id(md_t *, mde_cookie_t, uint64_t *); 1300a55fbb7Slm66018 static int vdc_do_ldc_up(vdc_t *vdc); 1311ae08745Sheppo static void vdc_terminate_ldc(vdc_t *vdc); 1321ae08745Sheppo static int vdc_init_descriptor_ring(vdc_t *vdc); 1331ae08745Sheppo static void vdc_destroy_descriptor_ring(vdc_t *vdc); 1344bac2208Snarayan static int vdc_setup_devid(vdc_t *vdc); 135*78fcd0a1Sachartre static void vdc_store_label_efi(vdc_t *vdc, struct dk_gpt *efi); 136*78fcd0a1Sachartre static void vdc_store_label_vtoc(vdc_t *, struct dk_geom *, struct vtoc *); 137*78fcd0a1Sachartre static void vdc_store_label_unk(vdc_t *vdc); 138*78fcd0a1Sachartre static boolean_t vdc_is_opened(vdc_t *vdc); 1391ae08745Sheppo 1401ae08745Sheppo /* handshake with vds */ 1410a55fbb7Slm66018 static int vdc_init_ver_negotiation(vdc_t *vdc, vio_ver_t ver); 1423af08d82Slm66018 static int vdc_ver_negotiation(vdc_t *vdcp); 1431ae08745Sheppo static int vdc_init_attr_negotiation(vdc_t *vdc); 1443af08d82Slm66018 static int vdc_attr_negotiation(vdc_t *vdcp); 1451ae08745Sheppo static int vdc_init_dring_negotiate(vdc_t *vdc); 1463af08d82Slm66018 static int vdc_dring_negotiation(vdc_t *vdcp); 1473af08d82Slm66018 static int vdc_send_rdx(vdc_t *vdcp); 1483af08d82Slm66018 static int vdc_rdx_exchange(vdc_t *vdcp); 1490a55fbb7Slm66018 static boolean_t vdc_is_supported_version(vio_ver_msg_t *ver_msg); 1501ae08745Sheppo 1510a55fbb7Slm66018 /* processing incoming messages from vDisk server */ 1521ae08745Sheppo static void vdc_process_msg_thread(vdc_t *vdc); 1533af08d82Slm66018 static int vdc_recv(vdc_t *vdc, vio_msg_t *msgp, size_t *nbytesp); 1543af08d82Slm66018 1550a55fbb7Slm66018 static uint_t vdc_handle_cb(uint64_t event, caddr_t arg); 1563af08d82Slm66018 static int vdc_process_data_msg(vdc_t *vdc, vio_msg_t *msg); 1571ae08745Sheppo static int vdc_process_err_msg(vdc_t *vdc, vio_msg_t msg); 1580a55fbb7Slm66018 static int vdc_handle_ver_msg(vdc_t *vdc, vio_ver_msg_t *ver_msg); 1590a55fbb7Slm66018 static int vdc_handle_attr_msg(vdc_t *vdc, vd_attr_msg_t *attr_msg); 1600a55fbb7Slm66018 static int vdc_handle_dring_reg_msg(vdc_t *vdc, vio_dring_reg_msg_t *msg); 1613af08d82Slm66018 static int vdc_send_request(vdc_t *vdcp, int operation, 1623af08d82Slm66018 caddr_t addr, size_t nbytes, int slice, diskaddr_t offset, 1633af08d82Slm66018 int cb_type, void *cb_arg, vio_desc_direction_t dir); 1643af08d82Slm66018 static int vdc_map_to_shared_dring(vdc_t *vdcp, int idx); 1653af08d82Slm66018 static int vdc_populate_descriptor(vdc_t *vdcp, int operation, 1663af08d82Slm66018 caddr_t addr, size_t nbytes, int slice, diskaddr_t offset, 1673af08d82Slm66018 int cb_type, void *cb_arg, vio_desc_direction_t dir); 1683af08d82Slm66018 static int vdc_do_sync_op(vdc_t *vdcp, int operation, 1693af08d82Slm66018 caddr_t addr, size_t nbytes, int slice, diskaddr_t offset, 1703af08d82Slm66018 int cb_type, void *cb_arg, vio_desc_direction_t dir); 1713af08d82Slm66018 1723af08d82Slm66018 static int vdc_wait_for_response(vdc_t *vdcp, vio_msg_t *msgp); 1733af08d82Slm66018 static int vdc_drain_response(vdc_t *vdcp); 1741ae08745Sheppo static int vdc_depopulate_descriptor(vdc_t *vdc, uint_t idx); 1753af08d82Slm66018 static int vdc_populate_mem_hdl(vdc_t *vdcp, vdc_local_desc_t *ldep); 176e1ebb9ecSlm66018 static int vdc_verify_seq_num(vdc_t *vdc, vio_dring_msg_t *dring_msg); 1771ae08745Sheppo 1781ae08745Sheppo /* dkio */ 1791ae08745Sheppo static int vd_process_ioctl(dev_t dev, int cmd, caddr_t arg, int mode); 180*78fcd0a1Sachartre static void vdc_create_fake_geometry(vdc_t *vdc); 181*78fcd0a1Sachartre static int vdc_validate_geometry(vdc_t *vdc); 182*78fcd0a1Sachartre static void vdc_validate(vdc_t *vdc); 183*78fcd0a1Sachartre static void vdc_validate_task(void *arg); 184d10e4ef2Snarayan static int vdc_null_copy_func(vdc_t *vdc, void *from, void *to, 185d10e4ef2Snarayan int mode, int dir); 1864bac2208Snarayan static int vdc_get_wce_convert(vdc_t *vdc, void *from, void *to, 1874bac2208Snarayan int mode, int dir); 1884bac2208Snarayan static int vdc_set_wce_convert(vdc_t *vdc, void *from, void *to, 1894bac2208Snarayan int mode, int dir); 190d10e4ef2Snarayan static int vdc_get_vtoc_convert(vdc_t *vdc, void *from, void *to, 191d10e4ef2Snarayan int mode, int dir); 192d10e4ef2Snarayan static int vdc_set_vtoc_convert(vdc_t *vdc, void *from, void *to, 193d10e4ef2Snarayan int mode, int dir); 194d10e4ef2Snarayan static int vdc_get_geom_convert(vdc_t *vdc, void *from, void *to, 195d10e4ef2Snarayan int mode, int dir); 196d10e4ef2Snarayan static int vdc_set_geom_convert(vdc_t *vdc, void *from, void *to, 197d10e4ef2Snarayan int mode, int dir); 198d10e4ef2Snarayan static int vdc_uscsicmd_convert(vdc_t *vdc, void *from, void *to, 199d10e4ef2Snarayan int mode, int dir); 2004bac2208Snarayan static int vdc_get_efi_convert(vdc_t *vdc, void *from, void *to, 2014bac2208Snarayan int mode, int dir); 2024bac2208Snarayan static int vdc_set_efi_convert(vdc_t *vdc, void *from, void *to, 2034bac2208Snarayan int mode, int dir); 2041ae08745Sheppo 2051ae08745Sheppo /* 2061ae08745Sheppo * Module variables 2071ae08745Sheppo */ 208e1ebb9ecSlm66018 209e1ebb9ecSlm66018 /* 210e1ebb9ecSlm66018 * Tunable variables to control how long vdc waits before timing out on 211e1ebb9ecSlm66018 * various operations 212e1ebb9ecSlm66018 */ 213e1ebb9ecSlm66018 static int vdc_retries = 10; 2143c96341aSnarayan static int vdc_hshake_retries = 3; 215e1ebb9ecSlm66018 216655fd6a9Sachartre static int vdc_timeout = 0; /* units: seconds */ 217655fd6a9Sachartre 218e1ebb9ecSlm66018 /* calculated from 'vdc_usec_timeout' during attach */ 219e1ebb9ecSlm66018 static uint64_t vdc_hz_timeout; /* units: Hz */ 220e1ebb9ecSlm66018 static uint64_t vdc_usec_timeout = 30 * MICROSEC; /* 30s units: ns */ 221e1ebb9ecSlm66018 2223af08d82Slm66018 static uint64_t vdc_hz_min_ldc_delay; 2233af08d82Slm66018 static uint64_t vdc_min_timeout_ldc = 1 * MILLISEC; 2243af08d82Slm66018 static uint64_t vdc_hz_max_ldc_delay; 2253af08d82Slm66018 static uint64_t vdc_max_timeout_ldc = 100 * MILLISEC; 2263af08d82Slm66018 2273af08d82Slm66018 static uint64_t vdc_ldc_read_init_delay = 1 * MILLISEC; 2283af08d82Slm66018 static uint64_t vdc_ldc_read_max_delay = 100 * MILLISEC; 229e1ebb9ecSlm66018 230e1ebb9ecSlm66018 /* values for dumping - need to run in a tighter loop */ 231e1ebb9ecSlm66018 static uint64_t vdc_usec_timeout_dump = 100 * MILLISEC; /* 0.1s units: ns */ 232e1ebb9ecSlm66018 static int vdc_dump_retries = 100; 233e1ebb9ecSlm66018 234e1ebb9ecSlm66018 /* Count of the number of vdc instances attached */ 235e1ebb9ecSlm66018 static volatile uint32_t vdc_instance_count = 0; 2361ae08745Sheppo 2371ae08745Sheppo /* Soft state pointer */ 2381ae08745Sheppo static void *vdc_state; 2391ae08745Sheppo 2403af08d82Slm66018 /* 2413af08d82Slm66018 * Controlling the verbosity of the error/debug messages 2423af08d82Slm66018 * 2433af08d82Slm66018 * vdc_msglevel - controls level of messages 2443af08d82Slm66018 * vdc_matchinst - 64-bit variable where each bit corresponds 2453af08d82Slm66018 * to the vdc instance the vdc_msglevel applies. 2463af08d82Slm66018 */ 2473af08d82Slm66018 int vdc_msglevel = 0x0; 2483af08d82Slm66018 uint64_t vdc_matchinst = 0ull; 2491ae08745Sheppo 2500a55fbb7Slm66018 /* 2510a55fbb7Slm66018 * Supported vDisk protocol version pairs. 2520a55fbb7Slm66018 * 2530a55fbb7Slm66018 * The first array entry is the latest and preferred version. 2540a55fbb7Slm66018 */ 2550a55fbb7Slm66018 static const vio_ver_t vdc_version[] = {{1, 0}}; 2561ae08745Sheppo 2571ae08745Sheppo static struct cb_ops vdc_cb_ops = { 2581ae08745Sheppo vdc_open, /* cb_open */ 2591ae08745Sheppo vdc_close, /* cb_close */ 2601ae08745Sheppo vdc_strategy, /* cb_strategy */ 2611ae08745Sheppo vdc_print, /* cb_print */ 2621ae08745Sheppo vdc_dump, /* cb_dump */ 2631ae08745Sheppo vdc_read, /* cb_read */ 2641ae08745Sheppo vdc_write, /* cb_write */ 2651ae08745Sheppo vdc_ioctl, /* cb_ioctl */ 2661ae08745Sheppo nodev, /* cb_devmap */ 2671ae08745Sheppo nodev, /* cb_mmap */ 2681ae08745Sheppo nodev, /* cb_segmap */ 2691ae08745Sheppo nochpoll, /* cb_chpoll */ 2701ae08745Sheppo ddi_prop_op, /* cb_prop_op */ 2711ae08745Sheppo NULL, /* cb_str */ 2721ae08745Sheppo D_MP | D_64BIT, /* cb_flag */ 2731ae08745Sheppo CB_REV, /* cb_rev */ 2741ae08745Sheppo vdc_aread, /* cb_aread */ 2751ae08745Sheppo vdc_awrite /* cb_awrite */ 2761ae08745Sheppo }; 2771ae08745Sheppo 2781ae08745Sheppo static struct dev_ops vdc_ops = { 2791ae08745Sheppo DEVO_REV, /* devo_rev */ 2801ae08745Sheppo 0, /* devo_refcnt */ 2811ae08745Sheppo vdc_getinfo, /* devo_getinfo */ 2821ae08745Sheppo nulldev, /* devo_identify */ 2831ae08745Sheppo nulldev, /* devo_probe */ 2841ae08745Sheppo vdc_attach, /* devo_attach */ 2851ae08745Sheppo vdc_detach, /* devo_detach */ 2861ae08745Sheppo nodev, /* devo_reset */ 2871ae08745Sheppo &vdc_cb_ops, /* devo_cb_ops */ 2881ae08745Sheppo NULL, /* devo_bus_ops */ 2891ae08745Sheppo nulldev /* devo_power */ 2901ae08745Sheppo }; 2911ae08745Sheppo 2921ae08745Sheppo static struct modldrv modldrv = { 2931ae08745Sheppo &mod_driverops, 294205eeb1aSlm66018 "virtual disk client", 2951ae08745Sheppo &vdc_ops, 2961ae08745Sheppo }; 2971ae08745Sheppo 2981ae08745Sheppo static struct modlinkage modlinkage = { 2991ae08745Sheppo MODREV_1, 3001ae08745Sheppo &modldrv, 3011ae08745Sheppo NULL 3021ae08745Sheppo }; 3031ae08745Sheppo 3041ae08745Sheppo /* -------------------------------------------------------------------------- */ 3051ae08745Sheppo 3061ae08745Sheppo /* 3071ae08745Sheppo * Device Driver housekeeping and setup 3081ae08745Sheppo */ 3091ae08745Sheppo 3101ae08745Sheppo int 3111ae08745Sheppo _init(void) 3121ae08745Sheppo { 3131ae08745Sheppo int status; 3141ae08745Sheppo 3151ae08745Sheppo if ((status = ddi_soft_state_init(&vdc_state, sizeof (vdc_t), 1)) != 0) 3161ae08745Sheppo return (status); 3171ae08745Sheppo if ((status = mod_install(&modlinkage)) != 0) 3181ae08745Sheppo ddi_soft_state_fini(&vdc_state); 3194bac2208Snarayan vdc_efi_init(vd_process_ioctl); 3201ae08745Sheppo return (status); 3211ae08745Sheppo } 3221ae08745Sheppo 3231ae08745Sheppo int 3241ae08745Sheppo _info(struct modinfo *modinfop) 3251ae08745Sheppo { 3261ae08745Sheppo return (mod_info(&modlinkage, modinfop)); 3271ae08745Sheppo } 3281ae08745Sheppo 3291ae08745Sheppo int 3301ae08745Sheppo _fini(void) 3311ae08745Sheppo { 3321ae08745Sheppo int status; 3331ae08745Sheppo 3341ae08745Sheppo if ((status = mod_remove(&modlinkage)) != 0) 3351ae08745Sheppo return (status); 3364bac2208Snarayan vdc_efi_fini(); 3371ae08745Sheppo ddi_soft_state_fini(&vdc_state); 3381ae08745Sheppo return (0); 3391ae08745Sheppo } 3401ae08745Sheppo 3411ae08745Sheppo static int 3421ae08745Sheppo vdc_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp) 3431ae08745Sheppo { 3441ae08745Sheppo _NOTE(ARGUNUSED(dip)) 3451ae08745Sheppo 3460d0c8d4bSnarayan int instance = VDCUNIT((dev_t)arg); 3471ae08745Sheppo vdc_t *vdc = NULL; 3481ae08745Sheppo 3491ae08745Sheppo switch (cmd) { 3501ae08745Sheppo case DDI_INFO_DEVT2DEVINFO: 3511ae08745Sheppo if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) { 3521ae08745Sheppo *resultp = NULL; 3531ae08745Sheppo return (DDI_FAILURE); 3541ae08745Sheppo } 3551ae08745Sheppo *resultp = vdc->dip; 3561ae08745Sheppo return (DDI_SUCCESS); 3571ae08745Sheppo case DDI_INFO_DEVT2INSTANCE: 3581ae08745Sheppo *resultp = (void *)(uintptr_t)instance; 3591ae08745Sheppo return (DDI_SUCCESS); 3601ae08745Sheppo default: 3611ae08745Sheppo *resultp = NULL; 3621ae08745Sheppo return (DDI_FAILURE); 3631ae08745Sheppo } 3641ae08745Sheppo } 3651ae08745Sheppo 3661ae08745Sheppo static int 3671ae08745Sheppo vdc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 3681ae08745Sheppo { 3691ae08745Sheppo int instance; 3701ae08745Sheppo int rv; 3711ae08745Sheppo vdc_t *vdc = NULL; 3721ae08745Sheppo 3731ae08745Sheppo switch (cmd) { 3741ae08745Sheppo case DDI_DETACH: 3751ae08745Sheppo /* the real work happens below */ 3761ae08745Sheppo break; 3771ae08745Sheppo case DDI_SUSPEND: 3781ae08745Sheppo /* nothing to do for this non-device */ 3791ae08745Sheppo return (DDI_SUCCESS); 3801ae08745Sheppo default: 3811ae08745Sheppo return (DDI_FAILURE); 3821ae08745Sheppo } 3831ae08745Sheppo 3841ae08745Sheppo ASSERT(cmd == DDI_DETACH); 3851ae08745Sheppo instance = ddi_get_instance(dip); 3863af08d82Slm66018 DMSGX(1, "[%d] Entered\n", instance); 3871ae08745Sheppo 3881ae08745Sheppo if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) { 389e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't get state structure", instance); 3901ae08745Sheppo return (DDI_FAILURE); 3911ae08745Sheppo } 3921ae08745Sheppo 393*78fcd0a1Sachartre if (vdc_is_opened(vdc)) { 3943af08d82Slm66018 DMSG(vdc, 0, "[%d] Cannot detach: device is open", instance); 3951ae08745Sheppo return (DDI_FAILURE); 3961ae08745Sheppo } 3971ae08745Sheppo 398*78fcd0a1Sachartre if (vdc->dkio_flush_pending) { 399*78fcd0a1Sachartre DMSG(vdc, 0, 400*78fcd0a1Sachartre "[%d] Cannot detach: %d outstanding DKIO flushes\n", 401*78fcd0a1Sachartre instance, vdc->dkio_flush_pending); 402*78fcd0a1Sachartre return (DDI_FAILURE); 403*78fcd0a1Sachartre } 404*78fcd0a1Sachartre 405*78fcd0a1Sachartre if (vdc->validate_pending) { 406*78fcd0a1Sachartre DMSG(vdc, 0, 407*78fcd0a1Sachartre "[%d] Cannot detach: %d outstanding validate request\n", 408*78fcd0a1Sachartre instance, vdc->validate_pending); 409*78fcd0a1Sachartre return (DDI_FAILURE); 410*78fcd0a1Sachartre } 411*78fcd0a1Sachartre 4123af08d82Slm66018 DMSG(vdc, 0, "[%d] proceeding...\n", instance); 4133af08d82Slm66018 4143af08d82Slm66018 /* mark instance as detaching */ 4153af08d82Slm66018 vdc->lifecycle = VDC_LC_DETACHING; 4161ae08745Sheppo 4171ae08745Sheppo /* 4181ae08745Sheppo * try and disable callbacks to prevent another handshake 4191ae08745Sheppo */ 4201ae08745Sheppo rv = ldc_set_cb_mode(vdc->ldc_handle, LDC_CB_DISABLE); 4213af08d82Slm66018 DMSG(vdc, 0, "callback disabled (rv=%d)\n", rv); 4221ae08745Sheppo 4231ae08745Sheppo if (vdc->initialized & VDC_THREAD) { 4243af08d82Slm66018 mutex_enter(&vdc->read_lock); 4253af08d82Slm66018 if ((vdc->read_state == VDC_READ_WAITING) || 4263af08d82Slm66018 (vdc->read_state == VDC_READ_RESET)) { 4273af08d82Slm66018 vdc->read_state = VDC_READ_RESET; 4283af08d82Slm66018 cv_signal(&vdc->read_cv); 4291ae08745Sheppo } 4303af08d82Slm66018 4313af08d82Slm66018 mutex_exit(&vdc->read_lock); 4323af08d82Slm66018 4333af08d82Slm66018 /* wake up any thread waiting for connection to come online */ 4343af08d82Slm66018 mutex_enter(&vdc->lock); 4353af08d82Slm66018 if (vdc->state == VDC_STATE_INIT_WAITING) { 4363af08d82Slm66018 DMSG(vdc, 0, 4373af08d82Slm66018 "[%d] write reset - move to resetting state...\n", 4383af08d82Slm66018 instance); 4393af08d82Slm66018 vdc->state = VDC_STATE_RESETTING; 4403af08d82Slm66018 cv_signal(&vdc->initwait_cv); 4413af08d82Slm66018 } 4423af08d82Slm66018 mutex_exit(&vdc->lock); 4433af08d82Slm66018 4443af08d82Slm66018 /* now wait until state transitions to VDC_STATE_DETACH */ 4453af08d82Slm66018 thread_join(vdc->msg_proc_thr->t_did); 4463af08d82Slm66018 ASSERT(vdc->state == VDC_STATE_DETACH); 4473af08d82Slm66018 DMSG(vdc, 0, "[%d] Reset thread exit and join ..\n", 4483af08d82Slm66018 vdc->instance); 4491ae08745Sheppo } 4501ae08745Sheppo 4511ae08745Sheppo mutex_enter(&vdc->lock); 4521ae08745Sheppo 4531ae08745Sheppo if (vdc->initialized & VDC_DRING) 4541ae08745Sheppo vdc_destroy_descriptor_ring(vdc); 4551ae08745Sheppo 4561ae08745Sheppo if (vdc->initialized & VDC_LDC) 4571ae08745Sheppo vdc_terminate_ldc(vdc); 4581ae08745Sheppo 4591ae08745Sheppo mutex_exit(&vdc->lock); 4601ae08745Sheppo 4611ae08745Sheppo if (vdc->initialized & VDC_MINOR) { 4621ae08745Sheppo ddi_prop_remove_all(dip); 4631ae08745Sheppo ddi_remove_minor_node(dip, NULL); 4641ae08745Sheppo } 4651ae08745Sheppo 4661ae08745Sheppo if (vdc->initialized & VDC_LOCKS) { 4671ae08745Sheppo mutex_destroy(&vdc->lock); 4683af08d82Slm66018 mutex_destroy(&vdc->read_lock); 4693af08d82Slm66018 cv_destroy(&vdc->initwait_cv); 4703af08d82Slm66018 cv_destroy(&vdc->dring_free_cv); 4713af08d82Slm66018 cv_destroy(&vdc->membind_cv); 4723af08d82Slm66018 cv_destroy(&vdc->sync_pending_cv); 4733af08d82Slm66018 cv_destroy(&vdc->sync_blocked_cv); 4743af08d82Slm66018 cv_destroy(&vdc->read_cv); 4753af08d82Slm66018 cv_destroy(&vdc->running_cv); 4761ae08745Sheppo } 4771ae08745Sheppo 4781ae08745Sheppo if (vdc->minfo) 4791ae08745Sheppo kmem_free(vdc->minfo, sizeof (struct dk_minfo)); 4801ae08745Sheppo 4811ae08745Sheppo if (vdc->cinfo) 4821ae08745Sheppo kmem_free(vdc->cinfo, sizeof (struct dk_cinfo)); 4831ae08745Sheppo 4841ae08745Sheppo if (vdc->vtoc) 4851ae08745Sheppo kmem_free(vdc->vtoc, sizeof (struct vtoc)); 4861ae08745Sheppo 487*78fcd0a1Sachartre if (vdc->geom) 488*78fcd0a1Sachartre kmem_free(vdc->geom, sizeof (struct dk_geom)); 4890a55fbb7Slm66018 4904bac2208Snarayan if (vdc->devid) { 4914bac2208Snarayan ddi_devid_unregister(dip); 4924bac2208Snarayan ddi_devid_free(vdc->devid); 4934bac2208Snarayan } 4944bac2208Snarayan 4951ae08745Sheppo if (vdc->initialized & VDC_SOFT_STATE) 4961ae08745Sheppo ddi_soft_state_free(vdc_state, instance); 4971ae08745Sheppo 4983af08d82Slm66018 DMSG(vdc, 0, "[%d] End %p\n", instance, (void *)vdc); 4991ae08745Sheppo 5001ae08745Sheppo return (DDI_SUCCESS); 5011ae08745Sheppo } 5021ae08745Sheppo 5031ae08745Sheppo 5041ae08745Sheppo static int 5051ae08745Sheppo vdc_do_attach(dev_info_t *dip) 5061ae08745Sheppo { 5071ae08745Sheppo int instance; 5081ae08745Sheppo vdc_t *vdc = NULL; 5091ae08745Sheppo int status; 510655fd6a9Sachartre md_t *mdp; 511655fd6a9Sachartre mde_cookie_t vd_node, vd_port; 5121ae08745Sheppo 5131ae08745Sheppo ASSERT(dip != NULL); 5141ae08745Sheppo 5151ae08745Sheppo instance = ddi_get_instance(dip); 5161ae08745Sheppo if (ddi_soft_state_zalloc(vdc_state, instance) != DDI_SUCCESS) { 517e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't alloc state structure", 518e1ebb9ecSlm66018 instance); 5191ae08745Sheppo return (DDI_FAILURE); 5201ae08745Sheppo } 5211ae08745Sheppo 5221ae08745Sheppo if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) { 523e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't get state structure", instance); 5241ae08745Sheppo return (DDI_FAILURE); 5251ae08745Sheppo } 5261ae08745Sheppo 5271ae08745Sheppo /* 5281ae08745Sheppo * We assign the value to initialized in this case to zero out the 5291ae08745Sheppo * variable and then set bits in it to indicate what has been done 5301ae08745Sheppo */ 5311ae08745Sheppo vdc->initialized = VDC_SOFT_STATE; 5321ae08745Sheppo 5331ae08745Sheppo vdc_hz_timeout = drv_usectohz(vdc_usec_timeout); 5343af08d82Slm66018 5353af08d82Slm66018 vdc_hz_min_ldc_delay = drv_usectohz(vdc_min_timeout_ldc); 5363af08d82Slm66018 vdc_hz_max_ldc_delay = drv_usectohz(vdc_max_timeout_ldc); 5371ae08745Sheppo 5381ae08745Sheppo vdc->dip = dip; 5391ae08745Sheppo vdc->instance = instance; 5401ae08745Sheppo vdc->vdisk_type = VD_DISK_TYPE_UNK; 5414bac2208Snarayan vdc->vdisk_label = VD_DISK_LABEL_UNK; 5423af08d82Slm66018 vdc->state = VDC_STATE_INIT; 5433af08d82Slm66018 vdc->lifecycle = VDC_LC_ATTACHING; 5441ae08745Sheppo vdc->ldc_state = 0; 5451ae08745Sheppo vdc->session_id = 0; 5461ae08745Sheppo vdc->block_size = DEV_BSIZE; 5478e6a2a04Slm66018 vdc->max_xfer_sz = maxphys / DEV_BSIZE; 5481ae08745Sheppo 5491ae08745Sheppo vdc->vtoc = NULL; 550*78fcd0a1Sachartre vdc->geom = NULL; 5511ae08745Sheppo vdc->cinfo = NULL; 5521ae08745Sheppo vdc->minfo = NULL; 5531ae08745Sheppo 5541ae08745Sheppo mutex_init(&vdc->lock, NULL, MUTEX_DRIVER, NULL); 5553af08d82Slm66018 cv_init(&vdc->initwait_cv, NULL, CV_DRIVER, NULL); 5563af08d82Slm66018 cv_init(&vdc->dring_free_cv, NULL, CV_DRIVER, NULL); 5573af08d82Slm66018 cv_init(&vdc->membind_cv, NULL, CV_DRIVER, NULL); 5583af08d82Slm66018 cv_init(&vdc->running_cv, NULL, CV_DRIVER, NULL); 5593af08d82Slm66018 5603af08d82Slm66018 vdc->threads_pending = 0; 5613af08d82Slm66018 vdc->sync_op_pending = B_FALSE; 5623af08d82Slm66018 vdc->sync_op_blocked = B_FALSE; 5633af08d82Slm66018 cv_init(&vdc->sync_pending_cv, NULL, CV_DRIVER, NULL); 5643af08d82Slm66018 cv_init(&vdc->sync_blocked_cv, NULL, CV_DRIVER, NULL); 5653af08d82Slm66018 5663af08d82Slm66018 /* init blocking msg read functionality */ 5673af08d82Slm66018 mutex_init(&vdc->read_lock, NULL, MUTEX_DRIVER, NULL); 5683af08d82Slm66018 cv_init(&vdc->read_cv, NULL, CV_DRIVER, NULL); 5693af08d82Slm66018 vdc->read_state = VDC_READ_IDLE; 5703af08d82Slm66018 5711ae08745Sheppo vdc->initialized |= VDC_LOCKS; 5721ae08745Sheppo 573655fd6a9Sachartre /* get device and port MD node for this disk instance */ 574655fd6a9Sachartre if (vdc_get_md_node(dip, &mdp, &vd_node, &vd_port) != 0) { 575655fd6a9Sachartre cmn_err(CE_NOTE, "[%d] Could not get machine description node", 576655fd6a9Sachartre instance); 577655fd6a9Sachartre return (DDI_FAILURE); 578655fd6a9Sachartre } 579655fd6a9Sachartre 580655fd6a9Sachartre /* set the connection timeout */ 581655fd6a9Sachartre if (vd_port == NULL || (md_get_prop_val(mdp, vd_port, 582655fd6a9Sachartre VDC_MD_TIMEOUT, &vdc->ctimeout) != 0)) { 583655fd6a9Sachartre vdc->ctimeout = 0; 584655fd6a9Sachartre } 585655fd6a9Sachartre 5863af08d82Slm66018 /* initialise LDC channel which will be used to communicate with vds */ 587655fd6a9Sachartre status = vdc_do_ldc_init(vdc, mdp, vd_node); 588655fd6a9Sachartre 589655fd6a9Sachartre (void) md_fini_handle(mdp); 590655fd6a9Sachartre 591655fd6a9Sachartre if (status != 0) { 5923af08d82Slm66018 cmn_err(CE_NOTE, "[%d] Couldn't initialize LDC", instance); 5933af08d82Slm66018 goto return_status; 5943af08d82Slm66018 } 5953af08d82Slm66018 5963af08d82Slm66018 /* initialize the thread responsible for managing state with server */ 5973af08d82Slm66018 vdc->msg_proc_thr = thread_create(NULL, 0, vdc_process_msg_thread, 5981ae08745Sheppo vdc, 0, &p0, TS_RUN, minclsyspri); 5993af08d82Slm66018 if (vdc->msg_proc_thr == NULL) { 6001ae08745Sheppo cmn_err(CE_NOTE, "[%d] Failed to create msg processing thread", 6011ae08745Sheppo instance); 6021ae08745Sheppo return (DDI_FAILURE); 6031ae08745Sheppo } 6043af08d82Slm66018 6051ae08745Sheppo vdc->initialized |= VDC_THREAD; 6061ae08745Sheppo 607e1ebb9ecSlm66018 atomic_inc_32(&vdc_instance_count); 6081ae08745Sheppo 6090a55fbb7Slm66018 /* 610*78fcd0a1Sachartre * Check the disk label. This will send requests and do the handshake. 611*78fcd0a1Sachartre * We don't really care about the disk label now. What we really need is 612*78fcd0a1Sachartre * the handshake do be done so that we know the type of the disk (slice 613*78fcd0a1Sachartre * or full disk) and the appropriate device nodes can be created. 6140a55fbb7Slm66018 */ 615*78fcd0a1Sachartre vdc->vdisk_label = VD_DISK_LABEL_UNK; 616*78fcd0a1Sachartre vdc->vtoc = kmem_zalloc(sizeof (struct vtoc), KM_SLEEP); 617*78fcd0a1Sachartre vdc->geom = kmem_zalloc(sizeof (struct dk_geom), KM_SLEEP); 618*78fcd0a1Sachartre 619*78fcd0a1Sachartre mutex_enter(&vdc->lock); 620*78fcd0a1Sachartre (void) vdc_validate_geometry(vdc); 621*78fcd0a1Sachartre mutex_exit(&vdc->lock); 6221ae08745Sheppo 6231ae08745Sheppo /* 6241ae08745Sheppo * Now that we have the device info we can create the 6251ae08745Sheppo * device nodes and properties 6261ae08745Sheppo */ 6271ae08745Sheppo status = vdc_create_device_nodes(vdc); 6281ae08745Sheppo if (status) { 6293af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to create device nodes", 6301ae08745Sheppo instance); 6313af08d82Slm66018 goto return_status; 6321ae08745Sheppo } 6331ae08745Sheppo status = vdc_create_device_nodes_props(vdc); 6341ae08745Sheppo if (status) { 6353af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to create device nodes" 6360a55fbb7Slm66018 " properties (%d)", instance, status); 6373af08d82Slm66018 goto return_status; 6381ae08745Sheppo } 6391ae08745Sheppo 6404bac2208Snarayan /* 6414bac2208Snarayan * Setup devid 6424bac2208Snarayan */ 6434bac2208Snarayan if (vdc_setup_devid(vdc)) { 6443af08d82Slm66018 DMSG(vdc, 0, "[%d] No device id available\n", instance); 6454bac2208Snarayan } 6464bac2208Snarayan 6471ae08745Sheppo ddi_report_dev(dip); 6483af08d82Slm66018 vdc->lifecycle = VDC_LC_ONLINE; 6493af08d82Slm66018 DMSG(vdc, 0, "[%d] Attach tasks successful\n", instance); 6501ae08745Sheppo 6513af08d82Slm66018 return_status: 6523af08d82Slm66018 DMSG(vdc, 0, "[%d] Attach completed\n", instance); 6531ae08745Sheppo return (status); 6541ae08745Sheppo } 6551ae08745Sheppo 6561ae08745Sheppo static int 6571ae08745Sheppo vdc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 6581ae08745Sheppo { 6591ae08745Sheppo int status; 6601ae08745Sheppo 6611ae08745Sheppo switch (cmd) { 6621ae08745Sheppo case DDI_ATTACH: 6631ae08745Sheppo if ((status = vdc_do_attach(dip)) != 0) 6641ae08745Sheppo (void) vdc_detach(dip, DDI_DETACH); 6651ae08745Sheppo return (status); 6661ae08745Sheppo case DDI_RESUME: 6671ae08745Sheppo /* nothing to do for this non-device */ 6681ae08745Sheppo return (DDI_SUCCESS); 6691ae08745Sheppo default: 6701ae08745Sheppo return (DDI_FAILURE); 6711ae08745Sheppo } 6721ae08745Sheppo } 6731ae08745Sheppo 6741ae08745Sheppo static int 675655fd6a9Sachartre vdc_do_ldc_init(vdc_t *vdc, md_t *mdp, mde_cookie_t vd_node) 6761ae08745Sheppo { 6771ae08745Sheppo int status = 0; 6781ae08745Sheppo ldc_status_t ldc_state; 6791ae08745Sheppo ldc_attr_t ldc_attr; 6801ae08745Sheppo uint64_t ldc_id = 0; 6811ae08745Sheppo 6821ae08745Sheppo ASSERT(vdc != NULL); 6831ae08745Sheppo 6841ae08745Sheppo vdc->initialized |= VDC_LDC; 6851ae08745Sheppo 686655fd6a9Sachartre if ((status = vdc_get_ldc_id(mdp, vd_node, &ldc_id)) != 0) { 6873af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to get LDC channel ID property", 688e1ebb9ecSlm66018 vdc->instance); 6891ae08745Sheppo return (EIO); 6901ae08745Sheppo } 691655fd6a9Sachartre 692655fd6a9Sachartre DMSGX(0, "[%d] LDC id is 0x%lx\n", vdc->instance, ldc_id); 693655fd6a9Sachartre 6941ae08745Sheppo vdc->ldc_id = ldc_id; 6951ae08745Sheppo 6961ae08745Sheppo ldc_attr.devclass = LDC_DEV_BLK; 6971ae08745Sheppo ldc_attr.instance = vdc->instance; 6981ae08745Sheppo ldc_attr.mode = LDC_MODE_UNRELIABLE; /* unreliable transport */ 699e1ebb9ecSlm66018 ldc_attr.mtu = VD_LDC_MTU; 7001ae08745Sheppo 7011ae08745Sheppo if ((vdc->initialized & VDC_LDC_INIT) == 0) { 7021ae08745Sheppo status = ldc_init(ldc_id, &ldc_attr, &vdc->ldc_handle); 7031ae08745Sheppo if (status != 0) { 7043af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_init(chan %ld) returned %d", 7051ae08745Sheppo vdc->instance, ldc_id, status); 7061ae08745Sheppo return (status); 7071ae08745Sheppo } 7081ae08745Sheppo vdc->initialized |= VDC_LDC_INIT; 7091ae08745Sheppo } 7101ae08745Sheppo status = ldc_status(vdc->ldc_handle, &ldc_state); 7111ae08745Sheppo if (status != 0) { 7123af08d82Slm66018 DMSG(vdc, 0, "[%d] Cannot discover LDC status [err=%d]", 713e1ebb9ecSlm66018 vdc->instance, status); 7141ae08745Sheppo return (status); 7151ae08745Sheppo } 7161ae08745Sheppo vdc->ldc_state = ldc_state; 7171ae08745Sheppo 7181ae08745Sheppo if ((vdc->initialized & VDC_LDC_CB) == 0) { 7191ae08745Sheppo status = ldc_reg_callback(vdc->ldc_handle, vdc_handle_cb, 7201ae08745Sheppo (caddr_t)vdc); 7211ae08745Sheppo if (status != 0) { 7223af08d82Slm66018 DMSG(vdc, 0, "[%d] LDC callback reg. failed (%d)", 723e1ebb9ecSlm66018 vdc->instance, status); 7241ae08745Sheppo return (status); 7251ae08745Sheppo } 7261ae08745Sheppo vdc->initialized |= VDC_LDC_CB; 7271ae08745Sheppo } 7281ae08745Sheppo 7291ae08745Sheppo vdc->initialized |= VDC_LDC; 7301ae08745Sheppo 7311ae08745Sheppo /* 7321ae08745Sheppo * At this stage we have initialised LDC, we will now try and open 7331ae08745Sheppo * the connection. 7341ae08745Sheppo */ 7351ae08745Sheppo if (vdc->ldc_state == LDC_INIT) { 7361ae08745Sheppo status = ldc_open(vdc->ldc_handle); 7371ae08745Sheppo if (status != 0) { 7383af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_open(chan %ld) returned %d", 7391ae08745Sheppo vdc->instance, vdc->ldc_id, status); 7401ae08745Sheppo return (status); 7411ae08745Sheppo } 7421ae08745Sheppo vdc->initialized |= VDC_LDC_OPEN; 7431ae08745Sheppo } 7441ae08745Sheppo 7451ae08745Sheppo return (status); 7461ae08745Sheppo } 7471ae08745Sheppo 7481ae08745Sheppo static int 7491ae08745Sheppo vdc_start_ldc_connection(vdc_t *vdc) 7501ae08745Sheppo { 7511ae08745Sheppo int status = 0; 7521ae08745Sheppo 7531ae08745Sheppo ASSERT(vdc != NULL); 7541ae08745Sheppo 7553af08d82Slm66018 ASSERT(MUTEX_HELD(&vdc->lock)); 7561ae08745Sheppo 7570a55fbb7Slm66018 status = vdc_do_ldc_up(vdc); 7581ae08745Sheppo 7593af08d82Slm66018 DMSG(vdc, 0, "[%d] Finished bringing up LDC\n", vdc->instance); 7601ae08745Sheppo 7613af08d82Slm66018 return (status); 7623af08d82Slm66018 } 7633af08d82Slm66018 7643af08d82Slm66018 static int 7653af08d82Slm66018 vdc_stop_ldc_connection(vdc_t *vdcp) 7663af08d82Slm66018 { 7673af08d82Slm66018 int status; 7683af08d82Slm66018 7693af08d82Slm66018 DMSG(vdcp, 0, ": Resetting connection to vDisk server : state %d\n", 7703af08d82Slm66018 vdcp->state); 7713af08d82Slm66018 7723af08d82Slm66018 status = ldc_down(vdcp->ldc_handle); 7733af08d82Slm66018 DMSG(vdcp, 0, "ldc_down() = %d\n", status); 7743af08d82Slm66018 7753af08d82Slm66018 vdcp->initialized &= ~VDC_HANDSHAKE; 7763af08d82Slm66018 DMSG(vdcp, 0, "initialized=%x\n", vdcp->initialized); 7771ae08745Sheppo 7781ae08745Sheppo return (status); 7791ae08745Sheppo } 7801ae08745Sheppo 7814bac2208Snarayan static int 7824bac2208Snarayan vdc_create_device_nodes_efi(vdc_t *vdc) 7834bac2208Snarayan { 7844bac2208Snarayan ddi_remove_minor_node(vdc->dip, "h"); 7854bac2208Snarayan ddi_remove_minor_node(vdc->dip, "h,raw"); 7864bac2208Snarayan 7874bac2208Snarayan if (ddi_create_minor_node(vdc->dip, "wd", S_IFBLK, 7884bac2208Snarayan VD_MAKE_DEV(vdc->instance, VD_EFI_WD_SLICE), 7894bac2208Snarayan DDI_NT_BLOCK, 0) != DDI_SUCCESS) { 7904bac2208Snarayan cmn_err(CE_NOTE, "[%d] Couldn't add block node 'wd'", 7914bac2208Snarayan vdc->instance); 7924bac2208Snarayan return (EIO); 7934bac2208Snarayan } 7944bac2208Snarayan 7954bac2208Snarayan /* if any device node is created we set this flag */ 7964bac2208Snarayan vdc->initialized |= VDC_MINOR; 7974bac2208Snarayan 7984bac2208Snarayan if (ddi_create_minor_node(vdc->dip, "wd,raw", S_IFCHR, 7994bac2208Snarayan VD_MAKE_DEV(vdc->instance, VD_EFI_WD_SLICE), 8004bac2208Snarayan DDI_NT_BLOCK, 0) != DDI_SUCCESS) { 8014bac2208Snarayan cmn_err(CE_NOTE, "[%d] Couldn't add block node 'wd,raw'", 8024bac2208Snarayan vdc->instance); 8034bac2208Snarayan return (EIO); 8044bac2208Snarayan } 8054bac2208Snarayan 8064bac2208Snarayan return (0); 8074bac2208Snarayan } 8084bac2208Snarayan 8094bac2208Snarayan static int 8104bac2208Snarayan vdc_create_device_nodes_vtoc(vdc_t *vdc) 8114bac2208Snarayan { 8124bac2208Snarayan ddi_remove_minor_node(vdc->dip, "wd"); 8134bac2208Snarayan ddi_remove_minor_node(vdc->dip, "wd,raw"); 8144bac2208Snarayan 8154bac2208Snarayan if (ddi_create_minor_node(vdc->dip, "h", S_IFBLK, 8164bac2208Snarayan VD_MAKE_DEV(vdc->instance, VD_EFI_WD_SLICE), 8174bac2208Snarayan DDI_NT_BLOCK, 0) != DDI_SUCCESS) { 8184bac2208Snarayan cmn_err(CE_NOTE, "[%d] Couldn't add block node 'h'", 8194bac2208Snarayan vdc->instance); 8204bac2208Snarayan return (EIO); 8214bac2208Snarayan } 8224bac2208Snarayan 8234bac2208Snarayan /* if any device node is created we set this flag */ 8244bac2208Snarayan vdc->initialized |= VDC_MINOR; 8254bac2208Snarayan 8264bac2208Snarayan if (ddi_create_minor_node(vdc->dip, "h,raw", S_IFCHR, 8274bac2208Snarayan VD_MAKE_DEV(vdc->instance, VD_EFI_WD_SLICE), 8284bac2208Snarayan DDI_NT_BLOCK, 0) != DDI_SUCCESS) { 8294bac2208Snarayan cmn_err(CE_NOTE, "[%d] Couldn't add block node 'h,raw'", 8304bac2208Snarayan vdc->instance); 8314bac2208Snarayan return (EIO); 8324bac2208Snarayan } 8334bac2208Snarayan 8344bac2208Snarayan return (0); 8354bac2208Snarayan } 8361ae08745Sheppo 8371ae08745Sheppo /* 8381ae08745Sheppo * Function: 8391ae08745Sheppo * vdc_create_device_nodes 8401ae08745Sheppo * 8411ae08745Sheppo * Description: 8421ae08745Sheppo * This function creates the block and character device nodes under 8431ae08745Sheppo * /devices along with the node properties. It is called as part of 8441ae08745Sheppo * the attach(9E) of the instance during the handshake with vds after 8451ae08745Sheppo * vds has sent the attributes to vdc. 8461ae08745Sheppo * 8471ae08745Sheppo * If the device is of type VD_DISK_TYPE_SLICE then the minor node 8481ae08745Sheppo * of 2 is used in keeping with the Solaris convention that slice 2 8491ae08745Sheppo * refers to a whole disk. Slices start at 'a' 8501ae08745Sheppo * 8511ae08745Sheppo * Parameters: 8521ae08745Sheppo * vdc - soft state pointer 8531ae08745Sheppo * 8541ae08745Sheppo * Return Values 8551ae08745Sheppo * 0 - Success 8561ae08745Sheppo * EIO - Failed to create node 8571ae08745Sheppo * EINVAL - Unknown type of disk exported 8581ae08745Sheppo */ 8591ae08745Sheppo static int 8601ae08745Sheppo vdc_create_device_nodes(vdc_t *vdc) 8611ae08745Sheppo { 8624bac2208Snarayan char name[sizeof ("s,raw")]; 8631ae08745Sheppo dev_info_t *dip = NULL; 8644bac2208Snarayan int instance, status; 8651ae08745Sheppo int num_slices = 1; 8661ae08745Sheppo int i; 8671ae08745Sheppo 8681ae08745Sheppo ASSERT(vdc != NULL); 8691ae08745Sheppo 8701ae08745Sheppo instance = vdc->instance; 8711ae08745Sheppo dip = vdc->dip; 8721ae08745Sheppo 8731ae08745Sheppo switch (vdc->vdisk_type) { 8741ae08745Sheppo case VD_DISK_TYPE_DISK: 8751ae08745Sheppo num_slices = V_NUMPAR; 8761ae08745Sheppo break; 8771ae08745Sheppo case VD_DISK_TYPE_SLICE: 8781ae08745Sheppo num_slices = 1; 8791ae08745Sheppo break; 8801ae08745Sheppo case VD_DISK_TYPE_UNK: 8811ae08745Sheppo default: 8821ae08745Sheppo return (EINVAL); 8831ae08745Sheppo } 8841ae08745Sheppo 8854bac2208Snarayan /* 8864bac2208Snarayan * Minor nodes are different for EFI disks: EFI disks do not have 8874bac2208Snarayan * a minor node 'g' for the minor number corresponding to slice 8884bac2208Snarayan * VD_EFI_WD_SLICE (slice 7) instead they have a minor node 'wd' 8894bac2208Snarayan * representing the whole disk. 8904bac2208Snarayan */ 8911ae08745Sheppo for (i = 0; i < num_slices; i++) { 8924bac2208Snarayan 8934bac2208Snarayan if (i == VD_EFI_WD_SLICE) { 8944bac2208Snarayan if (vdc->vdisk_label == VD_DISK_LABEL_EFI) 8954bac2208Snarayan status = vdc_create_device_nodes_efi(vdc); 8964bac2208Snarayan else 8974bac2208Snarayan status = vdc_create_device_nodes_vtoc(vdc); 8984bac2208Snarayan if (status != 0) 8994bac2208Snarayan return (status); 9004bac2208Snarayan continue; 9014bac2208Snarayan } 9024bac2208Snarayan 9031ae08745Sheppo (void) snprintf(name, sizeof (name), "%c", 'a' + i); 9041ae08745Sheppo if (ddi_create_minor_node(dip, name, S_IFBLK, 9051ae08745Sheppo VD_MAKE_DEV(instance, i), DDI_NT_BLOCK, 0) != DDI_SUCCESS) { 906e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't add block node '%s'", 907e1ebb9ecSlm66018 instance, name); 9081ae08745Sheppo return (EIO); 9091ae08745Sheppo } 9101ae08745Sheppo 9111ae08745Sheppo /* if any device node is created we set this flag */ 9121ae08745Sheppo vdc->initialized |= VDC_MINOR; 9131ae08745Sheppo 91487a7269eSachartre (void) snprintf(name, sizeof (name), "%c%s", 'a' + i, ",raw"); 91587a7269eSachartre 9161ae08745Sheppo if (ddi_create_minor_node(dip, name, S_IFCHR, 9171ae08745Sheppo VD_MAKE_DEV(instance, i), DDI_NT_BLOCK, 0) != DDI_SUCCESS) { 918e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't add raw node '%s'", 919e1ebb9ecSlm66018 instance, name); 9201ae08745Sheppo return (EIO); 9211ae08745Sheppo } 9221ae08745Sheppo } 9231ae08745Sheppo 9241ae08745Sheppo return (0); 9251ae08745Sheppo } 9261ae08745Sheppo 9271ae08745Sheppo /* 9281ae08745Sheppo * Function: 9291ae08745Sheppo * vdc_create_device_nodes_props 9301ae08745Sheppo * 9311ae08745Sheppo * Description: 9321ae08745Sheppo * This function creates the block and character device nodes under 9331ae08745Sheppo * /devices along with the node properties. It is called as part of 9341ae08745Sheppo * the attach(9E) of the instance during the handshake with vds after 9351ae08745Sheppo * vds has sent the attributes to vdc. 9361ae08745Sheppo * 9371ae08745Sheppo * Parameters: 9381ae08745Sheppo * vdc - soft state pointer 9391ae08745Sheppo * 9401ae08745Sheppo * Return Values 9411ae08745Sheppo * 0 - Success 9421ae08745Sheppo * EIO - Failed to create device node property 9431ae08745Sheppo * EINVAL - Unknown type of disk exported 9441ae08745Sheppo */ 9451ae08745Sheppo static int 9461ae08745Sheppo vdc_create_device_nodes_props(vdc_t *vdc) 9471ae08745Sheppo { 9481ae08745Sheppo dev_info_t *dip = NULL; 9491ae08745Sheppo int instance; 9501ae08745Sheppo int num_slices = 1; 9511ae08745Sheppo int64_t size = 0; 9521ae08745Sheppo dev_t dev; 9531ae08745Sheppo int rv; 9541ae08745Sheppo int i; 9551ae08745Sheppo 9561ae08745Sheppo ASSERT(vdc != NULL); 957*78fcd0a1Sachartre ASSERT(vdc->vtoc != NULL); 9581ae08745Sheppo 9591ae08745Sheppo instance = vdc->instance; 9601ae08745Sheppo dip = vdc->dip; 9611ae08745Sheppo 9621ae08745Sheppo switch (vdc->vdisk_type) { 9631ae08745Sheppo case VD_DISK_TYPE_DISK: 9641ae08745Sheppo num_slices = V_NUMPAR; 9651ae08745Sheppo break; 9661ae08745Sheppo case VD_DISK_TYPE_SLICE: 9671ae08745Sheppo num_slices = 1; 9681ae08745Sheppo break; 9691ae08745Sheppo case VD_DISK_TYPE_UNK: 9701ae08745Sheppo default: 9711ae08745Sheppo return (EINVAL); 9721ae08745Sheppo } 9731ae08745Sheppo 974*78fcd0a1Sachartre if (vdc->vdisk_label == VD_DISK_LABEL_UNK) { 975*78fcd0a1Sachartre /* remove all properties */ 976*78fcd0a1Sachartre for (i = 0; i < num_slices; i++) { 977*78fcd0a1Sachartre dev = makedevice(ddi_driver_major(dip), 978*78fcd0a1Sachartre VD_MAKE_DEV(instance, i)); 979*78fcd0a1Sachartre (void) ddi_prop_remove(dev, dip, VDC_SIZE_PROP_NAME); 980*78fcd0a1Sachartre (void) ddi_prop_remove(dev, dip, VDC_NBLOCKS_PROP_NAME); 981*78fcd0a1Sachartre } 982*78fcd0a1Sachartre return (0); 983*78fcd0a1Sachartre } 984*78fcd0a1Sachartre 9851ae08745Sheppo for (i = 0; i < num_slices; i++) { 9861ae08745Sheppo dev = makedevice(ddi_driver_major(dip), 9871ae08745Sheppo VD_MAKE_DEV(instance, i)); 9881ae08745Sheppo 9891ae08745Sheppo size = vdc->vtoc->v_part[i].p_size * vdc->vtoc->v_sectorsz; 9903af08d82Slm66018 DMSG(vdc, 0, "[%d] sz %ld (%ld Mb) p_size %lx\n", 991e1ebb9ecSlm66018 instance, size, size / (1024 * 1024), 9921ae08745Sheppo vdc->vtoc->v_part[i].p_size); 9931ae08745Sheppo 9941ae08745Sheppo rv = ddi_prop_update_int64(dev, dip, VDC_SIZE_PROP_NAME, size); 9951ae08745Sheppo if (rv != DDI_PROP_SUCCESS) { 996e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't add '%s' prop of [%ld]", 997e1ebb9ecSlm66018 instance, VDC_SIZE_PROP_NAME, size); 9981ae08745Sheppo return (EIO); 9991ae08745Sheppo } 10001ae08745Sheppo 10011ae08745Sheppo rv = ddi_prop_update_int64(dev, dip, VDC_NBLOCKS_PROP_NAME, 10021ae08745Sheppo lbtodb(size)); 10031ae08745Sheppo if (rv != DDI_PROP_SUCCESS) { 1004e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't add '%s' prop [%llu]", 10051ae08745Sheppo instance, VDC_NBLOCKS_PROP_NAME, lbtodb(size)); 10061ae08745Sheppo return (EIO); 10071ae08745Sheppo } 10081ae08745Sheppo } 10091ae08745Sheppo 10101ae08745Sheppo return (0); 10111ae08745Sheppo } 10121ae08745Sheppo 1013*78fcd0a1Sachartre /* 1014*78fcd0a1Sachartre * Function: 1015*78fcd0a1Sachartre * vdc_is_opened 1016*78fcd0a1Sachartre * 1017*78fcd0a1Sachartre * Description: 1018*78fcd0a1Sachartre * This function checks if any slice of a given virtual disk is 1019*78fcd0a1Sachartre * currently opened. 1020*78fcd0a1Sachartre * 1021*78fcd0a1Sachartre * Parameters: 1022*78fcd0a1Sachartre * vdc - soft state pointer 1023*78fcd0a1Sachartre * 1024*78fcd0a1Sachartre * Return Values 1025*78fcd0a1Sachartre * B_TRUE - at least one slice is opened. 1026*78fcd0a1Sachartre * B_FALSE - no slice is opened. 1027*78fcd0a1Sachartre */ 1028*78fcd0a1Sachartre static boolean_t 1029*78fcd0a1Sachartre vdc_is_opened(vdc_t *vdc) 1030*78fcd0a1Sachartre { 1031*78fcd0a1Sachartre int i, nslices; 1032*78fcd0a1Sachartre 1033*78fcd0a1Sachartre switch (vdc->vdisk_type) { 1034*78fcd0a1Sachartre case VD_DISK_TYPE_DISK: 1035*78fcd0a1Sachartre nslices = V_NUMPAR; 1036*78fcd0a1Sachartre break; 1037*78fcd0a1Sachartre case VD_DISK_TYPE_SLICE: 1038*78fcd0a1Sachartre nslices = 1; 1039*78fcd0a1Sachartre break; 1040*78fcd0a1Sachartre case VD_DISK_TYPE_UNK: 1041*78fcd0a1Sachartre default: 1042*78fcd0a1Sachartre ASSERT(0); 1043*78fcd0a1Sachartre } 1044*78fcd0a1Sachartre 1045*78fcd0a1Sachartre /* check if there's any layered open */ 1046*78fcd0a1Sachartre for (i = 0; i < nslices; i++) { 1047*78fcd0a1Sachartre if (vdc->open_lyr[i] > 0) 1048*78fcd0a1Sachartre return (B_TRUE); 1049*78fcd0a1Sachartre } 1050*78fcd0a1Sachartre 1051*78fcd0a1Sachartre /* check if there is any other kind of open */ 1052*78fcd0a1Sachartre for (i = 0; i < OTYPCNT; i++) { 1053*78fcd0a1Sachartre if (vdc->open[i] != 0) 1054*78fcd0a1Sachartre return (B_TRUE); 1055*78fcd0a1Sachartre } 1056*78fcd0a1Sachartre 1057*78fcd0a1Sachartre return (B_FALSE); 1058*78fcd0a1Sachartre } 1059*78fcd0a1Sachartre 1060*78fcd0a1Sachartre static int 1061*78fcd0a1Sachartre vdc_mark_opened(vdc_t *vdc, int slice, int flag, int otyp) 1062*78fcd0a1Sachartre { 1063*78fcd0a1Sachartre uint8_t slicemask; 1064*78fcd0a1Sachartre int i; 1065*78fcd0a1Sachartre 1066*78fcd0a1Sachartre ASSERT(otyp < OTYPCNT); 1067*78fcd0a1Sachartre ASSERT(slice < V_NUMPAR); 1068*78fcd0a1Sachartre ASSERT(MUTEX_HELD(&vdc->lock)); 1069*78fcd0a1Sachartre 1070*78fcd0a1Sachartre slicemask = 1 << slice; 1071*78fcd0a1Sachartre 1072*78fcd0a1Sachartre /* check if slice is already exclusively opened */ 1073*78fcd0a1Sachartre if (vdc->open_excl & slicemask) 1074*78fcd0a1Sachartre return (EBUSY); 1075*78fcd0a1Sachartre 1076*78fcd0a1Sachartre /* if open exclusive, check if slice is already opened */ 1077*78fcd0a1Sachartre if (flag & FEXCL) { 1078*78fcd0a1Sachartre if (vdc->open_lyr[slice] > 0) 1079*78fcd0a1Sachartre return (EBUSY); 1080*78fcd0a1Sachartre for (i = 0; i < OTYPCNT; i++) { 1081*78fcd0a1Sachartre if (vdc->open[i] & slicemask) 1082*78fcd0a1Sachartre return (EBUSY); 1083*78fcd0a1Sachartre } 1084*78fcd0a1Sachartre vdc->open_excl |= slicemask; 1085*78fcd0a1Sachartre } 1086*78fcd0a1Sachartre 1087*78fcd0a1Sachartre /* mark slice as opened */ 1088*78fcd0a1Sachartre if (otyp == OTYP_LYR) { 1089*78fcd0a1Sachartre vdc->open_lyr[slice]++; 1090*78fcd0a1Sachartre } else { 1091*78fcd0a1Sachartre vdc->open[otyp] |= slicemask; 1092*78fcd0a1Sachartre } 1093*78fcd0a1Sachartre 1094*78fcd0a1Sachartre return (0); 1095*78fcd0a1Sachartre } 1096*78fcd0a1Sachartre 1097*78fcd0a1Sachartre static void 1098*78fcd0a1Sachartre vdc_mark_closed(vdc_t *vdc, int slice, int flag, int otyp) 1099*78fcd0a1Sachartre { 1100*78fcd0a1Sachartre uint8_t slicemask; 1101*78fcd0a1Sachartre 1102*78fcd0a1Sachartre ASSERT(otyp < OTYPCNT); 1103*78fcd0a1Sachartre ASSERT(slice < V_NUMPAR); 1104*78fcd0a1Sachartre ASSERT(MUTEX_HELD(&vdc->lock)); 1105*78fcd0a1Sachartre 1106*78fcd0a1Sachartre slicemask = 1 << slice; 1107*78fcd0a1Sachartre 1108*78fcd0a1Sachartre if (otyp == OTYP_LYR) { 1109*78fcd0a1Sachartre ASSERT(vdc->open_lyr[slice] > 0); 1110*78fcd0a1Sachartre vdc->open_lyr[slice]--; 1111*78fcd0a1Sachartre } else { 1112*78fcd0a1Sachartre vdc->open[otyp] &= ~slicemask; 1113*78fcd0a1Sachartre } 1114*78fcd0a1Sachartre 1115*78fcd0a1Sachartre if (flag & FEXCL) 1116*78fcd0a1Sachartre vdc->open_excl &= ~slicemask; 1117*78fcd0a1Sachartre } 1118*78fcd0a1Sachartre 11191ae08745Sheppo static int 11201ae08745Sheppo vdc_open(dev_t *dev, int flag, int otyp, cred_t *cred) 11211ae08745Sheppo { 11221ae08745Sheppo _NOTE(ARGUNUSED(cred)) 11231ae08745Sheppo 11241ae08745Sheppo int instance; 1125*78fcd0a1Sachartre int slice, status = 0; 11261ae08745Sheppo vdc_t *vdc; 11271ae08745Sheppo 11281ae08745Sheppo ASSERT(dev != NULL); 11290d0c8d4bSnarayan instance = VDCUNIT(*dev); 11301ae08745Sheppo 1131*78fcd0a1Sachartre if (otyp >= OTYPCNT) 11321ae08745Sheppo return (EINVAL); 11331ae08745Sheppo 11341ae08745Sheppo if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) { 1135e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't get state structure", instance); 11361ae08745Sheppo return (ENXIO); 11371ae08745Sheppo } 11381ae08745Sheppo 11393af08d82Slm66018 DMSG(vdc, 0, "minor = %d flag = %x, otyp = %x\n", 11403af08d82Slm66018 getminor(*dev), flag, otyp); 11411ae08745Sheppo 1142*78fcd0a1Sachartre slice = VDCPART(*dev); 1143*78fcd0a1Sachartre 11441ae08745Sheppo mutex_enter(&vdc->lock); 1145*78fcd0a1Sachartre 1146*78fcd0a1Sachartre status = vdc_mark_opened(vdc, slice, flag, otyp); 1147*78fcd0a1Sachartre 1148*78fcd0a1Sachartre if (status != 0) { 1149*78fcd0a1Sachartre mutex_exit(&vdc->lock); 1150*78fcd0a1Sachartre return (status); 1151*78fcd0a1Sachartre } 1152*78fcd0a1Sachartre 1153*78fcd0a1Sachartre if (flag & (FNDELAY | FNONBLOCK)) { 1154*78fcd0a1Sachartre 1155*78fcd0a1Sachartre /* don't resubmit a validate request if there's already one */ 1156*78fcd0a1Sachartre if (vdc->validate_pending > 0) { 1157*78fcd0a1Sachartre mutex_exit(&vdc->lock); 1158*78fcd0a1Sachartre return (0); 1159*78fcd0a1Sachartre } 1160*78fcd0a1Sachartre 1161*78fcd0a1Sachartre /* call vdc_validate() asynchronously to avoid blocking */ 1162*78fcd0a1Sachartre if (taskq_dispatch(system_taskq, vdc_validate_task, 1163*78fcd0a1Sachartre (void *)vdc, TQ_NOSLEEP) == NULL) { 1164*78fcd0a1Sachartre vdc_mark_closed(vdc, slice, flag, otyp); 1165*78fcd0a1Sachartre mutex_exit(&vdc->lock); 1166*78fcd0a1Sachartre return (ENXIO); 1167*78fcd0a1Sachartre } 1168*78fcd0a1Sachartre 1169*78fcd0a1Sachartre vdc->validate_pending++; 1170*78fcd0a1Sachartre mutex_exit(&vdc->lock); 1171*78fcd0a1Sachartre return (0); 1172*78fcd0a1Sachartre } 1173*78fcd0a1Sachartre 11741ae08745Sheppo mutex_exit(&vdc->lock); 11751ae08745Sheppo 1176*78fcd0a1Sachartre vdc_validate(vdc); 1177*78fcd0a1Sachartre 1178*78fcd0a1Sachartre mutex_enter(&vdc->lock); 1179*78fcd0a1Sachartre 1180*78fcd0a1Sachartre if (vdc->vdisk_label == VD_DISK_LABEL_UNK || 1181*78fcd0a1Sachartre vdc->vtoc->v_part[slice].p_size == 0) { 1182*78fcd0a1Sachartre vdc_mark_closed(vdc, slice, flag, otyp); 1183*78fcd0a1Sachartre status = EIO; 1184*78fcd0a1Sachartre } 1185*78fcd0a1Sachartre 1186*78fcd0a1Sachartre mutex_exit(&vdc->lock); 1187*78fcd0a1Sachartre 1188*78fcd0a1Sachartre return (status); 11891ae08745Sheppo } 11901ae08745Sheppo 11911ae08745Sheppo static int 11921ae08745Sheppo vdc_close(dev_t dev, int flag, int otyp, cred_t *cred) 11931ae08745Sheppo { 11941ae08745Sheppo _NOTE(ARGUNUSED(cred)) 11951ae08745Sheppo 11961ae08745Sheppo int instance; 1197*78fcd0a1Sachartre int slice; 11981ae08745Sheppo vdc_t *vdc; 11991ae08745Sheppo 12000d0c8d4bSnarayan instance = VDCUNIT(dev); 12011ae08745Sheppo 1202*78fcd0a1Sachartre if (otyp >= OTYPCNT) 12031ae08745Sheppo return (EINVAL); 12041ae08745Sheppo 12051ae08745Sheppo if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) { 1206e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't get state structure", instance); 12071ae08745Sheppo return (ENXIO); 12081ae08745Sheppo } 12091ae08745Sheppo 12103af08d82Slm66018 DMSG(vdc, 0, "[%d] flag = %x, otyp = %x\n", instance, flag, otyp); 12111ae08745Sheppo 1212*78fcd0a1Sachartre slice = VDCPART(dev); 1213*78fcd0a1Sachartre 12141ae08745Sheppo mutex_enter(&vdc->lock); 1215*78fcd0a1Sachartre vdc_mark_closed(vdc, slice, flag, otyp); 12161ae08745Sheppo mutex_exit(&vdc->lock); 12171ae08745Sheppo 12181ae08745Sheppo return (0); 12191ae08745Sheppo } 12201ae08745Sheppo 12211ae08745Sheppo static int 12221ae08745Sheppo vdc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) 12231ae08745Sheppo { 12241ae08745Sheppo _NOTE(ARGUNUSED(credp)) 12251ae08745Sheppo _NOTE(ARGUNUSED(rvalp)) 12261ae08745Sheppo 12271ae08745Sheppo return (vd_process_ioctl(dev, cmd, (caddr_t)arg, mode)); 12281ae08745Sheppo } 12291ae08745Sheppo 12301ae08745Sheppo static int 12311ae08745Sheppo vdc_print(dev_t dev, char *str) 12321ae08745Sheppo { 12330d0c8d4bSnarayan cmn_err(CE_NOTE, "vdc%d: %s", VDCUNIT(dev), str); 12341ae08745Sheppo return (0); 12351ae08745Sheppo } 12361ae08745Sheppo 12371ae08745Sheppo static int 12381ae08745Sheppo vdc_dump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk) 12391ae08745Sheppo { 1240d10e4ef2Snarayan int rv; 1241d10e4ef2Snarayan size_t nbytes = nblk * DEV_BSIZE; 12420d0c8d4bSnarayan int instance = VDCUNIT(dev); 1243d10e4ef2Snarayan vdc_t *vdc = NULL; 12441ae08745Sheppo 12451ae08745Sheppo if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) { 1246e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't get state structure", instance); 12471ae08745Sheppo return (ENXIO); 12481ae08745Sheppo } 12491ae08745Sheppo 12503af08d82Slm66018 DMSG(vdc, 2, "[%d] dump %ld bytes at block 0x%lx : addr=0x%p\n", 12513af08d82Slm66018 instance, nbytes, blkno, (void *)addr); 12523af08d82Slm66018 rv = vdc_send_request(vdc, VD_OP_BWRITE, addr, nbytes, 12530d0c8d4bSnarayan VDCPART(dev), blkno, CB_STRATEGY, 0, VIO_write_dir); 12543af08d82Slm66018 if (rv) { 12553af08d82Slm66018 DMSG(vdc, 0, "Failed to do a disk dump (err=%d)\n", rv); 12561ae08745Sheppo return (rv); 12571ae08745Sheppo } 12581ae08745Sheppo 12593af08d82Slm66018 if (ddi_in_panic()) 12603af08d82Slm66018 (void) vdc_drain_response(vdc); 12613af08d82Slm66018 12623af08d82Slm66018 DMSG(vdc, 0, "[%d] End\n", instance); 12633af08d82Slm66018 12643af08d82Slm66018 return (0); 12653af08d82Slm66018 } 12663af08d82Slm66018 12671ae08745Sheppo /* -------------------------------------------------------------------------- */ 12681ae08745Sheppo 12691ae08745Sheppo /* 12701ae08745Sheppo * Disk access routines 12711ae08745Sheppo * 12721ae08745Sheppo */ 12731ae08745Sheppo 12741ae08745Sheppo /* 12751ae08745Sheppo * vdc_strategy() 12761ae08745Sheppo * 12771ae08745Sheppo * Return Value: 12781ae08745Sheppo * 0: As per strategy(9E), the strategy() function must return 0 12791ae08745Sheppo * [ bioerror(9f) sets b_flags to the proper error code ] 12801ae08745Sheppo */ 12811ae08745Sheppo static int 12821ae08745Sheppo vdc_strategy(struct buf *buf) 12831ae08745Sheppo { 12841ae08745Sheppo int rv = -1; 12851ae08745Sheppo vdc_t *vdc = NULL; 12860d0c8d4bSnarayan int instance = VDCUNIT(buf->b_edev); 12871ae08745Sheppo int op = (buf->b_flags & B_READ) ? VD_OP_BREAD : VD_OP_BWRITE; 128887a7269eSachartre int slice; 12891ae08745Sheppo 12901ae08745Sheppo if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) { 1291e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't get state structure", instance); 12921ae08745Sheppo bioerror(buf, ENXIO); 12931ae08745Sheppo biodone(buf); 12941ae08745Sheppo return (0); 12951ae08745Sheppo } 12961ae08745Sheppo 12973af08d82Slm66018 DMSG(vdc, 2, "[%d] %s %ld bytes at block %llx : b_addr=0x%p\n", 12983af08d82Slm66018 instance, (buf->b_flags & B_READ) ? "Read" : "Write", 12993af08d82Slm66018 buf->b_bcount, buf->b_lblkno, (void *)buf->b_un.b_addr); 1300d10e4ef2Snarayan DTRACE_IO2(vstart, buf_t *, buf, vdc_t *, vdc); 1301d10e4ef2Snarayan 13021ae08745Sheppo bp_mapin(buf); 13031ae08745Sheppo 130487a7269eSachartre if ((long)buf->b_private == VD_SLICE_NONE) { 130587a7269eSachartre /* I/O using an absolute disk offset */ 130687a7269eSachartre slice = VD_SLICE_NONE; 130787a7269eSachartre } else { 130887a7269eSachartre slice = VDCPART(buf->b_edev); 130987a7269eSachartre } 131087a7269eSachartre 13113af08d82Slm66018 rv = vdc_send_request(vdc, op, (caddr_t)buf->b_un.b_addr, 131287a7269eSachartre buf->b_bcount, slice, buf->b_lblkno, 13133af08d82Slm66018 CB_STRATEGY, buf, (op == VD_OP_BREAD) ? VIO_read_dir : 13143af08d82Slm66018 VIO_write_dir); 13153af08d82Slm66018 1316d10e4ef2Snarayan /* 1317d10e4ef2Snarayan * If the request was successfully sent, the strategy call returns and 1318d10e4ef2Snarayan * the ACK handler calls the bioxxx functions when the vDisk server is 1319d10e4ef2Snarayan * done. 1320d10e4ef2Snarayan */ 1321d10e4ef2Snarayan if (rv) { 13223af08d82Slm66018 DMSG(vdc, 0, "Failed to read/write (err=%d)\n", rv); 13231ae08745Sheppo bioerror(buf, rv); 13241ae08745Sheppo biodone(buf); 1325d10e4ef2Snarayan } 1326d10e4ef2Snarayan 13271ae08745Sheppo return (0); 13281ae08745Sheppo } 13291ae08745Sheppo 13300d0c8d4bSnarayan /* 13310d0c8d4bSnarayan * Function: 13320d0c8d4bSnarayan * vdc_min 13330d0c8d4bSnarayan * 13340d0c8d4bSnarayan * Description: 13350d0c8d4bSnarayan * Routine to limit the size of a data transfer. Used in 13360d0c8d4bSnarayan * conjunction with physio(9F). 13370d0c8d4bSnarayan * 13380d0c8d4bSnarayan * Arguments: 13390d0c8d4bSnarayan * bp - pointer to the indicated buf(9S) struct. 13400d0c8d4bSnarayan * 13410d0c8d4bSnarayan */ 13420d0c8d4bSnarayan static void 13430d0c8d4bSnarayan vdc_min(struct buf *bufp) 13440d0c8d4bSnarayan { 13450d0c8d4bSnarayan vdc_t *vdc = NULL; 13460d0c8d4bSnarayan int instance = VDCUNIT(bufp->b_edev); 13470d0c8d4bSnarayan 13480d0c8d4bSnarayan vdc = ddi_get_soft_state(vdc_state, instance); 13490d0c8d4bSnarayan VERIFY(vdc != NULL); 13500d0c8d4bSnarayan 13510d0c8d4bSnarayan if (bufp->b_bcount > (vdc->max_xfer_sz * vdc->block_size)) { 13520d0c8d4bSnarayan bufp->b_bcount = vdc->max_xfer_sz * vdc->block_size; 13530d0c8d4bSnarayan } 13540d0c8d4bSnarayan } 13551ae08745Sheppo 13561ae08745Sheppo static int 13571ae08745Sheppo vdc_read(dev_t dev, struct uio *uio, cred_t *cred) 13581ae08745Sheppo { 13591ae08745Sheppo _NOTE(ARGUNUSED(cred)) 13601ae08745Sheppo 13610d0c8d4bSnarayan DMSGX(1, "[%d] Entered", VDCUNIT(dev)); 13620d0c8d4bSnarayan return (physio(vdc_strategy, NULL, dev, B_READ, vdc_min, uio)); 13631ae08745Sheppo } 13641ae08745Sheppo 13651ae08745Sheppo static int 13661ae08745Sheppo vdc_write(dev_t dev, struct uio *uio, cred_t *cred) 13671ae08745Sheppo { 13681ae08745Sheppo _NOTE(ARGUNUSED(cred)) 13691ae08745Sheppo 13700d0c8d4bSnarayan DMSGX(1, "[%d] Entered", VDCUNIT(dev)); 13710d0c8d4bSnarayan return (physio(vdc_strategy, NULL, dev, B_WRITE, vdc_min, uio)); 13721ae08745Sheppo } 13731ae08745Sheppo 13741ae08745Sheppo static int 13751ae08745Sheppo vdc_aread(dev_t dev, struct aio_req *aio, cred_t *cred) 13761ae08745Sheppo { 13771ae08745Sheppo _NOTE(ARGUNUSED(cred)) 13781ae08745Sheppo 13790d0c8d4bSnarayan DMSGX(1, "[%d] Entered", VDCUNIT(dev)); 13800d0c8d4bSnarayan return (aphysio(vdc_strategy, anocancel, dev, B_READ, vdc_min, aio)); 13811ae08745Sheppo } 13821ae08745Sheppo 13831ae08745Sheppo static int 13841ae08745Sheppo vdc_awrite(dev_t dev, struct aio_req *aio, cred_t *cred) 13851ae08745Sheppo { 13861ae08745Sheppo _NOTE(ARGUNUSED(cred)) 13871ae08745Sheppo 13880d0c8d4bSnarayan DMSGX(1, "[%d] Entered", VDCUNIT(dev)); 13890d0c8d4bSnarayan return (aphysio(vdc_strategy, anocancel, dev, B_WRITE, vdc_min, aio)); 13901ae08745Sheppo } 13911ae08745Sheppo 13921ae08745Sheppo 13931ae08745Sheppo /* -------------------------------------------------------------------------- */ 13941ae08745Sheppo 13951ae08745Sheppo /* 13961ae08745Sheppo * Handshake support 13971ae08745Sheppo */ 13981ae08745Sheppo 13991ae08745Sheppo 14000a55fbb7Slm66018 /* 14010a55fbb7Slm66018 * Function: 14020a55fbb7Slm66018 * vdc_init_ver_negotiation() 14030a55fbb7Slm66018 * 14040a55fbb7Slm66018 * Description: 14050a55fbb7Slm66018 * 14060a55fbb7Slm66018 * Arguments: 14070a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 14080a55fbb7Slm66018 * 14090a55fbb7Slm66018 * Return Code: 14100a55fbb7Slm66018 * 0 - Success 14110a55fbb7Slm66018 */ 14121ae08745Sheppo static int 14130a55fbb7Slm66018 vdc_init_ver_negotiation(vdc_t *vdc, vio_ver_t ver) 14141ae08745Sheppo { 14151ae08745Sheppo vio_ver_msg_t pkt; 14161ae08745Sheppo size_t msglen = sizeof (pkt); 14171ae08745Sheppo int status = -1; 14181ae08745Sheppo 14191ae08745Sheppo ASSERT(vdc != NULL); 14201ae08745Sheppo ASSERT(mutex_owned(&vdc->lock)); 14211ae08745Sheppo 14223af08d82Slm66018 DMSG(vdc, 0, "[%d] Entered.\n", vdc->instance); 1423e1ebb9ecSlm66018 14241ae08745Sheppo /* 14251ae08745Sheppo * set the Session ID to a unique value 14261ae08745Sheppo * (the lower 32 bits of the clock tick) 14271ae08745Sheppo */ 14281ae08745Sheppo vdc->session_id = ((uint32_t)gettick() & 0xffffffff); 14293af08d82Slm66018 DMSG(vdc, 0, "[%d] Set SID to 0x%lx\n", vdc->instance, vdc->session_id); 14301ae08745Sheppo 14311ae08745Sheppo pkt.tag.vio_msgtype = VIO_TYPE_CTRL; 14321ae08745Sheppo pkt.tag.vio_subtype = VIO_SUBTYPE_INFO; 14331ae08745Sheppo pkt.tag.vio_subtype_env = VIO_VER_INFO; 14341ae08745Sheppo pkt.tag.vio_sid = vdc->session_id; 14351ae08745Sheppo pkt.dev_class = VDEV_DISK; 14360a55fbb7Slm66018 pkt.ver_major = ver.major; 14370a55fbb7Slm66018 pkt.ver_minor = ver.minor; 14381ae08745Sheppo 14390a55fbb7Slm66018 status = vdc_send(vdc, (caddr_t)&pkt, &msglen); 14403af08d82Slm66018 DMSG(vdc, 0, "[%d] Ver info sent (status = %d)\n", 14413af08d82Slm66018 vdc->instance, status); 14421ae08745Sheppo if ((status != 0) || (msglen != sizeof (vio_ver_msg_t))) { 14433af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to send Ver negotiation info: " 144487a7269eSachartre "id(%lx) rv(%d) size(%ld)", vdc->instance, vdc->ldc_handle, 14451ae08745Sheppo status, msglen); 14461ae08745Sheppo if (msglen != sizeof (vio_ver_msg_t)) 14471ae08745Sheppo status = ENOMSG; 14481ae08745Sheppo } 14491ae08745Sheppo 14501ae08745Sheppo return (status); 14511ae08745Sheppo } 14521ae08745Sheppo 14530a55fbb7Slm66018 /* 14540a55fbb7Slm66018 * Function: 14553af08d82Slm66018 * vdc_ver_negotiation() 14563af08d82Slm66018 * 14573af08d82Slm66018 * Description: 14583af08d82Slm66018 * 14593af08d82Slm66018 * Arguments: 14603af08d82Slm66018 * vdcp - soft state pointer for this instance of the device driver. 14613af08d82Slm66018 * 14623af08d82Slm66018 * Return Code: 14633af08d82Slm66018 * 0 - Success 14643af08d82Slm66018 */ 14653af08d82Slm66018 static int 14663af08d82Slm66018 vdc_ver_negotiation(vdc_t *vdcp) 14673af08d82Slm66018 { 14683af08d82Slm66018 vio_msg_t vio_msg; 14693af08d82Slm66018 int status; 14703af08d82Slm66018 14713af08d82Slm66018 if (status = vdc_init_ver_negotiation(vdcp, vdc_version[0])) 14723af08d82Slm66018 return (status); 14733af08d82Slm66018 14743af08d82Slm66018 /* release lock and wait for response */ 14753af08d82Slm66018 mutex_exit(&vdcp->lock); 14763af08d82Slm66018 status = vdc_wait_for_response(vdcp, &vio_msg); 14773af08d82Slm66018 mutex_enter(&vdcp->lock); 14783af08d82Slm66018 if (status) { 14793af08d82Slm66018 DMSG(vdcp, 0, 14803af08d82Slm66018 "[%d] Failed waiting for Ver negotiation response, rv(%d)", 14813af08d82Slm66018 vdcp->instance, status); 14823af08d82Slm66018 return (status); 14833af08d82Slm66018 } 14843af08d82Slm66018 14853af08d82Slm66018 /* check type and sub_type ... */ 14863af08d82Slm66018 if (vio_msg.tag.vio_msgtype != VIO_TYPE_CTRL || 14873af08d82Slm66018 vio_msg.tag.vio_subtype == VIO_SUBTYPE_INFO) { 14883af08d82Slm66018 DMSG(vdcp, 0, "[%d] Invalid ver negotiation response\n", 14893af08d82Slm66018 vdcp->instance); 14903af08d82Slm66018 return (EPROTO); 14913af08d82Slm66018 } 14923af08d82Slm66018 14933af08d82Slm66018 return (vdc_handle_ver_msg(vdcp, (vio_ver_msg_t *)&vio_msg)); 14943af08d82Slm66018 } 14953af08d82Slm66018 14963af08d82Slm66018 /* 14973af08d82Slm66018 * Function: 14980a55fbb7Slm66018 * vdc_init_attr_negotiation() 14990a55fbb7Slm66018 * 15000a55fbb7Slm66018 * Description: 15010a55fbb7Slm66018 * 15020a55fbb7Slm66018 * Arguments: 15030a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 15040a55fbb7Slm66018 * 15050a55fbb7Slm66018 * Return Code: 15060a55fbb7Slm66018 * 0 - Success 15070a55fbb7Slm66018 */ 15081ae08745Sheppo static int 15091ae08745Sheppo vdc_init_attr_negotiation(vdc_t *vdc) 15101ae08745Sheppo { 15111ae08745Sheppo vd_attr_msg_t pkt; 15121ae08745Sheppo size_t msglen = sizeof (pkt); 15131ae08745Sheppo int status; 15141ae08745Sheppo 15151ae08745Sheppo ASSERT(vdc != NULL); 15161ae08745Sheppo ASSERT(mutex_owned(&vdc->lock)); 15171ae08745Sheppo 15183af08d82Slm66018 DMSG(vdc, 0, "[%d] entered\n", vdc->instance); 15191ae08745Sheppo 15201ae08745Sheppo /* fill in tag */ 15211ae08745Sheppo pkt.tag.vio_msgtype = VIO_TYPE_CTRL; 15221ae08745Sheppo pkt.tag.vio_subtype = VIO_SUBTYPE_INFO; 15231ae08745Sheppo pkt.tag.vio_subtype_env = VIO_ATTR_INFO; 15241ae08745Sheppo pkt.tag.vio_sid = vdc->session_id; 15251ae08745Sheppo /* fill in payload */ 15261ae08745Sheppo pkt.max_xfer_sz = vdc->max_xfer_sz; 15271ae08745Sheppo pkt.vdisk_block_size = vdc->block_size; 15281ae08745Sheppo pkt.xfer_mode = VIO_DRING_MODE; 15291ae08745Sheppo pkt.operations = 0; /* server will set bits of valid operations */ 15301ae08745Sheppo pkt.vdisk_type = 0; /* server will set to valid device type */ 15311ae08745Sheppo pkt.vdisk_size = 0; /* server will set to valid size */ 15321ae08745Sheppo 15330a55fbb7Slm66018 status = vdc_send(vdc, (caddr_t)&pkt, &msglen); 15343af08d82Slm66018 DMSG(vdc, 0, "Attr info sent (status = %d)\n", status); 15351ae08745Sheppo 15361ae08745Sheppo if ((status != 0) || (msglen != sizeof (vio_ver_msg_t))) { 15373af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to send Attr negotiation info: " 153887a7269eSachartre "id(%lx) rv(%d) size(%ld)", vdc->instance, vdc->ldc_handle, 15391ae08745Sheppo status, msglen); 15401ae08745Sheppo if (msglen != sizeof (vio_ver_msg_t)) 15411ae08745Sheppo status = ENOMSG; 15421ae08745Sheppo } 15431ae08745Sheppo 15441ae08745Sheppo return (status); 15451ae08745Sheppo } 15461ae08745Sheppo 15470a55fbb7Slm66018 /* 15480a55fbb7Slm66018 * Function: 15493af08d82Slm66018 * vdc_attr_negotiation() 15503af08d82Slm66018 * 15513af08d82Slm66018 * Description: 15523af08d82Slm66018 * 15533af08d82Slm66018 * Arguments: 15543af08d82Slm66018 * vdc - soft state pointer for this instance of the device driver. 15553af08d82Slm66018 * 15563af08d82Slm66018 * Return Code: 15573af08d82Slm66018 * 0 - Success 15583af08d82Slm66018 */ 15593af08d82Slm66018 static int 15603af08d82Slm66018 vdc_attr_negotiation(vdc_t *vdcp) 15613af08d82Slm66018 { 15623af08d82Slm66018 int status; 15633af08d82Slm66018 vio_msg_t vio_msg; 15643af08d82Slm66018 15653af08d82Slm66018 if (status = vdc_init_attr_negotiation(vdcp)) 15663af08d82Slm66018 return (status); 15673af08d82Slm66018 15683af08d82Slm66018 /* release lock and wait for response */ 15693af08d82Slm66018 mutex_exit(&vdcp->lock); 15703af08d82Slm66018 status = vdc_wait_for_response(vdcp, &vio_msg); 15713af08d82Slm66018 mutex_enter(&vdcp->lock); 15723af08d82Slm66018 if (status) { 15733af08d82Slm66018 DMSG(vdcp, 0, 15743af08d82Slm66018 "[%d] Failed waiting for Attr negotiation response, rv(%d)", 15753af08d82Slm66018 vdcp->instance, status); 15763af08d82Slm66018 return (status); 15773af08d82Slm66018 } 15783af08d82Slm66018 15793af08d82Slm66018 /* check type and sub_type ... */ 15803af08d82Slm66018 if (vio_msg.tag.vio_msgtype != VIO_TYPE_CTRL || 15813af08d82Slm66018 vio_msg.tag.vio_subtype == VIO_SUBTYPE_INFO) { 15823af08d82Slm66018 DMSG(vdcp, 0, "[%d] Invalid attr negotiation response\n", 15833af08d82Slm66018 vdcp->instance); 15843af08d82Slm66018 return (EPROTO); 15853af08d82Slm66018 } 15863af08d82Slm66018 15873af08d82Slm66018 return (vdc_handle_attr_msg(vdcp, (vd_attr_msg_t *)&vio_msg)); 15883af08d82Slm66018 } 15893af08d82Slm66018 15903af08d82Slm66018 15913af08d82Slm66018 /* 15923af08d82Slm66018 * Function: 15930a55fbb7Slm66018 * vdc_init_dring_negotiate() 15940a55fbb7Slm66018 * 15950a55fbb7Slm66018 * Description: 15960a55fbb7Slm66018 * 15970a55fbb7Slm66018 * Arguments: 15980a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 15990a55fbb7Slm66018 * 16000a55fbb7Slm66018 * Return Code: 16010a55fbb7Slm66018 * 0 - Success 16020a55fbb7Slm66018 */ 16031ae08745Sheppo static int 16041ae08745Sheppo vdc_init_dring_negotiate(vdc_t *vdc) 16051ae08745Sheppo { 16061ae08745Sheppo vio_dring_reg_msg_t pkt; 16071ae08745Sheppo size_t msglen = sizeof (pkt); 16081ae08745Sheppo int status = -1; 16093af08d82Slm66018 int retry; 16103af08d82Slm66018 int nretries = 10; 16111ae08745Sheppo 16121ae08745Sheppo ASSERT(vdc != NULL); 16131ae08745Sheppo ASSERT(mutex_owned(&vdc->lock)); 16141ae08745Sheppo 16153af08d82Slm66018 for (retry = 0; retry < nretries; retry++) { 16161ae08745Sheppo status = vdc_init_descriptor_ring(vdc); 16173af08d82Slm66018 if (status != EAGAIN) 16183af08d82Slm66018 break; 16193af08d82Slm66018 drv_usecwait(vdc_min_timeout_ldc); 16203af08d82Slm66018 } 16213af08d82Slm66018 16221ae08745Sheppo if (status != 0) { 16233af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to init DRing (status = %d)\n", 16241ae08745Sheppo vdc->instance, status); 16251ae08745Sheppo return (status); 16261ae08745Sheppo } 16273af08d82Slm66018 16283af08d82Slm66018 DMSG(vdc, 0, "[%d] Init of descriptor ring completed (status = %d)\n", 1629e1ebb9ecSlm66018 vdc->instance, status); 16301ae08745Sheppo 16311ae08745Sheppo /* fill in tag */ 16321ae08745Sheppo pkt.tag.vio_msgtype = VIO_TYPE_CTRL; 16331ae08745Sheppo pkt.tag.vio_subtype = VIO_SUBTYPE_INFO; 16341ae08745Sheppo pkt.tag.vio_subtype_env = VIO_DRING_REG; 16351ae08745Sheppo pkt.tag.vio_sid = vdc->session_id; 16361ae08745Sheppo /* fill in payload */ 16371ae08745Sheppo pkt.dring_ident = 0; 1638e1ebb9ecSlm66018 pkt.num_descriptors = vdc->dring_len; 1639e1ebb9ecSlm66018 pkt.descriptor_size = vdc->dring_entry_size; 16401ae08745Sheppo pkt.options = (VIO_TX_DRING | VIO_RX_DRING); 16411ae08745Sheppo pkt.ncookies = vdc->dring_cookie_count; 16421ae08745Sheppo pkt.cookie[0] = vdc->dring_cookie[0]; /* for now just one cookie */ 16431ae08745Sheppo 16440a55fbb7Slm66018 status = vdc_send(vdc, (caddr_t)&pkt, &msglen); 16451ae08745Sheppo if (status != 0) { 16463af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to register DRing (err = %d)", 1647e1ebb9ecSlm66018 vdc->instance, status); 16481ae08745Sheppo } 16491ae08745Sheppo 16501ae08745Sheppo return (status); 16511ae08745Sheppo } 16521ae08745Sheppo 16531ae08745Sheppo 16543af08d82Slm66018 /* 16553af08d82Slm66018 * Function: 16563af08d82Slm66018 * vdc_dring_negotiation() 16573af08d82Slm66018 * 16583af08d82Slm66018 * Description: 16593af08d82Slm66018 * 16603af08d82Slm66018 * Arguments: 16613af08d82Slm66018 * vdc - soft state pointer for this instance of the device driver. 16623af08d82Slm66018 * 16633af08d82Slm66018 * Return Code: 16643af08d82Slm66018 * 0 - Success 16653af08d82Slm66018 */ 16663af08d82Slm66018 static int 16673af08d82Slm66018 vdc_dring_negotiation(vdc_t *vdcp) 16683af08d82Slm66018 { 16693af08d82Slm66018 int status; 16703af08d82Slm66018 vio_msg_t vio_msg; 16713af08d82Slm66018 16723af08d82Slm66018 if (status = vdc_init_dring_negotiate(vdcp)) 16733af08d82Slm66018 return (status); 16743af08d82Slm66018 16753af08d82Slm66018 /* release lock and wait for response */ 16763af08d82Slm66018 mutex_exit(&vdcp->lock); 16773af08d82Slm66018 status = vdc_wait_for_response(vdcp, &vio_msg); 16783af08d82Slm66018 mutex_enter(&vdcp->lock); 16793af08d82Slm66018 if (status) { 16803af08d82Slm66018 DMSG(vdcp, 0, 16813af08d82Slm66018 "[%d] Failed waiting for Dring negotiation response," 16823af08d82Slm66018 " rv(%d)", vdcp->instance, status); 16833af08d82Slm66018 return (status); 16843af08d82Slm66018 } 16853af08d82Slm66018 16863af08d82Slm66018 /* check type and sub_type ... */ 16873af08d82Slm66018 if (vio_msg.tag.vio_msgtype != VIO_TYPE_CTRL || 16883af08d82Slm66018 vio_msg.tag.vio_subtype == VIO_SUBTYPE_INFO) { 16893af08d82Slm66018 DMSG(vdcp, 0, "[%d] Invalid Dring negotiation response\n", 16903af08d82Slm66018 vdcp->instance); 16913af08d82Slm66018 return (EPROTO); 16923af08d82Slm66018 } 16933af08d82Slm66018 16943af08d82Slm66018 return (vdc_handle_dring_reg_msg(vdcp, 16953af08d82Slm66018 (vio_dring_reg_msg_t *)&vio_msg)); 16963af08d82Slm66018 } 16973af08d82Slm66018 16983af08d82Slm66018 16993af08d82Slm66018 /* 17003af08d82Slm66018 * Function: 17013af08d82Slm66018 * vdc_send_rdx() 17023af08d82Slm66018 * 17033af08d82Slm66018 * Description: 17043af08d82Slm66018 * 17053af08d82Slm66018 * Arguments: 17063af08d82Slm66018 * vdc - soft state pointer for this instance of the device driver. 17073af08d82Slm66018 * 17083af08d82Slm66018 * Return Code: 17093af08d82Slm66018 * 0 - Success 17103af08d82Slm66018 */ 17113af08d82Slm66018 static int 17123af08d82Slm66018 vdc_send_rdx(vdc_t *vdcp) 17133af08d82Slm66018 { 17143af08d82Slm66018 vio_msg_t msg; 17153af08d82Slm66018 size_t msglen = sizeof (vio_msg_t); 17163af08d82Slm66018 int status; 17173af08d82Slm66018 17183af08d82Slm66018 /* 17193af08d82Slm66018 * Send an RDX message to vds to indicate we are ready 17203af08d82Slm66018 * to send data 17213af08d82Slm66018 */ 17223af08d82Slm66018 msg.tag.vio_msgtype = VIO_TYPE_CTRL; 17233af08d82Slm66018 msg.tag.vio_subtype = VIO_SUBTYPE_INFO; 17243af08d82Slm66018 msg.tag.vio_subtype_env = VIO_RDX; 17253af08d82Slm66018 msg.tag.vio_sid = vdcp->session_id; 17263af08d82Slm66018 status = vdc_send(vdcp, (caddr_t)&msg, &msglen); 17273af08d82Slm66018 if (status != 0) { 17283af08d82Slm66018 DMSG(vdcp, 0, "[%d] Failed to send RDX message (%d)", 17293af08d82Slm66018 vdcp->instance, status); 17303af08d82Slm66018 } 17313af08d82Slm66018 17323af08d82Slm66018 return (status); 17333af08d82Slm66018 } 17343af08d82Slm66018 17353af08d82Slm66018 /* 17363af08d82Slm66018 * Function: 17373af08d82Slm66018 * vdc_handle_rdx() 17383af08d82Slm66018 * 17393af08d82Slm66018 * Description: 17403af08d82Slm66018 * 17413af08d82Slm66018 * Arguments: 17423af08d82Slm66018 * vdc - soft state pointer for this instance of the device driver. 17433af08d82Slm66018 * msgp - received msg 17443af08d82Slm66018 * 17453af08d82Slm66018 * Return Code: 17463af08d82Slm66018 * 0 - Success 17473af08d82Slm66018 */ 17483af08d82Slm66018 static int 17493af08d82Slm66018 vdc_handle_rdx(vdc_t *vdcp, vio_rdx_msg_t *msgp) 17503af08d82Slm66018 { 17513af08d82Slm66018 _NOTE(ARGUNUSED(vdcp)) 17523af08d82Slm66018 _NOTE(ARGUNUSED(msgp)) 17533af08d82Slm66018 17543af08d82Slm66018 ASSERT(msgp->tag.vio_msgtype == VIO_TYPE_CTRL); 17553af08d82Slm66018 ASSERT(msgp->tag.vio_subtype == VIO_SUBTYPE_ACK); 17563af08d82Slm66018 ASSERT(msgp->tag.vio_subtype_env == VIO_RDX); 17573af08d82Slm66018 17583af08d82Slm66018 DMSG(vdcp, 1, "[%d] Got an RDX msg", vdcp->instance); 17593af08d82Slm66018 17603af08d82Slm66018 return (0); 17613af08d82Slm66018 } 17623af08d82Slm66018 17633af08d82Slm66018 /* 17643af08d82Slm66018 * Function: 17653af08d82Slm66018 * vdc_rdx_exchange() 17663af08d82Slm66018 * 17673af08d82Slm66018 * Description: 17683af08d82Slm66018 * 17693af08d82Slm66018 * Arguments: 17703af08d82Slm66018 * vdc - soft state pointer for this instance of the device driver. 17713af08d82Slm66018 * 17723af08d82Slm66018 * Return Code: 17733af08d82Slm66018 * 0 - Success 17743af08d82Slm66018 */ 17753af08d82Slm66018 static int 17763af08d82Slm66018 vdc_rdx_exchange(vdc_t *vdcp) 17773af08d82Slm66018 { 17783af08d82Slm66018 int status; 17793af08d82Slm66018 vio_msg_t vio_msg; 17803af08d82Slm66018 17813af08d82Slm66018 if (status = vdc_send_rdx(vdcp)) 17823af08d82Slm66018 return (status); 17833af08d82Slm66018 17843af08d82Slm66018 /* release lock and wait for response */ 17853af08d82Slm66018 mutex_exit(&vdcp->lock); 17863af08d82Slm66018 status = vdc_wait_for_response(vdcp, &vio_msg); 17873af08d82Slm66018 mutex_enter(&vdcp->lock); 17883af08d82Slm66018 if (status) { 178987a7269eSachartre DMSG(vdcp, 0, "[%d] Failed waiting for RDX response, rv(%d)", 179087a7269eSachartre vdcp->instance, status); 17913af08d82Slm66018 return (status); 17923af08d82Slm66018 } 17933af08d82Slm66018 17943af08d82Slm66018 /* check type and sub_type ... */ 17953af08d82Slm66018 if (vio_msg.tag.vio_msgtype != VIO_TYPE_CTRL || 17963af08d82Slm66018 vio_msg.tag.vio_subtype != VIO_SUBTYPE_ACK) { 179787a7269eSachartre DMSG(vdcp, 0, "[%d] Invalid RDX response\n", vdcp->instance); 17983af08d82Slm66018 return (EPROTO); 17993af08d82Slm66018 } 18003af08d82Slm66018 18013af08d82Slm66018 return (vdc_handle_rdx(vdcp, (vio_rdx_msg_t *)&vio_msg)); 18023af08d82Slm66018 } 18033af08d82Slm66018 18043af08d82Slm66018 18051ae08745Sheppo /* -------------------------------------------------------------------------- */ 18061ae08745Sheppo 18071ae08745Sheppo /* 18081ae08745Sheppo * LDC helper routines 18091ae08745Sheppo */ 18101ae08745Sheppo 18113af08d82Slm66018 static int 18123af08d82Slm66018 vdc_recv(vdc_t *vdc, vio_msg_t *msgp, size_t *nbytesp) 18133af08d82Slm66018 { 18143af08d82Slm66018 int status; 18153af08d82Slm66018 boolean_t q_has_pkts = B_FALSE; 18163af08d82Slm66018 int delay_time; 18173af08d82Slm66018 size_t len; 18183af08d82Slm66018 18193af08d82Slm66018 mutex_enter(&vdc->read_lock); 18203af08d82Slm66018 18213af08d82Slm66018 if (vdc->read_state == VDC_READ_IDLE) 18223af08d82Slm66018 vdc->read_state = VDC_READ_WAITING; 18233af08d82Slm66018 18243af08d82Slm66018 while (vdc->read_state != VDC_READ_PENDING) { 18253af08d82Slm66018 18263af08d82Slm66018 /* detect if the connection has been reset */ 18273af08d82Slm66018 if (vdc->read_state == VDC_READ_RESET) { 18283af08d82Slm66018 status = ECONNRESET; 18293af08d82Slm66018 goto done; 18303af08d82Slm66018 } 18313af08d82Slm66018 18323af08d82Slm66018 cv_wait(&vdc->read_cv, &vdc->read_lock); 18333af08d82Slm66018 } 18343af08d82Slm66018 18353af08d82Slm66018 /* 18363af08d82Slm66018 * Until we get a blocking ldc read we have to retry 18373af08d82Slm66018 * until the entire LDC message has arrived before 18383af08d82Slm66018 * ldc_read() will succeed. Note we also bail out if 1839eff7243fSlm66018 * the channel is reset or goes away. 18403af08d82Slm66018 */ 18413af08d82Slm66018 delay_time = vdc_ldc_read_init_delay; 18423af08d82Slm66018 loop: 18433af08d82Slm66018 len = *nbytesp; 18443af08d82Slm66018 status = ldc_read(vdc->ldc_handle, (caddr_t)msgp, &len); 18453af08d82Slm66018 switch (status) { 18463af08d82Slm66018 case EAGAIN: 18473af08d82Slm66018 delay_time *= 2; 18483af08d82Slm66018 if (delay_time >= vdc_ldc_read_max_delay) 18493af08d82Slm66018 delay_time = vdc_ldc_read_max_delay; 18503af08d82Slm66018 delay(delay_time); 18513af08d82Slm66018 goto loop; 18523af08d82Slm66018 18533af08d82Slm66018 case 0: 18543af08d82Slm66018 if (len == 0) { 18553af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_read returned 0 bytes with " 18563af08d82Slm66018 "no error!\n", vdc->instance); 18573af08d82Slm66018 goto loop; 18583af08d82Slm66018 } 18593af08d82Slm66018 18603af08d82Slm66018 *nbytesp = len; 18613af08d82Slm66018 18623af08d82Slm66018 /* 18633af08d82Slm66018 * If there are pending messages, leave the 18643af08d82Slm66018 * read state as pending. Otherwise, set the state 18653af08d82Slm66018 * back to idle. 18663af08d82Slm66018 */ 18673af08d82Slm66018 status = ldc_chkq(vdc->ldc_handle, &q_has_pkts); 18683af08d82Slm66018 if (status == 0 && !q_has_pkts) 18693af08d82Slm66018 vdc->read_state = VDC_READ_IDLE; 18703af08d82Slm66018 18713af08d82Slm66018 break; 18723af08d82Slm66018 default: 18733af08d82Slm66018 DMSG(vdc, 0, "ldc_read returned %d\n", status); 18743af08d82Slm66018 break; 18753af08d82Slm66018 } 18763af08d82Slm66018 18773af08d82Slm66018 done: 18783af08d82Slm66018 mutex_exit(&vdc->read_lock); 18793af08d82Slm66018 18803af08d82Slm66018 return (status); 18813af08d82Slm66018 } 18823af08d82Slm66018 18833af08d82Slm66018 18843af08d82Slm66018 18853af08d82Slm66018 #ifdef DEBUG 18863af08d82Slm66018 void 18873af08d82Slm66018 vdc_decode_tag(vdc_t *vdcp, vio_msg_t *msg) 18883af08d82Slm66018 { 18893af08d82Slm66018 char *ms, *ss, *ses; 18903af08d82Slm66018 switch (msg->tag.vio_msgtype) { 18913af08d82Slm66018 #define Q(_s) case _s : ms = #_s; break; 18923af08d82Slm66018 Q(VIO_TYPE_CTRL) 18933af08d82Slm66018 Q(VIO_TYPE_DATA) 18943af08d82Slm66018 Q(VIO_TYPE_ERR) 18953af08d82Slm66018 #undef Q 18963af08d82Slm66018 default: ms = "unknown"; break; 18973af08d82Slm66018 } 18983af08d82Slm66018 18993af08d82Slm66018 switch (msg->tag.vio_subtype) { 19003af08d82Slm66018 #define Q(_s) case _s : ss = #_s; break; 19013af08d82Slm66018 Q(VIO_SUBTYPE_INFO) 19023af08d82Slm66018 Q(VIO_SUBTYPE_ACK) 19033af08d82Slm66018 Q(VIO_SUBTYPE_NACK) 19043af08d82Slm66018 #undef Q 19053af08d82Slm66018 default: ss = "unknown"; break; 19063af08d82Slm66018 } 19073af08d82Slm66018 19083af08d82Slm66018 switch (msg->tag.vio_subtype_env) { 19093af08d82Slm66018 #define Q(_s) case _s : ses = #_s; break; 19103af08d82Slm66018 Q(VIO_VER_INFO) 19113af08d82Slm66018 Q(VIO_ATTR_INFO) 19123af08d82Slm66018 Q(VIO_DRING_REG) 19133af08d82Slm66018 Q(VIO_DRING_UNREG) 19143af08d82Slm66018 Q(VIO_RDX) 19153af08d82Slm66018 Q(VIO_PKT_DATA) 19163af08d82Slm66018 Q(VIO_DESC_DATA) 19173af08d82Slm66018 Q(VIO_DRING_DATA) 19183af08d82Slm66018 #undef Q 19193af08d82Slm66018 default: ses = "unknown"; break; 19203af08d82Slm66018 } 19213af08d82Slm66018 19223af08d82Slm66018 DMSG(vdcp, 3, "(%x/%x/%x) message : (%s/%s/%s)\n", 19233af08d82Slm66018 msg->tag.vio_msgtype, msg->tag.vio_subtype, 19243af08d82Slm66018 msg->tag.vio_subtype_env, ms, ss, ses); 19253af08d82Slm66018 } 19263af08d82Slm66018 #endif 19273af08d82Slm66018 19281ae08745Sheppo /* 19291ae08745Sheppo * Function: 19301ae08745Sheppo * vdc_send() 19311ae08745Sheppo * 19321ae08745Sheppo * Description: 19331ae08745Sheppo * The function encapsulates the call to write a message using LDC. 19341ae08745Sheppo * If LDC indicates that the call failed due to the queue being full, 19351ae08745Sheppo * we retry the ldc_write() [ up to 'vdc_retries' time ], otherwise 19361ae08745Sheppo * we return the error returned by LDC. 19371ae08745Sheppo * 19381ae08745Sheppo * Arguments: 19391ae08745Sheppo * ldc_handle - LDC handle for the channel this instance of vdc uses 19401ae08745Sheppo * pkt - address of LDC message to be sent 19411ae08745Sheppo * msglen - the size of the message being sent. When the function 19421ae08745Sheppo * returns, this contains the number of bytes written. 19431ae08745Sheppo * 19441ae08745Sheppo * Return Code: 19451ae08745Sheppo * 0 - Success. 19461ae08745Sheppo * EINVAL - pkt or msglen were NULL 19471ae08745Sheppo * ECONNRESET - The connection was not up. 19481ae08745Sheppo * EWOULDBLOCK - LDC queue is full 19491ae08745Sheppo * xxx - other error codes returned by ldc_write 19501ae08745Sheppo */ 19511ae08745Sheppo static int 19520a55fbb7Slm66018 vdc_send(vdc_t *vdc, caddr_t pkt, size_t *msglen) 19531ae08745Sheppo { 19541ae08745Sheppo size_t size = 0; 19551ae08745Sheppo int status = 0; 19563af08d82Slm66018 clock_t delay_ticks; 19571ae08745Sheppo 19580a55fbb7Slm66018 ASSERT(vdc != NULL); 19590a55fbb7Slm66018 ASSERT(mutex_owned(&vdc->lock)); 19601ae08745Sheppo ASSERT(msglen != NULL); 19611ae08745Sheppo ASSERT(*msglen != 0); 19621ae08745Sheppo 19633af08d82Slm66018 #ifdef DEBUG 19643af08d82Slm66018 vdc_decode_tag(vdc, (vio_msg_t *)pkt); 19653af08d82Slm66018 #endif 19663af08d82Slm66018 /* 19673af08d82Slm66018 * Wait indefinitely to send if channel 19683af08d82Slm66018 * is busy, but bail out if we succeed or 19693af08d82Slm66018 * if the channel closes or is reset. 19703af08d82Slm66018 */ 19713af08d82Slm66018 delay_ticks = vdc_hz_min_ldc_delay; 19721ae08745Sheppo do { 19731ae08745Sheppo size = *msglen; 19740a55fbb7Slm66018 status = ldc_write(vdc->ldc_handle, pkt, &size); 19753af08d82Slm66018 if (status == EWOULDBLOCK) { 19763af08d82Slm66018 delay(delay_ticks); 19773af08d82Slm66018 /* geometric backoff */ 19783af08d82Slm66018 delay_ticks *= 2; 19793af08d82Slm66018 if (delay_ticks > vdc_hz_max_ldc_delay) 19803af08d82Slm66018 delay_ticks = vdc_hz_max_ldc_delay; 19813af08d82Slm66018 } 19823af08d82Slm66018 } while (status == EWOULDBLOCK); 19831ae08745Sheppo 19840a55fbb7Slm66018 /* if LDC had serious issues --- reset vdc state */ 19850a55fbb7Slm66018 if (status == EIO || status == ECONNRESET) { 19863af08d82Slm66018 /* LDC had serious issues --- reset vdc state */ 19873af08d82Slm66018 mutex_enter(&vdc->read_lock); 19883af08d82Slm66018 if ((vdc->read_state == VDC_READ_WAITING) || 19893af08d82Slm66018 (vdc->read_state == VDC_READ_RESET)) 19903af08d82Slm66018 cv_signal(&vdc->read_cv); 19913af08d82Slm66018 vdc->read_state = VDC_READ_RESET; 19923af08d82Slm66018 mutex_exit(&vdc->read_lock); 19933af08d82Slm66018 19943af08d82Slm66018 /* wake up any waiters in the reset thread */ 19953af08d82Slm66018 if (vdc->state == VDC_STATE_INIT_WAITING) { 19963af08d82Slm66018 DMSG(vdc, 0, "[%d] write reset - " 19973af08d82Slm66018 "vdc is resetting ..\n", vdc->instance); 19983af08d82Slm66018 vdc->state = VDC_STATE_RESETTING; 19993af08d82Slm66018 cv_signal(&vdc->initwait_cv); 20003af08d82Slm66018 } 20013af08d82Slm66018 20023af08d82Slm66018 return (ECONNRESET); 20030a55fbb7Slm66018 } 20040a55fbb7Slm66018 20051ae08745Sheppo /* return the last size written */ 20061ae08745Sheppo *msglen = size; 20071ae08745Sheppo 20081ae08745Sheppo return (status); 20091ae08745Sheppo } 20101ae08745Sheppo 20111ae08745Sheppo /* 20121ae08745Sheppo * Function: 2013655fd6a9Sachartre * vdc_get_md_node 20141ae08745Sheppo * 20151ae08745Sheppo * Description: 2016655fd6a9Sachartre * Get the MD, the device node and the port node for the given 2017655fd6a9Sachartre * disk instance. The caller is responsible for cleaning up the 2018655fd6a9Sachartre * reference to the returned MD (mdpp) by calling md_fini_handle(). 20191ae08745Sheppo * 20201ae08745Sheppo * Arguments: 20211ae08745Sheppo * dip - dev info pointer for this instance of the device driver. 2022655fd6a9Sachartre * mdpp - the returned MD. 2023655fd6a9Sachartre * vd_nodep - the returned device node. 2024655fd6a9Sachartre * vd_portp - the returned port node. The returned port node is NULL 2025655fd6a9Sachartre * if no port node is found. 20261ae08745Sheppo * 20271ae08745Sheppo * Return Code: 20281ae08745Sheppo * 0 - Success. 20291ae08745Sheppo * ENOENT - Expected node or property did not exist. 20301ae08745Sheppo * ENXIO - Unexpected error communicating with MD framework 20311ae08745Sheppo */ 20321ae08745Sheppo static int 2033655fd6a9Sachartre vdc_get_md_node(dev_info_t *dip, md_t **mdpp, mde_cookie_t *vd_nodep, 2034655fd6a9Sachartre mde_cookie_t *vd_portp) 20351ae08745Sheppo { 20361ae08745Sheppo int status = ENOENT; 20371ae08745Sheppo char *node_name = NULL; 20381ae08745Sheppo md_t *mdp = NULL; 20391ae08745Sheppo int num_nodes; 20401ae08745Sheppo int num_vdevs; 2041655fd6a9Sachartre int num_vports; 20421ae08745Sheppo mde_cookie_t rootnode; 20431ae08745Sheppo mde_cookie_t *listp = NULL; 20441ae08745Sheppo boolean_t found_inst = B_FALSE; 20451ae08745Sheppo int listsz; 20461ae08745Sheppo int idx; 20471ae08745Sheppo uint64_t md_inst; 20481ae08745Sheppo int obp_inst; 20491ae08745Sheppo int instance = ddi_get_instance(dip); 20501ae08745Sheppo 20511ae08745Sheppo /* 20521ae08745Sheppo * Get the OBP instance number for comparison with the MD instance 20531ae08745Sheppo * 20541ae08745Sheppo * The "cfg-handle" property of a vdc node in an MD contains the MD's 20551ae08745Sheppo * notion of "instance", or unique identifier, for that node; OBP 20561ae08745Sheppo * stores the value of the "cfg-handle" MD property as the value of 20571ae08745Sheppo * the "reg" property on the node in the device tree it builds from 20581ae08745Sheppo * the MD and passes to Solaris. Thus, we look up the devinfo node's 20591ae08745Sheppo * "reg" property value to uniquely identify this device instance. 20601ae08745Sheppo * If the "reg" property cannot be found, the device tree state is 20611ae08745Sheppo * presumably so broken that there is no point in continuing. 20621ae08745Sheppo */ 20631ae08745Sheppo if (!ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, OBP_REG)) { 20641ae08745Sheppo cmn_err(CE_WARN, "'%s' property does not exist", OBP_REG); 20651ae08745Sheppo return (ENOENT); 20661ae08745Sheppo } 20671ae08745Sheppo obp_inst = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 20681ae08745Sheppo OBP_REG, -1); 20693af08d82Slm66018 DMSGX(1, "[%d] OBP inst=%d\n", instance, obp_inst); 20701ae08745Sheppo 20711ae08745Sheppo /* 2072655fd6a9Sachartre * We now walk the MD nodes to find the node for this vdisk. 20731ae08745Sheppo */ 20741ae08745Sheppo if ((mdp = md_get_handle()) == NULL) { 20751ae08745Sheppo cmn_err(CE_WARN, "unable to init machine description"); 20761ae08745Sheppo return (ENXIO); 20771ae08745Sheppo } 20781ae08745Sheppo 20791ae08745Sheppo num_nodes = md_node_count(mdp); 20801ae08745Sheppo ASSERT(num_nodes > 0); 20811ae08745Sheppo 20821ae08745Sheppo listsz = num_nodes * sizeof (mde_cookie_t); 20831ae08745Sheppo 20841ae08745Sheppo /* allocate memory for nodes */ 20851ae08745Sheppo listp = kmem_zalloc(listsz, KM_SLEEP); 20861ae08745Sheppo 20871ae08745Sheppo rootnode = md_root_node(mdp); 20881ae08745Sheppo ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE); 20891ae08745Sheppo 20901ae08745Sheppo /* 20911ae08745Sheppo * Search for all the virtual devices, we will then check to see which 20921ae08745Sheppo * ones are disk nodes. 20931ae08745Sheppo */ 20941ae08745Sheppo num_vdevs = md_scan_dag(mdp, rootnode, 20951ae08745Sheppo md_find_name(mdp, VDC_MD_VDEV_NAME), 20961ae08745Sheppo md_find_name(mdp, "fwd"), listp); 20971ae08745Sheppo 20981ae08745Sheppo if (num_vdevs <= 0) { 20991ae08745Sheppo cmn_err(CE_NOTE, "No '%s' node found", VDC_MD_VDEV_NAME); 21001ae08745Sheppo status = ENOENT; 21011ae08745Sheppo goto done; 21021ae08745Sheppo } 21031ae08745Sheppo 21043af08d82Slm66018 DMSGX(1, "[%d] num_vdevs=%d\n", instance, num_vdevs); 21051ae08745Sheppo for (idx = 0; idx < num_vdevs; idx++) { 21061ae08745Sheppo status = md_get_prop_str(mdp, listp[idx], "name", &node_name); 21071ae08745Sheppo if ((status != 0) || (node_name == NULL)) { 21081ae08745Sheppo cmn_err(CE_NOTE, "Unable to get name of node type '%s'" 21091ae08745Sheppo ": err %d", VDC_MD_VDEV_NAME, status); 21101ae08745Sheppo continue; 21111ae08745Sheppo } 21121ae08745Sheppo 21133af08d82Slm66018 DMSGX(1, "[%d] Found node '%s'\n", instance, node_name); 21141ae08745Sheppo if (strcmp(VDC_MD_DISK_NAME, node_name) == 0) { 21151ae08745Sheppo status = md_get_prop_val(mdp, listp[idx], 21161ae08745Sheppo VDC_MD_CFG_HDL, &md_inst); 21173af08d82Slm66018 DMSGX(1, "[%d] vdc inst in MD=%lx\n", 21183af08d82Slm66018 instance, md_inst); 21191ae08745Sheppo if ((status == 0) && (md_inst == obp_inst)) { 21201ae08745Sheppo found_inst = B_TRUE; 21211ae08745Sheppo break; 21221ae08745Sheppo } 21231ae08745Sheppo } 21241ae08745Sheppo } 21251ae08745Sheppo 21260a55fbb7Slm66018 if (!found_inst) { 21273af08d82Slm66018 DMSGX(0, "Unable to find correct '%s' node", VDC_MD_DISK_NAME); 21281ae08745Sheppo status = ENOENT; 21291ae08745Sheppo goto done; 21301ae08745Sheppo } 21313af08d82Slm66018 DMSGX(0, "[%d] MD inst=%lx\n", instance, md_inst); 21321ae08745Sheppo 2133655fd6a9Sachartre *vd_nodep = listp[idx]; 2134655fd6a9Sachartre *mdpp = mdp; 2135655fd6a9Sachartre 2136655fd6a9Sachartre num_vports = md_scan_dag(mdp, *vd_nodep, 2137655fd6a9Sachartre md_find_name(mdp, VDC_MD_PORT_NAME), 2138655fd6a9Sachartre md_find_name(mdp, "fwd"), listp); 2139655fd6a9Sachartre 2140655fd6a9Sachartre if (num_vports != 1) { 2141655fd6a9Sachartre DMSGX(0, "Expected 1 '%s' node for '%s' port, found %d\n", 2142655fd6a9Sachartre VDC_MD_PORT_NAME, VDC_MD_VDEV_NAME, num_vports); 2143655fd6a9Sachartre } 2144655fd6a9Sachartre 2145655fd6a9Sachartre *vd_portp = (num_vports == 0)? NULL: listp[0]; 2146655fd6a9Sachartre 2147655fd6a9Sachartre done: 2148655fd6a9Sachartre kmem_free(listp, listsz); 2149655fd6a9Sachartre return (status); 2150655fd6a9Sachartre } 2151655fd6a9Sachartre 2152655fd6a9Sachartre /* 2153655fd6a9Sachartre * Function: 2154655fd6a9Sachartre * vdc_get_ldc_id() 2155655fd6a9Sachartre * 2156655fd6a9Sachartre * Description: 2157655fd6a9Sachartre * This function gets the 'ldc-id' for this particular instance of vdc. 2158655fd6a9Sachartre * The id returned is the guest domain channel endpoint LDC uses for 2159655fd6a9Sachartre * communication with vds. 2160655fd6a9Sachartre * 2161655fd6a9Sachartre * Arguments: 2162655fd6a9Sachartre * mdp - pointer to the machine description. 2163655fd6a9Sachartre * vd_node - the vdisk element from the MD. 2164655fd6a9Sachartre * ldc_id - pointer to variable used to return the 'ldc-id' found. 2165655fd6a9Sachartre * 2166655fd6a9Sachartre * Return Code: 2167655fd6a9Sachartre * 0 - Success. 2168655fd6a9Sachartre * ENOENT - Expected node or property did not exist. 2169655fd6a9Sachartre */ 2170655fd6a9Sachartre static int 2171655fd6a9Sachartre vdc_get_ldc_id(md_t *mdp, mde_cookie_t vd_node, uint64_t *ldc_id) 2172655fd6a9Sachartre { 2173655fd6a9Sachartre mde_cookie_t *chanp = NULL; 2174655fd6a9Sachartre int listsz; 2175655fd6a9Sachartre int num_chans; 2176655fd6a9Sachartre int num_nodes; 2177655fd6a9Sachartre int status = 0; 2178655fd6a9Sachartre 2179655fd6a9Sachartre num_nodes = md_node_count(mdp); 2180655fd6a9Sachartre ASSERT(num_nodes > 0); 2181655fd6a9Sachartre 2182655fd6a9Sachartre listsz = num_nodes * sizeof (mde_cookie_t); 2183655fd6a9Sachartre 2184655fd6a9Sachartre /* allocate memory for nodes */ 2185655fd6a9Sachartre chanp = kmem_zalloc(listsz, KM_SLEEP); 2186655fd6a9Sachartre 21871ae08745Sheppo /* get the channels for this node */ 2188655fd6a9Sachartre num_chans = md_scan_dag(mdp, vd_node, 21891ae08745Sheppo md_find_name(mdp, VDC_MD_CHAN_NAME), 21901ae08745Sheppo md_find_name(mdp, "fwd"), chanp); 21911ae08745Sheppo 21921ae08745Sheppo /* expecting at least one channel */ 21931ae08745Sheppo if (num_chans <= 0) { 21941ae08745Sheppo cmn_err(CE_NOTE, "No '%s' node for '%s' port", 21951ae08745Sheppo VDC_MD_CHAN_NAME, VDC_MD_VDEV_NAME); 21961ae08745Sheppo status = ENOENT; 21971ae08745Sheppo goto done; 21981ae08745Sheppo 21991ae08745Sheppo } else if (num_chans != 1) { 2200655fd6a9Sachartre DMSGX(0, "Expected 1 '%s' node for '%s' port, found %d\n", 2201655fd6a9Sachartre VDC_MD_CHAN_NAME, VDC_MD_VDEV_NAME, num_chans); 22021ae08745Sheppo } 22031ae08745Sheppo 22041ae08745Sheppo /* 22051ae08745Sheppo * We use the first channel found (index 0), irrespective of how 22061ae08745Sheppo * many are there in total. 22071ae08745Sheppo */ 2208655fd6a9Sachartre if (md_get_prop_val(mdp, chanp[0], VDC_MD_ID, ldc_id) != 0) { 2209655fd6a9Sachartre cmn_err(CE_NOTE, "Channel '%s' property not found", VDC_MD_ID); 22101ae08745Sheppo status = ENOENT; 22111ae08745Sheppo } 22121ae08745Sheppo 22131ae08745Sheppo done: 22141ae08745Sheppo kmem_free(chanp, listsz); 22151ae08745Sheppo return (status); 22161ae08745Sheppo } 22171ae08745Sheppo 22180a55fbb7Slm66018 static int 22190a55fbb7Slm66018 vdc_do_ldc_up(vdc_t *vdc) 22200a55fbb7Slm66018 { 22210a55fbb7Slm66018 int status; 22223af08d82Slm66018 ldc_status_t ldc_state; 22230a55fbb7Slm66018 22243af08d82Slm66018 DMSG(vdc, 0, "[%d] Bringing up channel %lx\n", 22253af08d82Slm66018 vdc->instance, vdc->ldc_id); 22263af08d82Slm66018 22273af08d82Slm66018 if (vdc->lifecycle == VDC_LC_DETACHING) 22283af08d82Slm66018 return (EINVAL); 22290a55fbb7Slm66018 22300a55fbb7Slm66018 if ((status = ldc_up(vdc->ldc_handle)) != 0) { 22310a55fbb7Slm66018 switch (status) { 22320a55fbb7Slm66018 case ECONNREFUSED: /* listener not ready at other end */ 22333af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_up(%lx,...) return %d\n", 2234e1ebb9ecSlm66018 vdc->instance, vdc->ldc_id, status); 22350a55fbb7Slm66018 status = 0; 22360a55fbb7Slm66018 break; 22370a55fbb7Slm66018 default: 22383af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to bring up LDC: " 22393af08d82Slm66018 "channel=%ld, err=%d", vdc->instance, vdc->ldc_id, 22403af08d82Slm66018 status); 22413af08d82Slm66018 break; 22423af08d82Slm66018 } 22433af08d82Slm66018 } 22443af08d82Slm66018 22453af08d82Slm66018 if (ldc_status(vdc->ldc_handle, &ldc_state) == 0) { 22463af08d82Slm66018 vdc->ldc_state = ldc_state; 22473af08d82Slm66018 if (ldc_state == LDC_UP) { 22483af08d82Slm66018 DMSG(vdc, 0, "[%d] LDC channel already up\n", 22493af08d82Slm66018 vdc->instance); 22503af08d82Slm66018 vdc->seq_num = 1; 22513af08d82Slm66018 vdc->seq_num_reply = 0; 22520a55fbb7Slm66018 } 22530a55fbb7Slm66018 } 22540a55fbb7Slm66018 22550a55fbb7Slm66018 return (status); 22560a55fbb7Slm66018 } 22570a55fbb7Slm66018 22580a55fbb7Slm66018 /* 22590a55fbb7Slm66018 * Function: 22600a55fbb7Slm66018 * vdc_terminate_ldc() 22610a55fbb7Slm66018 * 22620a55fbb7Slm66018 * Description: 22630a55fbb7Slm66018 * 22640a55fbb7Slm66018 * Arguments: 22650a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 22660a55fbb7Slm66018 * 22670a55fbb7Slm66018 * Return Code: 22680a55fbb7Slm66018 * None 22690a55fbb7Slm66018 */ 22701ae08745Sheppo static void 22711ae08745Sheppo vdc_terminate_ldc(vdc_t *vdc) 22721ae08745Sheppo { 22731ae08745Sheppo int instance = ddi_get_instance(vdc->dip); 22741ae08745Sheppo 22751ae08745Sheppo ASSERT(vdc != NULL); 22761ae08745Sheppo ASSERT(mutex_owned(&vdc->lock)); 22771ae08745Sheppo 22783af08d82Slm66018 DMSG(vdc, 0, "[%d] initialized=%x\n", instance, vdc->initialized); 22791ae08745Sheppo 22801ae08745Sheppo if (vdc->initialized & VDC_LDC_OPEN) { 22813af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_close()\n", instance); 22821ae08745Sheppo (void) ldc_close(vdc->ldc_handle); 22831ae08745Sheppo } 22841ae08745Sheppo if (vdc->initialized & VDC_LDC_CB) { 22853af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_unreg_callback()\n", instance); 22861ae08745Sheppo (void) ldc_unreg_callback(vdc->ldc_handle); 22871ae08745Sheppo } 22881ae08745Sheppo if (vdc->initialized & VDC_LDC) { 22893af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_fini()\n", instance); 22901ae08745Sheppo (void) ldc_fini(vdc->ldc_handle); 22911ae08745Sheppo vdc->ldc_handle = NULL; 22921ae08745Sheppo } 22931ae08745Sheppo 22941ae08745Sheppo vdc->initialized &= ~(VDC_LDC | VDC_LDC_CB | VDC_LDC_OPEN); 22951ae08745Sheppo } 22961ae08745Sheppo 22971ae08745Sheppo /* -------------------------------------------------------------------------- */ 22981ae08745Sheppo 22991ae08745Sheppo /* 23001ae08745Sheppo * Descriptor Ring helper routines 23011ae08745Sheppo */ 23021ae08745Sheppo 23030a55fbb7Slm66018 /* 23040a55fbb7Slm66018 * Function: 23050a55fbb7Slm66018 * vdc_init_descriptor_ring() 23060a55fbb7Slm66018 * 23070a55fbb7Slm66018 * Description: 23080a55fbb7Slm66018 * 23090a55fbb7Slm66018 * Arguments: 23100a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 23110a55fbb7Slm66018 * 23120a55fbb7Slm66018 * Return Code: 23130a55fbb7Slm66018 * 0 - Success 23140a55fbb7Slm66018 */ 23151ae08745Sheppo static int 23161ae08745Sheppo vdc_init_descriptor_ring(vdc_t *vdc) 23171ae08745Sheppo { 23181ae08745Sheppo vd_dring_entry_t *dep = NULL; /* DRing Entry pointer */ 23190a55fbb7Slm66018 int status = 0; 23201ae08745Sheppo int i; 23211ae08745Sheppo 23223af08d82Slm66018 DMSG(vdc, 0, "[%d] initialized=%x\n", vdc->instance, vdc->initialized); 23231ae08745Sheppo 23241ae08745Sheppo ASSERT(vdc != NULL); 23251ae08745Sheppo ASSERT(mutex_owned(&vdc->lock)); 23261ae08745Sheppo ASSERT(vdc->ldc_handle != NULL); 23271ae08745Sheppo 2328e1ebb9ecSlm66018 /* ensure we have enough room to store max sized block */ 2329e1ebb9ecSlm66018 ASSERT(maxphys <= VD_MAX_BLOCK_SIZE); 2330e1ebb9ecSlm66018 23310a55fbb7Slm66018 if ((vdc->initialized & VDC_DRING_INIT) == 0) { 23323af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_mem_dring_create\n", vdc->instance); 2333e1ebb9ecSlm66018 /* 2334e1ebb9ecSlm66018 * Calculate the maximum block size we can transmit using one 2335e1ebb9ecSlm66018 * Descriptor Ring entry from the attributes returned by the 2336e1ebb9ecSlm66018 * vDisk server. This is subject to a minimum of 'maxphys' 2337e1ebb9ecSlm66018 * as we do not have the capability to split requests over 2338e1ebb9ecSlm66018 * multiple DRing entries. 2339e1ebb9ecSlm66018 */ 2340e1ebb9ecSlm66018 if ((vdc->max_xfer_sz * vdc->block_size) < maxphys) { 23413af08d82Slm66018 DMSG(vdc, 0, "[%d] using minimum DRing size\n", 2342e1ebb9ecSlm66018 vdc->instance); 2343e1ebb9ecSlm66018 vdc->dring_max_cookies = maxphys / PAGESIZE; 2344e1ebb9ecSlm66018 } else { 2345e1ebb9ecSlm66018 vdc->dring_max_cookies = 2346e1ebb9ecSlm66018 (vdc->max_xfer_sz * vdc->block_size) / PAGESIZE; 2347e1ebb9ecSlm66018 } 2348e1ebb9ecSlm66018 vdc->dring_entry_size = (sizeof (vd_dring_entry_t) + 2349e1ebb9ecSlm66018 (sizeof (ldc_mem_cookie_t) * 2350e1ebb9ecSlm66018 (vdc->dring_max_cookies - 1))); 2351e1ebb9ecSlm66018 vdc->dring_len = VD_DRING_LEN; 2352e1ebb9ecSlm66018 2353e1ebb9ecSlm66018 status = ldc_mem_dring_create(vdc->dring_len, 2354e1ebb9ecSlm66018 vdc->dring_entry_size, &vdc->ldc_dring_hdl); 23551ae08745Sheppo if ((vdc->ldc_dring_hdl == NULL) || (status != 0)) { 23563af08d82Slm66018 DMSG(vdc, 0, "[%d] Descriptor ring creation failed", 2357e1ebb9ecSlm66018 vdc->instance); 23581ae08745Sheppo return (status); 23591ae08745Sheppo } 23600a55fbb7Slm66018 vdc->initialized |= VDC_DRING_INIT; 23610a55fbb7Slm66018 } 23621ae08745Sheppo 23630a55fbb7Slm66018 if ((vdc->initialized & VDC_DRING_BOUND) == 0) { 23643af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_mem_dring_bind\n", vdc->instance); 23650a55fbb7Slm66018 vdc->dring_cookie = 23660a55fbb7Slm66018 kmem_zalloc(sizeof (ldc_mem_cookie_t), KM_SLEEP); 23671ae08745Sheppo 23681ae08745Sheppo status = ldc_mem_dring_bind(vdc->ldc_handle, vdc->ldc_dring_hdl, 23694bac2208Snarayan LDC_SHADOW_MAP|LDC_DIRECT_MAP, LDC_MEM_RW, 23700a55fbb7Slm66018 &vdc->dring_cookie[0], 23711ae08745Sheppo &vdc->dring_cookie_count); 23721ae08745Sheppo if (status != 0) { 23733af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to bind descriptor ring " 23743af08d82Slm66018 "(%lx) to channel (%lx) status=%d\n", 23753af08d82Slm66018 vdc->instance, vdc->ldc_dring_hdl, 23763af08d82Slm66018 vdc->ldc_handle, status); 23771ae08745Sheppo return (status); 23781ae08745Sheppo } 23791ae08745Sheppo ASSERT(vdc->dring_cookie_count == 1); 23801ae08745Sheppo vdc->initialized |= VDC_DRING_BOUND; 23810a55fbb7Slm66018 } 23821ae08745Sheppo 23831ae08745Sheppo status = ldc_mem_dring_info(vdc->ldc_dring_hdl, &vdc->dring_mem_info); 23841ae08745Sheppo if (status != 0) { 23853af08d82Slm66018 DMSG(vdc, 0, 23863af08d82Slm66018 "[%d] Failed to get info for descriptor ring (%lx)\n", 2387e1ebb9ecSlm66018 vdc->instance, vdc->ldc_dring_hdl); 23881ae08745Sheppo return (status); 23891ae08745Sheppo } 23901ae08745Sheppo 23910a55fbb7Slm66018 if ((vdc->initialized & VDC_DRING_LOCAL) == 0) { 23923af08d82Slm66018 DMSG(vdc, 0, "[%d] local dring\n", vdc->instance); 23930a55fbb7Slm66018 23941ae08745Sheppo /* Allocate the local copy of this dring */ 23950a55fbb7Slm66018 vdc->local_dring = 2396e1ebb9ecSlm66018 kmem_zalloc(vdc->dring_len * sizeof (vdc_local_desc_t), 23971ae08745Sheppo KM_SLEEP); 23981ae08745Sheppo vdc->initialized |= VDC_DRING_LOCAL; 23990a55fbb7Slm66018 } 24001ae08745Sheppo 24011ae08745Sheppo /* 24020a55fbb7Slm66018 * Mark all DRing entries as free and initialize the private 24030a55fbb7Slm66018 * descriptor's memory handles. If any entry is initialized, 24040a55fbb7Slm66018 * we need to free it later so we set the bit in 'initialized' 24050a55fbb7Slm66018 * at the start. 24061ae08745Sheppo */ 24071ae08745Sheppo vdc->initialized |= VDC_DRING_ENTRY; 2408e1ebb9ecSlm66018 for (i = 0; i < vdc->dring_len; i++) { 24091ae08745Sheppo dep = VDC_GET_DRING_ENTRY_PTR(vdc, i); 24101ae08745Sheppo dep->hdr.dstate = VIO_DESC_FREE; 24111ae08745Sheppo 24121ae08745Sheppo status = ldc_mem_alloc_handle(vdc->ldc_handle, 24131ae08745Sheppo &vdc->local_dring[i].desc_mhdl); 24141ae08745Sheppo if (status != 0) { 24153af08d82Slm66018 DMSG(vdc, 0, "![%d] Failed to alloc mem handle for" 24161ae08745Sheppo " descriptor %d", vdc->instance, i); 24171ae08745Sheppo return (status); 24181ae08745Sheppo } 24193af08d82Slm66018 vdc->local_dring[i].is_free = B_TRUE; 24201ae08745Sheppo vdc->local_dring[i].dep = dep; 24211ae08745Sheppo } 24221ae08745Sheppo 24233af08d82Slm66018 /* Initialize the starting index */ 24243af08d82Slm66018 vdc->dring_curr_idx = 0; 24251ae08745Sheppo 24261ae08745Sheppo return (status); 24271ae08745Sheppo } 24281ae08745Sheppo 24290a55fbb7Slm66018 /* 24300a55fbb7Slm66018 * Function: 24310a55fbb7Slm66018 * vdc_destroy_descriptor_ring() 24320a55fbb7Slm66018 * 24330a55fbb7Slm66018 * Description: 24340a55fbb7Slm66018 * 24350a55fbb7Slm66018 * Arguments: 24360a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 24370a55fbb7Slm66018 * 24380a55fbb7Slm66018 * Return Code: 24390a55fbb7Slm66018 * None 24400a55fbb7Slm66018 */ 24411ae08745Sheppo static void 24421ae08745Sheppo vdc_destroy_descriptor_ring(vdc_t *vdc) 24431ae08745Sheppo { 24440a55fbb7Slm66018 vdc_local_desc_t *ldep = NULL; /* Local Dring Entry Pointer */ 24451ae08745Sheppo ldc_mem_handle_t mhdl = NULL; 24463af08d82Slm66018 ldc_mem_info_t minfo; 24471ae08745Sheppo int status = -1; 24481ae08745Sheppo int i; /* loop */ 24491ae08745Sheppo 24501ae08745Sheppo ASSERT(vdc != NULL); 24511ae08745Sheppo ASSERT(mutex_owned(&vdc->lock)); 24521ae08745Sheppo 24533af08d82Slm66018 DMSG(vdc, 0, "[%d] Entered\n", vdc->instance); 24541ae08745Sheppo 24551ae08745Sheppo if (vdc->initialized & VDC_DRING_ENTRY) { 24563af08d82Slm66018 DMSG(vdc, 0, 24573af08d82Slm66018 "[%d] Removing Local DRing entries\n", vdc->instance); 2458e1ebb9ecSlm66018 for (i = 0; i < vdc->dring_len; i++) { 24590a55fbb7Slm66018 ldep = &vdc->local_dring[i]; 24600a55fbb7Slm66018 mhdl = ldep->desc_mhdl; 24611ae08745Sheppo 24620a55fbb7Slm66018 if (mhdl == NULL) 24630a55fbb7Slm66018 continue; 24640a55fbb7Slm66018 24653af08d82Slm66018 if ((status = ldc_mem_info(mhdl, &minfo)) != 0) { 24663af08d82Slm66018 DMSG(vdc, 0, 24673af08d82Slm66018 "ldc_mem_info returned an error: %d\n", 24683af08d82Slm66018 status); 24693af08d82Slm66018 24703af08d82Slm66018 /* 24713af08d82Slm66018 * This must mean that the mem handle 24723af08d82Slm66018 * is not valid. Clear it out so that 24733af08d82Slm66018 * no one tries to use it. 24743af08d82Slm66018 */ 24753af08d82Slm66018 ldep->desc_mhdl = NULL; 24763af08d82Slm66018 continue; 24773af08d82Slm66018 } 24783af08d82Slm66018 24793af08d82Slm66018 if (minfo.status == LDC_BOUND) { 24803af08d82Slm66018 (void) ldc_mem_unbind_handle(mhdl); 24813af08d82Slm66018 } 24823af08d82Slm66018 24831ae08745Sheppo (void) ldc_mem_free_handle(mhdl); 24843af08d82Slm66018 24853af08d82Slm66018 ldep->desc_mhdl = NULL; 24861ae08745Sheppo } 24871ae08745Sheppo vdc->initialized &= ~VDC_DRING_ENTRY; 24881ae08745Sheppo } 24891ae08745Sheppo 24901ae08745Sheppo if (vdc->initialized & VDC_DRING_LOCAL) { 24913af08d82Slm66018 DMSG(vdc, 0, "[%d] Freeing Local DRing\n", vdc->instance); 24921ae08745Sheppo kmem_free(vdc->local_dring, 2493e1ebb9ecSlm66018 vdc->dring_len * sizeof (vdc_local_desc_t)); 24941ae08745Sheppo vdc->initialized &= ~VDC_DRING_LOCAL; 24951ae08745Sheppo } 24961ae08745Sheppo 24971ae08745Sheppo if (vdc->initialized & VDC_DRING_BOUND) { 24983af08d82Slm66018 DMSG(vdc, 0, "[%d] Unbinding DRing\n", vdc->instance); 24991ae08745Sheppo status = ldc_mem_dring_unbind(vdc->ldc_dring_hdl); 25001ae08745Sheppo if (status == 0) { 25011ae08745Sheppo vdc->initialized &= ~VDC_DRING_BOUND; 25021ae08745Sheppo } else { 25033af08d82Slm66018 DMSG(vdc, 0, "[%d] Error %d unbinding DRing %lx", 2504e1ebb9ecSlm66018 vdc->instance, status, vdc->ldc_dring_hdl); 25051ae08745Sheppo } 25063af08d82Slm66018 kmem_free(vdc->dring_cookie, sizeof (ldc_mem_cookie_t)); 25071ae08745Sheppo } 25081ae08745Sheppo 25091ae08745Sheppo if (vdc->initialized & VDC_DRING_INIT) { 25103af08d82Slm66018 DMSG(vdc, 0, "[%d] Destroying DRing\n", vdc->instance); 25111ae08745Sheppo status = ldc_mem_dring_destroy(vdc->ldc_dring_hdl); 25121ae08745Sheppo if (status == 0) { 25131ae08745Sheppo vdc->ldc_dring_hdl = NULL; 25141ae08745Sheppo bzero(&vdc->dring_mem_info, sizeof (ldc_mem_info_t)); 25151ae08745Sheppo vdc->initialized &= ~VDC_DRING_INIT; 25161ae08745Sheppo } else { 25173af08d82Slm66018 DMSG(vdc, 0, "[%d] Error %d destroying DRing (%lx)", 2518e1ebb9ecSlm66018 vdc->instance, status, vdc->ldc_dring_hdl); 25191ae08745Sheppo } 25201ae08745Sheppo } 25211ae08745Sheppo } 25221ae08745Sheppo 25231ae08745Sheppo /* 25243af08d82Slm66018 * Function: 25253af08d82Slm66018 * vdc_map_to_shared_ring() 25261ae08745Sheppo * 25271ae08745Sheppo * Description: 25283af08d82Slm66018 * Copy contents of the local descriptor to the shared 25293af08d82Slm66018 * memory descriptor. 25301ae08745Sheppo * 25313af08d82Slm66018 * Arguments: 25323af08d82Slm66018 * vdcp - soft state pointer for this instance of the device driver. 25333af08d82Slm66018 * idx - descriptor ring index 25343af08d82Slm66018 * 25353af08d82Slm66018 * Return Code: 25363af08d82Slm66018 * None 25371ae08745Sheppo */ 25381ae08745Sheppo static int 25393af08d82Slm66018 vdc_map_to_shared_dring(vdc_t *vdcp, int idx) 25401ae08745Sheppo { 25413af08d82Slm66018 vdc_local_desc_t *ldep; 25423af08d82Slm66018 vd_dring_entry_t *dep; 25433af08d82Slm66018 int rv; 25441ae08745Sheppo 25453af08d82Slm66018 ldep = &(vdcp->local_dring[idx]); 25461ae08745Sheppo 25473af08d82Slm66018 /* for now leave in the old pop_mem_hdl stuff */ 25483af08d82Slm66018 if (ldep->nbytes > 0) { 25493af08d82Slm66018 rv = vdc_populate_mem_hdl(vdcp, ldep); 25503af08d82Slm66018 if (rv) { 25513af08d82Slm66018 DMSG(vdcp, 0, "[%d] Cannot populate mem handle\n", 25523af08d82Slm66018 vdcp->instance); 25533af08d82Slm66018 return (rv); 25543af08d82Slm66018 } 25553af08d82Slm66018 } 25561ae08745Sheppo 25573af08d82Slm66018 /* 25583af08d82Slm66018 * fill in the data details into the DRing 25593af08d82Slm66018 */ 2560d10e4ef2Snarayan dep = ldep->dep; 25611ae08745Sheppo ASSERT(dep != NULL); 25621ae08745Sheppo 25633af08d82Slm66018 dep->payload.req_id = VDC_GET_NEXT_REQ_ID(vdcp); 25643af08d82Slm66018 dep->payload.operation = ldep->operation; 25653af08d82Slm66018 dep->payload.addr = ldep->offset; 25663af08d82Slm66018 dep->payload.nbytes = ldep->nbytes; 2567055d7c80Scarlsonj dep->payload.status = (uint32_t)-1; /* vds will set valid value */ 25683af08d82Slm66018 dep->payload.slice = ldep->slice; 25693af08d82Slm66018 dep->hdr.dstate = VIO_DESC_READY; 25703af08d82Slm66018 dep->hdr.ack = 1; /* request an ACK for every message */ 25711ae08745Sheppo 25723af08d82Slm66018 return (0); 25731ae08745Sheppo } 25741ae08745Sheppo 25751ae08745Sheppo /* 25761ae08745Sheppo * Function: 25773af08d82Slm66018 * vdc_send_request 25783af08d82Slm66018 * 25793af08d82Slm66018 * Description: 25803af08d82Slm66018 * This routine writes the data to be transmitted to vds into the 25813af08d82Slm66018 * descriptor, notifies vds that the ring has been updated and 25823af08d82Slm66018 * then waits for the request to be processed. 25833af08d82Slm66018 * 25843af08d82Slm66018 * Arguments: 25853af08d82Slm66018 * vdcp - the soft state pointer 25863af08d82Slm66018 * operation - operation we want vds to perform (VD_OP_XXX) 25873af08d82Slm66018 * addr - address of data buf to be read/written. 25883af08d82Slm66018 * nbytes - number of bytes to read/write 25893af08d82Slm66018 * slice - the disk slice this request is for 25903af08d82Slm66018 * offset - relative disk offset 25913af08d82Slm66018 * cb_type - type of call - STRATEGY or SYNC 25923af08d82Slm66018 * cb_arg - parameter to be sent to server (depends on VD_OP_XXX type) 25933af08d82Slm66018 * . mode for ioctl(9e) 25943af08d82Slm66018 * . LP64 diskaddr_t (block I/O) 25953af08d82Slm66018 * dir - direction of operation (READ/WRITE/BOTH) 25963af08d82Slm66018 * 25973af08d82Slm66018 * Return Codes: 25983af08d82Slm66018 * 0 25993af08d82Slm66018 * ENXIO 26003af08d82Slm66018 */ 26013af08d82Slm66018 static int 26023af08d82Slm66018 vdc_send_request(vdc_t *vdcp, int operation, caddr_t addr, 26033af08d82Slm66018 size_t nbytes, int slice, diskaddr_t offset, int cb_type, 26043af08d82Slm66018 void *cb_arg, vio_desc_direction_t dir) 26053af08d82Slm66018 { 26063af08d82Slm66018 ASSERT(vdcp != NULL); 260787a7269eSachartre ASSERT(slice == VD_SLICE_NONE || slice < V_NUMPAR); 26083af08d82Slm66018 26093af08d82Slm66018 mutex_enter(&vdcp->lock); 26103af08d82Slm66018 26113af08d82Slm66018 do { 26123c96341aSnarayan while (vdcp->state != VDC_STATE_RUNNING) { 26133af08d82Slm66018 26143c96341aSnarayan /* return error if detaching */ 26153c96341aSnarayan if (vdcp->state == VDC_STATE_DETACH) { 26163c96341aSnarayan mutex_exit(&vdcp->lock); 26173c96341aSnarayan return (ENXIO); 26183c96341aSnarayan } 2619655fd6a9Sachartre 2620655fd6a9Sachartre /* fail request if connection timeout is reached */ 2621655fd6a9Sachartre if (vdcp->ctimeout_reached) { 2622655fd6a9Sachartre mutex_exit(&vdcp->lock); 2623655fd6a9Sachartre return (EIO); 2624655fd6a9Sachartre } 2625655fd6a9Sachartre 2626655fd6a9Sachartre cv_wait(&vdcp->running_cv, &vdcp->lock); 26273c96341aSnarayan } 26283c96341aSnarayan 26293af08d82Slm66018 } while (vdc_populate_descriptor(vdcp, operation, addr, 26303af08d82Slm66018 nbytes, slice, offset, cb_type, cb_arg, dir)); 26313af08d82Slm66018 26323af08d82Slm66018 mutex_exit(&vdcp->lock); 26333af08d82Slm66018 return (0); 26343af08d82Slm66018 } 26353af08d82Slm66018 26363af08d82Slm66018 26373af08d82Slm66018 /* 26383af08d82Slm66018 * Function: 26391ae08745Sheppo * vdc_populate_descriptor 26401ae08745Sheppo * 26411ae08745Sheppo * Description: 26421ae08745Sheppo * This routine writes the data to be transmitted to vds into the 26431ae08745Sheppo * descriptor, notifies vds that the ring has been updated and 26441ae08745Sheppo * then waits for the request to be processed. 26451ae08745Sheppo * 26461ae08745Sheppo * Arguments: 26473af08d82Slm66018 * vdcp - the soft state pointer 26481ae08745Sheppo * operation - operation we want vds to perform (VD_OP_XXX) 26493af08d82Slm66018 * addr - address of data buf to be read/written. 26503af08d82Slm66018 * nbytes - number of bytes to read/write 26513af08d82Slm66018 * slice - the disk slice this request is for 26523af08d82Slm66018 * offset - relative disk offset 26533af08d82Slm66018 * cb_type - type of call - STRATEGY or SYNC 26543af08d82Slm66018 * cb_arg - parameter to be sent to server (depends on VD_OP_XXX type) 26551ae08745Sheppo * . mode for ioctl(9e) 26561ae08745Sheppo * . LP64 diskaddr_t (block I/O) 26573af08d82Slm66018 * dir - direction of operation (READ/WRITE/BOTH) 26581ae08745Sheppo * 26591ae08745Sheppo * Return Codes: 26601ae08745Sheppo * 0 26611ae08745Sheppo * EAGAIN 26621ae08745Sheppo * EFAULT 26631ae08745Sheppo * ENXIO 26641ae08745Sheppo * EIO 26651ae08745Sheppo */ 26661ae08745Sheppo static int 26673af08d82Slm66018 vdc_populate_descriptor(vdc_t *vdcp, int operation, caddr_t addr, 26683af08d82Slm66018 size_t nbytes, int slice, diskaddr_t offset, int cb_type, 26693af08d82Slm66018 void *cb_arg, vio_desc_direction_t dir) 26701ae08745Sheppo { 26713af08d82Slm66018 vdc_local_desc_t *local_dep = NULL; /* Local Dring Pointer */ 26723af08d82Slm66018 int idx; /* Index of DRing entry used */ 26733af08d82Slm66018 int next_idx; 26741ae08745Sheppo vio_dring_msg_t dmsg; 26753af08d82Slm66018 size_t msglen; 26768e6a2a04Slm66018 int rv; 26771ae08745Sheppo 26783af08d82Slm66018 ASSERT(MUTEX_HELD(&vdcp->lock)); 26793af08d82Slm66018 vdcp->threads_pending++; 26803af08d82Slm66018 loop: 26813af08d82Slm66018 DMSG(vdcp, 2, ": dring_curr_idx = %d\n", vdcp->dring_curr_idx); 26821ae08745Sheppo 26833af08d82Slm66018 /* Get next available D-Ring entry */ 26843af08d82Slm66018 idx = vdcp->dring_curr_idx; 26853af08d82Slm66018 local_dep = &(vdcp->local_dring[idx]); 26861ae08745Sheppo 26873af08d82Slm66018 if (!local_dep->is_free) { 26883af08d82Slm66018 DMSG(vdcp, 2, "[%d]: dring full - waiting for space\n", 26893af08d82Slm66018 vdcp->instance); 26903af08d82Slm66018 cv_wait(&vdcp->dring_free_cv, &vdcp->lock); 26913af08d82Slm66018 if (vdcp->state == VDC_STATE_RUNNING || 26923af08d82Slm66018 vdcp->state == VDC_STATE_HANDLE_PENDING) { 26933af08d82Slm66018 goto loop; 26943af08d82Slm66018 } 26953af08d82Slm66018 vdcp->threads_pending--; 26963af08d82Slm66018 return (ECONNRESET); 26971ae08745Sheppo } 26981ae08745Sheppo 26993af08d82Slm66018 next_idx = idx + 1; 27003af08d82Slm66018 if (next_idx >= vdcp->dring_len) 27013af08d82Slm66018 next_idx = 0; 27023af08d82Slm66018 vdcp->dring_curr_idx = next_idx; 27031ae08745Sheppo 27043af08d82Slm66018 ASSERT(local_dep->is_free); 27051ae08745Sheppo 27063af08d82Slm66018 local_dep->operation = operation; 2707d10e4ef2Snarayan local_dep->addr = addr; 27083af08d82Slm66018 local_dep->nbytes = nbytes; 27093af08d82Slm66018 local_dep->slice = slice; 27103af08d82Slm66018 local_dep->offset = offset; 27113af08d82Slm66018 local_dep->cb_type = cb_type; 27123af08d82Slm66018 local_dep->cb_arg = cb_arg; 27133af08d82Slm66018 local_dep->dir = dir; 27143af08d82Slm66018 27153af08d82Slm66018 local_dep->is_free = B_FALSE; 27163af08d82Slm66018 27173af08d82Slm66018 rv = vdc_map_to_shared_dring(vdcp, idx); 27183af08d82Slm66018 if (rv) { 27193af08d82Slm66018 DMSG(vdcp, 0, "[%d]: cannot bind memory - waiting ..\n", 27203af08d82Slm66018 vdcp->instance); 27213af08d82Slm66018 /* free the descriptor */ 27223af08d82Slm66018 local_dep->is_free = B_TRUE; 27233af08d82Slm66018 vdcp->dring_curr_idx = idx; 27243af08d82Slm66018 cv_wait(&vdcp->membind_cv, &vdcp->lock); 27253af08d82Slm66018 if (vdcp->state == VDC_STATE_RUNNING || 27263af08d82Slm66018 vdcp->state == VDC_STATE_HANDLE_PENDING) { 27273af08d82Slm66018 goto loop; 27281ae08745Sheppo } 27293af08d82Slm66018 vdcp->threads_pending--; 27303af08d82Slm66018 return (ECONNRESET); 27311ae08745Sheppo } 27321ae08745Sheppo 27331ae08745Sheppo /* 27341ae08745Sheppo * Send a msg with the DRing details to vds 27351ae08745Sheppo */ 27361ae08745Sheppo VIO_INIT_DRING_DATA_TAG(dmsg); 27373af08d82Slm66018 VDC_INIT_DRING_DATA_MSG_IDS(dmsg, vdcp); 27383af08d82Slm66018 dmsg.dring_ident = vdcp->dring_ident; 27391ae08745Sheppo dmsg.start_idx = idx; 27401ae08745Sheppo dmsg.end_idx = idx; 27413af08d82Slm66018 vdcp->seq_num++; 27421ae08745Sheppo 27433af08d82Slm66018 DTRACE_IO2(send, vio_dring_msg_t *, &dmsg, vdc_t *, vdcp); 2744d10e4ef2Snarayan 27453af08d82Slm66018 DMSG(vdcp, 2, "ident=0x%lx, st=%u, end=%u, seq=%ld\n", 27463af08d82Slm66018 vdcp->dring_ident, dmsg.start_idx, dmsg.end_idx, dmsg.seq_num); 27471ae08745Sheppo 27483af08d82Slm66018 /* 27493af08d82Slm66018 * note we're still holding the lock here to 27503af08d82Slm66018 * make sure the message goes out in order !!!... 27513af08d82Slm66018 */ 27523af08d82Slm66018 msglen = sizeof (dmsg); 27533af08d82Slm66018 rv = vdc_send(vdcp, (caddr_t)&dmsg, &msglen); 27543af08d82Slm66018 switch (rv) { 27553af08d82Slm66018 case ECONNRESET: 27563af08d82Slm66018 /* 27573af08d82Slm66018 * vdc_send initiates the reset on failure. 27583af08d82Slm66018 * Since the transaction has already been put 27593af08d82Slm66018 * on the local dring, it will automatically get 27603af08d82Slm66018 * retried when the channel is reset. Given that, 27613af08d82Slm66018 * it is ok to just return success even though the 27623af08d82Slm66018 * send failed. 27633af08d82Slm66018 */ 27643af08d82Slm66018 rv = 0; 27653af08d82Slm66018 break; 2766d10e4ef2Snarayan 27673af08d82Slm66018 case 0: /* EOK */ 27683af08d82Slm66018 DMSG(vdcp, 1, "sent via LDC: rv=%d\n", rv); 27693af08d82Slm66018 break; 2770d10e4ef2Snarayan 27713af08d82Slm66018 default: 27723af08d82Slm66018 goto cleanup_and_exit; 27733af08d82Slm66018 } 2774e1ebb9ecSlm66018 27753af08d82Slm66018 vdcp->threads_pending--; 27763af08d82Slm66018 return (rv); 27773af08d82Slm66018 27783af08d82Slm66018 cleanup_and_exit: 27793af08d82Slm66018 DMSG(vdcp, 0, "unexpected error, rv=%d\n", rv); 27803af08d82Slm66018 return (ENXIO); 27811ae08745Sheppo } 27821ae08745Sheppo 27831ae08745Sheppo /* 27843af08d82Slm66018 * Function: 27853af08d82Slm66018 * vdc_do_sync_op 27863af08d82Slm66018 * 27873af08d82Slm66018 * Description: 27883af08d82Slm66018 * Wrapper around vdc_populate_descriptor that blocks until the 27893af08d82Slm66018 * response to the message is available. 27903af08d82Slm66018 * 27913af08d82Slm66018 * Arguments: 27923af08d82Slm66018 * vdcp - the soft state pointer 27933af08d82Slm66018 * operation - operation we want vds to perform (VD_OP_XXX) 27943af08d82Slm66018 * addr - address of data buf to be read/written. 27953af08d82Slm66018 * nbytes - number of bytes to read/write 27963af08d82Slm66018 * slice - the disk slice this request is for 27973af08d82Slm66018 * offset - relative disk offset 27983af08d82Slm66018 * cb_type - type of call - STRATEGY or SYNC 27993af08d82Slm66018 * cb_arg - parameter to be sent to server (depends on VD_OP_XXX type) 28003af08d82Slm66018 * . mode for ioctl(9e) 28013af08d82Slm66018 * . LP64 diskaddr_t (block I/O) 28023af08d82Slm66018 * dir - direction of operation (READ/WRITE/BOTH) 28033af08d82Slm66018 * 28043af08d82Slm66018 * Return Codes: 28053af08d82Slm66018 * 0 28063af08d82Slm66018 * EAGAIN 28073af08d82Slm66018 * EFAULT 28083af08d82Slm66018 * ENXIO 28093af08d82Slm66018 * EIO 28100a55fbb7Slm66018 */ 28113af08d82Slm66018 static int 28123af08d82Slm66018 vdc_do_sync_op(vdc_t *vdcp, int operation, caddr_t addr, size_t nbytes, 28133af08d82Slm66018 int slice, diskaddr_t offset, int cb_type, void *cb_arg, 28143af08d82Slm66018 vio_desc_direction_t dir) 28153af08d82Slm66018 { 28163af08d82Slm66018 int status; 28173af08d82Slm66018 28183af08d82Slm66018 ASSERT(cb_type == CB_SYNC); 28191ae08745Sheppo 28201ae08745Sheppo /* 28213af08d82Slm66018 * Grab the lock, if blocked wait until the server 28223af08d82Slm66018 * response causes us to wake up again. 28233af08d82Slm66018 */ 28243af08d82Slm66018 mutex_enter(&vdcp->lock); 28253af08d82Slm66018 vdcp->sync_op_cnt++; 28263af08d82Slm66018 while (vdcp->sync_op_blocked && vdcp->state != VDC_STATE_DETACH) 28273af08d82Slm66018 cv_wait(&vdcp->sync_blocked_cv, &vdcp->lock); 28283af08d82Slm66018 28293af08d82Slm66018 if (vdcp->state == VDC_STATE_DETACH) { 28303af08d82Slm66018 cv_broadcast(&vdcp->sync_blocked_cv); 28313af08d82Slm66018 vdcp->sync_op_cnt--; 28323af08d82Slm66018 mutex_exit(&vdcp->lock); 28333af08d82Slm66018 return (ENXIO); 28343af08d82Slm66018 } 28353af08d82Slm66018 28363af08d82Slm66018 /* now block anyone other thread entering after us */ 28373af08d82Slm66018 vdcp->sync_op_blocked = B_TRUE; 28383af08d82Slm66018 vdcp->sync_op_pending = B_TRUE; 28393af08d82Slm66018 mutex_exit(&vdcp->lock); 28403af08d82Slm66018 2841655fd6a9Sachartre status = vdc_send_request(vdcp, operation, addr, 28423af08d82Slm66018 nbytes, slice, offset, cb_type, cb_arg, dir); 28433af08d82Slm66018 2844655fd6a9Sachartre mutex_enter(&vdcp->lock); 2845655fd6a9Sachartre 2846655fd6a9Sachartre if (status != 0) { 2847655fd6a9Sachartre vdcp->sync_op_pending = B_FALSE; 2848655fd6a9Sachartre } else { 28493af08d82Slm66018 /* 28503af08d82Slm66018 * block until our transaction completes. 28513af08d82Slm66018 * Also anyone else waiting also gets to go next. 28523af08d82Slm66018 */ 28533af08d82Slm66018 while (vdcp->sync_op_pending && vdcp->state != VDC_STATE_DETACH) 28543af08d82Slm66018 cv_wait(&vdcp->sync_pending_cv, &vdcp->lock); 28553af08d82Slm66018 2856655fd6a9Sachartre DMSG(vdcp, 2, ": operation returned %d\n", 2857655fd6a9Sachartre vdcp->sync_op_status); 28583c96341aSnarayan if (vdcp->state == VDC_STATE_DETACH) { 28593c96341aSnarayan vdcp->sync_op_pending = B_FALSE; 28603af08d82Slm66018 status = ENXIO; 28613c96341aSnarayan } else { 28623af08d82Slm66018 status = vdcp->sync_op_status; 28633c96341aSnarayan } 2864655fd6a9Sachartre } 28653c96341aSnarayan 28663af08d82Slm66018 vdcp->sync_op_status = 0; 28673af08d82Slm66018 vdcp->sync_op_blocked = B_FALSE; 28683af08d82Slm66018 vdcp->sync_op_cnt--; 28693af08d82Slm66018 28703af08d82Slm66018 /* signal the next waiting thread */ 28713af08d82Slm66018 cv_signal(&vdcp->sync_blocked_cv); 28723af08d82Slm66018 mutex_exit(&vdcp->lock); 28733af08d82Slm66018 28743af08d82Slm66018 return (status); 28753af08d82Slm66018 } 28763af08d82Slm66018 28773af08d82Slm66018 28783af08d82Slm66018 /* 28793af08d82Slm66018 * Function: 28803af08d82Slm66018 * vdc_drain_response() 28813af08d82Slm66018 * 28823af08d82Slm66018 * Description: 28831ae08745Sheppo * When a guest is panicking, the completion of requests needs to be 28841ae08745Sheppo * handled differently because interrupts are disabled and vdc 28851ae08745Sheppo * will not get messages. We have to poll for the messages instead. 28863af08d82Slm66018 * 28873af08d82Slm66018 * Arguments: 28883af08d82Slm66018 * vdc - soft state pointer for this instance of the device driver. 28893af08d82Slm66018 * 28903af08d82Slm66018 * Return Code: 28913af08d82Slm66018 * 0 - Success 28921ae08745Sheppo */ 28933af08d82Slm66018 static int 28943af08d82Slm66018 vdc_drain_response(vdc_t *vdc) 28953af08d82Slm66018 { 28963af08d82Slm66018 int rv, idx, retries; 28973af08d82Slm66018 size_t msglen; 28983af08d82Slm66018 vdc_local_desc_t *ldep = NULL; /* Local Dring Entry Pointer */ 28993af08d82Slm66018 vio_dring_msg_t dmsg; 29003af08d82Slm66018 29013af08d82Slm66018 mutex_enter(&vdc->lock); 29023af08d82Slm66018 29031ae08745Sheppo retries = 0; 29041ae08745Sheppo for (;;) { 29051ae08745Sheppo msglen = sizeof (dmsg); 29063af08d82Slm66018 rv = ldc_read(vdc->ldc_handle, (caddr_t)&dmsg, &msglen); 29078e6a2a04Slm66018 if (rv) { 29088e6a2a04Slm66018 rv = EINVAL; 29091ae08745Sheppo break; 29101ae08745Sheppo } 29111ae08745Sheppo 29121ae08745Sheppo /* 29131ae08745Sheppo * if there are no packets wait and check again 29141ae08745Sheppo */ 29158e6a2a04Slm66018 if ((rv == 0) && (msglen == 0)) { 29161ae08745Sheppo if (retries++ > vdc_dump_retries) { 29178e6a2a04Slm66018 rv = EAGAIN; 29181ae08745Sheppo break; 29191ae08745Sheppo } 29201ae08745Sheppo 2921d10e4ef2Snarayan drv_usecwait(vdc_usec_timeout_dump); 29221ae08745Sheppo continue; 29231ae08745Sheppo } 29241ae08745Sheppo 29251ae08745Sheppo /* 29261ae08745Sheppo * Ignore all messages that are not ACKs/NACKs to 29271ae08745Sheppo * DRing requests. 29281ae08745Sheppo */ 29291ae08745Sheppo if ((dmsg.tag.vio_msgtype != VIO_TYPE_DATA) || 29301ae08745Sheppo (dmsg.tag.vio_subtype_env != VIO_DRING_DATA)) { 29313af08d82Slm66018 DMSG(vdc, 0, "discard pkt: type=%d sub=%d env=%d\n", 29321ae08745Sheppo dmsg.tag.vio_msgtype, 29331ae08745Sheppo dmsg.tag.vio_subtype, 29341ae08745Sheppo dmsg.tag.vio_subtype_env); 29351ae08745Sheppo continue; 29361ae08745Sheppo } 29371ae08745Sheppo 29381ae08745Sheppo /* 29393af08d82Slm66018 * set the appropriate return value for the current request. 29401ae08745Sheppo */ 29411ae08745Sheppo switch (dmsg.tag.vio_subtype) { 29421ae08745Sheppo case VIO_SUBTYPE_ACK: 29438e6a2a04Slm66018 rv = 0; 29441ae08745Sheppo break; 29451ae08745Sheppo case VIO_SUBTYPE_NACK: 29468e6a2a04Slm66018 rv = EAGAIN; 29471ae08745Sheppo break; 29481ae08745Sheppo default: 29491ae08745Sheppo continue; 29501ae08745Sheppo } 29511ae08745Sheppo 29523af08d82Slm66018 idx = dmsg.start_idx; 29533af08d82Slm66018 if (idx >= vdc->dring_len) { 29543af08d82Slm66018 DMSG(vdc, 0, "[%d] Bogus ack data : start %d\n", 2955e1ebb9ecSlm66018 vdc->instance, idx); 29563af08d82Slm66018 continue; 29571ae08745Sheppo } 29583af08d82Slm66018 ldep = &vdc->local_dring[idx]; 29593af08d82Slm66018 if (ldep->dep->hdr.dstate != VIO_DESC_DONE) { 29603af08d82Slm66018 DMSG(vdc, 0, "[%d] Entry @ %d - state !DONE %d\n", 29613af08d82Slm66018 vdc->instance, idx, ldep->dep->hdr.dstate); 29621ae08745Sheppo continue; 29631ae08745Sheppo } 29641ae08745Sheppo 29653af08d82Slm66018 DMSG(vdc, 1, "[%d] Depopulating idx=%d state=%d\n", 29663af08d82Slm66018 vdc->instance, idx, ldep->dep->hdr.dstate); 29673af08d82Slm66018 rv = vdc_depopulate_descriptor(vdc, idx); 29683af08d82Slm66018 if (rv) { 29693af08d82Slm66018 DMSG(vdc, 0, 29703af08d82Slm66018 "[%d] Entry @ %d - depopulate failed ..\n", 29713af08d82Slm66018 vdc->instance, idx); 29721ae08745Sheppo } 29731ae08745Sheppo 29743af08d82Slm66018 /* if this is the last descriptor - break out of loop */ 29753af08d82Slm66018 if ((idx + 1) % vdc->dring_len == vdc->dring_curr_idx) 29763af08d82Slm66018 break; 29773af08d82Slm66018 } 29783af08d82Slm66018 29793af08d82Slm66018 mutex_exit(&vdc->lock); 29803af08d82Slm66018 DMSG(vdc, 0, "End idx=%d\n", idx); 29813af08d82Slm66018 29823af08d82Slm66018 return (rv); 29831ae08745Sheppo } 29841ae08745Sheppo 29851ae08745Sheppo 29860a55fbb7Slm66018 /* 29870a55fbb7Slm66018 * Function: 29880a55fbb7Slm66018 * vdc_depopulate_descriptor() 29890a55fbb7Slm66018 * 29900a55fbb7Slm66018 * Description: 29910a55fbb7Slm66018 * 29920a55fbb7Slm66018 * Arguments: 29930a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 29940a55fbb7Slm66018 * idx - Index of the Descriptor Ring entry being modified 29950a55fbb7Slm66018 * 29960a55fbb7Slm66018 * Return Code: 29970a55fbb7Slm66018 * 0 - Success 29980a55fbb7Slm66018 */ 29991ae08745Sheppo static int 30001ae08745Sheppo vdc_depopulate_descriptor(vdc_t *vdc, uint_t idx) 30011ae08745Sheppo { 30021ae08745Sheppo vd_dring_entry_t *dep = NULL; /* Dring Entry Pointer */ 30031ae08745Sheppo vdc_local_desc_t *ldep = NULL; /* Local Dring Entry Pointer */ 30041ae08745Sheppo int status = ENXIO; 30058e6a2a04Slm66018 int rv = 0; 30061ae08745Sheppo 30071ae08745Sheppo ASSERT(vdc != NULL); 3008e1ebb9ecSlm66018 ASSERT(idx < vdc->dring_len); 30091ae08745Sheppo ldep = &vdc->local_dring[idx]; 30101ae08745Sheppo ASSERT(ldep != NULL); 30113af08d82Slm66018 ASSERT(MUTEX_HELD(&vdc->lock)); 30123af08d82Slm66018 30133af08d82Slm66018 DMSG(vdc, 2, ": idx = %d\n", idx); 30141ae08745Sheppo dep = ldep->dep; 30151ae08745Sheppo ASSERT(dep != NULL); 3016e1ebb9ecSlm66018 ASSERT((dep->hdr.dstate == VIO_DESC_DONE) || 3017e1ebb9ecSlm66018 (dep->payload.status == ECANCELED)); 30181ae08745Sheppo 3019e1ebb9ecSlm66018 VDC_MARK_DRING_ENTRY_FREE(vdc, idx); 30203af08d82Slm66018 30213af08d82Slm66018 ldep->is_free = B_TRUE; 30221ae08745Sheppo status = dep->payload.status; 3023205eeb1aSlm66018 DMSG(vdc, 2, ": is_free = %d : status = %d\n", ldep->is_free, status); 30241ae08745Sheppo 3025eff7243fSlm66018 /* 3026eff7243fSlm66018 * If no buffers were used to transfer information to the server when 3027eff7243fSlm66018 * populating the descriptor then no memory handles need to be unbound 3028eff7243fSlm66018 * and we can return now. 3029eff7243fSlm66018 */ 3030eff7243fSlm66018 if (ldep->nbytes == 0) { 3031eff7243fSlm66018 cv_signal(&vdc->dring_free_cv); 30328e6a2a04Slm66018 return (status); 3033eff7243fSlm66018 } 30348e6a2a04Slm66018 30351ae08745Sheppo /* 30361ae08745Sheppo * If the upper layer passed in a misaligned address we copied the 30371ae08745Sheppo * data into an aligned buffer before sending it to LDC - we now 30381ae08745Sheppo * copy it back to the original buffer. 30391ae08745Sheppo */ 30401ae08745Sheppo if (ldep->align_addr) { 30411ae08745Sheppo ASSERT(ldep->addr != NULL); 30421ae08745Sheppo 30433c96341aSnarayan if (dep->payload.nbytes > 0) 30443c96341aSnarayan bcopy(ldep->align_addr, ldep->addr, 30453c96341aSnarayan dep->payload.nbytes); 30461ae08745Sheppo kmem_free(ldep->align_addr, 30473c96341aSnarayan sizeof (caddr_t) * P2ROUNDUP(ldep->nbytes, 8)); 30481ae08745Sheppo ldep->align_addr = NULL; 30491ae08745Sheppo } 30501ae08745Sheppo 30518e6a2a04Slm66018 rv = ldc_mem_unbind_handle(ldep->desc_mhdl); 30528e6a2a04Slm66018 if (rv != 0) { 30533af08d82Slm66018 DMSG(vdc, 0, "?[%d] unbind mhdl 0x%lx @ idx %d failed (%d)", 30548e6a2a04Slm66018 vdc->instance, ldep->desc_mhdl, idx, rv); 30558e6a2a04Slm66018 /* 30568e6a2a04Slm66018 * The error returned by the vDisk server is more informative 30578e6a2a04Slm66018 * and thus has a higher priority but if it isn't set we ensure 30588e6a2a04Slm66018 * that this function returns an error. 30598e6a2a04Slm66018 */ 30608e6a2a04Slm66018 if (status == 0) 30618e6a2a04Slm66018 status = EINVAL; 30621ae08745Sheppo } 30631ae08745Sheppo 30643af08d82Slm66018 cv_signal(&vdc->membind_cv); 30653af08d82Slm66018 cv_signal(&vdc->dring_free_cv); 30663af08d82Slm66018 30671ae08745Sheppo return (status); 30681ae08745Sheppo } 30691ae08745Sheppo 30700a55fbb7Slm66018 /* 30710a55fbb7Slm66018 * Function: 30720a55fbb7Slm66018 * vdc_populate_mem_hdl() 30730a55fbb7Slm66018 * 30740a55fbb7Slm66018 * Description: 30750a55fbb7Slm66018 * 30760a55fbb7Slm66018 * Arguments: 30770a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 30780a55fbb7Slm66018 * idx - Index of the Descriptor Ring entry being modified 30790a55fbb7Slm66018 * addr - virtual address being mapped in 30800a55fbb7Slm66018 * nybtes - number of bytes in 'addr' 30810a55fbb7Slm66018 * operation - the vDisk operation being performed (VD_OP_xxx) 30820a55fbb7Slm66018 * 30830a55fbb7Slm66018 * Return Code: 30840a55fbb7Slm66018 * 0 - Success 30850a55fbb7Slm66018 */ 30861ae08745Sheppo static int 30873af08d82Slm66018 vdc_populate_mem_hdl(vdc_t *vdcp, vdc_local_desc_t *ldep) 30881ae08745Sheppo { 30891ae08745Sheppo vd_dring_entry_t *dep = NULL; 30901ae08745Sheppo ldc_mem_handle_t mhdl; 30911ae08745Sheppo caddr_t vaddr; 30923af08d82Slm66018 size_t nbytes; 30934bac2208Snarayan uint8_t perm = LDC_MEM_RW; 30944bac2208Snarayan uint8_t maptype; 30951ae08745Sheppo int rv = 0; 30961ae08745Sheppo int i; 30971ae08745Sheppo 30983af08d82Slm66018 ASSERT(vdcp != NULL); 30991ae08745Sheppo 31003af08d82Slm66018 dep = ldep->dep; 31011ae08745Sheppo mhdl = ldep->desc_mhdl; 31021ae08745Sheppo 31033af08d82Slm66018 switch (ldep->dir) { 31043af08d82Slm66018 case VIO_read_dir: 31051ae08745Sheppo perm = LDC_MEM_W; 31061ae08745Sheppo break; 31071ae08745Sheppo 31083af08d82Slm66018 case VIO_write_dir: 31091ae08745Sheppo perm = LDC_MEM_R; 31101ae08745Sheppo break; 31111ae08745Sheppo 31123af08d82Slm66018 case VIO_both_dir: 31131ae08745Sheppo perm = LDC_MEM_RW; 31141ae08745Sheppo break; 31151ae08745Sheppo 31161ae08745Sheppo default: 31171ae08745Sheppo ASSERT(0); /* catch bad programming in vdc */ 31181ae08745Sheppo } 31191ae08745Sheppo 31201ae08745Sheppo /* 31211ae08745Sheppo * LDC expects any addresses passed in to be 8-byte aligned. We need 31221ae08745Sheppo * to copy the contents of any misaligned buffers to a newly allocated 31231ae08745Sheppo * buffer and bind it instead (and copy the the contents back to the 31241ae08745Sheppo * original buffer passed in when depopulating the descriptor) 31251ae08745Sheppo */ 31263af08d82Slm66018 vaddr = ldep->addr; 31273af08d82Slm66018 nbytes = ldep->nbytes; 31283af08d82Slm66018 if (((uint64_t)vaddr & 0x7) != 0) { 3129d10e4ef2Snarayan ASSERT(ldep->align_addr == NULL); 31301ae08745Sheppo ldep->align_addr = 31313af08d82Slm66018 kmem_alloc(sizeof (caddr_t) * 31323af08d82Slm66018 P2ROUNDUP(nbytes, 8), KM_SLEEP); 31333af08d82Slm66018 DMSG(vdcp, 0, "[%d] Misaligned address %p reallocating " 31343af08d82Slm66018 "(buf=%p nb=%ld op=%d)\n", 31353af08d82Slm66018 vdcp->instance, (void *)vaddr, (void *)ldep->align_addr, 31363af08d82Slm66018 nbytes, ldep->operation); 31373af08d82Slm66018 if (perm != LDC_MEM_W) 31383af08d82Slm66018 bcopy(vaddr, ldep->align_addr, nbytes); 31391ae08745Sheppo vaddr = ldep->align_addr; 31401ae08745Sheppo } 31411ae08745Sheppo 31424bac2208Snarayan maptype = LDC_IO_MAP|LDC_SHADOW_MAP|LDC_DIRECT_MAP; 31431ae08745Sheppo rv = ldc_mem_bind_handle(mhdl, vaddr, P2ROUNDUP(nbytes, 8), 314487a7269eSachartre maptype, perm, &dep->payload.cookie[0], &dep->payload.ncookies); 31453af08d82Slm66018 DMSG(vdcp, 2, "[%d] bound mem handle; ncookies=%d\n", 31463af08d82Slm66018 vdcp->instance, dep->payload.ncookies); 31471ae08745Sheppo if (rv != 0) { 31483af08d82Slm66018 DMSG(vdcp, 0, "[%d] Failed to bind LDC memory handle " 31493af08d82Slm66018 "(mhdl=%p, buf=%p, err=%d)\n", 31503af08d82Slm66018 vdcp->instance, (void *)mhdl, (void *)vaddr, rv); 31511ae08745Sheppo if (ldep->align_addr) { 31521ae08745Sheppo kmem_free(ldep->align_addr, 3153d10e4ef2Snarayan sizeof (caddr_t) * P2ROUNDUP(nbytes, 8)); 31541ae08745Sheppo ldep->align_addr = NULL; 31551ae08745Sheppo } 31561ae08745Sheppo return (EAGAIN); 31571ae08745Sheppo } 31581ae08745Sheppo 31591ae08745Sheppo /* 31601ae08745Sheppo * Get the other cookies (if any). 31611ae08745Sheppo */ 31621ae08745Sheppo for (i = 1; i < dep->payload.ncookies; i++) { 31631ae08745Sheppo rv = ldc_mem_nextcookie(mhdl, &dep->payload.cookie[i]); 31641ae08745Sheppo if (rv != 0) { 31651ae08745Sheppo (void) ldc_mem_unbind_handle(mhdl); 31663af08d82Slm66018 DMSG(vdcp, 0, "?[%d] Failed to get next cookie " 3167e1ebb9ecSlm66018 "(mhdl=%lx cnum=%d), err=%d", 31683af08d82Slm66018 vdcp->instance, mhdl, i, rv); 31691ae08745Sheppo if (ldep->align_addr) { 31701ae08745Sheppo kmem_free(ldep->align_addr, 31713c96341aSnarayan sizeof (caddr_t) * ldep->nbytes); 31721ae08745Sheppo ldep->align_addr = NULL; 31731ae08745Sheppo } 31741ae08745Sheppo return (EAGAIN); 31751ae08745Sheppo } 31761ae08745Sheppo } 31771ae08745Sheppo 31781ae08745Sheppo return (rv); 31791ae08745Sheppo } 31801ae08745Sheppo 31811ae08745Sheppo /* 31821ae08745Sheppo * Interrupt handlers for messages from LDC 31831ae08745Sheppo */ 31841ae08745Sheppo 31850a55fbb7Slm66018 /* 31860a55fbb7Slm66018 * Function: 31870a55fbb7Slm66018 * vdc_handle_cb() 31880a55fbb7Slm66018 * 31890a55fbb7Slm66018 * Description: 31900a55fbb7Slm66018 * 31910a55fbb7Slm66018 * Arguments: 31920a55fbb7Slm66018 * event - Type of event (LDC_EVT_xxx) that triggered the callback 31930a55fbb7Slm66018 * arg - soft state pointer for this instance of the device driver. 31940a55fbb7Slm66018 * 31950a55fbb7Slm66018 * Return Code: 31960a55fbb7Slm66018 * 0 - Success 31970a55fbb7Slm66018 */ 31981ae08745Sheppo static uint_t 31991ae08745Sheppo vdc_handle_cb(uint64_t event, caddr_t arg) 32001ae08745Sheppo { 32011ae08745Sheppo ldc_status_t ldc_state; 32021ae08745Sheppo int rv = 0; 32031ae08745Sheppo 32041ae08745Sheppo vdc_t *vdc = (vdc_t *)(void *)arg; 32051ae08745Sheppo 32061ae08745Sheppo ASSERT(vdc != NULL); 32071ae08745Sheppo 32083af08d82Slm66018 DMSG(vdc, 1, "evt=%lx seqID=%ld\n", event, vdc->seq_num); 32091ae08745Sheppo 32101ae08745Sheppo /* 32111ae08745Sheppo * Depending on the type of event that triggered this callback, 32123af08d82Slm66018 * we modify the handshake state or read the data. 32131ae08745Sheppo * 32141ae08745Sheppo * NOTE: not done as a switch() as event could be triggered by 32151ae08745Sheppo * a state change and a read request. Also the ordering of the 32161ae08745Sheppo * check for the event types is deliberate. 32171ae08745Sheppo */ 32181ae08745Sheppo if (event & LDC_EVT_UP) { 32193af08d82Slm66018 DMSG(vdc, 0, "[%d] Received LDC_EVT_UP\n", vdc->instance); 32203af08d82Slm66018 32213af08d82Slm66018 mutex_enter(&vdc->lock); 32221ae08745Sheppo 32231ae08745Sheppo /* get LDC state */ 32241ae08745Sheppo rv = ldc_status(vdc->ldc_handle, &ldc_state); 32251ae08745Sheppo if (rv != 0) { 32263af08d82Slm66018 DMSG(vdc, 0, "[%d] Couldn't get LDC status %d", 32271ae08745Sheppo vdc->instance, rv); 32281ae08745Sheppo return (LDC_SUCCESS); 32291ae08745Sheppo } 32303af08d82Slm66018 if (vdc->ldc_state != LDC_UP && ldc_state == LDC_UP) { 32311ae08745Sheppo /* 32323af08d82Slm66018 * Reset the transaction sequence numbers when 32333af08d82Slm66018 * LDC comes up. We then kick off the handshake 32343af08d82Slm66018 * negotiation with the vDisk server. 32351ae08745Sheppo */ 32360a55fbb7Slm66018 vdc->seq_num = 1; 32371ae08745Sheppo vdc->seq_num_reply = 0; 32381ae08745Sheppo vdc->ldc_state = ldc_state; 32393af08d82Slm66018 cv_signal(&vdc->initwait_cv); 32403af08d82Slm66018 } 32413af08d82Slm66018 32421ae08745Sheppo mutex_exit(&vdc->lock); 32431ae08745Sheppo } 32441ae08745Sheppo 32451ae08745Sheppo if (event & LDC_EVT_READ) { 32463af08d82Slm66018 DMSG(vdc, 0, "[%d] Received LDC_EVT_READ\n", vdc->instance); 32473af08d82Slm66018 mutex_enter(&vdc->read_lock); 32483af08d82Slm66018 cv_signal(&vdc->read_cv); 32493af08d82Slm66018 vdc->read_state = VDC_READ_PENDING; 32503af08d82Slm66018 mutex_exit(&vdc->read_lock); 32511ae08745Sheppo 32521ae08745Sheppo /* that's all we have to do - no need to handle DOWN/RESET */ 32531ae08745Sheppo return (LDC_SUCCESS); 32541ae08745Sheppo } 32551ae08745Sheppo 32563af08d82Slm66018 if (event & (LDC_EVT_RESET|LDC_EVT_DOWN)) { 32570a55fbb7Slm66018 32583af08d82Slm66018 DMSG(vdc, 0, "[%d] Received LDC RESET event\n", vdc->instance); 32593af08d82Slm66018 32600a55fbb7Slm66018 mutex_enter(&vdc->lock); 32613af08d82Slm66018 /* 32623af08d82Slm66018 * Need to wake up any readers so they will 32633af08d82Slm66018 * detect that a reset has occurred. 32643af08d82Slm66018 */ 32653af08d82Slm66018 mutex_enter(&vdc->read_lock); 32663af08d82Slm66018 if ((vdc->read_state == VDC_READ_WAITING) || 32673af08d82Slm66018 (vdc->read_state == VDC_READ_RESET)) 32683af08d82Slm66018 cv_signal(&vdc->read_cv); 32693af08d82Slm66018 vdc->read_state = VDC_READ_RESET; 32703af08d82Slm66018 mutex_exit(&vdc->read_lock); 32710a55fbb7Slm66018 32723af08d82Slm66018 /* wake up any threads waiting for connection to come up */ 32733af08d82Slm66018 if (vdc->state == VDC_STATE_INIT_WAITING) { 32743af08d82Slm66018 vdc->state = VDC_STATE_RESETTING; 32753af08d82Slm66018 cv_signal(&vdc->initwait_cv); 32761ae08745Sheppo } 32771ae08745Sheppo 32780a55fbb7Slm66018 mutex_exit(&vdc->lock); 32791ae08745Sheppo } 32801ae08745Sheppo 32811ae08745Sheppo if (event & ~(LDC_EVT_UP | LDC_EVT_RESET | LDC_EVT_DOWN | LDC_EVT_READ)) 32823af08d82Slm66018 DMSG(vdc, 0, "![%d] Unexpected LDC event (%lx) received", 32831ae08745Sheppo vdc->instance, event); 32841ae08745Sheppo 32851ae08745Sheppo return (LDC_SUCCESS); 32861ae08745Sheppo } 32871ae08745Sheppo 32883af08d82Slm66018 /* 32893af08d82Slm66018 * Function: 32903af08d82Slm66018 * vdc_wait_for_response() 32913af08d82Slm66018 * 32923af08d82Slm66018 * Description: 32933af08d82Slm66018 * Block waiting for a response from the server. If there is 32943af08d82Slm66018 * no data the thread block on the read_cv that is signalled 32953af08d82Slm66018 * by the callback when an EVT_READ occurs. 32963af08d82Slm66018 * 32973af08d82Slm66018 * Arguments: 32983af08d82Slm66018 * vdcp - soft state pointer for this instance of the device driver. 32993af08d82Slm66018 * 33003af08d82Slm66018 * Return Code: 33013af08d82Slm66018 * 0 - Success 33023af08d82Slm66018 */ 33033af08d82Slm66018 static int 33043af08d82Slm66018 vdc_wait_for_response(vdc_t *vdcp, vio_msg_t *msgp) 33053af08d82Slm66018 { 33063af08d82Slm66018 size_t nbytes = sizeof (*msgp); 33073af08d82Slm66018 int status; 33083af08d82Slm66018 33093af08d82Slm66018 ASSERT(vdcp != NULL); 33103af08d82Slm66018 33113af08d82Slm66018 DMSG(vdcp, 1, "[%d] Entered\n", vdcp->instance); 33123af08d82Slm66018 33133af08d82Slm66018 status = vdc_recv(vdcp, msgp, &nbytes); 33143af08d82Slm66018 DMSG(vdcp, 3, "vdc_read() done.. status=0x%x size=0x%x\n", 33153af08d82Slm66018 status, (int)nbytes); 33163af08d82Slm66018 if (status) { 33173af08d82Slm66018 DMSG(vdcp, 0, "?[%d] Error %d reading LDC msg\n", 33183af08d82Slm66018 vdcp->instance, status); 33193af08d82Slm66018 return (status); 33203af08d82Slm66018 } 33213af08d82Slm66018 33223af08d82Slm66018 if (nbytes < sizeof (vio_msg_tag_t)) { 33233af08d82Slm66018 DMSG(vdcp, 0, "?[%d] Expect %lu bytes; recv'd %lu\n", 33243af08d82Slm66018 vdcp->instance, sizeof (vio_msg_tag_t), nbytes); 33253af08d82Slm66018 return (ENOMSG); 33263af08d82Slm66018 } 33273af08d82Slm66018 33283af08d82Slm66018 DMSG(vdcp, 2, "[%d] (%x/%x/%x)\n", vdcp->instance, 33293af08d82Slm66018 msgp->tag.vio_msgtype, 33303af08d82Slm66018 msgp->tag.vio_subtype, 33313af08d82Slm66018 msgp->tag.vio_subtype_env); 33323af08d82Slm66018 33333af08d82Slm66018 /* 33343af08d82Slm66018 * Verify the Session ID of the message 33353af08d82Slm66018 * 33363af08d82Slm66018 * Every message after the Version has been negotiated should 33373af08d82Slm66018 * have the correct session ID set. 33383af08d82Slm66018 */ 33393af08d82Slm66018 if ((msgp->tag.vio_sid != vdcp->session_id) && 33403af08d82Slm66018 (msgp->tag.vio_subtype_env != VIO_VER_INFO)) { 33413af08d82Slm66018 DMSG(vdcp, 0, "[%d] Invalid SID: received 0x%x, " 33423af08d82Slm66018 "expected 0x%lx [seq num %lx @ %d]", 33433af08d82Slm66018 vdcp->instance, msgp->tag.vio_sid, 33443af08d82Slm66018 vdcp->session_id, 33453af08d82Slm66018 ((vio_dring_msg_t *)msgp)->seq_num, 33463af08d82Slm66018 ((vio_dring_msg_t *)msgp)->start_idx); 33473af08d82Slm66018 return (ENOMSG); 33483af08d82Slm66018 } 33493af08d82Slm66018 return (0); 33503af08d82Slm66018 } 33513af08d82Slm66018 33523af08d82Slm66018 33533af08d82Slm66018 /* 33543af08d82Slm66018 * Function: 33553af08d82Slm66018 * vdc_resubmit_backup_dring() 33563af08d82Slm66018 * 33573af08d82Slm66018 * Description: 33583af08d82Slm66018 * Resubmit each descriptor in the backed up dring to 33593af08d82Slm66018 * vDisk server. The Dring was backed up during connection 33603af08d82Slm66018 * reset. 33613af08d82Slm66018 * 33623af08d82Slm66018 * Arguments: 33633af08d82Slm66018 * vdcp - soft state pointer for this instance of the device driver. 33643af08d82Slm66018 * 33653af08d82Slm66018 * Return Code: 33663af08d82Slm66018 * 0 - Success 33673af08d82Slm66018 */ 33683af08d82Slm66018 static int 33693af08d82Slm66018 vdc_resubmit_backup_dring(vdc_t *vdcp) 33703af08d82Slm66018 { 33713af08d82Slm66018 int count; 33723af08d82Slm66018 int b_idx; 33733af08d82Slm66018 int rv; 33743af08d82Slm66018 int dring_size; 33753af08d82Slm66018 int status; 33763af08d82Slm66018 vio_msg_t vio_msg; 33773af08d82Slm66018 vdc_local_desc_t *curr_ldep; 33783af08d82Slm66018 33793af08d82Slm66018 ASSERT(MUTEX_NOT_HELD(&vdcp->lock)); 33803af08d82Slm66018 ASSERT(vdcp->state == VDC_STATE_HANDLE_PENDING); 33813af08d82Slm66018 3382655fd6a9Sachartre if (vdcp->local_dring_backup == NULL) { 3383655fd6a9Sachartre /* the pending requests have already been processed */ 3384655fd6a9Sachartre return (0); 3385655fd6a9Sachartre } 3386655fd6a9Sachartre 33873af08d82Slm66018 DMSG(vdcp, 1, "restoring pending dring entries (len=%d, tail=%d)\n", 33883af08d82Slm66018 vdcp->local_dring_backup_len, vdcp->local_dring_backup_tail); 33893af08d82Slm66018 33903af08d82Slm66018 /* 33913af08d82Slm66018 * Walk the backup copy of the local descriptor ring and 33923af08d82Slm66018 * resubmit all the outstanding transactions. 33933af08d82Slm66018 */ 33943af08d82Slm66018 b_idx = vdcp->local_dring_backup_tail; 33953af08d82Slm66018 for (count = 0; count < vdcp->local_dring_backup_len; count++) { 33963af08d82Slm66018 33973af08d82Slm66018 curr_ldep = &(vdcp->local_dring_backup[b_idx]); 33983af08d82Slm66018 3399eff7243fSlm66018 /* only resubmit outstanding transactions */ 34003af08d82Slm66018 if (!curr_ldep->is_free) { 34013af08d82Slm66018 34023af08d82Slm66018 DMSG(vdcp, 1, "resubmitting entry idx=%x\n", b_idx); 34033af08d82Slm66018 mutex_enter(&vdcp->lock); 34043af08d82Slm66018 rv = vdc_populate_descriptor(vdcp, curr_ldep->operation, 34053af08d82Slm66018 curr_ldep->addr, curr_ldep->nbytes, 34063af08d82Slm66018 curr_ldep->slice, curr_ldep->offset, 34073af08d82Slm66018 curr_ldep->cb_type, curr_ldep->cb_arg, 34083af08d82Slm66018 curr_ldep->dir); 34093af08d82Slm66018 mutex_exit(&vdcp->lock); 34103af08d82Slm66018 if (rv) { 34113af08d82Slm66018 DMSG(vdcp, 1, "[%d] cannot resubmit entry %d\n", 34123af08d82Slm66018 vdcp->instance, b_idx); 34133af08d82Slm66018 return (rv); 34143af08d82Slm66018 } 34153af08d82Slm66018 34163af08d82Slm66018 /* Wait for the response message. */ 34173af08d82Slm66018 DMSG(vdcp, 1, "waiting for response to idx=%x\n", 34183af08d82Slm66018 b_idx); 34193af08d82Slm66018 status = vdc_wait_for_response(vdcp, &vio_msg); 34203af08d82Slm66018 if (status) { 34213af08d82Slm66018 DMSG(vdcp, 1, "[%d] wait_for_response " 34223af08d82Slm66018 "returned err=%d\n", vdcp->instance, 34233af08d82Slm66018 status); 34243af08d82Slm66018 return (status); 34253af08d82Slm66018 } 34263af08d82Slm66018 34273af08d82Slm66018 DMSG(vdcp, 1, "processing msg for idx=%x\n", b_idx); 34283af08d82Slm66018 status = vdc_process_data_msg(vdcp, &vio_msg); 34293af08d82Slm66018 if (status) { 34303af08d82Slm66018 DMSG(vdcp, 1, "[%d] process_data_msg " 34313af08d82Slm66018 "returned err=%d\n", vdcp->instance, 34323af08d82Slm66018 status); 34333af08d82Slm66018 return (status); 34343af08d82Slm66018 } 34353af08d82Slm66018 } 34363af08d82Slm66018 34373af08d82Slm66018 /* get the next element to submit */ 34383af08d82Slm66018 if (++b_idx >= vdcp->local_dring_backup_len) 34393af08d82Slm66018 b_idx = 0; 34403af08d82Slm66018 } 34413af08d82Slm66018 34423af08d82Slm66018 /* all done - now clear up pending dring copy */ 34433af08d82Slm66018 dring_size = vdcp->local_dring_backup_len * 34443af08d82Slm66018 sizeof (vdcp->local_dring_backup[0]); 34453af08d82Slm66018 34463af08d82Slm66018 (void) kmem_free(vdcp->local_dring_backup, dring_size); 34473af08d82Slm66018 34483af08d82Slm66018 vdcp->local_dring_backup = NULL; 34493af08d82Slm66018 34503af08d82Slm66018 return (0); 34513af08d82Slm66018 } 34523af08d82Slm66018 34533af08d82Slm66018 /* 34543af08d82Slm66018 * Function: 3455655fd6a9Sachartre * vdc_cancel_backup_dring 3456655fd6a9Sachartre * 3457655fd6a9Sachartre * Description: 3458655fd6a9Sachartre * Cancel each descriptor in the backed up dring to vDisk server. 3459655fd6a9Sachartre * The Dring was backed up during connection reset. 3460655fd6a9Sachartre * 3461655fd6a9Sachartre * Arguments: 3462655fd6a9Sachartre * vdcp - soft state pointer for this instance of the device driver. 3463655fd6a9Sachartre * 3464655fd6a9Sachartre * Return Code: 3465655fd6a9Sachartre * None 3466655fd6a9Sachartre */ 3467655fd6a9Sachartre void 3468655fd6a9Sachartre vdc_cancel_backup_ring(vdc_t *vdcp) 3469655fd6a9Sachartre { 3470655fd6a9Sachartre vdc_local_desc_t *ldep; 3471655fd6a9Sachartre struct buf *bufp; 3472655fd6a9Sachartre int count; 3473655fd6a9Sachartre int b_idx; 3474655fd6a9Sachartre int dring_size; 3475655fd6a9Sachartre 3476655fd6a9Sachartre ASSERT(MUTEX_HELD(&vdcp->lock)); 3477655fd6a9Sachartre ASSERT(vdcp->state == VDC_STATE_INIT || 3478655fd6a9Sachartre vdcp->state == VDC_STATE_INIT_WAITING || 3479655fd6a9Sachartre vdcp->state == VDC_STATE_NEGOTIATE || 3480655fd6a9Sachartre vdcp->state == VDC_STATE_RESETTING); 3481655fd6a9Sachartre 3482655fd6a9Sachartre if (vdcp->local_dring_backup == NULL) { 3483655fd6a9Sachartre /* the pending requests have already been processed */ 3484655fd6a9Sachartre return; 3485655fd6a9Sachartre } 3486655fd6a9Sachartre 3487655fd6a9Sachartre DMSG(vdcp, 1, "cancelling pending dring entries (len=%d, tail=%d)\n", 3488655fd6a9Sachartre vdcp->local_dring_backup_len, vdcp->local_dring_backup_tail); 3489655fd6a9Sachartre 3490655fd6a9Sachartre /* 3491655fd6a9Sachartre * Walk the backup copy of the local descriptor ring and 3492655fd6a9Sachartre * cancel all the outstanding transactions. 3493655fd6a9Sachartre */ 3494655fd6a9Sachartre b_idx = vdcp->local_dring_backup_tail; 3495655fd6a9Sachartre for (count = 0; count < vdcp->local_dring_backup_len; count++) { 3496655fd6a9Sachartre 3497655fd6a9Sachartre ldep = &(vdcp->local_dring_backup[b_idx]); 3498655fd6a9Sachartre 3499655fd6a9Sachartre /* only cancel outstanding transactions */ 3500655fd6a9Sachartre if (!ldep->is_free) { 3501655fd6a9Sachartre 3502655fd6a9Sachartre DMSG(vdcp, 1, "cancelling entry idx=%x\n", b_idx); 3503655fd6a9Sachartre 3504655fd6a9Sachartre /* 3505655fd6a9Sachartre * All requests have already been cleared from the 3506655fd6a9Sachartre * local descriptor ring and the LDC channel has been 3507655fd6a9Sachartre * reset so we will never get any reply for these 3508655fd6a9Sachartre * requests. Now we just have to notify threads waiting 3509655fd6a9Sachartre * for replies that the request has failed. 3510655fd6a9Sachartre */ 3511655fd6a9Sachartre switch (ldep->cb_type) { 3512655fd6a9Sachartre case CB_SYNC: 3513655fd6a9Sachartre ASSERT(vdcp->sync_op_pending); 3514655fd6a9Sachartre vdcp->sync_op_status = EIO; 3515655fd6a9Sachartre vdcp->sync_op_pending = B_FALSE; 3516655fd6a9Sachartre cv_signal(&vdcp->sync_pending_cv); 3517655fd6a9Sachartre break; 3518655fd6a9Sachartre 3519655fd6a9Sachartre case CB_STRATEGY: 3520655fd6a9Sachartre bufp = ldep->cb_arg; 3521655fd6a9Sachartre ASSERT(bufp != NULL); 3522655fd6a9Sachartre bufp->b_resid = bufp->b_bcount; 3523655fd6a9Sachartre bioerror(bufp, EIO); 3524655fd6a9Sachartre biodone(bufp); 3525655fd6a9Sachartre break; 3526655fd6a9Sachartre 3527655fd6a9Sachartre default: 3528655fd6a9Sachartre ASSERT(0); 3529655fd6a9Sachartre } 3530655fd6a9Sachartre 3531655fd6a9Sachartre } 3532655fd6a9Sachartre 3533655fd6a9Sachartre /* get the next element to cancel */ 3534655fd6a9Sachartre if (++b_idx >= vdcp->local_dring_backup_len) 3535655fd6a9Sachartre b_idx = 0; 3536655fd6a9Sachartre } 3537655fd6a9Sachartre 3538655fd6a9Sachartre /* all done - now clear up pending dring copy */ 3539655fd6a9Sachartre dring_size = vdcp->local_dring_backup_len * 3540655fd6a9Sachartre sizeof (vdcp->local_dring_backup[0]); 3541655fd6a9Sachartre 3542655fd6a9Sachartre (void) kmem_free(vdcp->local_dring_backup, dring_size); 3543655fd6a9Sachartre 3544655fd6a9Sachartre vdcp->local_dring_backup = NULL; 3545655fd6a9Sachartre 3546655fd6a9Sachartre DTRACE_IO2(processed, int, count, vdc_t *, vdcp); 3547655fd6a9Sachartre } 3548655fd6a9Sachartre 3549655fd6a9Sachartre /* 3550655fd6a9Sachartre * Function: 3551655fd6a9Sachartre * vdc_connection_timeout 3552655fd6a9Sachartre * 3553655fd6a9Sachartre * Description: 3554655fd6a9Sachartre * This function is invoked if the timeout set to establish the connection 3555655fd6a9Sachartre * with vds expires. This will happen if we spend too much time in the 3556655fd6a9Sachartre * VDC_STATE_INIT_WAITING or VDC_STATE_NEGOTIATE states. Then we will 3557655fd6a9Sachartre * cancel any pending request and mark them as failed. 3558655fd6a9Sachartre * 3559655fd6a9Sachartre * If the timeout does not expire, it will be cancelled when we reach the 3560655fd6a9Sachartre * VDC_STATE_HANDLE_PENDING or VDC_STATE_RESETTING state. This function can 3561655fd6a9Sachartre * be invoked while we are in the VDC_STATE_HANDLE_PENDING or 3562655fd6a9Sachartre * VDC_STATE_RESETTING state in which case we do nothing because the 3563655fd6a9Sachartre * timeout is being cancelled. 3564655fd6a9Sachartre * 3565655fd6a9Sachartre * Arguments: 3566655fd6a9Sachartre * arg - argument of the timeout function actually a soft state 3567655fd6a9Sachartre * pointer for the instance of the device driver. 3568655fd6a9Sachartre * 3569655fd6a9Sachartre * Return Code: 3570655fd6a9Sachartre * None 3571655fd6a9Sachartre */ 3572655fd6a9Sachartre void 3573655fd6a9Sachartre vdc_connection_timeout(void *arg) 3574655fd6a9Sachartre { 3575655fd6a9Sachartre vdc_t *vdcp = (vdc_t *)arg; 3576655fd6a9Sachartre 3577655fd6a9Sachartre mutex_enter(&vdcp->lock); 3578655fd6a9Sachartre 3579655fd6a9Sachartre if (vdcp->state == VDC_STATE_HANDLE_PENDING || 3580655fd6a9Sachartre vdcp->state == VDC_STATE_DETACH) { 3581655fd6a9Sachartre /* 3582655fd6a9Sachartre * The connection has just been re-established or 3583655fd6a9Sachartre * we are detaching. 3584655fd6a9Sachartre */ 3585655fd6a9Sachartre vdcp->ctimeout_reached = B_FALSE; 3586655fd6a9Sachartre mutex_exit(&vdcp->lock); 3587655fd6a9Sachartre return; 3588655fd6a9Sachartre } 3589655fd6a9Sachartre 3590655fd6a9Sachartre vdcp->ctimeout_reached = B_TRUE; 3591655fd6a9Sachartre 3592655fd6a9Sachartre /* notify requests waiting for sending */ 3593655fd6a9Sachartre cv_broadcast(&vdcp->running_cv); 3594655fd6a9Sachartre 3595655fd6a9Sachartre /* cancel requests waiting for a result */ 3596655fd6a9Sachartre vdc_cancel_backup_ring(vdcp); 3597655fd6a9Sachartre 3598655fd6a9Sachartre mutex_exit(&vdcp->lock); 3599655fd6a9Sachartre 3600655fd6a9Sachartre cmn_err(CE_NOTE, "[%d] connection to service domain timeout", 3601655fd6a9Sachartre vdcp->instance); 3602655fd6a9Sachartre } 3603655fd6a9Sachartre 3604655fd6a9Sachartre /* 3605655fd6a9Sachartre * Function: 36063af08d82Slm66018 * vdc_backup_local_dring() 36073af08d82Slm66018 * 36083af08d82Slm66018 * Description: 36093af08d82Slm66018 * Backup the current dring in the event of a reset. The Dring 36103af08d82Slm66018 * transactions will be resubmitted to the server when the 36113af08d82Slm66018 * connection is restored. 36123af08d82Slm66018 * 36133af08d82Slm66018 * Arguments: 36143af08d82Slm66018 * vdcp - soft state pointer for this instance of the device driver. 36153af08d82Slm66018 * 36163af08d82Slm66018 * Return Code: 36173af08d82Slm66018 * NONE 36183af08d82Slm66018 */ 36193af08d82Slm66018 static void 36203af08d82Slm66018 vdc_backup_local_dring(vdc_t *vdcp) 36213af08d82Slm66018 { 36223af08d82Slm66018 int dring_size; 36233af08d82Slm66018 3624655fd6a9Sachartre ASSERT(MUTEX_HELD(&vdcp->lock)); 36253af08d82Slm66018 ASSERT(vdcp->state == VDC_STATE_RESETTING); 36263af08d82Slm66018 36273af08d82Slm66018 /* 36283af08d82Slm66018 * If the backup dring is stil around, it means 36293af08d82Slm66018 * that the last restore did not complete. However, 36303af08d82Slm66018 * since we never got back into the running state, 36313af08d82Slm66018 * the backup copy we have is still valid. 36323af08d82Slm66018 */ 36333af08d82Slm66018 if (vdcp->local_dring_backup != NULL) { 36343af08d82Slm66018 DMSG(vdcp, 1, "reusing local descriptor ring backup " 36353af08d82Slm66018 "(len=%d, tail=%d)\n", vdcp->local_dring_backup_len, 36363af08d82Slm66018 vdcp->local_dring_backup_tail); 36373af08d82Slm66018 return; 36383af08d82Slm66018 } 36393af08d82Slm66018 3640655fd6a9Sachartre /* 3641655fd6a9Sachartre * The backup dring can be NULL and the local dring may not be 3642655fd6a9Sachartre * initialized. This can happen if we had a reset while establishing 3643655fd6a9Sachartre * a new connection but after the connection has timed out. In that 3644655fd6a9Sachartre * case the backup dring is NULL because the requests have been 3645655fd6a9Sachartre * cancelled and the request occured before the local dring is 3646655fd6a9Sachartre * initialized. 3647655fd6a9Sachartre */ 3648655fd6a9Sachartre if (!(vdcp->initialized & VDC_DRING_LOCAL)) 3649655fd6a9Sachartre return; 3650655fd6a9Sachartre 36513af08d82Slm66018 DMSG(vdcp, 1, "backing up the local descriptor ring (len=%d, " 36523af08d82Slm66018 "tail=%d)\n", vdcp->dring_len, vdcp->dring_curr_idx); 36533af08d82Slm66018 36543af08d82Slm66018 dring_size = vdcp->dring_len * sizeof (vdcp->local_dring[0]); 36553af08d82Slm66018 36563af08d82Slm66018 vdcp->local_dring_backup = kmem_alloc(dring_size, KM_SLEEP); 36573af08d82Slm66018 bcopy(vdcp->local_dring, vdcp->local_dring_backup, dring_size); 36583af08d82Slm66018 36593af08d82Slm66018 vdcp->local_dring_backup_tail = vdcp->dring_curr_idx; 36603af08d82Slm66018 vdcp->local_dring_backup_len = vdcp->dring_len; 36613af08d82Slm66018 } 36623af08d82Slm66018 36631ae08745Sheppo /* -------------------------------------------------------------------------- */ 36641ae08745Sheppo 36651ae08745Sheppo /* 36661ae08745Sheppo * The following functions process the incoming messages from vds 36671ae08745Sheppo */ 36681ae08745Sheppo 36690a55fbb7Slm66018 /* 36700a55fbb7Slm66018 * Function: 36710a55fbb7Slm66018 * vdc_process_msg_thread() 36720a55fbb7Slm66018 * 36730a55fbb7Slm66018 * Description: 36740a55fbb7Slm66018 * 36753af08d82Slm66018 * Main VDC message processing thread. Each vDisk instance 36763af08d82Slm66018 * consists of a copy of this thread. This thread triggers 36773af08d82Slm66018 * all the handshakes and data exchange with the server. It 36783af08d82Slm66018 * also handles all channel resets 36793af08d82Slm66018 * 36800a55fbb7Slm66018 * Arguments: 36810a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 36820a55fbb7Slm66018 * 36830a55fbb7Slm66018 * Return Code: 36840a55fbb7Slm66018 * None 36850a55fbb7Slm66018 */ 36861ae08745Sheppo static void 36873af08d82Slm66018 vdc_process_msg_thread(vdc_t *vdcp) 36881ae08745Sheppo { 36891ae08745Sheppo int status; 3690655fd6a9Sachartre int ctimeout; 3691655fd6a9Sachartre timeout_id_t tmid = 0; 36921ae08745Sheppo 36933af08d82Slm66018 mutex_enter(&vdcp->lock); 36941ae08745Sheppo 36951ae08745Sheppo for (;;) { 36961ae08745Sheppo 36973af08d82Slm66018 #define Q(_s) (vdcp->state == _s) ? #_s : 36983af08d82Slm66018 DMSG(vdcp, 3, "state = %d (%s)\n", vdcp->state, 36993af08d82Slm66018 Q(VDC_STATE_INIT) 37003af08d82Slm66018 Q(VDC_STATE_INIT_WAITING) 37013af08d82Slm66018 Q(VDC_STATE_NEGOTIATE) 37023af08d82Slm66018 Q(VDC_STATE_HANDLE_PENDING) 37033af08d82Slm66018 Q(VDC_STATE_RUNNING) 37043af08d82Slm66018 Q(VDC_STATE_RESETTING) 37053af08d82Slm66018 Q(VDC_STATE_DETACH) 37063af08d82Slm66018 "UNKNOWN"); 37071ae08745Sheppo 37083af08d82Slm66018 switch (vdcp->state) { 37093af08d82Slm66018 case VDC_STATE_INIT: 37103af08d82Slm66018 3711655fd6a9Sachartre /* 3712655fd6a9Sachartre * If requested, start a timeout to check if the 3713655fd6a9Sachartre * connection with vds is established in the 3714655fd6a9Sachartre * specified delay. If the timeout expires, we 3715655fd6a9Sachartre * will cancel any pending request. 3716655fd6a9Sachartre * 3717655fd6a9Sachartre * If some reset have occurred while establishing 3718655fd6a9Sachartre * the connection, we already have a timeout armed 3719655fd6a9Sachartre * and in that case we don't need to arm a new one. 3720655fd6a9Sachartre */ 3721655fd6a9Sachartre ctimeout = (vdc_timeout != 0)? 3722655fd6a9Sachartre vdc_timeout : vdcp->ctimeout; 3723655fd6a9Sachartre 3724655fd6a9Sachartre if (ctimeout != 0 && tmid == 0) { 3725655fd6a9Sachartre tmid = timeout(vdc_connection_timeout, vdcp, 3726655fd6a9Sachartre ctimeout * drv_usectohz(1000000)); 3727655fd6a9Sachartre } 3728655fd6a9Sachartre 37293af08d82Slm66018 /* Check if have re-initializing repeatedly */ 3730655fd6a9Sachartre if (vdcp->hshake_cnt++ > vdc_hshake_retries && 3731655fd6a9Sachartre vdcp->lifecycle != VDC_LC_ONLINE) { 37323c96341aSnarayan cmn_err(CE_NOTE, "[%d] disk access failed.\n", 37333c96341aSnarayan vdcp->instance); 37343af08d82Slm66018 vdcp->state = VDC_STATE_DETACH; 37353af08d82Slm66018 break; 37363af08d82Slm66018 } 37373af08d82Slm66018 37383af08d82Slm66018 /* Bring up connection with vds via LDC */ 37393af08d82Slm66018 status = vdc_start_ldc_connection(vdcp); 3740655fd6a9Sachartre if (status == EINVAL) { 37413af08d82Slm66018 DMSG(vdcp, 0, "[%d] Could not start LDC", 37423af08d82Slm66018 vdcp->instance); 37433af08d82Slm66018 vdcp->state = VDC_STATE_DETACH; 3744655fd6a9Sachartre } else { 37453af08d82Slm66018 vdcp->state = VDC_STATE_INIT_WAITING; 37463af08d82Slm66018 } 37473af08d82Slm66018 break; 37483af08d82Slm66018 37493af08d82Slm66018 case VDC_STATE_INIT_WAITING: 37503af08d82Slm66018 37513af08d82Slm66018 /* 37523af08d82Slm66018 * Let the callback event move us on 37533af08d82Slm66018 * when channel is open to server 37543af08d82Slm66018 */ 37553af08d82Slm66018 while (vdcp->ldc_state != LDC_UP) { 37563af08d82Slm66018 cv_wait(&vdcp->initwait_cv, &vdcp->lock); 37573af08d82Slm66018 if (vdcp->state != VDC_STATE_INIT_WAITING) { 37583af08d82Slm66018 DMSG(vdcp, 0, 37593af08d82Slm66018 "state moved to %d out from under us...\n", 37603af08d82Slm66018 vdcp->state); 37613af08d82Slm66018 37623af08d82Slm66018 break; 37633af08d82Slm66018 } 37643af08d82Slm66018 } 37653af08d82Slm66018 if (vdcp->state == VDC_STATE_INIT_WAITING && 37663af08d82Slm66018 vdcp->ldc_state == LDC_UP) { 37673af08d82Slm66018 vdcp->state = VDC_STATE_NEGOTIATE; 37683af08d82Slm66018 } 37693af08d82Slm66018 break; 37703af08d82Slm66018 37713af08d82Slm66018 case VDC_STATE_NEGOTIATE: 37723af08d82Slm66018 switch (status = vdc_ver_negotiation(vdcp)) { 37733af08d82Slm66018 case 0: 37743af08d82Slm66018 break; 37753af08d82Slm66018 default: 37763af08d82Slm66018 DMSG(vdcp, 0, "ver negotiate failed (%d)..\n", 37773af08d82Slm66018 status); 37783af08d82Slm66018 goto reset; 37793af08d82Slm66018 } 37803af08d82Slm66018 37813af08d82Slm66018 switch (status = vdc_attr_negotiation(vdcp)) { 37823af08d82Slm66018 case 0: 37833af08d82Slm66018 break; 37843af08d82Slm66018 default: 37853af08d82Slm66018 DMSG(vdcp, 0, "attr negotiate failed (%d)..\n", 37863af08d82Slm66018 status); 37873af08d82Slm66018 goto reset; 37883af08d82Slm66018 } 37893af08d82Slm66018 37903af08d82Slm66018 switch (status = vdc_dring_negotiation(vdcp)) { 37913af08d82Slm66018 case 0: 37923af08d82Slm66018 break; 37933af08d82Slm66018 default: 37943af08d82Slm66018 DMSG(vdcp, 0, "dring negotiate failed (%d)..\n", 37953af08d82Slm66018 status); 37963af08d82Slm66018 goto reset; 37973af08d82Slm66018 } 37983af08d82Slm66018 37993af08d82Slm66018 switch (status = vdc_rdx_exchange(vdcp)) { 38003af08d82Slm66018 case 0: 38013af08d82Slm66018 vdcp->state = VDC_STATE_HANDLE_PENDING; 38023af08d82Slm66018 goto done; 38033af08d82Slm66018 default: 38043af08d82Slm66018 DMSG(vdcp, 0, "RDX xchg failed ..(%d)\n", 38053af08d82Slm66018 status); 38063af08d82Slm66018 goto reset; 38073af08d82Slm66018 } 38083af08d82Slm66018 reset: 38093af08d82Slm66018 DMSG(vdcp, 0, "negotiation failed: resetting (%d)\n", 38103af08d82Slm66018 status); 38113af08d82Slm66018 vdcp->state = VDC_STATE_RESETTING; 3812655fd6a9Sachartre vdcp->self_reset = B_TRUE; 38133af08d82Slm66018 done: 38143af08d82Slm66018 DMSG(vdcp, 0, "negotiation complete (state=0x%x)...\n", 38153af08d82Slm66018 vdcp->state); 38163af08d82Slm66018 break; 38173af08d82Slm66018 38183af08d82Slm66018 case VDC_STATE_HANDLE_PENDING: 38193af08d82Slm66018 3820655fd6a9Sachartre if (vdcp->ctimeout_reached) { 3821655fd6a9Sachartre /* 3822655fd6a9Sachartre * The connection timeout had been reached so 3823655fd6a9Sachartre * pending requests have been cancelled. Now 3824655fd6a9Sachartre * that the connection is back we can reset 3825655fd6a9Sachartre * the timeout. 3826655fd6a9Sachartre */ 3827655fd6a9Sachartre ASSERT(vdcp->local_dring_backup == NULL); 3828655fd6a9Sachartre ASSERT(tmid != 0); 3829655fd6a9Sachartre tmid = 0; 3830655fd6a9Sachartre vdcp->ctimeout_reached = B_FALSE; 3831655fd6a9Sachartre vdcp->state = VDC_STATE_RUNNING; 3832655fd6a9Sachartre DMSG(vdcp, 0, "[%d] connection to service " 3833655fd6a9Sachartre "domain is up", vdcp->instance); 3834655fd6a9Sachartre break; 3835655fd6a9Sachartre } 3836655fd6a9Sachartre 38373af08d82Slm66018 mutex_exit(&vdcp->lock); 3838655fd6a9Sachartre if (tmid != 0) { 3839655fd6a9Sachartre (void) untimeout(tmid); 3840655fd6a9Sachartre tmid = 0; 3841655fd6a9Sachartre } 38423af08d82Slm66018 status = vdc_resubmit_backup_dring(vdcp); 38433af08d82Slm66018 mutex_enter(&vdcp->lock); 38443af08d82Slm66018 38453af08d82Slm66018 if (status) 38463af08d82Slm66018 vdcp->state = VDC_STATE_RESETTING; 38473af08d82Slm66018 else 38483af08d82Slm66018 vdcp->state = VDC_STATE_RUNNING; 38493af08d82Slm66018 38503af08d82Slm66018 break; 38513af08d82Slm66018 38523af08d82Slm66018 /* enter running state */ 38533af08d82Slm66018 case VDC_STATE_RUNNING: 38543af08d82Slm66018 /* 38553af08d82Slm66018 * Signal anyone waiting for the connection 38563af08d82Slm66018 * to come on line. 38573af08d82Slm66018 */ 38583af08d82Slm66018 vdcp->hshake_cnt = 0; 38593af08d82Slm66018 cv_broadcast(&vdcp->running_cv); 38603af08d82Slm66018 mutex_exit(&vdcp->lock); 38613af08d82Slm66018 38623af08d82Slm66018 for (;;) { 38633af08d82Slm66018 vio_msg_t msg; 38643af08d82Slm66018 status = vdc_wait_for_response(vdcp, &msg); 38653af08d82Slm66018 if (status) break; 38663af08d82Slm66018 38673af08d82Slm66018 DMSG(vdcp, 1, "[%d] new pkt(s) available\n", 38683af08d82Slm66018 vdcp->instance); 38693af08d82Slm66018 status = vdc_process_data_msg(vdcp, &msg); 38701ae08745Sheppo if (status) { 38713af08d82Slm66018 DMSG(vdcp, 1, "[%d] process_data_msg " 38723af08d82Slm66018 "returned err=%d\n", vdcp->instance, 38733af08d82Slm66018 status); 38741ae08745Sheppo break; 38751ae08745Sheppo } 38761ae08745Sheppo 38773af08d82Slm66018 } 3878e1ebb9ecSlm66018 38793af08d82Slm66018 mutex_enter(&vdcp->lock); 38803af08d82Slm66018 38813af08d82Slm66018 vdcp->state = VDC_STATE_RESETTING; 3882690555a1Sachartre vdcp->self_reset = B_TRUE; 38833af08d82Slm66018 break; 38843af08d82Slm66018 38853af08d82Slm66018 case VDC_STATE_RESETTING: 3886655fd6a9Sachartre /* 3887655fd6a9Sachartre * When we reach this state, we either come from the 3888655fd6a9Sachartre * VDC_STATE_RUNNING state and we can have pending 3889655fd6a9Sachartre * request but no timeout is armed; or we come from 3890655fd6a9Sachartre * the VDC_STATE_INIT_WAITING, VDC_NEGOTIATE or 3891655fd6a9Sachartre * VDC_HANDLE_PENDING state and there is no pending 3892655fd6a9Sachartre * request or pending requests have already been copied 3893655fd6a9Sachartre * into the backup dring. So we can safely keep the 3894655fd6a9Sachartre * connection timeout armed while we are in this state. 3895655fd6a9Sachartre */ 3896655fd6a9Sachartre 38973af08d82Slm66018 DMSG(vdcp, 0, "Initiating channel reset " 38983af08d82Slm66018 "(pending = %d)\n", (int)vdcp->threads_pending); 38993af08d82Slm66018 39003af08d82Slm66018 if (vdcp->self_reset) { 39013af08d82Slm66018 DMSG(vdcp, 0, 39023af08d82Slm66018 "[%d] calling stop_ldc_connection.\n", 39033af08d82Slm66018 vdcp->instance); 39043af08d82Slm66018 status = vdc_stop_ldc_connection(vdcp); 39053af08d82Slm66018 vdcp->self_reset = B_FALSE; 39061ae08745Sheppo } 39071ae08745Sheppo 39081ae08745Sheppo /* 39093af08d82Slm66018 * Wait for all threads currently waiting 39103af08d82Slm66018 * for a free dring entry to use. 39111ae08745Sheppo */ 39123af08d82Slm66018 while (vdcp->threads_pending) { 39133af08d82Slm66018 cv_broadcast(&vdcp->membind_cv); 39143af08d82Slm66018 cv_broadcast(&vdcp->dring_free_cv); 39153af08d82Slm66018 mutex_exit(&vdcp->lock); 3916205eeb1aSlm66018 /* give the waiters enough time to wake up */ 3917205eeb1aSlm66018 delay(vdc_hz_min_ldc_delay); 39183af08d82Slm66018 mutex_enter(&vdcp->lock); 39191ae08745Sheppo } 39201ae08745Sheppo 39213af08d82Slm66018 ASSERT(vdcp->threads_pending == 0); 39221ae08745Sheppo 39233af08d82Slm66018 /* Sanity check that no thread is receiving */ 39243af08d82Slm66018 ASSERT(vdcp->read_state != VDC_READ_WAITING); 39250a55fbb7Slm66018 39263af08d82Slm66018 vdcp->read_state = VDC_READ_IDLE; 39273af08d82Slm66018 39283af08d82Slm66018 vdc_backup_local_dring(vdcp); 39293af08d82Slm66018 39303af08d82Slm66018 /* cleanup the old d-ring */ 39313af08d82Slm66018 vdc_destroy_descriptor_ring(vdcp); 39323af08d82Slm66018 39333af08d82Slm66018 /* go and start again */ 39343af08d82Slm66018 vdcp->state = VDC_STATE_INIT; 39353af08d82Slm66018 39360a55fbb7Slm66018 break; 39370a55fbb7Slm66018 39383af08d82Slm66018 case VDC_STATE_DETACH: 39393af08d82Slm66018 DMSG(vdcp, 0, "[%d] Reset thread exit cleanup ..\n", 39403af08d82Slm66018 vdcp->instance); 39413af08d82Slm66018 3942655fd6a9Sachartre /* cancel any pending timeout */ 3943655fd6a9Sachartre mutex_exit(&vdcp->lock); 3944655fd6a9Sachartre if (tmid != 0) { 3945655fd6a9Sachartre (void) untimeout(tmid); 3946655fd6a9Sachartre tmid = 0; 3947655fd6a9Sachartre } 3948655fd6a9Sachartre mutex_enter(&vdcp->lock); 3949655fd6a9Sachartre 39503c96341aSnarayan /* 39513c96341aSnarayan * Signal anyone waiting for connection 39523c96341aSnarayan * to come online 39533c96341aSnarayan */ 39543c96341aSnarayan cv_broadcast(&vdcp->running_cv); 39553c96341aSnarayan 39563af08d82Slm66018 while (vdcp->sync_op_pending) { 39573af08d82Slm66018 cv_signal(&vdcp->sync_pending_cv); 39583af08d82Slm66018 cv_signal(&vdcp->sync_blocked_cv); 39593af08d82Slm66018 mutex_exit(&vdcp->lock); 3960205eeb1aSlm66018 /* give the waiters enough time to wake up */ 3961205eeb1aSlm66018 delay(vdc_hz_min_ldc_delay); 39623af08d82Slm66018 mutex_enter(&vdcp->lock); 39630a55fbb7Slm66018 } 39641ae08745Sheppo 39653af08d82Slm66018 mutex_exit(&vdcp->lock); 39663af08d82Slm66018 39673af08d82Slm66018 DMSG(vdcp, 0, "[%d] Msg processing thread exiting ..\n", 39683af08d82Slm66018 vdcp->instance); 39693af08d82Slm66018 thread_exit(); 39703af08d82Slm66018 break; 39713af08d82Slm66018 } 39723af08d82Slm66018 } 39730a55fbb7Slm66018 } 39740a55fbb7Slm66018 39750a55fbb7Slm66018 39760a55fbb7Slm66018 /* 39770a55fbb7Slm66018 * Function: 39780a55fbb7Slm66018 * vdc_process_data_msg() 39790a55fbb7Slm66018 * 39800a55fbb7Slm66018 * Description: 39810a55fbb7Slm66018 * This function is called by the message processing thread each time 39820a55fbb7Slm66018 * a message with a msgtype of VIO_TYPE_DATA is received. It will either 39830a55fbb7Slm66018 * be an ACK or NACK from vds[1] which vdc handles as follows. 39840a55fbb7Slm66018 * ACK - wake up the waiting thread 39850a55fbb7Slm66018 * NACK - resend any messages necessary 39860a55fbb7Slm66018 * 39870a55fbb7Slm66018 * [1] Although the message format allows it, vds should not send a 39880a55fbb7Slm66018 * VIO_SUBTYPE_INFO message to vdc asking it to read data; if for 39890a55fbb7Slm66018 * some bizarre reason it does, vdc will reset the connection. 39900a55fbb7Slm66018 * 39910a55fbb7Slm66018 * Arguments: 39920a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 39930a55fbb7Slm66018 * msg - the LDC message sent by vds 39940a55fbb7Slm66018 * 39950a55fbb7Slm66018 * Return Code: 39960a55fbb7Slm66018 * 0 - Success. 39970a55fbb7Slm66018 * > 0 - error value returned by LDC 39980a55fbb7Slm66018 */ 39990a55fbb7Slm66018 static int 40003af08d82Slm66018 vdc_process_data_msg(vdc_t *vdcp, vio_msg_t *msg) 40010a55fbb7Slm66018 { 40020a55fbb7Slm66018 int status = 0; 40033af08d82Slm66018 vio_dring_msg_t *dring_msg; 4004d10e4ef2Snarayan vdc_local_desc_t *ldep = NULL; 40053af08d82Slm66018 int start, end; 40063af08d82Slm66018 int idx; 40070a55fbb7Slm66018 40083af08d82Slm66018 dring_msg = (vio_dring_msg_t *)msg; 40090a55fbb7Slm66018 40103af08d82Slm66018 ASSERT(msg->tag.vio_msgtype == VIO_TYPE_DATA); 40113af08d82Slm66018 ASSERT(vdcp != NULL); 40123af08d82Slm66018 40133af08d82Slm66018 mutex_enter(&vdcp->lock); 40140a55fbb7Slm66018 40150a55fbb7Slm66018 /* 40160a55fbb7Slm66018 * Check to see if the message has bogus data 40170a55fbb7Slm66018 */ 4018e1ebb9ecSlm66018 idx = start = dring_msg->start_idx; 40190a55fbb7Slm66018 end = dring_msg->end_idx; 40203af08d82Slm66018 if ((start >= vdcp->dring_len) || 40213af08d82Slm66018 (end >= vdcp->dring_len) || (end < -1)) { 40223af08d82Slm66018 DMSG(vdcp, 0, "[%d] Bogus ACK data : start %d, end %d\n", 40233af08d82Slm66018 vdcp->instance, start, end); 40243af08d82Slm66018 mutex_exit(&vdcp->lock); 4025e1ebb9ecSlm66018 return (EINVAL); 40260a55fbb7Slm66018 } 40270a55fbb7Slm66018 40280a55fbb7Slm66018 /* 40290a55fbb7Slm66018 * Verify that the sequence number is what vdc expects. 40300a55fbb7Slm66018 */ 40313af08d82Slm66018 switch (vdc_verify_seq_num(vdcp, dring_msg)) { 4032e1ebb9ecSlm66018 case VDC_SEQ_NUM_TODO: 4033e1ebb9ecSlm66018 break; /* keep processing this message */ 4034e1ebb9ecSlm66018 case VDC_SEQ_NUM_SKIP: 40353af08d82Slm66018 mutex_exit(&vdcp->lock); 4036e1ebb9ecSlm66018 return (0); 4037e1ebb9ecSlm66018 case VDC_SEQ_NUM_INVALID: 40383af08d82Slm66018 mutex_exit(&vdcp->lock); 40393af08d82Slm66018 DMSG(vdcp, 0, "[%d] invalid seqno\n", vdcp->instance); 40400a55fbb7Slm66018 return (ENXIO); 40410a55fbb7Slm66018 } 40420a55fbb7Slm66018 40433af08d82Slm66018 if (msg->tag.vio_subtype == VIO_SUBTYPE_NACK) { 40443af08d82Slm66018 DMSG(vdcp, 0, "[%d] DATA NACK\n", vdcp->instance); 4045e1ebb9ecSlm66018 VDC_DUMP_DRING_MSG(dring_msg); 40463af08d82Slm66018 mutex_exit(&vdcp->lock); 4047e1ebb9ecSlm66018 return (EIO); 40480a55fbb7Slm66018 40493af08d82Slm66018 } else if (msg->tag.vio_subtype == VIO_SUBTYPE_INFO) { 40503af08d82Slm66018 mutex_exit(&vdcp->lock); 4051e1ebb9ecSlm66018 return (EPROTO); 4052e1ebb9ecSlm66018 } 4053e1ebb9ecSlm66018 40543af08d82Slm66018 DTRACE_IO2(recv, vio_dring_msg_t, dring_msg, vdc_t *, vdcp); 40553af08d82Slm66018 DMSG(vdcp, 1, ": start %d end %d\n", start, end); 40563af08d82Slm66018 ASSERT(start == end); 40573af08d82Slm66018 40583af08d82Slm66018 ldep = &vdcp->local_dring[idx]; 40593af08d82Slm66018 40603af08d82Slm66018 DMSG(vdcp, 1, ": state 0x%x - cb_type 0x%x\n", 40613af08d82Slm66018 ldep->dep->hdr.dstate, ldep->cb_type); 40623af08d82Slm66018 4063e1ebb9ecSlm66018 if (ldep->dep->hdr.dstate == VIO_DESC_DONE) { 40643af08d82Slm66018 struct buf *bufp; 4065e1ebb9ecSlm66018 40663af08d82Slm66018 switch (ldep->cb_type) { 40673af08d82Slm66018 case CB_SYNC: 40683af08d82Slm66018 ASSERT(vdcp->sync_op_pending); 4069d10e4ef2Snarayan 40703af08d82Slm66018 status = vdc_depopulate_descriptor(vdcp, idx); 40713af08d82Slm66018 vdcp->sync_op_status = status; 40723af08d82Slm66018 vdcp->sync_op_pending = B_FALSE; 40733af08d82Slm66018 cv_signal(&vdcp->sync_pending_cv); 40743af08d82Slm66018 break; 40754bac2208Snarayan 40763af08d82Slm66018 case CB_STRATEGY: 40773af08d82Slm66018 bufp = ldep->cb_arg; 40783af08d82Slm66018 ASSERT(bufp != NULL); 40793c96341aSnarayan bufp->b_resid = 40803c96341aSnarayan bufp->b_bcount - ldep->dep->payload.nbytes; 40813af08d82Slm66018 status = ldep->dep->payload.status; /* Future:ntoh */ 40823af08d82Slm66018 if (status != 0) { 40833af08d82Slm66018 DMSG(vdcp, 1, "strategy status=%d\n", status); 40843af08d82Slm66018 bioerror(bufp, status); 4085d10e4ef2Snarayan } 40863af08d82Slm66018 status = vdc_depopulate_descriptor(vdcp, idx); 40873af08d82Slm66018 biodone(bufp); 40883c96341aSnarayan 40893c96341aSnarayan DMSG(vdcp, 1, 40903c96341aSnarayan "strategy complete req=%ld bytes resp=%ld bytes\n", 40913c96341aSnarayan bufp->b_bcount, ldep->dep->payload.nbytes); 40923af08d82Slm66018 break; 40933af08d82Slm66018 40943af08d82Slm66018 default: 40953af08d82Slm66018 ASSERT(0); 40960a55fbb7Slm66018 } 40973af08d82Slm66018 } 40983af08d82Slm66018 40993af08d82Slm66018 /* let the arrival signal propogate */ 41003af08d82Slm66018 mutex_exit(&vdcp->lock); 41010a55fbb7Slm66018 4102e1ebb9ecSlm66018 /* probe gives the count of how many entries were processed */ 41033af08d82Slm66018 DTRACE_IO2(processed, int, 1, vdc_t *, vdcp); 41040a55fbb7Slm66018 41053af08d82Slm66018 return (0); 41060a55fbb7Slm66018 } 41070a55fbb7Slm66018 41080a55fbb7Slm66018 /* 41090a55fbb7Slm66018 * Function: 41100a55fbb7Slm66018 * vdc_process_err_msg() 41110a55fbb7Slm66018 * 41120a55fbb7Slm66018 * NOTE: No error messages are used as part of the vDisk protocol 41130a55fbb7Slm66018 */ 41140a55fbb7Slm66018 static int 41150a55fbb7Slm66018 vdc_process_err_msg(vdc_t *vdc, vio_msg_t msg) 41160a55fbb7Slm66018 { 41170a55fbb7Slm66018 _NOTE(ARGUNUSED(vdc)) 41180a55fbb7Slm66018 _NOTE(ARGUNUSED(msg)) 41190a55fbb7Slm66018 41200a55fbb7Slm66018 ASSERT(msg.tag.vio_msgtype == VIO_TYPE_ERR); 41213af08d82Slm66018 DMSG(vdc, 1, "[%d] Got an ERR msg", vdc->instance); 41220a55fbb7Slm66018 41230a55fbb7Slm66018 return (ENOTSUP); 41240a55fbb7Slm66018 } 41250a55fbb7Slm66018 41260a55fbb7Slm66018 /* 41270a55fbb7Slm66018 * Function: 41280a55fbb7Slm66018 * vdc_handle_ver_msg() 41290a55fbb7Slm66018 * 41300a55fbb7Slm66018 * Description: 41310a55fbb7Slm66018 * 41320a55fbb7Slm66018 * Arguments: 41330a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 41340a55fbb7Slm66018 * ver_msg - LDC message sent by vDisk server 41350a55fbb7Slm66018 * 41360a55fbb7Slm66018 * Return Code: 41370a55fbb7Slm66018 * 0 - Success 41380a55fbb7Slm66018 */ 41390a55fbb7Slm66018 static int 41400a55fbb7Slm66018 vdc_handle_ver_msg(vdc_t *vdc, vio_ver_msg_t *ver_msg) 41410a55fbb7Slm66018 { 41420a55fbb7Slm66018 int status = 0; 41430a55fbb7Slm66018 41440a55fbb7Slm66018 ASSERT(vdc != NULL); 41450a55fbb7Slm66018 ASSERT(mutex_owned(&vdc->lock)); 41460a55fbb7Slm66018 41470a55fbb7Slm66018 if (ver_msg->tag.vio_subtype_env != VIO_VER_INFO) { 41480a55fbb7Slm66018 return (EPROTO); 41490a55fbb7Slm66018 } 41500a55fbb7Slm66018 41510a55fbb7Slm66018 if (ver_msg->dev_class != VDEV_DISK_SERVER) { 41520a55fbb7Slm66018 return (EINVAL); 41530a55fbb7Slm66018 } 41540a55fbb7Slm66018 41550a55fbb7Slm66018 switch (ver_msg->tag.vio_subtype) { 41560a55fbb7Slm66018 case VIO_SUBTYPE_ACK: 41570a55fbb7Slm66018 /* 41580a55fbb7Slm66018 * We check to see if the version returned is indeed supported 41590a55fbb7Slm66018 * (The server may have also adjusted the minor number downwards 41600a55fbb7Slm66018 * and if so 'ver_msg' will contain the actual version agreed) 41610a55fbb7Slm66018 */ 41620a55fbb7Slm66018 if (vdc_is_supported_version(ver_msg)) { 41630a55fbb7Slm66018 vdc->ver.major = ver_msg->ver_major; 41640a55fbb7Slm66018 vdc->ver.minor = ver_msg->ver_minor; 41650a55fbb7Slm66018 ASSERT(vdc->ver.major > 0); 41660a55fbb7Slm66018 } else { 41670a55fbb7Slm66018 status = EPROTO; 41680a55fbb7Slm66018 } 41690a55fbb7Slm66018 break; 41700a55fbb7Slm66018 41710a55fbb7Slm66018 case VIO_SUBTYPE_NACK: 41720a55fbb7Slm66018 /* 41730a55fbb7Slm66018 * call vdc_is_supported_version() which will return the next 41740a55fbb7Slm66018 * supported version (if any) in 'ver_msg' 41750a55fbb7Slm66018 */ 41760a55fbb7Slm66018 (void) vdc_is_supported_version(ver_msg); 41770a55fbb7Slm66018 if (ver_msg->ver_major > 0) { 41780a55fbb7Slm66018 size_t len = sizeof (*ver_msg); 41790a55fbb7Slm66018 41800a55fbb7Slm66018 ASSERT(vdc->ver.major > 0); 41810a55fbb7Slm66018 41820a55fbb7Slm66018 /* reset the necessary fields and resend */ 41830a55fbb7Slm66018 ver_msg->tag.vio_subtype = VIO_SUBTYPE_INFO; 41840a55fbb7Slm66018 ver_msg->dev_class = VDEV_DISK; 41850a55fbb7Slm66018 41860a55fbb7Slm66018 status = vdc_send(vdc, (caddr_t)ver_msg, &len); 41873af08d82Slm66018 DMSG(vdc, 0, "[%d] Resend VER info (LDC status = %d)\n", 41880a55fbb7Slm66018 vdc->instance, status); 41890a55fbb7Slm66018 if (len != sizeof (*ver_msg)) 41900a55fbb7Slm66018 status = EBADMSG; 41910a55fbb7Slm66018 } else { 419287a7269eSachartre DMSG(vdc, 0, "[%d] No common version with vDisk server", 419387a7269eSachartre vdc->instance); 41940a55fbb7Slm66018 status = ENOTSUP; 41950a55fbb7Slm66018 } 41960a55fbb7Slm66018 41970a55fbb7Slm66018 break; 41981ae08745Sheppo case VIO_SUBTYPE_INFO: 41991ae08745Sheppo /* 42001ae08745Sheppo * Handle the case where vds starts handshake 4201eff7243fSlm66018 * (for now only vdc is the instigator) 42021ae08745Sheppo */ 42031ae08745Sheppo status = ENOTSUP; 42041ae08745Sheppo break; 42051ae08745Sheppo 42061ae08745Sheppo default: 42070a55fbb7Slm66018 status = EINVAL; 42081ae08745Sheppo break; 42091ae08745Sheppo } 42101ae08745Sheppo 42110a55fbb7Slm66018 return (status); 42120a55fbb7Slm66018 } 42130a55fbb7Slm66018 42140a55fbb7Slm66018 /* 42150a55fbb7Slm66018 * Function: 42160a55fbb7Slm66018 * vdc_handle_attr_msg() 42170a55fbb7Slm66018 * 42180a55fbb7Slm66018 * Description: 42190a55fbb7Slm66018 * 42200a55fbb7Slm66018 * Arguments: 42210a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 42220a55fbb7Slm66018 * attr_msg - LDC message sent by vDisk server 42230a55fbb7Slm66018 * 42240a55fbb7Slm66018 * Return Code: 42250a55fbb7Slm66018 * 0 - Success 42260a55fbb7Slm66018 */ 42270a55fbb7Slm66018 static int 42280a55fbb7Slm66018 vdc_handle_attr_msg(vdc_t *vdc, vd_attr_msg_t *attr_msg) 42290a55fbb7Slm66018 { 42300a55fbb7Slm66018 int status = 0; 42310a55fbb7Slm66018 42320a55fbb7Slm66018 ASSERT(vdc != NULL); 42330a55fbb7Slm66018 ASSERT(mutex_owned(&vdc->lock)); 42340a55fbb7Slm66018 42350a55fbb7Slm66018 if (attr_msg->tag.vio_subtype_env != VIO_ATTR_INFO) { 42360a55fbb7Slm66018 return (EPROTO); 42370a55fbb7Slm66018 } 42380a55fbb7Slm66018 42390a55fbb7Slm66018 switch (attr_msg->tag.vio_subtype) { 42401ae08745Sheppo case VIO_SUBTYPE_ACK: 42411ae08745Sheppo /* 42421ae08745Sheppo * We now verify the attributes sent by vds. 42431ae08745Sheppo */ 4244*78fcd0a1Sachartre if (attr_msg->vdisk_size == 0) { 4245*78fcd0a1Sachartre DMSG(vdc, 0, "[%d] Invalid disk size from vds", 4246*78fcd0a1Sachartre vdc->instance); 4247*78fcd0a1Sachartre status = EINVAL; 4248*78fcd0a1Sachartre break; 4249*78fcd0a1Sachartre } 4250*78fcd0a1Sachartre 4251*78fcd0a1Sachartre if (attr_msg->max_xfer_sz == 0) { 4252*78fcd0a1Sachartre DMSG(vdc, 0, "[%d] Invalid transfer size from vds", 4253*78fcd0a1Sachartre vdc->instance); 4254*78fcd0a1Sachartre status = EINVAL; 4255*78fcd0a1Sachartre break; 4256*78fcd0a1Sachartre } 4257*78fcd0a1Sachartre 4258*78fcd0a1Sachartre /* 4259*78fcd0a1Sachartre * If the disk size is already set check that it hasn't changed. 4260*78fcd0a1Sachartre */ 4261*78fcd0a1Sachartre if ((vdc->vdisk_size != 0) && 4262*78fcd0a1Sachartre (vdc->vdisk_size != attr_msg->vdisk_size)) { 4263*78fcd0a1Sachartre DMSG(vdc, 0, "[%d] Different disk size from vds " 4264*78fcd0a1Sachartre "(old=0x%lx - new=0x%lx", vdc->instance, 4265*78fcd0a1Sachartre vdc->vdisk_size, attr_msg->vdisk_size) 4266*78fcd0a1Sachartre status = EINVAL; 4267*78fcd0a1Sachartre break; 4268*78fcd0a1Sachartre } 4269*78fcd0a1Sachartre 42701ae08745Sheppo vdc->vdisk_size = attr_msg->vdisk_size; 42711ae08745Sheppo vdc->vdisk_type = attr_msg->vdisk_type; 42721ae08745Sheppo 42733af08d82Slm66018 DMSG(vdc, 0, "[%d] max_xfer_sz: sent %lx acked %lx\n", 4274e1ebb9ecSlm66018 vdc->instance, vdc->max_xfer_sz, attr_msg->max_xfer_sz); 42753af08d82Slm66018 DMSG(vdc, 0, "[%d] vdisk_block_size: sent %lx acked %x\n", 4276e1ebb9ecSlm66018 vdc->instance, vdc->block_size, 4277e1ebb9ecSlm66018 attr_msg->vdisk_block_size); 4278e1ebb9ecSlm66018 42791ae08745Sheppo /* 4280e1ebb9ecSlm66018 * We don't know at compile time what the vDisk server will 4281e1ebb9ecSlm66018 * think are good values but we apply an large (arbitrary) 4282e1ebb9ecSlm66018 * upper bound to prevent memory exhaustion in vdc if it was 4283e1ebb9ecSlm66018 * allocating a DRing based of huge values sent by the server. 4284e1ebb9ecSlm66018 * We probably will never exceed this except if the message 4285e1ebb9ecSlm66018 * was garbage. 42861ae08745Sheppo */ 4287e1ebb9ecSlm66018 if ((attr_msg->max_xfer_sz * attr_msg->vdisk_block_size) <= 4288e1ebb9ecSlm66018 (PAGESIZE * DEV_BSIZE)) { 4289e1ebb9ecSlm66018 vdc->max_xfer_sz = attr_msg->max_xfer_sz; 4290e1ebb9ecSlm66018 vdc->block_size = attr_msg->vdisk_block_size; 4291e1ebb9ecSlm66018 } else { 42923af08d82Slm66018 DMSG(vdc, 0, "[%d] vds block transfer size too big;" 4293e1ebb9ecSlm66018 " using max supported by vdc", vdc->instance); 42941ae08745Sheppo } 42951ae08745Sheppo 42961ae08745Sheppo if ((attr_msg->xfer_mode != VIO_DRING_MODE) || 42971ae08745Sheppo (attr_msg->vdisk_size > INT64_MAX) || 42981ae08745Sheppo (attr_msg->vdisk_type > VD_DISK_TYPE_DISK)) { 42993af08d82Slm66018 DMSG(vdc, 0, "[%d] Invalid attributes from vds", 4300e1ebb9ecSlm66018 vdc->instance); 43011ae08745Sheppo status = EINVAL; 43021ae08745Sheppo break; 43031ae08745Sheppo } 43041ae08745Sheppo 4305*78fcd0a1Sachartre /* 4306*78fcd0a1Sachartre * Now that we have received all attributes we can create a 4307*78fcd0a1Sachartre * fake geometry for the disk. 4308*78fcd0a1Sachartre */ 4309*78fcd0a1Sachartre vdc_create_fake_geometry(vdc); 43101ae08745Sheppo break; 43111ae08745Sheppo 43121ae08745Sheppo case VIO_SUBTYPE_NACK: 43131ae08745Sheppo /* 43141ae08745Sheppo * vds could not handle the attributes we sent so we 43151ae08745Sheppo * stop negotiating. 43161ae08745Sheppo */ 43171ae08745Sheppo status = EPROTO; 43181ae08745Sheppo break; 43191ae08745Sheppo 43201ae08745Sheppo case VIO_SUBTYPE_INFO: 43211ae08745Sheppo /* 43221ae08745Sheppo * Handle the case where vds starts the handshake 43231ae08745Sheppo * (for now; vdc is the only supported instigatior) 43241ae08745Sheppo */ 43251ae08745Sheppo status = ENOTSUP; 43261ae08745Sheppo break; 43271ae08745Sheppo 43281ae08745Sheppo default: 43291ae08745Sheppo status = ENOTSUP; 43301ae08745Sheppo break; 43311ae08745Sheppo } 43321ae08745Sheppo 43330a55fbb7Slm66018 return (status); 43341ae08745Sheppo } 43351ae08745Sheppo 43360a55fbb7Slm66018 /* 43370a55fbb7Slm66018 * Function: 43380a55fbb7Slm66018 * vdc_handle_dring_reg_msg() 43390a55fbb7Slm66018 * 43400a55fbb7Slm66018 * Description: 43410a55fbb7Slm66018 * 43420a55fbb7Slm66018 * Arguments: 43430a55fbb7Slm66018 * vdc - soft state pointer for this instance of the driver. 43440a55fbb7Slm66018 * dring_msg - LDC message sent by vDisk server 43450a55fbb7Slm66018 * 43460a55fbb7Slm66018 * Return Code: 43470a55fbb7Slm66018 * 0 - Success 43480a55fbb7Slm66018 */ 43490a55fbb7Slm66018 static int 43500a55fbb7Slm66018 vdc_handle_dring_reg_msg(vdc_t *vdc, vio_dring_reg_msg_t *dring_msg) 43510a55fbb7Slm66018 { 43520a55fbb7Slm66018 int status = 0; 43531ae08745Sheppo 43540a55fbb7Slm66018 ASSERT(vdc != NULL); 43550a55fbb7Slm66018 ASSERT(mutex_owned(&vdc->lock)); 43560a55fbb7Slm66018 43570a55fbb7Slm66018 if (dring_msg->tag.vio_subtype_env != VIO_DRING_REG) { 43580a55fbb7Slm66018 return (EPROTO); 43590a55fbb7Slm66018 } 43600a55fbb7Slm66018 43610a55fbb7Slm66018 switch (dring_msg->tag.vio_subtype) { 43620a55fbb7Slm66018 case VIO_SUBTYPE_ACK: 43631ae08745Sheppo /* save the received dring_ident */ 43641ae08745Sheppo vdc->dring_ident = dring_msg->dring_ident; 43653af08d82Slm66018 DMSG(vdc, 0, "[%d] Received dring ident=0x%lx\n", 4366e1ebb9ecSlm66018 vdc->instance, vdc->dring_ident); 43671ae08745Sheppo break; 43681ae08745Sheppo 43691ae08745Sheppo case VIO_SUBTYPE_NACK: 43701ae08745Sheppo /* 43711ae08745Sheppo * vds could not handle the DRing info we sent so we 43721ae08745Sheppo * stop negotiating. 43731ae08745Sheppo */ 43743af08d82Slm66018 DMSG(vdc, 0, "[%d] server could not register DRing\n", 43753af08d82Slm66018 vdc->instance); 43761ae08745Sheppo status = EPROTO; 43771ae08745Sheppo break; 43781ae08745Sheppo 43791ae08745Sheppo case VIO_SUBTYPE_INFO: 43801ae08745Sheppo /* 43811ae08745Sheppo * Handle the case where vds starts handshake 43821ae08745Sheppo * (for now only vdc is the instigatior) 43831ae08745Sheppo */ 43841ae08745Sheppo status = ENOTSUP; 43851ae08745Sheppo break; 43861ae08745Sheppo default: 43871ae08745Sheppo status = ENOTSUP; 43881ae08745Sheppo } 43891ae08745Sheppo 43901ae08745Sheppo return (status); 43911ae08745Sheppo } 43921ae08745Sheppo 43931ae08745Sheppo /* 43941ae08745Sheppo * Function: 43951ae08745Sheppo * vdc_verify_seq_num() 43961ae08745Sheppo * 43971ae08745Sheppo * Description: 4398e1ebb9ecSlm66018 * This functions verifies that the sequence number sent back by the vDisk 4399e1ebb9ecSlm66018 * server with the latest message is what is expected (i.e. it is greater 4400e1ebb9ecSlm66018 * than the last seq num sent by the vDisk server and less than or equal 4401e1ebb9ecSlm66018 * to the last seq num generated by vdc). 4402e1ebb9ecSlm66018 * 4403e1ebb9ecSlm66018 * It then checks the request ID to see if any requests need processing 4404e1ebb9ecSlm66018 * in the DRing. 44051ae08745Sheppo * 44061ae08745Sheppo * Arguments: 44071ae08745Sheppo * vdc - soft state pointer for this instance of the driver. 44081ae08745Sheppo * dring_msg - pointer to the LDC message sent by vds 44091ae08745Sheppo * 44101ae08745Sheppo * Return Code: 4411e1ebb9ecSlm66018 * VDC_SEQ_NUM_TODO - Message needs to be processed 4412e1ebb9ecSlm66018 * VDC_SEQ_NUM_SKIP - Message has already been processed 4413e1ebb9ecSlm66018 * VDC_SEQ_NUM_INVALID - The seq numbers are so out of sync, 4414e1ebb9ecSlm66018 * vdc cannot deal with them 44151ae08745Sheppo */ 4416e1ebb9ecSlm66018 static int 4417e1ebb9ecSlm66018 vdc_verify_seq_num(vdc_t *vdc, vio_dring_msg_t *dring_msg) 44181ae08745Sheppo { 44191ae08745Sheppo ASSERT(vdc != NULL); 44201ae08745Sheppo ASSERT(dring_msg != NULL); 4421d10e4ef2Snarayan ASSERT(mutex_owned(&vdc->lock)); 44221ae08745Sheppo 44231ae08745Sheppo /* 44241ae08745Sheppo * Check to see if the messages were responded to in the correct 4425e1ebb9ecSlm66018 * order by vds. 44261ae08745Sheppo */ 4427e1ebb9ecSlm66018 if ((dring_msg->seq_num <= vdc->seq_num_reply) || 4428e1ebb9ecSlm66018 (dring_msg->seq_num > vdc->seq_num)) { 44293af08d82Slm66018 DMSG(vdc, 0, "?[%d] Bogus sequence_number %lu: " 4430e1ebb9ecSlm66018 "%lu > expected <= %lu (last proc req %lu sent %lu)\n", 4431e1ebb9ecSlm66018 vdc->instance, dring_msg->seq_num, 4432e1ebb9ecSlm66018 vdc->seq_num_reply, vdc->seq_num, 4433e1ebb9ecSlm66018 vdc->req_id_proc, vdc->req_id); 4434e1ebb9ecSlm66018 return (VDC_SEQ_NUM_INVALID); 44351ae08745Sheppo } 4436e1ebb9ecSlm66018 vdc->seq_num_reply = dring_msg->seq_num; 44371ae08745Sheppo 4438e1ebb9ecSlm66018 if (vdc->req_id_proc < vdc->req_id) 4439e1ebb9ecSlm66018 return (VDC_SEQ_NUM_TODO); 4440e1ebb9ecSlm66018 else 4441e1ebb9ecSlm66018 return (VDC_SEQ_NUM_SKIP); 44421ae08745Sheppo } 44431ae08745Sheppo 44440a55fbb7Slm66018 44450a55fbb7Slm66018 /* 44460a55fbb7Slm66018 * Function: 44470a55fbb7Slm66018 * vdc_is_supported_version() 44480a55fbb7Slm66018 * 44490a55fbb7Slm66018 * Description: 44500a55fbb7Slm66018 * This routine checks if the major/minor version numbers specified in 44510a55fbb7Slm66018 * 'ver_msg' are supported. If not it finds the next version that is 44520a55fbb7Slm66018 * in the supported version list 'vdc_version[]' and sets the fields in 44530a55fbb7Slm66018 * 'ver_msg' to those values 44540a55fbb7Slm66018 * 44550a55fbb7Slm66018 * Arguments: 44560a55fbb7Slm66018 * ver_msg - LDC message sent by vDisk server 44570a55fbb7Slm66018 * 44580a55fbb7Slm66018 * Return Code: 44590a55fbb7Slm66018 * B_TRUE - Success 44600a55fbb7Slm66018 * B_FALSE - Version not supported 44610a55fbb7Slm66018 */ 44620a55fbb7Slm66018 static boolean_t 44630a55fbb7Slm66018 vdc_is_supported_version(vio_ver_msg_t *ver_msg) 44640a55fbb7Slm66018 { 44650a55fbb7Slm66018 int vdc_num_versions = sizeof (vdc_version) / sizeof (vdc_version[0]); 44660a55fbb7Slm66018 44670a55fbb7Slm66018 for (int i = 0; i < vdc_num_versions; i++) { 44680a55fbb7Slm66018 ASSERT(vdc_version[i].major > 0); 44690a55fbb7Slm66018 ASSERT((i == 0) || 44700a55fbb7Slm66018 (vdc_version[i].major < vdc_version[i-1].major)); 44710a55fbb7Slm66018 44720a55fbb7Slm66018 /* 44730a55fbb7Slm66018 * If the major versions match, adjust the minor version, if 44740a55fbb7Slm66018 * necessary, down to the highest value supported by this 44750a55fbb7Slm66018 * client. The server should support all minor versions lower 44760a55fbb7Slm66018 * than the value it sent 44770a55fbb7Slm66018 */ 44780a55fbb7Slm66018 if (ver_msg->ver_major == vdc_version[i].major) { 44790a55fbb7Slm66018 if (ver_msg->ver_minor > vdc_version[i].minor) { 44803af08d82Slm66018 DMSGX(0, 44813af08d82Slm66018 "Adjusting minor version from %u to %u", 44820a55fbb7Slm66018 ver_msg->ver_minor, vdc_version[i].minor); 44830a55fbb7Slm66018 ver_msg->ver_minor = vdc_version[i].minor; 44840a55fbb7Slm66018 } 44850a55fbb7Slm66018 return (B_TRUE); 44860a55fbb7Slm66018 } 44870a55fbb7Slm66018 44880a55fbb7Slm66018 /* 44890a55fbb7Slm66018 * If the message contains a higher major version number, set 44900a55fbb7Slm66018 * the message's major/minor versions to the current values 44910a55fbb7Slm66018 * and return false, so this message will get resent with 44920a55fbb7Slm66018 * these values, and the server will potentially try again 44930a55fbb7Slm66018 * with the same or a lower version 44940a55fbb7Slm66018 */ 44950a55fbb7Slm66018 if (ver_msg->ver_major > vdc_version[i].major) { 44960a55fbb7Slm66018 ver_msg->ver_major = vdc_version[i].major; 44970a55fbb7Slm66018 ver_msg->ver_minor = vdc_version[i].minor; 44983af08d82Slm66018 DMSGX(0, "Suggesting major/minor (0x%x/0x%x)\n", 44990a55fbb7Slm66018 ver_msg->ver_major, ver_msg->ver_minor); 45000a55fbb7Slm66018 45010a55fbb7Slm66018 return (B_FALSE); 45020a55fbb7Slm66018 } 45030a55fbb7Slm66018 45040a55fbb7Slm66018 /* 45050a55fbb7Slm66018 * Otherwise, the message's major version is less than the 45060a55fbb7Slm66018 * current major version, so continue the loop to the next 45070a55fbb7Slm66018 * (lower) supported version 45080a55fbb7Slm66018 */ 45090a55fbb7Slm66018 } 45100a55fbb7Slm66018 45110a55fbb7Slm66018 /* 45120a55fbb7Slm66018 * No common version was found; "ground" the version pair in the 45130a55fbb7Slm66018 * message to terminate negotiation 45140a55fbb7Slm66018 */ 45150a55fbb7Slm66018 ver_msg->ver_major = 0; 45160a55fbb7Slm66018 ver_msg->ver_minor = 0; 45170a55fbb7Slm66018 45180a55fbb7Slm66018 return (B_FALSE); 45190a55fbb7Slm66018 } 45201ae08745Sheppo /* -------------------------------------------------------------------------- */ 45211ae08745Sheppo 45221ae08745Sheppo /* 45231ae08745Sheppo * DKIO(7) support 45241ae08745Sheppo */ 45251ae08745Sheppo 45261ae08745Sheppo typedef struct vdc_dk_arg { 45271ae08745Sheppo struct dk_callback dkc; 45281ae08745Sheppo int mode; 45291ae08745Sheppo dev_t dev; 45301ae08745Sheppo vdc_t *vdc; 45311ae08745Sheppo } vdc_dk_arg_t; 45321ae08745Sheppo 45331ae08745Sheppo /* 45341ae08745Sheppo * Function: 45351ae08745Sheppo * vdc_dkio_flush_cb() 45361ae08745Sheppo * 45371ae08745Sheppo * Description: 45381ae08745Sheppo * This routine is a callback for DKIOCFLUSHWRITECACHE which can be called 45391ae08745Sheppo * by kernel code. 45401ae08745Sheppo * 45411ae08745Sheppo * Arguments: 45421ae08745Sheppo * arg - a pointer to a vdc_dk_arg_t structure. 45431ae08745Sheppo */ 45441ae08745Sheppo void 45451ae08745Sheppo vdc_dkio_flush_cb(void *arg) 45461ae08745Sheppo { 45471ae08745Sheppo struct vdc_dk_arg *dk_arg = (struct vdc_dk_arg *)arg; 45481ae08745Sheppo struct dk_callback *dkc = NULL; 45491ae08745Sheppo vdc_t *vdc = NULL; 45501ae08745Sheppo int rv; 45511ae08745Sheppo 45521ae08745Sheppo if (dk_arg == NULL) { 45533af08d82Slm66018 cmn_err(CE_NOTE, "?[Unk] DKIOCFLUSHWRITECACHE arg is NULL\n"); 45541ae08745Sheppo return; 45551ae08745Sheppo } 45561ae08745Sheppo dkc = &dk_arg->dkc; 45571ae08745Sheppo vdc = dk_arg->vdc; 45581ae08745Sheppo ASSERT(vdc != NULL); 45591ae08745Sheppo 45603af08d82Slm66018 rv = vdc_do_sync_op(vdc, VD_OP_FLUSH, NULL, 0, 45610d0c8d4bSnarayan VDCPART(dk_arg->dev), 0, CB_SYNC, 0, VIO_both_dir); 45621ae08745Sheppo if (rv != 0) { 45633af08d82Slm66018 DMSG(vdc, 0, "[%d] DKIOCFLUSHWRITECACHE failed %d : model %x\n", 4564e1ebb9ecSlm66018 vdc->instance, rv, 45651ae08745Sheppo ddi_model_convert_from(dk_arg->mode & FMODELS)); 45661ae08745Sheppo } 45671ae08745Sheppo 45681ae08745Sheppo /* 45691ae08745Sheppo * Trigger the call back to notify the caller the the ioctl call has 45701ae08745Sheppo * been completed. 45711ae08745Sheppo */ 45721ae08745Sheppo if ((dk_arg->mode & FKIOCTL) && 45731ae08745Sheppo (dkc != NULL) && 45741ae08745Sheppo (dkc->dkc_callback != NULL)) { 45751ae08745Sheppo ASSERT(dkc->dkc_cookie != NULL); 45768e6a2a04Slm66018 (*dkc->dkc_callback)(dkc->dkc_cookie, rv); 45771ae08745Sheppo } 45781ae08745Sheppo 45791ae08745Sheppo /* Indicate that one less DKIO write flush is outstanding */ 45801ae08745Sheppo mutex_enter(&vdc->lock); 45811ae08745Sheppo vdc->dkio_flush_pending--; 45821ae08745Sheppo ASSERT(vdc->dkio_flush_pending >= 0); 45831ae08745Sheppo mutex_exit(&vdc->lock); 45848e6a2a04Slm66018 45858e6a2a04Slm66018 /* free the mem that was allocated when the callback was dispatched */ 45868e6a2a04Slm66018 kmem_free(arg, sizeof (vdc_dk_arg_t)); 45871ae08745Sheppo } 45881ae08745Sheppo 45891ae08745Sheppo /* 459087a7269eSachartre * Function: 459187a7269eSachartre * vdc_dkio_get_partition() 459287a7269eSachartre * 459387a7269eSachartre * Description: 459487a7269eSachartre * This function implements the DKIOCGAPART ioctl. 459587a7269eSachartre * 459687a7269eSachartre * Arguments: 4597*78fcd0a1Sachartre * vdc - soft state pointer 459887a7269eSachartre * arg - a pointer to a dk_map[NDKMAP] or dk_map32[NDKMAP] structure 459987a7269eSachartre * flag - ioctl flags 460087a7269eSachartre */ 460187a7269eSachartre static int 4602*78fcd0a1Sachartre vdc_dkio_get_partition(vdc_t *vdc, caddr_t arg, int flag) 460387a7269eSachartre { 4604*78fcd0a1Sachartre struct dk_geom *geom; 4605*78fcd0a1Sachartre struct vtoc *vtoc; 460687a7269eSachartre union { 460787a7269eSachartre struct dk_map map[NDKMAP]; 460887a7269eSachartre struct dk_map32 map32[NDKMAP]; 460987a7269eSachartre } data; 461087a7269eSachartre int i, rv, size; 461187a7269eSachartre 4612*78fcd0a1Sachartre mutex_enter(&vdc->lock); 461387a7269eSachartre 4614*78fcd0a1Sachartre if ((rv = vdc_validate_geometry(vdc)) != 0) { 4615*78fcd0a1Sachartre mutex_exit(&vdc->lock); 461687a7269eSachartre return (rv); 4617*78fcd0a1Sachartre } 461887a7269eSachartre 4619*78fcd0a1Sachartre vtoc = vdc->vtoc; 4620*78fcd0a1Sachartre geom = vdc->geom; 462187a7269eSachartre 462287a7269eSachartre if (ddi_model_convert_from(flag & FMODELS) == DDI_MODEL_ILP32) { 462387a7269eSachartre 4624*78fcd0a1Sachartre for (i = 0; i < vtoc->v_nparts; i++) { 4625*78fcd0a1Sachartre data.map32[i].dkl_cylno = vtoc->v_part[i].p_start / 4626*78fcd0a1Sachartre (geom->dkg_nhead * geom->dkg_nsect); 4627*78fcd0a1Sachartre data.map32[i].dkl_nblk = vtoc->v_part[i].p_size; 462887a7269eSachartre } 462987a7269eSachartre size = NDKMAP * sizeof (struct dk_map32); 463087a7269eSachartre 463187a7269eSachartre } else { 463287a7269eSachartre 4633*78fcd0a1Sachartre for (i = 0; i < vtoc->v_nparts; i++) { 4634*78fcd0a1Sachartre data.map[i].dkl_cylno = vtoc->v_part[i].p_start / 4635*78fcd0a1Sachartre (geom->dkg_nhead * geom->dkg_nsect); 4636*78fcd0a1Sachartre data.map[i].dkl_nblk = vtoc->v_part[i].p_size; 463787a7269eSachartre } 463887a7269eSachartre size = NDKMAP * sizeof (struct dk_map); 463987a7269eSachartre 464087a7269eSachartre } 464187a7269eSachartre 4642*78fcd0a1Sachartre mutex_exit(&vdc->lock); 4643*78fcd0a1Sachartre 464487a7269eSachartre if (ddi_copyout(&data, arg, size, flag) != 0) 464587a7269eSachartre return (EFAULT); 464687a7269eSachartre 464787a7269eSachartre return (0); 464887a7269eSachartre } 464987a7269eSachartre 465087a7269eSachartre /* 465187a7269eSachartre * Function: 465287a7269eSachartre * vdc_dioctl_rwcmd() 465387a7269eSachartre * 465487a7269eSachartre * Description: 465587a7269eSachartre * This function implements the DIOCTL_RWCMD ioctl. This ioctl is used 465687a7269eSachartre * for DKC_DIRECT disks to read or write at an absolute disk offset. 465787a7269eSachartre * 465887a7269eSachartre * Arguments: 465987a7269eSachartre * dev - device 466087a7269eSachartre * arg - a pointer to a dadkio_rwcmd or dadkio_rwcmd32 structure 466187a7269eSachartre * flag - ioctl flags 466287a7269eSachartre */ 466387a7269eSachartre static int 466487a7269eSachartre vdc_dioctl_rwcmd(dev_t dev, caddr_t arg, int flag) 466587a7269eSachartre { 466687a7269eSachartre struct dadkio_rwcmd32 rwcmd32; 466787a7269eSachartre struct dadkio_rwcmd rwcmd; 466887a7269eSachartre struct iovec aiov; 466987a7269eSachartre struct uio auio; 467087a7269eSachartre int rw, status; 467187a7269eSachartre struct buf *buf; 467287a7269eSachartre 467387a7269eSachartre if (ddi_model_convert_from(flag & FMODELS) == DDI_MODEL_ILP32) { 467487a7269eSachartre if (ddi_copyin((caddr_t)arg, (caddr_t)&rwcmd32, 467587a7269eSachartre sizeof (struct dadkio_rwcmd32), flag)) { 467687a7269eSachartre return (EFAULT); 467787a7269eSachartre } 467887a7269eSachartre rwcmd.cmd = rwcmd32.cmd; 467987a7269eSachartre rwcmd.flags = rwcmd32.flags; 468087a7269eSachartre rwcmd.blkaddr = (daddr_t)rwcmd32.blkaddr; 468187a7269eSachartre rwcmd.buflen = rwcmd32.buflen; 468287a7269eSachartre rwcmd.bufaddr = (caddr_t)(uintptr_t)rwcmd32.bufaddr; 468387a7269eSachartre } else { 468487a7269eSachartre if (ddi_copyin((caddr_t)arg, (caddr_t)&rwcmd, 468587a7269eSachartre sizeof (struct dadkio_rwcmd), flag)) { 468687a7269eSachartre return (EFAULT); 468787a7269eSachartre } 468887a7269eSachartre } 468987a7269eSachartre 469087a7269eSachartre switch (rwcmd.cmd) { 469187a7269eSachartre case DADKIO_RWCMD_READ: 469287a7269eSachartre rw = B_READ; 469387a7269eSachartre break; 469487a7269eSachartre case DADKIO_RWCMD_WRITE: 469587a7269eSachartre rw = B_WRITE; 469687a7269eSachartre break; 469787a7269eSachartre default: 469887a7269eSachartre return (EINVAL); 469987a7269eSachartre } 470087a7269eSachartre 470187a7269eSachartre bzero((caddr_t)&aiov, sizeof (struct iovec)); 470287a7269eSachartre aiov.iov_base = rwcmd.bufaddr; 470387a7269eSachartre aiov.iov_len = rwcmd.buflen; 470487a7269eSachartre 470587a7269eSachartre bzero((caddr_t)&auio, sizeof (struct uio)); 470687a7269eSachartre auio.uio_iov = &aiov; 470787a7269eSachartre auio.uio_iovcnt = 1; 470887a7269eSachartre auio.uio_loffset = rwcmd.blkaddr * DEV_BSIZE; 470987a7269eSachartre auio.uio_resid = rwcmd.buflen; 471087a7269eSachartre auio.uio_segflg = flag & FKIOCTL ? UIO_SYSSPACE : UIO_USERSPACE; 471187a7269eSachartre 471287a7269eSachartre buf = kmem_alloc(sizeof (buf_t), KM_SLEEP); 471387a7269eSachartre bioinit(buf); 471487a7269eSachartre /* 471587a7269eSachartre * We use the private field of buf to specify that this is an 471687a7269eSachartre * I/O using an absolute offset. 471787a7269eSachartre */ 471887a7269eSachartre buf->b_private = (void *)VD_SLICE_NONE; 471987a7269eSachartre 472087a7269eSachartre status = physio(vdc_strategy, buf, dev, rw, vdc_min, &auio); 472187a7269eSachartre 472287a7269eSachartre biofini(buf); 472387a7269eSachartre kmem_free(buf, sizeof (buf_t)); 472487a7269eSachartre 472587a7269eSachartre return (status); 472687a7269eSachartre } 472787a7269eSachartre 472887a7269eSachartre /* 47291ae08745Sheppo * This structure is used in the DKIO(7I) array below. 47301ae08745Sheppo */ 47311ae08745Sheppo typedef struct vdc_dk_ioctl { 47321ae08745Sheppo uint8_t op; /* VD_OP_XXX value */ 47331ae08745Sheppo int cmd; /* Solaris ioctl operation number */ 47341ae08745Sheppo size_t nbytes; /* size of structure to be copied */ 47350a55fbb7Slm66018 47360a55fbb7Slm66018 /* function to convert between vDisk and Solaris structure formats */ 4737d10e4ef2Snarayan int (*convert)(vdc_t *vdc, void *vd_buf, void *ioctl_arg, 4738d10e4ef2Snarayan int mode, int dir); 47391ae08745Sheppo } vdc_dk_ioctl_t; 47401ae08745Sheppo 47411ae08745Sheppo /* 47421ae08745Sheppo * Subset of DKIO(7I) operations currently supported 47431ae08745Sheppo */ 47441ae08745Sheppo static vdc_dk_ioctl_t dk_ioctl[] = { 4745eff7243fSlm66018 {VD_OP_FLUSH, DKIOCFLUSHWRITECACHE, 0, 47460a55fbb7Slm66018 vdc_null_copy_func}, 47470a55fbb7Slm66018 {VD_OP_GET_WCE, DKIOCGETWCE, sizeof (int), 47484bac2208Snarayan vdc_get_wce_convert}, 47490a55fbb7Slm66018 {VD_OP_SET_WCE, DKIOCSETWCE, sizeof (int), 47504bac2208Snarayan vdc_set_wce_convert}, 47510a55fbb7Slm66018 {VD_OP_GET_VTOC, DKIOCGVTOC, sizeof (vd_vtoc_t), 47520a55fbb7Slm66018 vdc_get_vtoc_convert}, 47530a55fbb7Slm66018 {VD_OP_SET_VTOC, DKIOCSVTOC, sizeof (vd_vtoc_t), 47540a55fbb7Slm66018 vdc_set_vtoc_convert}, 47550a55fbb7Slm66018 {VD_OP_GET_DISKGEOM, DKIOCGGEOM, sizeof (vd_geom_t), 47560a55fbb7Slm66018 vdc_get_geom_convert}, 47570a55fbb7Slm66018 {VD_OP_GET_DISKGEOM, DKIOCG_PHYGEOM, sizeof (vd_geom_t), 47580a55fbb7Slm66018 vdc_get_geom_convert}, 47590a55fbb7Slm66018 {VD_OP_GET_DISKGEOM, DKIOCG_VIRTGEOM, sizeof (vd_geom_t), 47600a55fbb7Slm66018 vdc_get_geom_convert}, 47610a55fbb7Slm66018 {VD_OP_SET_DISKGEOM, DKIOCSGEOM, sizeof (vd_geom_t), 47620a55fbb7Slm66018 vdc_set_geom_convert}, 47634bac2208Snarayan {VD_OP_GET_EFI, DKIOCGETEFI, 0, 47644bac2208Snarayan vdc_get_efi_convert}, 47654bac2208Snarayan {VD_OP_SET_EFI, DKIOCSETEFI, 0, 47664bac2208Snarayan vdc_set_efi_convert}, 47670a55fbb7Slm66018 476887a7269eSachartre /* DIOCTL_RWCMD is converted to a read or a write */ 476987a7269eSachartre {0, DIOCTL_RWCMD, sizeof (struct dadkio_rwcmd), NULL}, 477087a7269eSachartre 47710a55fbb7Slm66018 /* 47720a55fbb7Slm66018 * These particular ioctls are not sent to the server - vdc fakes up 47730a55fbb7Slm66018 * the necessary info. 47740a55fbb7Slm66018 */ 47750a55fbb7Slm66018 {0, DKIOCINFO, sizeof (struct dk_cinfo), vdc_null_copy_func}, 47760a55fbb7Slm66018 {0, DKIOCGMEDIAINFO, sizeof (struct dk_minfo), vdc_null_copy_func}, 47770a55fbb7Slm66018 {0, USCSICMD, sizeof (struct uscsi_cmd), vdc_null_copy_func}, 477887a7269eSachartre {0, DKIOCGAPART, 0, vdc_null_copy_func }, 47790a55fbb7Slm66018 {0, DKIOCREMOVABLE, 0, vdc_null_copy_func}, 47800a55fbb7Slm66018 {0, CDROMREADOFFSET, 0, vdc_null_copy_func} 47811ae08745Sheppo }; 47821ae08745Sheppo 47831ae08745Sheppo /* 47841ae08745Sheppo * Function: 47851ae08745Sheppo * vd_process_ioctl() 47861ae08745Sheppo * 47871ae08745Sheppo * Description: 47880a55fbb7Slm66018 * This routine processes disk specific ioctl calls 47891ae08745Sheppo * 47901ae08745Sheppo * Arguments: 47911ae08745Sheppo * dev - the device number 47921ae08745Sheppo * cmd - the operation [dkio(7I)] to be processed 47931ae08745Sheppo * arg - pointer to user provided structure 47941ae08745Sheppo * (contains data to be set or reference parameter for get) 47951ae08745Sheppo * mode - bit flag, indicating open settings, 32/64 bit type, etc 47961ae08745Sheppo * 47971ae08745Sheppo * Return Code: 47981ae08745Sheppo * 0 47991ae08745Sheppo * EFAULT 48001ae08745Sheppo * ENXIO 48011ae08745Sheppo * EIO 48021ae08745Sheppo * ENOTSUP 48031ae08745Sheppo */ 48041ae08745Sheppo static int 48051ae08745Sheppo vd_process_ioctl(dev_t dev, int cmd, caddr_t arg, int mode) 48061ae08745Sheppo { 48070d0c8d4bSnarayan int instance = VDCUNIT(dev); 48081ae08745Sheppo vdc_t *vdc = NULL; 48091ae08745Sheppo int rv = -1; 48101ae08745Sheppo int idx = 0; /* index into dk_ioctl[] */ 48111ae08745Sheppo size_t len = 0; /* #bytes to send to vds */ 48121ae08745Sheppo size_t alloc_len = 0; /* #bytes to allocate mem for */ 48131ae08745Sheppo caddr_t mem_p = NULL; 48141ae08745Sheppo size_t nioctls = (sizeof (dk_ioctl)) / (sizeof (dk_ioctl[0])); 48153af08d82Slm66018 vdc_dk_ioctl_t *iop; 48161ae08745Sheppo 48171ae08745Sheppo vdc = ddi_get_soft_state(vdc_state, instance); 48181ae08745Sheppo if (vdc == NULL) { 48191ae08745Sheppo cmn_err(CE_NOTE, "![%d] Could not get soft state structure", 48201ae08745Sheppo instance); 48211ae08745Sheppo return (ENXIO); 48221ae08745Sheppo } 48231ae08745Sheppo 48243af08d82Slm66018 DMSG(vdc, 0, "[%d] Processing ioctl(%x) for dev %lx : model %x\n", 48253af08d82Slm66018 instance, cmd, dev, ddi_model_convert_from(mode & FMODELS)); 48261ae08745Sheppo 48271ae08745Sheppo /* 48281ae08745Sheppo * Validate the ioctl operation to be performed. 48291ae08745Sheppo * 48301ae08745Sheppo * If we have looped through the array without finding a match then we 48311ae08745Sheppo * don't support this ioctl. 48321ae08745Sheppo */ 48331ae08745Sheppo for (idx = 0; idx < nioctls; idx++) { 48341ae08745Sheppo if (cmd == dk_ioctl[idx].cmd) 48351ae08745Sheppo break; 48361ae08745Sheppo } 48371ae08745Sheppo 48381ae08745Sheppo if (idx >= nioctls) { 48393af08d82Slm66018 DMSG(vdc, 0, "[%d] Unsupported ioctl (0x%x)\n", 4840e1ebb9ecSlm66018 vdc->instance, cmd); 48411ae08745Sheppo return (ENOTSUP); 48421ae08745Sheppo } 48431ae08745Sheppo 48443af08d82Slm66018 iop = &(dk_ioctl[idx]); 48453af08d82Slm66018 48464bac2208Snarayan if (cmd == DKIOCGETEFI || cmd == DKIOCSETEFI) { 48474bac2208Snarayan /* size is not fixed for EFI ioctls, it depends on ioctl arg */ 48484bac2208Snarayan dk_efi_t dk_efi; 48494bac2208Snarayan 48504bac2208Snarayan rv = ddi_copyin(arg, &dk_efi, sizeof (dk_efi_t), mode); 48514bac2208Snarayan if (rv != 0) 48524bac2208Snarayan return (EFAULT); 48534bac2208Snarayan 48544bac2208Snarayan len = sizeof (vd_efi_t) - 1 + dk_efi.dki_length; 48554bac2208Snarayan } else { 48563af08d82Slm66018 len = iop->nbytes; 48574bac2208Snarayan } 48581ae08745Sheppo 48591ae08745Sheppo /* 48600a55fbb7Slm66018 * Deal with the ioctls which the server does not provide. vdc can 48610a55fbb7Slm66018 * fake these up and return immediately 48621ae08745Sheppo */ 48631ae08745Sheppo switch (cmd) { 48641ae08745Sheppo case CDROMREADOFFSET: 48651ae08745Sheppo case DKIOCREMOVABLE: 48660a55fbb7Slm66018 case USCSICMD: 48671ae08745Sheppo return (ENOTTY); 48681ae08745Sheppo 486987a7269eSachartre case DIOCTL_RWCMD: 487087a7269eSachartre { 4871*78fcd0a1Sachartre if (vdc->cinfo == NULL) 4872*78fcd0a1Sachartre return (ENXIO); 4873*78fcd0a1Sachartre 487487a7269eSachartre if (vdc->cinfo->dki_ctype != DKC_DIRECT) 487587a7269eSachartre return (ENOTTY); 487687a7269eSachartre 487787a7269eSachartre return (vdc_dioctl_rwcmd(dev, arg, mode)); 487887a7269eSachartre } 487987a7269eSachartre 488087a7269eSachartre case DKIOCGAPART: 488187a7269eSachartre { 4882*78fcd0a1Sachartre return (vdc_dkio_get_partition(vdc, arg, mode)); 488387a7269eSachartre } 488487a7269eSachartre 48851ae08745Sheppo case DKIOCINFO: 48861ae08745Sheppo { 48871ae08745Sheppo struct dk_cinfo cinfo; 48881ae08745Sheppo if (vdc->cinfo == NULL) 48891ae08745Sheppo return (ENXIO); 48901ae08745Sheppo 48911ae08745Sheppo bcopy(vdc->cinfo, &cinfo, sizeof (struct dk_cinfo)); 48920d0c8d4bSnarayan cinfo.dki_partition = VDCPART(dev); 48931ae08745Sheppo 48941ae08745Sheppo rv = ddi_copyout(&cinfo, (void *)arg, 48951ae08745Sheppo sizeof (struct dk_cinfo), mode); 48961ae08745Sheppo if (rv != 0) 48971ae08745Sheppo return (EFAULT); 48981ae08745Sheppo 48991ae08745Sheppo return (0); 49001ae08745Sheppo } 49011ae08745Sheppo 49021ae08745Sheppo case DKIOCGMEDIAINFO: 49038e6a2a04Slm66018 { 49041ae08745Sheppo if (vdc->minfo == NULL) 49051ae08745Sheppo return (ENXIO); 49061ae08745Sheppo 49071ae08745Sheppo rv = ddi_copyout(vdc->minfo, (void *)arg, 49081ae08745Sheppo sizeof (struct dk_minfo), mode); 49091ae08745Sheppo if (rv != 0) 49101ae08745Sheppo return (EFAULT); 49111ae08745Sheppo 49121ae08745Sheppo return (0); 49131ae08745Sheppo } 49141ae08745Sheppo 49158e6a2a04Slm66018 case DKIOCFLUSHWRITECACHE: 49168e6a2a04Slm66018 { 49178e6a2a04Slm66018 struct dk_callback *dkc = (struct dk_callback *)arg; 49188e6a2a04Slm66018 vdc_dk_arg_t *dkarg = NULL; 49198e6a2a04Slm66018 49203af08d82Slm66018 DMSG(vdc, 1, "[%d] Flush W$: mode %x\n", 49213af08d82Slm66018 instance, mode); 49228e6a2a04Slm66018 49238e6a2a04Slm66018 /* 49248e6a2a04Slm66018 * If the backing device is not a 'real' disk then the 49258e6a2a04Slm66018 * W$ operation request to the vDisk server will fail 49268e6a2a04Slm66018 * so we might as well save the cycles and return now. 49278e6a2a04Slm66018 */ 49288e6a2a04Slm66018 if (vdc->vdisk_type != VD_DISK_TYPE_DISK) 49298e6a2a04Slm66018 return (ENOTTY); 49308e6a2a04Slm66018 49318e6a2a04Slm66018 /* 49328e6a2a04Slm66018 * If arg is NULL, then there is no callback function 49338e6a2a04Slm66018 * registered and the call operates synchronously; we 49348e6a2a04Slm66018 * break and continue with the rest of the function and 49358e6a2a04Slm66018 * wait for vds to return (i.e. after the request to 49368e6a2a04Slm66018 * vds returns successfully, all writes completed prior 49378e6a2a04Slm66018 * to the ioctl will have been flushed from the disk 49388e6a2a04Slm66018 * write cache to persistent media. 49398e6a2a04Slm66018 * 49408e6a2a04Slm66018 * If a callback function is registered, we dispatch 49418e6a2a04Slm66018 * the request on a task queue and return immediately. 49428e6a2a04Slm66018 * The callback will deal with informing the calling 49438e6a2a04Slm66018 * thread that the flush request is completed. 49448e6a2a04Slm66018 */ 49458e6a2a04Slm66018 if (dkc == NULL) 49468e6a2a04Slm66018 break; 49478e6a2a04Slm66018 4948eff7243fSlm66018 /* 4949eff7243fSlm66018 * the asynchronous callback is only supported if 4950eff7243fSlm66018 * invoked from within the kernel 4951eff7243fSlm66018 */ 4952eff7243fSlm66018 if ((mode & FKIOCTL) == 0) 4953eff7243fSlm66018 return (ENOTSUP); 4954eff7243fSlm66018 49558e6a2a04Slm66018 dkarg = kmem_zalloc(sizeof (vdc_dk_arg_t), KM_SLEEP); 49568e6a2a04Slm66018 49578e6a2a04Slm66018 dkarg->mode = mode; 49588e6a2a04Slm66018 dkarg->dev = dev; 49598e6a2a04Slm66018 bcopy(dkc, &dkarg->dkc, sizeof (*dkc)); 49608e6a2a04Slm66018 49618e6a2a04Slm66018 mutex_enter(&vdc->lock); 49628e6a2a04Slm66018 vdc->dkio_flush_pending++; 49638e6a2a04Slm66018 dkarg->vdc = vdc; 49648e6a2a04Slm66018 mutex_exit(&vdc->lock); 49658e6a2a04Slm66018 49668e6a2a04Slm66018 /* put the request on a task queue */ 49678e6a2a04Slm66018 rv = taskq_dispatch(system_taskq, vdc_dkio_flush_cb, 49688e6a2a04Slm66018 (void *)dkarg, DDI_SLEEP); 49693af08d82Slm66018 if (rv == NULL) { 49703af08d82Slm66018 /* clean up if dispatch fails */ 49713af08d82Slm66018 mutex_enter(&vdc->lock); 49723af08d82Slm66018 vdc->dkio_flush_pending--; 4973*78fcd0a1Sachartre mutex_exit(&vdc->lock); 49743af08d82Slm66018 kmem_free(dkarg, sizeof (vdc_dk_arg_t)); 49753af08d82Slm66018 } 49768e6a2a04Slm66018 49778e6a2a04Slm66018 return (rv == NULL ? ENOMEM : 0); 49788e6a2a04Slm66018 } 49798e6a2a04Slm66018 } 49808e6a2a04Slm66018 49811ae08745Sheppo /* catch programming error in vdc - should be a VD_OP_XXX ioctl */ 49823af08d82Slm66018 ASSERT(iop->op != 0); 49831ae08745Sheppo 49841ae08745Sheppo /* LDC requires that the memory being mapped is 8-byte aligned */ 49851ae08745Sheppo alloc_len = P2ROUNDUP(len, sizeof (uint64_t)); 49863af08d82Slm66018 DMSG(vdc, 1, "[%d] struct size %ld alloc %ld\n", 49873af08d82Slm66018 instance, len, alloc_len); 49881ae08745Sheppo 4989eff7243fSlm66018 ASSERT(alloc_len >= 0); /* sanity check */ 4990eff7243fSlm66018 if (alloc_len > 0) 49911ae08745Sheppo mem_p = kmem_zalloc(alloc_len, KM_SLEEP); 49921ae08745Sheppo 49930a55fbb7Slm66018 /* 4994eff7243fSlm66018 * Call the conversion function for this ioctl which, if necessary, 49950a55fbb7Slm66018 * converts from the Solaris format to the format ARC'ed 49960a55fbb7Slm66018 * as part of the vDisk protocol (FWARC 2006/195) 49970a55fbb7Slm66018 */ 49983af08d82Slm66018 ASSERT(iop->convert != NULL); 49993af08d82Slm66018 rv = (iop->convert)(vdc, arg, mem_p, mode, VD_COPYIN); 50001ae08745Sheppo if (rv != 0) { 50013af08d82Slm66018 DMSG(vdc, 0, "[%d] convert func returned %d for ioctl 0x%x\n", 5002e1ebb9ecSlm66018 instance, rv, cmd); 50031ae08745Sheppo if (mem_p != NULL) 50041ae08745Sheppo kmem_free(mem_p, alloc_len); 50050a55fbb7Slm66018 return (rv); 50061ae08745Sheppo } 50071ae08745Sheppo 50081ae08745Sheppo /* 50091ae08745Sheppo * send request to vds to service the ioctl. 50101ae08745Sheppo */ 50113af08d82Slm66018 rv = vdc_do_sync_op(vdc, iop->op, mem_p, alloc_len, 50120d0c8d4bSnarayan VDCPART(dev), 0, CB_SYNC, (void *)(uint64_t)mode, 50133af08d82Slm66018 VIO_both_dir); 50143af08d82Slm66018 5015*78fcd0a1Sachartre if (cmd == DKIOCSVTOC || cmd == DKIOCSETEFI) { 5016*78fcd0a1Sachartre /* 5017*78fcd0a1Sachartre * The disk label may have changed. Revalidate the disk 5018*78fcd0a1Sachartre * geometry. This will also update the device nodes and 5019*78fcd0a1Sachartre * properties. 5020*78fcd0a1Sachartre */ 5021*78fcd0a1Sachartre vdc_validate(vdc); 5022*78fcd0a1Sachartre } 5023*78fcd0a1Sachartre 50241ae08745Sheppo if (rv != 0) { 50251ae08745Sheppo /* 50261ae08745Sheppo * This is not necessarily an error. The ioctl could 50271ae08745Sheppo * be returning a value such as ENOTTY to indicate 50281ae08745Sheppo * that the ioctl is not applicable. 50291ae08745Sheppo */ 50303af08d82Slm66018 DMSG(vdc, 0, "[%d] vds returned %d for ioctl 0x%x\n", 5031e1ebb9ecSlm66018 instance, rv, cmd); 50321ae08745Sheppo if (mem_p != NULL) 50331ae08745Sheppo kmem_free(mem_p, alloc_len); 5034d10e4ef2Snarayan 50351ae08745Sheppo return (rv); 50361ae08745Sheppo } 50371ae08745Sheppo 50381ae08745Sheppo /* 50390a55fbb7Slm66018 * Call the conversion function (if it exists) for this ioctl 50400a55fbb7Slm66018 * which converts from the format ARC'ed as part of the vDisk 50410a55fbb7Slm66018 * protocol (FWARC 2006/195) back to a format understood by 50420a55fbb7Slm66018 * the rest of Solaris. 50431ae08745Sheppo */ 50443af08d82Slm66018 rv = (iop->convert)(vdc, mem_p, arg, mode, VD_COPYOUT); 50450a55fbb7Slm66018 if (rv != 0) { 50463af08d82Slm66018 DMSG(vdc, 0, "[%d] convert func returned %d for ioctl 0x%x\n", 5047e1ebb9ecSlm66018 instance, rv, cmd); 50481ae08745Sheppo if (mem_p != NULL) 50491ae08745Sheppo kmem_free(mem_p, alloc_len); 50500a55fbb7Slm66018 return (rv); 50511ae08745Sheppo } 50521ae08745Sheppo 50531ae08745Sheppo if (mem_p != NULL) 50541ae08745Sheppo kmem_free(mem_p, alloc_len); 50551ae08745Sheppo 50561ae08745Sheppo return (rv); 50571ae08745Sheppo } 50581ae08745Sheppo 50591ae08745Sheppo /* 50601ae08745Sheppo * Function: 50610a55fbb7Slm66018 * 50620a55fbb7Slm66018 * Description: 50630a55fbb7Slm66018 * This is an empty conversion function used by ioctl calls which 50640a55fbb7Slm66018 * do not need to convert the data being passed in/out to userland 50650a55fbb7Slm66018 */ 50660a55fbb7Slm66018 static int 5067d10e4ef2Snarayan vdc_null_copy_func(vdc_t *vdc, void *from, void *to, int mode, int dir) 50680a55fbb7Slm66018 { 5069d10e4ef2Snarayan _NOTE(ARGUNUSED(vdc)) 50700a55fbb7Slm66018 _NOTE(ARGUNUSED(from)) 50710a55fbb7Slm66018 _NOTE(ARGUNUSED(to)) 50720a55fbb7Slm66018 _NOTE(ARGUNUSED(mode)) 50730a55fbb7Slm66018 _NOTE(ARGUNUSED(dir)) 50740a55fbb7Slm66018 50750a55fbb7Slm66018 return (0); 50760a55fbb7Slm66018 } 50770a55fbb7Slm66018 50784bac2208Snarayan static int 50794bac2208Snarayan vdc_get_wce_convert(vdc_t *vdc, void *from, void *to, 50804bac2208Snarayan int mode, int dir) 50814bac2208Snarayan { 50824bac2208Snarayan _NOTE(ARGUNUSED(vdc)) 50834bac2208Snarayan 50844bac2208Snarayan if (dir == VD_COPYIN) 50854bac2208Snarayan return (0); /* nothing to do */ 50864bac2208Snarayan 50874bac2208Snarayan if (ddi_copyout(from, to, sizeof (int), mode) != 0) 50884bac2208Snarayan return (EFAULT); 50894bac2208Snarayan 50904bac2208Snarayan return (0); 50914bac2208Snarayan } 50924bac2208Snarayan 50934bac2208Snarayan static int 50944bac2208Snarayan vdc_set_wce_convert(vdc_t *vdc, void *from, void *to, 50954bac2208Snarayan int mode, int dir) 50964bac2208Snarayan { 50974bac2208Snarayan _NOTE(ARGUNUSED(vdc)) 50984bac2208Snarayan 50994bac2208Snarayan if (dir == VD_COPYOUT) 51004bac2208Snarayan return (0); /* nothing to do */ 51014bac2208Snarayan 51024bac2208Snarayan if (ddi_copyin(from, to, sizeof (int), mode) != 0) 51034bac2208Snarayan return (EFAULT); 51044bac2208Snarayan 51054bac2208Snarayan return (0); 51064bac2208Snarayan } 51074bac2208Snarayan 51080a55fbb7Slm66018 /* 51090a55fbb7Slm66018 * Function: 51100a55fbb7Slm66018 * vdc_get_vtoc_convert() 51110a55fbb7Slm66018 * 51120a55fbb7Slm66018 * Description: 5113d10e4ef2Snarayan * This routine performs the necessary convertions from the DKIOCGVTOC 5114d10e4ef2Snarayan * Solaris structure to the format defined in FWARC 2006/195. 5115d10e4ef2Snarayan * 5116d10e4ef2Snarayan * In the struct vtoc definition, the timestamp field is marked as not 5117d10e4ef2Snarayan * supported so it is not part of vDisk protocol (FWARC 2006/195). 5118d10e4ef2Snarayan * However SVM uses that field to check it can write into the VTOC, 5119d10e4ef2Snarayan * so we fake up the info of that field. 51200a55fbb7Slm66018 * 51210a55fbb7Slm66018 * Arguments: 5122d10e4ef2Snarayan * vdc - the vDisk client 51230a55fbb7Slm66018 * from - the buffer containing the data to be copied from 51240a55fbb7Slm66018 * to - the buffer to be copied to 51250a55fbb7Slm66018 * mode - flags passed to ioctl() call 51260a55fbb7Slm66018 * dir - the "direction" of the copy - VD_COPYIN or VD_COPYOUT 51270a55fbb7Slm66018 * 51280a55fbb7Slm66018 * Return Code: 51290a55fbb7Slm66018 * 0 - Success 51300a55fbb7Slm66018 * ENXIO - incorrect buffer passed in. 5131d10e4ef2Snarayan * EFAULT - ddi_copyout routine encountered an error. 51320a55fbb7Slm66018 */ 51330a55fbb7Slm66018 static int 5134d10e4ef2Snarayan vdc_get_vtoc_convert(vdc_t *vdc, void *from, void *to, int mode, int dir) 51350a55fbb7Slm66018 { 5136d10e4ef2Snarayan int i; 51370a55fbb7Slm66018 void *tmp_mem = NULL; 51380a55fbb7Slm66018 void *tmp_memp; 51390a55fbb7Slm66018 struct vtoc vt; 51400a55fbb7Slm66018 struct vtoc32 vt32; 51410a55fbb7Slm66018 int copy_len = 0; 51420a55fbb7Slm66018 int rv = 0; 51430a55fbb7Slm66018 51440a55fbb7Slm66018 if (dir != VD_COPYOUT) 51450a55fbb7Slm66018 return (0); /* nothing to do */ 51460a55fbb7Slm66018 51470a55fbb7Slm66018 if ((from == NULL) || (to == NULL)) 51480a55fbb7Slm66018 return (ENXIO); 51490a55fbb7Slm66018 51500a55fbb7Slm66018 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) 51510a55fbb7Slm66018 copy_len = sizeof (struct vtoc32); 51520a55fbb7Slm66018 else 51530a55fbb7Slm66018 copy_len = sizeof (struct vtoc); 51540a55fbb7Slm66018 51550a55fbb7Slm66018 tmp_mem = kmem_alloc(copy_len, KM_SLEEP); 51560a55fbb7Slm66018 51570a55fbb7Slm66018 VD_VTOC2VTOC((vd_vtoc_t *)from, &vt); 5158d10e4ef2Snarayan 5159d10e4ef2Snarayan /* fake the VTOC timestamp field */ 5160d10e4ef2Snarayan for (i = 0; i < V_NUMPAR; i++) { 5161d10e4ef2Snarayan vt.timestamp[i] = vdc->vtoc->timestamp[i]; 5162d10e4ef2Snarayan } 5163d10e4ef2Snarayan 51640a55fbb7Slm66018 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 51650a55fbb7Slm66018 vtoctovtoc32(vt, vt32); 51660a55fbb7Slm66018 tmp_memp = &vt32; 51670a55fbb7Slm66018 } else { 51680a55fbb7Slm66018 tmp_memp = &vt; 51690a55fbb7Slm66018 } 51700a55fbb7Slm66018 rv = ddi_copyout(tmp_memp, to, copy_len, mode); 51710a55fbb7Slm66018 if (rv != 0) 51720a55fbb7Slm66018 rv = EFAULT; 51730a55fbb7Slm66018 51740a55fbb7Slm66018 kmem_free(tmp_mem, copy_len); 51750a55fbb7Slm66018 return (rv); 51760a55fbb7Slm66018 } 51770a55fbb7Slm66018 51780a55fbb7Slm66018 /* 51790a55fbb7Slm66018 * Function: 51800a55fbb7Slm66018 * vdc_set_vtoc_convert() 51810a55fbb7Slm66018 * 51820a55fbb7Slm66018 * Description: 5183d10e4ef2Snarayan * This routine performs the necessary convertions from the DKIOCSVTOC 5184d10e4ef2Snarayan * Solaris structure to the format defined in FWARC 2006/195. 51850a55fbb7Slm66018 * 51860a55fbb7Slm66018 * Arguments: 5187d10e4ef2Snarayan * vdc - the vDisk client 51880a55fbb7Slm66018 * from - Buffer with data 51890a55fbb7Slm66018 * to - Buffer where data is to be copied to 51900a55fbb7Slm66018 * mode - flags passed to ioctl 51910a55fbb7Slm66018 * dir - direction of copy (in or out) 51920a55fbb7Slm66018 * 51930a55fbb7Slm66018 * Return Code: 51940a55fbb7Slm66018 * 0 - Success 51950a55fbb7Slm66018 * ENXIO - Invalid buffer passed in 51960a55fbb7Slm66018 * EFAULT - ddi_copyin of data failed 51970a55fbb7Slm66018 */ 51980a55fbb7Slm66018 static int 5199d10e4ef2Snarayan vdc_set_vtoc_convert(vdc_t *vdc, void *from, void *to, int mode, int dir) 52000a55fbb7Slm66018 { 5201*78fcd0a1Sachartre _NOTE(ARGUNUSED(vdc)) 5202*78fcd0a1Sachartre 52030a55fbb7Slm66018 void *tmp_mem = NULL; 52040a55fbb7Slm66018 struct vtoc vt; 52050a55fbb7Slm66018 struct vtoc *vtp = &vt; 52060a55fbb7Slm66018 vd_vtoc_t vtvd; 52070a55fbb7Slm66018 int copy_len = 0; 52080a55fbb7Slm66018 int rv = 0; 52090a55fbb7Slm66018 52100a55fbb7Slm66018 if (dir != VD_COPYIN) 52110a55fbb7Slm66018 return (0); /* nothing to do */ 52120a55fbb7Slm66018 52130a55fbb7Slm66018 if ((from == NULL) || (to == NULL)) 52140a55fbb7Slm66018 return (ENXIO); 52150a55fbb7Slm66018 52160a55fbb7Slm66018 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) 52170a55fbb7Slm66018 copy_len = sizeof (struct vtoc32); 52180a55fbb7Slm66018 else 52190a55fbb7Slm66018 copy_len = sizeof (struct vtoc); 52200a55fbb7Slm66018 52210a55fbb7Slm66018 tmp_mem = kmem_alloc(copy_len, KM_SLEEP); 52220a55fbb7Slm66018 52230a55fbb7Slm66018 rv = ddi_copyin(from, tmp_mem, copy_len, mode); 52240a55fbb7Slm66018 if (rv != 0) { 52250a55fbb7Slm66018 kmem_free(tmp_mem, copy_len); 52260a55fbb7Slm66018 return (EFAULT); 52270a55fbb7Slm66018 } 52280a55fbb7Slm66018 52290a55fbb7Slm66018 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 52300a55fbb7Slm66018 vtoc32tovtoc((*(struct vtoc32 *)tmp_mem), vt); 52310a55fbb7Slm66018 } else { 52320a55fbb7Slm66018 vtp = tmp_mem; 52330a55fbb7Slm66018 } 52340a55fbb7Slm66018 52350a55fbb7Slm66018 VTOC2VD_VTOC(vtp, &vtvd); 52360a55fbb7Slm66018 bcopy(&vtvd, to, sizeof (vd_vtoc_t)); 52370a55fbb7Slm66018 kmem_free(tmp_mem, copy_len); 52380a55fbb7Slm66018 52390a55fbb7Slm66018 return (0); 52400a55fbb7Slm66018 } 52410a55fbb7Slm66018 52420a55fbb7Slm66018 /* 52430a55fbb7Slm66018 * Function: 52440a55fbb7Slm66018 * vdc_get_geom_convert() 52450a55fbb7Slm66018 * 52460a55fbb7Slm66018 * Description: 5247d10e4ef2Snarayan * This routine performs the necessary convertions from the DKIOCGGEOM, 5248d10e4ef2Snarayan * DKIOCG_PHYSGEOM and DKIOG_VIRTGEOM Solaris structures to the format 5249d10e4ef2Snarayan * defined in FWARC 2006/195 52500a55fbb7Slm66018 * 52510a55fbb7Slm66018 * Arguments: 5252d10e4ef2Snarayan * vdc - the vDisk client 52530a55fbb7Slm66018 * from - Buffer with data 52540a55fbb7Slm66018 * to - Buffer where data is to be copied to 52550a55fbb7Slm66018 * mode - flags passed to ioctl 52560a55fbb7Slm66018 * dir - direction of copy (in or out) 52570a55fbb7Slm66018 * 52580a55fbb7Slm66018 * Return Code: 52590a55fbb7Slm66018 * 0 - Success 52600a55fbb7Slm66018 * ENXIO - Invalid buffer passed in 5261d10e4ef2Snarayan * EFAULT - ddi_copyout of data failed 52620a55fbb7Slm66018 */ 52630a55fbb7Slm66018 static int 5264d10e4ef2Snarayan vdc_get_geom_convert(vdc_t *vdc, void *from, void *to, int mode, int dir) 52650a55fbb7Slm66018 { 5266d10e4ef2Snarayan _NOTE(ARGUNUSED(vdc)) 5267d10e4ef2Snarayan 52680a55fbb7Slm66018 struct dk_geom geom; 52690a55fbb7Slm66018 int copy_len = sizeof (struct dk_geom); 52700a55fbb7Slm66018 int rv = 0; 52710a55fbb7Slm66018 52720a55fbb7Slm66018 if (dir != VD_COPYOUT) 52730a55fbb7Slm66018 return (0); /* nothing to do */ 52740a55fbb7Slm66018 52750a55fbb7Slm66018 if ((from == NULL) || (to == NULL)) 52760a55fbb7Slm66018 return (ENXIO); 52770a55fbb7Slm66018 52780a55fbb7Slm66018 VD_GEOM2DK_GEOM((vd_geom_t *)from, &geom); 52790a55fbb7Slm66018 rv = ddi_copyout(&geom, to, copy_len, mode); 52800a55fbb7Slm66018 if (rv != 0) 52810a55fbb7Slm66018 rv = EFAULT; 52820a55fbb7Slm66018 52830a55fbb7Slm66018 return (rv); 52840a55fbb7Slm66018 } 52850a55fbb7Slm66018 52860a55fbb7Slm66018 /* 52870a55fbb7Slm66018 * Function: 52880a55fbb7Slm66018 * vdc_set_geom_convert() 52890a55fbb7Slm66018 * 52900a55fbb7Slm66018 * Description: 5291d10e4ef2Snarayan * This routine performs the necessary convertions from the DKIOCSGEOM 5292d10e4ef2Snarayan * Solaris structure to the format defined in FWARC 2006/195. 52930a55fbb7Slm66018 * 52940a55fbb7Slm66018 * Arguments: 5295d10e4ef2Snarayan * vdc - the vDisk client 52960a55fbb7Slm66018 * from - Buffer with data 52970a55fbb7Slm66018 * to - Buffer where data is to be copied to 52980a55fbb7Slm66018 * mode - flags passed to ioctl 52990a55fbb7Slm66018 * dir - direction of copy (in or out) 53000a55fbb7Slm66018 * 53010a55fbb7Slm66018 * Return Code: 53020a55fbb7Slm66018 * 0 - Success 53030a55fbb7Slm66018 * ENXIO - Invalid buffer passed in 53040a55fbb7Slm66018 * EFAULT - ddi_copyin of data failed 53050a55fbb7Slm66018 */ 53060a55fbb7Slm66018 static int 5307d10e4ef2Snarayan vdc_set_geom_convert(vdc_t *vdc, void *from, void *to, int mode, int dir) 53080a55fbb7Slm66018 { 5309d10e4ef2Snarayan _NOTE(ARGUNUSED(vdc)) 5310d10e4ef2Snarayan 53110a55fbb7Slm66018 vd_geom_t vdgeom; 53120a55fbb7Slm66018 void *tmp_mem = NULL; 53130a55fbb7Slm66018 int copy_len = sizeof (struct dk_geom); 53140a55fbb7Slm66018 int rv = 0; 53150a55fbb7Slm66018 53160a55fbb7Slm66018 if (dir != VD_COPYIN) 53170a55fbb7Slm66018 return (0); /* nothing to do */ 53180a55fbb7Slm66018 53190a55fbb7Slm66018 if ((from == NULL) || (to == NULL)) 53200a55fbb7Slm66018 return (ENXIO); 53210a55fbb7Slm66018 53220a55fbb7Slm66018 tmp_mem = kmem_alloc(copy_len, KM_SLEEP); 53230a55fbb7Slm66018 53240a55fbb7Slm66018 rv = ddi_copyin(from, tmp_mem, copy_len, mode); 53250a55fbb7Slm66018 if (rv != 0) { 53260a55fbb7Slm66018 kmem_free(tmp_mem, copy_len); 53270a55fbb7Slm66018 return (EFAULT); 53280a55fbb7Slm66018 } 53290a55fbb7Slm66018 DK_GEOM2VD_GEOM((struct dk_geom *)tmp_mem, &vdgeom); 53300a55fbb7Slm66018 bcopy(&vdgeom, to, sizeof (vdgeom)); 53310a55fbb7Slm66018 kmem_free(tmp_mem, copy_len); 53320a55fbb7Slm66018 53330a55fbb7Slm66018 return (0); 53340a55fbb7Slm66018 } 53350a55fbb7Slm66018 53364bac2208Snarayan static int 53374bac2208Snarayan vdc_get_efi_convert(vdc_t *vdc, void *from, void *to, int mode, int dir) 53384bac2208Snarayan { 53394bac2208Snarayan _NOTE(ARGUNUSED(vdc)) 53404bac2208Snarayan 53414bac2208Snarayan vd_efi_t *vd_efi; 53424bac2208Snarayan dk_efi_t dk_efi; 53434bac2208Snarayan int rv = 0; 53444bac2208Snarayan void *uaddr; 53454bac2208Snarayan 53464bac2208Snarayan if ((from == NULL) || (to == NULL)) 53474bac2208Snarayan return (ENXIO); 53484bac2208Snarayan 53494bac2208Snarayan if (dir == VD_COPYIN) { 53504bac2208Snarayan 53514bac2208Snarayan vd_efi = (vd_efi_t *)to; 53524bac2208Snarayan 53534bac2208Snarayan rv = ddi_copyin(from, &dk_efi, sizeof (dk_efi_t), mode); 53544bac2208Snarayan if (rv != 0) 53554bac2208Snarayan return (EFAULT); 53564bac2208Snarayan 53574bac2208Snarayan vd_efi->lba = dk_efi.dki_lba; 53584bac2208Snarayan vd_efi->length = dk_efi.dki_length; 53594bac2208Snarayan bzero(vd_efi->data, vd_efi->length); 53604bac2208Snarayan 53614bac2208Snarayan } else { 53624bac2208Snarayan 53634bac2208Snarayan rv = ddi_copyin(to, &dk_efi, sizeof (dk_efi_t), mode); 53644bac2208Snarayan if (rv != 0) 53654bac2208Snarayan return (EFAULT); 53664bac2208Snarayan 53674bac2208Snarayan uaddr = dk_efi.dki_data; 53684bac2208Snarayan 53694bac2208Snarayan dk_efi.dki_data = kmem_alloc(dk_efi.dki_length, KM_SLEEP); 53704bac2208Snarayan 53714bac2208Snarayan VD_EFI2DK_EFI((vd_efi_t *)from, &dk_efi); 53724bac2208Snarayan 53734bac2208Snarayan rv = ddi_copyout(dk_efi.dki_data, uaddr, dk_efi.dki_length, 53744bac2208Snarayan mode); 53754bac2208Snarayan if (rv != 0) 53764bac2208Snarayan return (EFAULT); 53774bac2208Snarayan 53784bac2208Snarayan kmem_free(dk_efi.dki_data, dk_efi.dki_length); 53794bac2208Snarayan } 53804bac2208Snarayan 53814bac2208Snarayan return (0); 53824bac2208Snarayan } 53834bac2208Snarayan 53844bac2208Snarayan static int 53854bac2208Snarayan vdc_set_efi_convert(vdc_t *vdc, void *from, void *to, int mode, int dir) 53864bac2208Snarayan { 53874bac2208Snarayan _NOTE(ARGUNUSED(vdc)) 53884bac2208Snarayan 53894bac2208Snarayan dk_efi_t dk_efi; 53904bac2208Snarayan void *uaddr; 53914bac2208Snarayan 53924bac2208Snarayan if (dir == VD_COPYOUT) 53934bac2208Snarayan return (0); /* nothing to do */ 53944bac2208Snarayan 53954bac2208Snarayan if ((from == NULL) || (to == NULL)) 53964bac2208Snarayan return (ENXIO); 53974bac2208Snarayan 53984bac2208Snarayan if (ddi_copyin(from, &dk_efi, sizeof (dk_efi_t), mode) != 0) 53994bac2208Snarayan return (EFAULT); 54004bac2208Snarayan 54014bac2208Snarayan uaddr = dk_efi.dki_data; 54024bac2208Snarayan 54034bac2208Snarayan dk_efi.dki_data = kmem_alloc(dk_efi.dki_length, KM_SLEEP); 54044bac2208Snarayan 54054bac2208Snarayan if (ddi_copyin(uaddr, dk_efi.dki_data, dk_efi.dki_length, mode) != 0) 54064bac2208Snarayan return (EFAULT); 54074bac2208Snarayan 54084bac2208Snarayan DK_EFI2VD_EFI(&dk_efi, (vd_efi_t *)to); 54094bac2208Snarayan 54104bac2208Snarayan kmem_free(dk_efi.dki_data, dk_efi.dki_length); 54114bac2208Snarayan 54124bac2208Snarayan return (0); 54134bac2208Snarayan } 54144bac2208Snarayan 54150a55fbb7Slm66018 /* 54160a55fbb7Slm66018 * Function: 54171ae08745Sheppo * vdc_create_fake_geometry() 54181ae08745Sheppo * 54191ae08745Sheppo * Description: 54201ae08745Sheppo * This routine fakes up the disk info needed for some DKIO ioctls. 54211ae08745Sheppo * - DKIOCINFO 54221ae08745Sheppo * - DKIOCGMEDIAINFO 54231ae08745Sheppo * 54241ae08745Sheppo * [ just like lofi(7D) and ramdisk(7D) ] 54251ae08745Sheppo * 54261ae08745Sheppo * Arguments: 54271ae08745Sheppo * vdc - soft state pointer for this instance of the device driver. 54281ae08745Sheppo * 54291ae08745Sheppo * Return Code: 5430*78fcd0a1Sachartre * none. 54311ae08745Sheppo */ 5432*78fcd0a1Sachartre static void 54331ae08745Sheppo vdc_create_fake_geometry(vdc_t *vdc) 54341ae08745Sheppo { 54351ae08745Sheppo ASSERT(vdc != NULL); 5436*78fcd0a1Sachartre ASSERT(vdc->vdisk_size != 0); 5437*78fcd0a1Sachartre ASSERT(vdc->max_xfer_sz != 0); 54380d0c8d4bSnarayan 54390d0c8d4bSnarayan /* 54401ae08745Sheppo * DKIOCINFO support 54411ae08745Sheppo */ 5442*78fcd0a1Sachartre if (vdc->cinfo == NULL) 54431ae08745Sheppo vdc->cinfo = kmem_zalloc(sizeof (struct dk_cinfo), KM_SLEEP); 54441ae08745Sheppo 54451ae08745Sheppo (void) strcpy(vdc->cinfo->dki_cname, VDC_DRIVER_NAME); 54461ae08745Sheppo (void) strcpy(vdc->cinfo->dki_dname, VDC_DRIVER_NAME); 54478e6a2a04Slm66018 /* max_xfer_sz is #blocks so we don't need to divide by DEV_BSIZE */ 54488e6a2a04Slm66018 vdc->cinfo->dki_maxtransfer = vdc->max_xfer_sz; 544987a7269eSachartre /* 545087a7269eSachartre * We currently set the controller type to DKC_DIRECT for any disk. 545187a7269eSachartre * When SCSI support is implemented, we will eventually change this 545287a7269eSachartre * type to DKC_SCSI_CCS for disks supporting the SCSI protocol. 545387a7269eSachartre */ 545487a7269eSachartre vdc->cinfo->dki_ctype = DKC_DIRECT; 54551ae08745Sheppo vdc->cinfo->dki_flags = DKI_FMTVOL; 54561ae08745Sheppo vdc->cinfo->dki_cnum = 0; 54571ae08745Sheppo vdc->cinfo->dki_addr = 0; 54581ae08745Sheppo vdc->cinfo->dki_space = 0; 54591ae08745Sheppo vdc->cinfo->dki_prio = 0; 54601ae08745Sheppo vdc->cinfo->dki_vec = 0; 54611ae08745Sheppo vdc->cinfo->dki_unit = vdc->instance; 54621ae08745Sheppo vdc->cinfo->dki_slave = 0; 54631ae08745Sheppo /* 54641ae08745Sheppo * The partition number will be created on the fly depending on the 54651ae08745Sheppo * actual slice (i.e. minor node) that is used to request the data. 54661ae08745Sheppo */ 54671ae08745Sheppo vdc->cinfo->dki_partition = 0; 54681ae08745Sheppo 54691ae08745Sheppo /* 54701ae08745Sheppo * DKIOCGMEDIAINFO support 54711ae08745Sheppo */ 54720a55fbb7Slm66018 if (vdc->minfo == NULL) 54731ae08745Sheppo vdc->minfo = kmem_zalloc(sizeof (struct dk_minfo), KM_SLEEP); 54741ae08745Sheppo vdc->minfo->dki_media_type = DK_FIXED_DISK; 54754bac2208Snarayan vdc->minfo->dki_capacity = vdc->vdisk_size; 54761ae08745Sheppo vdc->minfo->dki_lbsize = DEV_BSIZE; 5477*78fcd0a1Sachartre } 54781ae08745Sheppo 5479*78fcd0a1Sachartre static ushort_t 5480*78fcd0a1Sachartre vdc_lbl2cksum(struct dk_label *label) 5481*78fcd0a1Sachartre { 5482*78fcd0a1Sachartre int count; 5483*78fcd0a1Sachartre ushort_t sum, *sp; 5484*78fcd0a1Sachartre 5485*78fcd0a1Sachartre count = (sizeof (struct dk_label)) / (sizeof (short)) - 1; 5486*78fcd0a1Sachartre sp = (ushort_t *)label; 5487*78fcd0a1Sachartre sum = 0; 5488*78fcd0a1Sachartre while (count--) { 5489*78fcd0a1Sachartre sum ^= *sp++; 5490*78fcd0a1Sachartre } 5491*78fcd0a1Sachartre 5492*78fcd0a1Sachartre return (sum); 54930a55fbb7Slm66018 } 54940a55fbb7Slm66018 54950a55fbb7Slm66018 /* 54960a55fbb7Slm66018 * Function: 5497*78fcd0a1Sachartre * vdc_validate_geometry 54980a55fbb7Slm66018 * 54990a55fbb7Slm66018 * Description: 5500*78fcd0a1Sachartre * This routine discovers the label and geometry of the disk. It stores 5501*78fcd0a1Sachartre * the disk label and related information in the vdc structure. If it 5502*78fcd0a1Sachartre * fails to validate the geometry or to discover the disk label then 5503*78fcd0a1Sachartre * the label is marked as unknown (VD_DISK_LABEL_UNK). 55040a55fbb7Slm66018 * 55050a55fbb7Slm66018 * Arguments: 55060a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 55070a55fbb7Slm66018 * 55080a55fbb7Slm66018 * Return Code: 5509*78fcd0a1Sachartre * 0 - success. 5510*78fcd0a1Sachartre * EINVAL - unknown disk label. 5511*78fcd0a1Sachartre * ENOTSUP - geometry not applicable (EFI label). 5512*78fcd0a1Sachartre * EIO - error accessing the disk. 55130a55fbb7Slm66018 */ 55140a55fbb7Slm66018 static int 5515*78fcd0a1Sachartre vdc_validate_geometry(vdc_t *vdc) 55160a55fbb7Slm66018 { 5517d10e4ef2Snarayan buf_t *buf; /* BREAD requests need to be in a buf_t structure */ 55180a55fbb7Slm66018 dev_t dev; 5519*78fcd0a1Sachartre int rv; 5520*78fcd0a1Sachartre struct dk_label label; 5521*78fcd0a1Sachartre struct dk_geom geom; 5522*78fcd0a1Sachartre struct vtoc vtoc; 55230a55fbb7Slm66018 55240a55fbb7Slm66018 ASSERT(vdc != NULL); 5525*78fcd0a1Sachartre ASSERT(vdc->vtoc != NULL && vdc->geom != NULL); 5526*78fcd0a1Sachartre ASSERT(MUTEX_HELD(&vdc->lock)); 55270a55fbb7Slm66018 5528*78fcd0a1Sachartre mutex_exit(&vdc->lock); 55290a55fbb7Slm66018 55300a55fbb7Slm66018 dev = makedevice(ddi_driver_major(vdc->dip), 55310a55fbb7Slm66018 VD_MAKE_DEV(vdc->instance, 0)); 55324bac2208Snarayan 5533*78fcd0a1Sachartre rv = vd_process_ioctl(dev, DKIOCGGEOM, (caddr_t)&geom, FKIOCTL); 5534*78fcd0a1Sachartre if (rv == 0) 5535*78fcd0a1Sachartre rv = vd_process_ioctl(dev, DKIOCGVTOC, (caddr_t)&vtoc, FKIOCTL); 55360d0c8d4bSnarayan 55374bac2208Snarayan if (rv == ENOTSUP) { 55384bac2208Snarayan /* 55394bac2208Snarayan * If the device does not support VTOC then we try 55404bac2208Snarayan * to read an EFI label. 55414bac2208Snarayan */ 55424bac2208Snarayan struct dk_gpt *efi; 55434bac2208Snarayan size_t efi_len; 55444bac2208Snarayan 55454bac2208Snarayan rv = vdc_efi_alloc_and_read(dev, &efi, &efi_len); 55464bac2208Snarayan 55474bac2208Snarayan if (rv) { 55483af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to get EFI (err=%d)", 55494bac2208Snarayan vdc->instance, rv); 5550*78fcd0a1Sachartre mutex_enter(&vdc->lock); 5551*78fcd0a1Sachartre vdc_store_label_unk(vdc); 5552*78fcd0a1Sachartre return (EIO); 5553*78fcd0a1Sachartre } 5554*78fcd0a1Sachartre 5555*78fcd0a1Sachartre mutex_enter(&vdc->lock); 5556*78fcd0a1Sachartre vdc_store_label_efi(vdc, efi); 5557*78fcd0a1Sachartre vd_efi_free(efi, efi_len); 5558*78fcd0a1Sachartre return (ENOTSUP); 5559*78fcd0a1Sachartre } 5560*78fcd0a1Sachartre 5561*78fcd0a1Sachartre if (rv != 0) { 5562*78fcd0a1Sachartre DMSG(vdc, 0, "[%d] Failed to get VTOC (err=%d)", 5563*78fcd0a1Sachartre vdc->instance, rv); 5564*78fcd0a1Sachartre mutex_enter(&vdc->lock); 5565*78fcd0a1Sachartre vdc_store_label_unk(vdc); 5566*78fcd0a1Sachartre if (rv != EINVAL) 5567*78fcd0a1Sachartre rv = EIO; 55684bac2208Snarayan return (rv); 55694bac2208Snarayan } 55704bac2208Snarayan 5571*78fcd0a1Sachartre /* check that geometry and vtoc are valid */ 5572*78fcd0a1Sachartre if (geom.dkg_nhead == 0 || geom.dkg_nsect == 0 || 5573*78fcd0a1Sachartre vtoc.v_sanity != VTOC_SANE) { 5574*78fcd0a1Sachartre mutex_enter(&vdc->lock); 5575*78fcd0a1Sachartre vdc_store_label_unk(vdc); 5576*78fcd0a1Sachartre return (EINVAL); 5577*78fcd0a1Sachartre } 55784bac2208Snarayan 5579*78fcd0a1Sachartre /* 5580*78fcd0a1Sachartre * We have a disk and a valid VTOC. However this does not mean 5581*78fcd0a1Sachartre * that the disk currently have a VTOC label. The returned VTOC may 5582*78fcd0a1Sachartre * be a default VTOC to be used for configuring the disk (this is 5583*78fcd0a1Sachartre * what is done for disk image). So we read the label from the 5584*78fcd0a1Sachartre * beginning of the disk to ensure we really have a VTOC label. 5585*78fcd0a1Sachartre * 5586*78fcd0a1Sachartre * FUTURE: This could be the default way for reading the VTOC 5587*78fcd0a1Sachartre * from the disk as opposed to sending the VD_OP_GET_VTOC 5588*78fcd0a1Sachartre * to the server. This will be the default if vdc is implemented 5589*78fcd0a1Sachartre * ontop of cmlb. 5590*78fcd0a1Sachartre */ 5591*78fcd0a1Sachartre 5592*78fcd0a1Sachartre /* 5593*78fcd0a1Sachartre * Single slice disk does not support read using an absolute disk 5594*78fcd0a1Sachartre * offset so we just rely on the DKIOCGVTOC ioctl in that case. 5595*78fcd0a1Sachartre */ 5596*78fcd0a1Sachartre if (vdc->vdisk_type == VD_DISK_TYPE_SLICE) { 5597*78fcd0a1Sachartre mutex_enter(&vdc->lock); 5598*78fcd0a1Sachartre if (vtoc.v_nparts != 1) { 5599*78fcd0a1Sachartre vdc_store_label_unk(vdc); 5600*78fcd0a1Sachartre return (EINVAL); 5601*78fcd0a1Sachartre } 5602*78fcd0a1Sachartre vdc_store_label_vtoc(vdc, &geom, &vtoc); 56034bac2208Snarayan return (0); 56044bac2208Snarayan } 56054bac2208Snarayan 5606*78fcd0a1Sachartre if (vtoc.v_nparts != V_NUMPAR) { 5607*78fcd0a1Sachartre mutex_enter(&vdc->lock); 5608*78fcd0a1Sachartre vdc_store_label_unk(vdc); 5609*78fcd0a1Sachartre return (EINVAL); 56100a55fbb7Slm66018 } 5611d10e4ef2Snarayan 5612d10e4ef2Snarayan /* 5613d10e4ef2Snarayan * Read disk label from start of disk 5614d10e4ef2Snarayan */ 5615d10e4ef2Snarayan buf = kmem_alloc(sizeof (buf_t), KM_SLEEP); 5616d10e4ef2Snarayan bioinit(buf); 5617*78fcd0a1Sachartre buf->b_un.b_addr = (caddr_t)&label; 5618d10e4ef2Snarayan buf->b_bcount = DK_LABEL_SIZE; 5619d10e4ef2Snarayan buf->b_flags = B_BUSY | B_READ; 5620d10e4ef2Snarayan buf->b_dev = dev; 5621*78fcd0a1Sachartre rv = vdc_send_request(vdc, VD_OP_BREAD, (caddr_t)&label, 5622*78fcd0a1Sachartre DK_LABEL_SIZE, VD_SLICE_NONE, 0, CB_STRATEGY, buf, VIO_read_dir); 56233af08d82Slm66018 if (rv) { 56243af08d82Slm66018 DMSG(vdc, 1, "[%d] Failed to read disk block 0\n", 56253af08d82Slm66018 vdc->instance); 5626*78fcd0a1Sachartre } else { 5627d10e4ef2Snarayan rv = biowait(buf); 5628d10e4ef2Snarayan biofini(buf); 5629*78fcd0a1Sachartre } 5630d10e4ef2Snarayan kmem_free(buf, sizeof (buf_t)); 56310a55fbb7Slm66018 5632*78fcd0a1Sachartre if (rv != 0 || label.dkl_magic != DKL_MAGIC || 5633*78fcd0a1Sachartre label.dkl_cksum != vdc_lbl2cksum(&label)) { 5634*78fcd0a1Sachartre DMSG(vdc, 1, "[%d] Got VTOC with invalid label\n", 5635*78fcd0a1Sachartre vdc->instance); 5636*78fcd0a1Sachartre mutex_enter(&vdc->lock); 5637*78fcd0a1Sachartre vdc_store_label_unk(vdc); 5638*78fcd0a1Sachartre return (EINVAL); 5639*78fcd0a1Sachartre } 5640*78fcd0a1Sachartre 5641*78fcd0a1Sachartre mutex_enter(&vdc->lock); 5642*78fcd0a1Sachartre vdc_store_label_vtoc(vdc, &geom, &vtoc); 5643*78fcd0a1Sachartre return (0); 5644*78fcd0a1Sachartre } 5645*78fcd0a1Sachartre 5646*78fcd0a1Sachartre /* 5647*78fcd0a1Sachartre * Function: 5648*78fcd0a1Sachartre * vdc_validate 5649*78fcd0a1Sachartre * 5650*78fcd0a1Sachartre * Description: 5651*78fcd0a1Sachartre * This routine discovers the label of the disk and create the 5652*78fcd0a1Sachartre * appropriate device nodes if the label has changed. 5653*78fcd0a1Sachartre * 5654*78fcd0a1Sachartre * Arguments: 5655*78fcd0a1Sachartre * vdc - soft state pointer for this instance of the device driver. 5656*78fcd0a1Sachartre * 5657*78fcd0a1Sachartre * Return Code: 5658*78fcd0a1Sachartre * none. 5659*78fcd0a1Sachartre */ 5660*78fcd0a1Sachartre static void 5661*78fcd0a1Sachartre vdc_validate(vdc_t *vdc) 5662*78fcd0a1Sachartre { 5663*78fcd0a1Sachartre vd_disk_label_t old_label; 5664*78fcd0a1Sachartre struct vtoc old_vtoc; 5665*78fcd0a1Sachartre int rv; 5666*78fcd0a1Sachartre 5667*78fcd0a1Sachartre ASSERT(!MUTEX_HELD(&vdc->lock)); 5668*78fcd0a1Sachartre 5669*78fcd0a1Sachartre mutex_enter(&vdc->lock); 5670*78fcd0a1Sachartre 5671*78fcd0a1Sachartre /* save the current label and vtoc */ 5672*78fcd0a1Sachartre old_label = vdc->vdisk_label; 5673*78fcd0a1Sachartre bcopy(vdc->vtoc, &old_vtoc, sizeof (struct vtoc)); 5674*78fcd0a1Sachartre 5675*78fcd0a1Sachartre /* check the geometry */ 5676*78fcd0a1Sachartre (void) vdc_validate_geometry(vdc); 5677*78fcd0a1Sachartre 5678*78fcd0a1Sachartre /* if the disk label has changed, update device nodes */ 5679*78fcd0a1Sachartre if (vdc->vdisk_label != old_label) { 5680*78fcd0a1Sachartre 5681*78fcd0a1Sachartre if (vdc->vdisk_label == VD_DISK_LABEL_EFI) 5682*78fcd0a1Sachartre rv = vdc_create_device_nodes_efi(vdc); 5683*78fcd0a1Sachartre else 5684*78fcd0a1Sachartre rv = vdc_create_device_nodes_vtoc(vdc); 5685*78fcd0a1Sachartre 5686*78fcd0a1Sachartre if (rv != 0) { 5687*78fcd0a1Sachartre DMSG(vdc, 0, "![%d] Failed to update device nodes", 5688*78fcd0a1Sachartre vdc->instance); 5689*78fcd0a1Sachartre } 5690*78fcd0a1Sachartre } 5691*78fcd0a1Sachartre 5692*78fcd0a1Sachartre /* if the vtoc has changed, update device nodes properties */ 5693*78fcd0a1Sachartre if (bcmp(vdc->vtoc, &old_vtoc, sizeof (struct vtoc)) != 0) { 5694*78fcd0a1Sachartre 5695*78fcd0a1Sachartre if (vdc_create_device_nodes_props(vdc) != 0) { 5696*78fcd0a1Sachartre DMSG(vdc, 0, "![%d] Failed to update device nodes" 5697*78fcd0a1Sachartre " properties", vdc->instance); 5698*78fcd0a1Sachartre } 5699*78fcd0a1Sachartre } 5700*78fcd0a1Sachartre 5701*78fcd0a1Sachartre mutex_exit(&vdc->lock); 5702*78fcd0a1Sachartre } 5703*78fcd0a1Sachartre 5704*78fcd0a1Sachartre static void 5705*78fcd0a1Sachartre vdc_validate_task(void *arg) 5706*78fcd0a1Sachartre { 5707*78fcd0a1Sachartre vdc_t *vdc = (vdc_t *)arg; 5708*78fcd0a1Sachartre 5709*78fcd0a1Sachartre vdc_validate(vdc); 5710*78fcd0a1Sachartre 5711*78fcd0a1Sachartre mutex_enter(&vdc->lock); 5712*78fcd0a1Sachartre ASSERT(vdc->validate_pending > 0); 5713*78fcd0a1Sachartre vdc->validate_pending--; 5714*78fcd0a1Sachartre mutex_exit(&vdc->lock); 57151ae08745Sheppo } 57164bac2208Snarayan 57174bac2208Snarayan /* 57184bac2208Snarayan * Function: 57194bac2208Snarayan * vdc_setup_devid() 57204bac2208Snarayan * 57214bac2208Snarayan * Description: 57224bac2208Snarayan * This routine discovers the devid of a vDisk. It requests the devid of 57234bac2208Snarayan * the underlying device from the vDisk server, builds an encapsulated 57244bac2208Snarayan * devid based on the retrieved devid and registers that new devid to 57254bac2208Snarayan * the vDisk. 57264bac2208Snarayan * 57274bac2208Snarayan * Arguments: 57284bac2208Snarayan * vdc - soft state pointer for this instance of the device driver. 57294bac2208Snarayan * 57304bac2208Snarayan * Return Code: 57314bac2208Snarayan * 0 - A devid was succesfully registered for the vDisk 57324bac2208Snarayan */ 57334bac2208Snarayan static int 57344bac2208Snarayan vdc_setup_devid(vdc_t *vdc) 57354bac2208Snarayan { 57364bac2208Snarayan int rv; 57374bac2208Snarayan vd_devid_t *vd_devid; 57384bac2208Snarayan size_t bufsize, bufid_len; 57394bac2208Snarayan 57404bac2208Snarayan /* 57414bac2208Snarayan * At first sight, we don't know the size of the devid that the 57424bac2208Snarayan * server will return but this size will be encoded into the 57434bac2208Snarayan * reply. So we do a first request using a default size then we 57444bac2208Snarayan * check if this size was large enough. If not then we do a second 57454bac2208Snarayan * request with the correct size returned by the server. Note that 57464bac2208Snarayan * ldc requires size to be 8-byte aligned. 57474bac2208Snarayan */ 57484bac2208Snarayan bufsize = P2ROUNDUP(VD_DEVID_SIZE(VD_DEVID_DEFAULT_LEN), 57494bac2208Snarayan sizeof (uint64_t)); 57504bac2208Snarayan vd_devid = kmem_zalloc(bufsize, KM_SLEEP); 57514bac2208Snarayan bufid_len = bufsize - sizeof (vd_efi_t) - 1; 57524bac2208Snarayan 57533af08d82Slm66018 rv = vdc_do_sync_op(vdc, VD_OP_GET_DEVID, (caddr_t)vd_devid, 57543af08d82Slm66018 bufsize, 0, 0, CB_SYNC, 0, VIO_both_dir); 57553af08d82Slm66018 57563af08d82Slm66018 DMSG(vdc, 2, "sync_op returned %d\n", rv); 57573af08d82Slm66018 57584bac2208Snarayan if (rv) { 57594bac2208Snarayan kmem_free(vd_devid, bufsize); 57604bac2208Snarayan return (rv); 57614bac2208Snarayan } 57624bac2208Snarayan 57634bac2208Snarayan if (vd_devid->length > bufid_len) { 57644bac2208Snarayan /* 57654bac2208Snarayan * The returned devid is larger than the buffer used. Try again 57664bac2208Snarayan * with a buffer with the right size. 57674bac2208Snarayan */ 57684bac2208Snarayan kmem_free(vd_devid, bufsize); 57694bac2208Snarayan bufsize = P2ROUNDUP(VD_DEVID_SIZE(vd_devid->length), 57704bac2208Snarayan sizeof (uint64_t)); 57714bac2208Snarayan vd_devid = kmem_zalloc(bufsize, KM_SLEEP); 57724bac2208Snarayan bufid_len = bufsize - sizeof (vd_efi_t) - 1; 57734bac2208Snarayan 57743af08d82Slm66018 rv = vdc_do_sync_op(vdc, VD_OP_GET_DEVID, 57753af08d82Slm66018 (caddr_t)vd_devid, bufsize, 0, 0, CB_SYNC, 0, 57763af08d82Slm66018 VIO_both_dir); 57773af08d82Slm66018 57784bac2208Snarayan if (rv) { 57794bac2208Snarayan kmem_free(vd_devid, bufsize); 57804bac2208Snarayan return (rv); 57814bac2208Snarayan } 57824bac2208Snarayan } 57834bac2208Snarayan 57844bac2208Snarayan /* 57854bac2208Snarayan * The virtual disk should have the same device id as the one associated 57864bac2208Snarayan * with the physical disk it is mapped on, otherwise sharing a disk 57874bac2208Snarayan * between a LDom and a non-LDom may not work (for example for a shared 57884bac2208Snarayan * SVM disk set). 57894bac2208Snarayan * 57904bac2208Snarayan * The DDI framework does not allow creating a device id with any 57914bac2208Snarayan * type so we first create a device id of type DEVID_ENCAP and then 57924bac2208Snarayan * we restore the orignal type of the physical device. 57934bac2208Snarayan */ 57944bac2208Snarayan 57953af08d82Slm66018 DMSG(vdc, 2, ": devid length = %d\n", vd_devid->length); 57963af08d82Slm66018 57974bac2208Snarayan /* build an encapsulated devid based on the returned devid */ 57984bac2208Snarayan if (ddi_devid_init(vdc->dip, DEVID_ENCAP, vd_devid->length, 57994bac2208Snarayan vd_devid->id, &vdc->devid) != DDI_SUCCESS) { 58003af08d82Slm66018 DMSG(vdc, 1, "[%d] Fail to created devid\n", vdc->instance); 58014bac2208Snarayan kmem_free(vd_devid, bufsize); 58024bac2208Snarayan return (1); 58034bac2208Snarayan } 58044bac2208Snarayan 58054bac2208Snarayan DEVID_FORMTYPE((impl_devid_t *)vdc->devid, vd_devid->type); 58064bac2208Snarayan 58074bac2208Snarayan ASSERT(ddi_devid_valid(vdc->devid) == DDI_SUCCESS); 58084bac2208Snarayan 58094bac2208Snarayan kmem_free(vd_devid, bufsize); 58104bac2208Snarayan 58114bac2208Snarayan if (ddi_devid_register(vdc->dip, vdc->devid) != DDI_SUCCESS) { 58123af08d82Slm66018 DMSG(vdc, 1, "[%d] Fail to register devid\n", vdc->instance); 58134bac2208Snarayan return (1); 58144bac2208Snarayan } 58154bac2208Snarayan 58164bac2208Snarayan return (0); 58174bac2208Snarayan } 58184bac2208Snarayan 58194bac2208Snarayan static void 5820*78fcd0a1Sachartre vdc_store_label_efi(vdc_t *vdc, struct dk_gpt *efi) 58214bac2208Snarayan { 58224bac2208Snarayan struct vtoc *vtoc = vdc->vtoc; 58234bac2208Snarayan 5824*78fcd0a1Sachartre ASSERT(MUTEX_HELD(&vdc->lock)); 5825*78fcd0a1Sachartre 5826*78fcd0a1Sachartre vdc->vdisk_label = VD_DISK_LABEL_EFI; 5827*78fcd0a1Sachartre bzero(vdc->geom, sizeof (struct dk_geom)); 58284bac2208Snarayan vd_efi_to_vtoc(efi, vtoc); 58294bac2208Snarayan if (vdc->vdisk_type == VD_DISK_TYPE_SLICE) { 58304bac2208Snarayan /* 58314bac2208Snarayan * vd_efi_to_vtoc() will store information about the EFI Sun 58324bac2208Snarayan * reserved partition (representing the entire disk) into 58334bac2208Snarayan * partition 7. However single-slice device will only have 58344bac2208Snarayan * that single partition and the vdc driver expects to find 58354bac2208Snarayan * information about that partition in slice 0. So we need 58364bac2208Snarayan * to copy information from slice 7 to slice 0. 58374bac2208Snarayan */ 58384bac2208Snarayan vtoc->v_part[0].p_tag = vtoc->v_part[VD_EFI_WD_SLICE].p_tag; 58394bac2208Snarayan vtoc->v_part[0].p_flag = vtoc->v_part[VD_EFI_WD_SLICE].p_flag; 58404bac2208Snarayan vtoc->v_part[0].p_start = vtoc->v_part[VD_EFI_WD_SLICE].p_start; 58414bac2208Snarayan vtoc->v_part[0].p_size = vtoc->v_part[VD_EFI_WD_SLICE].p_size; 58424bac2208Snarayan } 58434bac2208Snarayan } 5844*78fcd0a1Sachartre 5845*78fcd0a1Sachartre static void 5846*78fcd0a1Sachartre vdc_store_label_vtoc(vdc_t *vdc, struct dk_geom *geom, struct vtoc *vtoc) 5847*78fcd0a1Sachartre { 5848*78fcd0a1Sachartre ASSERT(MUTEX_HELD(&vdc->lock)); 5849*78fcd0a1Sachartre 5850*78fcd0a1Sachartre vdc->vdisk_label = VD_DISK_LABEL_VTOC; 5851*78fcd0a1Sachartre bcopy(vtoc, vdc->vtoc, sizeof (struct vtoc)); 5852*78fcd0a1Sachartre bcopy(geom, vdc->geom, sizeof (struct dk_geom)); 5853*78fcd0a1Sachartre } 5854*78fcd0a1Sachartre 5855*78fcd0a1Sachartre static void 5856*78fcd0a1Sachartre vdc_store_label_unk(vdc_t *vdc) 5857*78fcd0a1Sachartre { 5858*78fcd0a1Sachartre ASSERT(MUTEX_HELD(&vdc->lock)); 5859*78fcd0a1Sachartre 5860*78fcd0a1Sachartre vdc->vdisk_label = VD_DISK_LABEL_UNK; 5861*78fcd0a1Sachartre bzero(vdc->vtoc, sizeof (struct vtoc)); 5862*78fcd0a1Sachartre bzero(vdc->geom, sizeof (struct dk_geom)); 5863*78fcd0a1Sachartre } 5864