11ae08745Sheppo /* 21ae08745Sheppo * CDDL HEADER START 31ae08745Sheppo * 41ae08745Sheppo * The contents of this file are subject to the terms of the 51ae08745Sheppo * Common Development and Distribution License (the "License"). 61ae08745Sheppo * You may not use this file except in compliance with the License. 71ae08745Sheppo * 81ae08745Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91ae08745Sheppo * or http://www.opensolaris.org/os/licensing. 101ae08745Sheppo * See the License for the specific language governing permissions 111ae08745Sheppo * and limitations under the License. 121ae08745Sheppo * 131ae08745Sheppo * When distributing Covered Code, include this CDDL HEADER in each 141ae08745Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151ae08745Sheppo * If applicable, add the following below this CDDL HEADER, with the 161ae08745Sheppo * fields enclosed by brackets "[]" replaced with your own identifying 171ae08745Sheppo * information: Portions Copyright [yyyy] [name of copyright owner] 181ae08745Sheppo * 191ae08745Sheppo * CDDL HEADER END 201ae08745Sheppo */ 211ae08745Sheppo 221ae08745Sheppo /* 231ae08745Sheppo * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 241ae08745Sheppo * Use is subject to license terms. 251ae08745Sheppo */ 261ae08745Sheppo 271ae08745Sheppo #pragma ident "%Z%%M% %I% %E% SMI" 281ae08745Sheppo 291ae08745Sheppo /* 301ae08745Sheppo * LDoms virtual disk client (vdc) device driver 311ae08745Sheppo * 321ae08745Sheppo * This driver runs on a guest logical domain and communicates with the virtual 331ae08745Sheppo * disk server (vds) driver running on the service domain which is exporting 341ae08745Sheppo * virtualized "disks" to the guest logical domain. 351ae08745Sheppo * 361ae08745Sheppo * The driver can be divided into four sections: 371ae08745Sheppo * 381ae08745Sheppo * 1) generic device driver housekeeping 391ae08745Sheppo * _init, _fini, attach, detach, ops structures, etc. 401ae08745Sheppo * 411ae08745Sheppo * 2) communication channel setup 421ae08745Sheppo * Setup the communications link over the LDC channel that vdc uses to 431ae08745Sheppo * talk to the vDisk server. Initialise the descriptor ring which 441ae08745Sheppo * allows the LDC clients to transfer data via memory mappings. 451ae08745Sheppo * 461ae08745Sheppo * 3) Support exported to upper layers (filesystems, etc) 471ae08745Sheppo * The upper layers call into vdc via strategy(9E) and DKIO(7I) 481ae08745Sheppo * ioctl calls. vdc will copy the data to be written to the descriptor 491ae08745Sheppo * ring or maps the buffer to store the data read by the vDisk 501ae08745Sheppo * server into the descriptor ring. It then sends a message to the 511ae08745Sheppo * vDisk server requesting it to complete the operation. 521ae08745Sheppo * 531ae08745Sheppo * 4) Handling responses from vDisk server. 541ae08745Sheppo * The vDisk server will ACK some or all of the messages vdc sends to it 551ae08745Sheppo * (this is configured during the handshake). Upon receipt of an ACK 561ae08745Sheppo * vdc will check the descriptor ring and signal to the upper layer 571ae08745Sheppo * code waiting on the IO. 581ae08745Sheppo */ 591ae08745Sheppo 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/cm.h> 841ae08745Sheppo #include <sys/dktp/fdisk.h> 851ae08745Sheppo #include <sys/scsi/generic/sense.h> 861ae08745Sheppo #include <sys/scsi/impl/uscsi.h> /* Needed for defn of USCSICMD ioctl */ 871ae08745Sheppo #include <sys/scsi/targets/sddef.h> 881ae08745Sheppo 891ae08745Sheppo #include <sys/ldoms.h> 901ae08745Sheppo #include <sys/ldc.h> 911ae08745Sheppo #include <sys/vio_common.h> 921ae08745Sheppo #include <sys/vio_mailbox.h> 931ae08745Sheppo #include <sys/vdsk_common.h> 941ae08745Sheppo #include <sys/vdsk_mailbox.h> 951ae08745Sheppo #include <sys/vdc.h> 961ae08745Sheppo 971ae08745Sheppo /* 981ae08745Sheppo * function prototypes 991ae08745Sheppo */ 1001ae08745Sheppo 1011ae08745Sheppo /* standard driver functions */ 1021ae08745Sheppo static int vdc_open(dev_t *dev, int flag, int otyp, cred_t *cred); 1031ae08745Sheppo static int vdc_close(dev_t dev, int flag, int otyp, cred_t *cred); 1041ae08745Sheppo static int vdc_strategy(struct buf *buf); 1051ae08745Sheppo static int vdc_print(dev_t dev, char *str); 1061ae08745Sheppo static int vdc_dump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk); 1071ae08745Sheppo static int vdc_read(dev_t dev, struct uio *uio, cred_t *cred); 1081ae08745Sheppo static int vdc_write(dev_t dev, struct uio *uio, cred_t *cred); 1091ae08745Sheppo static int vdc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 1101ae08745Sheppo cred_t *credp, int *rvalp); 1111ae08745Sheppo static int vdc_aread(dev_t dev, struct aio_req *aio, cred_t *cred); 1121ae08745Sheppo static int vdc_awrite(dev_t dev, struct aio_req *aio, cred_t *cred); 1131ae08745Sheppo 1141ae08745Sheppo static int vdc_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, 1151ae08745Sheppo void *arg, void **resultp); 1161ae08745Sheppo static int vdc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 1171ae08745Sheppo static int vdc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 1181ae08745Sheppo 1191ae08745Sheppo /* setup */ 1200a55fbb7Slm66018 static int vdc_send(vdc_t *vdc, caddr_t pkt, size_t *msglen); 1211ae08745Sheppo static int vdc_do_ldc_init(vdc_t *vdc); 1221ae08745Sheppo static int vdc_start_ldc_connection(vdc_t *vdc); 1231ae08745Sheppo static int vdc_create_device_nodes(vdc_t *vdc); 1244bac2208Snarayan static int vdc_create_device_nodes_efi(vdc_t *vdc); 1254bac2208Snarayan static int vdc_create_device_nodes_vtoc(vdc_t *vdc); 1261ae08745Sheppo static int vdc_create_device_nodes_props(vdc_t *vdc); 1271ae08745Sheppo static int vdc_get_ldc_id(dev_info_t *dip, uint64_t *ldc_id); 1280a55fbb7Slm66018 static int vdc_do_ldc_up(vdc_t *vdc); 1291ae08745Sheppo static void vdc_terminate_ldc(vdc_t *vdc); 1301ae08745Sheppo static int vdc_init_descriptor_ring(vdc_t *vdc); 1311ae08745Sheppo static void vdc_destroy_descriptor_ring(vdc_t *vdc); 1324bac2208Snarayan static int vdc_setup_devid(vdc_t *vdc); 1334bac2208Snarayan static void vdc_store_efi(vdc_t *vdc, struct dk_gpt *efi); 1341ae08745Sheppo 1351ae08745Sheppo /* handshake with vds */ 1360a55fbb7Slm66018 static int vdc_init_ver_negotiation(vdc_t *vdc, vio_ver_t ver); 137*3af08d82Slm66018 static int vdc_ver_negotiation(vdc_t *vdcp); 1381ae08745Sheppo static int vdc_init_attr_negotiation(vdc_t *vdc); 139*3af08d82Slm66018 static int vdc_attr_negotiation(vdc_t *vdcp); 1401ae08745Sheppo static int vdc_init_dring_negotiate(vdc_t *vdc); 141*3af08d82Slm66018 static int vdc_dring_negotiation(vdc_t *vdcp); 142*3af08d82Slm66018 static int vdc_send_rdx(vdc_t *vdcp); 143*3af08d82Slm66018 static int vdc_rdx_exchange(vdc_t *vdcp); 1440a55fbb7Slm66018 static boolean_t vdc_is_supported_version(vio_ver_msg_t *ver_msg); 1451ae08745Sheppo 1460a55fbb7Slm66018 /* processing incoming messages from vDisk server */ 1471ae08745Sheppo static void vdc_process_msg_thread(vdc_t *vdc); 148*3af08d82Slm66018 static int vdc_recv(vdc_t *vdc, vio_msg_t *msgp, size_t *nbytesp); 149*3af08d82Slm66018 1500a55fbb7Slm66018 static uint_t vdc_handle_cb(uint64_t event, caddr_t arg); 151*3af08d82Slm66018 static int vdc_process_data_msg(vdc_t *vdc, vio_msg_t *msg); 1521ae08745Sheppo static int vdc_process_err_msg(vdc_t *vdc, vio_msg_t msg); 1530a55fbb7Slm66018 static int vdc_handle_ver_msg(vdc_t *vdc, vio_ver_msg_t *ver_msg); 1540a55fbb7Slm66018 static int vdc_handle_attr_msg(vdc_t *vdc, vd_attr_msg_t *attr_msg); 1550a55fbb7Slm66018 static int vdc_handle_dring_reg_msg(vdc_t *vdc, vio_dring_reg_msg_t *msg); 156*3af08d82Slm66018 static int vdc_send_request(vdc_t *vdcp, int operation, 157*3af08d82Slm66018 caddr_t addr, size_t nbytes, int slice, diskaddr_t offset, 158*3af08d82Slm66018 int cb_type, void *cb_arg, vio_desc_direction_t dir); 159*3af08d82Slm66018 static int vdc_map_to_shared_dring(vdc_t *vdcp, int idx); 160*3af08d82Slm66018 static int vdc_populate_descriptor(vdc_t *vdcp, int operation, 161*3af08d82Slm66018 caddr_t addr, size_t nbytes, int slice, diskaddr_t offset, 162*3af08d82Slm66018 int cb_type, void *cb_arg, vio_desc_direction_t dir); 163*3af08d82Slm66018 static int vdc_do_sync_op(vdc_t *vdcp, int operation, 164*3af08d82Slm66018 caddr_t addr, size_t nbytes, int slice, diskaddr_t offset, 165*3af08d82Slm66018 int cb_type, void *cb_arg, vio_desc_direction_t dir); 166*3af08d82Slm66018 167*3af08d82Slm66018 static int vdc_wait_for_response(vdc_t *vdcp, vio_msg_t *msgp); 168*3af08d82Slm66018 static int vdc_drain_response(vdc_t *vdcp); 1691ae08745Sheppo static int vdc_depopulate_descriptor(vdc_t *vdc, uint_t idx); 170*3af08d82Slm66018 static int vdc_populate_mem_hdl(vdc_t *vdcp, vdc_local_desc_t *ldep); 171e1ebb9ecSlm66018 static int vdc_verify_seq_num(vdc_t *vdc, vio_dring_msg_t *dring_msg); 1721ae08745Sheppo 1731ae08745Sheppo /* dkio */ 1741ae08745Sheppo static int vd_process_ioctl(dev_t dev, int cmd, caddr_t arg, int mode); 1751ae08745Sheppo static int vdc_create_fake_geometry(vdc_t *vdc); 1760a55fbb7Slm66018 static int vdc_setup_disk_layout(vdc_t *vdc); 177d10e4ef2Snarayan static int vdc_null_copy_func(vdc_t *vdc, void *from, void *to, 178d10e4ef2Snarayan int mode, int dir); 1794bac2208Snarayan static int vdc_get_wce_convert(vdc_t *vdc, void *from, void *to, 1804bac2208Snarayan int mode, int dir); 1814bac2208Snarayan static int vdc_set_wce_convert(vdc_t *vdc, void *from, void *to, 1824bac2208Snarayan int mode, int dir); 183d10e4ef2Snarayan static int vdc_get_vtoc_convert(vdc_t *vdc, void *from, void *to, 184d10e4ef2Snarayan int mode, int dir); 185d10e4ef2Snarayan static int vdc_set_vtoc_convert(vdc_t *vdc, void *from, void *to, 186d10e4ef2Snarayan int mode, int dir); 187d10e4ef2Snarayan static int vdc_get_geom_convert(vdc_t *vdc, void *from, void *to, 188d10e4ef2Snarayan int mode, int dir); 189d10e4ef2Snarayan static int vdc_set_geom_convert(vdc_t *vdc, void *from, void *to, 190d10e4ef2Snarayan int mode, int dir); 191d10e4ef2Snarayan static int vdc_uscsicmd_convert(vdc_t *vdc, void *from, void *to, 192d10e4ef2Snarayan int mode, int dir); 1934bac2208Snarayan static int vdc_get_efi_convert(vdc_t *vdc, void *from, void *to, 1944bac2208Snarayan int mode, int dir); 1954bac2208Snarayan static int vdc_set_efi_convert(vdc_t *vdc, void *from, void *to, 1964bac2208Snarayan int mode, int dir); 1971ae08745Sheppo 1981ae08745Sheppo /* 1991ae08745Sheppo * Module variables 2001ae08745Sheppo */ 201e1ebb9ecSlm66018 202e1ebb9ecSlm66018 /* 203e1ebb9ecSlm66018 * Tunable variables to control how long vdc waits before timing out on 204e1ebb9ecSlm66018 * various operations 205e1ebb9ecSlm66018 */ 206e1ebb9ecSlm66018 static int vdc_retries = 10; 207e1ebb9ecSlm66018 208e1ebb9ecSlm66018 /* calculated from 'vdc_usec_timeout' during attach */ 209e1ebb9ecSlm66018 static uint64_t vdc_hz_timeout; /* units: Hz */ 210e1ebb9ecSlm66018 static uint64_t vdc_usec_timeout = 30 * MICROSEC; /* 30s units: ns */ 211e1ebb9ecSlm66018 212*3af08d82Slm66018 static uint64_t vdc_hz_min_ldc_delay; 213*3af08d82Slm66018 static uint64_t vdc_min_timeout_ldc = 1 * MILLISEC; 214*3af08d82Slm66018 static uint64_t vdc_hz_max_ldc_delay; 215*3af08d82Slm66018 static uint64_t vdc_max_timeout_ldc = 100 * MILLISEC; 216*3af08d82Slm66018 217*3af08d82Slm66018 static uint64_t vdc_ldc_read_init_delay = 1 * MILLISEC; 218*3af08d82Slm66018 static uint64_t vdc_ldc_read_max_delay = 100 * MILLISEC; 219e1ebb9ecSlm66018 220e1ebb9ecSlm66018 /* values for dumping - need to run in a tighter loop */ 221e1ebb9ecSlm66018 static uint64_t vdc_usec_timeout_dump = 100 * MILLISEC; /* 0.1s units: ns */ 222e1ebb9ecSlm66018 static int vdc_dump_retries = 100; 223e1ebb9ecSlm66018 224e1ebb9ecSlm66018 /* Count of the number of vdc instances attached */ 225e1ebb9ecSlm66018 static volatile uint32_t vdc_instance_count = 0; 2261ae08745Sheppo 2271ae08745Sheppo /* Soft state pointer */ 2281ae08745Sheppo static void *vdc_state; 2291ae08745Sheppo 230*3af08d82Slm66018 /* 231*3af08d82Slm66018 * Controlling the verbosity of the error/debug messages 232*3af08d82Slm66018 * 233*3af08d82Slm66018 * vdc_msglevel - controls level of messages 234*3af08d82Slm66018 * vdc_matchinst - 64-bit variable where each bit corresponds 235*3af08d82Slm66018 * to the vdc instance the vdc_msglevel applies. 236*3af08d82Slm66018 */ 237*3af08d82Slm66018 int vdc_msglevel = 0x0; 238*3af08d82Slm66018 uint64_t vdc_matchinst = 0ull; 2391ae08745Sheppo 2400a55fbb7Slm66018 /* 2410a55fbb7Slm66018 * Supported vDisk protocol version pairs. 2420a55fbb7Slm66018 * 2430a55fbb7Slm66018 * The first array entry is the latest and preferred version. 2440a55fbb7Slm66018 */ 2450a55fbb7Slm66018 static const vio_ver_t vdc_version[] = {{1, 0}}; 2461ae08745Sheppo 2471ae08745Sheppo static struct cb_ops vdc_cb_ops = { 2481ae08745Sheppo vdc_open, /* cb_open */ 2491ae08745Sheppo vdc_close, /* cb_close */ 2501ae08745Sheppo vdc_strategy, /* cb_strategy */ 2511ae08745Sheppo vdc_print, /* cb_print */ 2521ae08745Sheppo vdc_dump, /* cb_dump */ 2531ae08745Sheppo vdc_read, /* cb_read */ 2541ae08745Sheppo vdc_write, /* cb_write */ 2551ae08745Sheppo vdc_ioctl, /* cb_ioctl */ 2561ae08745Sheppo nodev, /* cb_devmap */ 2571ae08745Sheppo nodev, /* cb_mmap */ 2581ae08745Sheppo nodev, /* cb_segmap */ 2591ae08745Sheppo nochpoll, /* cb_chpoll */ 2601ae08745Sheppo ddi_prop_op, /* cb_prop_op */ 2611ae08745Sheppo NULL, /* cb_str */ 2621ae08745Sheppo D_MP | D_64BIT, /* cb_flag */ 2631ae08745Sheppo CB_REV, /* cb_rev */ 2641ae08745Sheppo vdc_aread, /* cb_aread */ 2651ae08745Sheppo vdc_awrite /* cb_awrite */ 2661ae08745Sheppo }; 2671ae08745Sheppo 2681ae08745Sheppo static struct dev_ops vdc_ops = { 2691ae08745Sheppo DEVO_REV, /* devo_rev */ 2701ae08745Sheppo 0, /* devo_refcnt */ 2711ae08745Sheppo vdc_getinfo, /* devo_getinfo */ 2721ae08745Sheppo nulldev, /* devo_identify */ 2731ae08745Sheppo nulldev, /* devo_probe */ 2741ae08745Sheppo vdc_attach, /* devo_attach */ 2751ae08745Sheppo vdc_detach, /* devo_detach */ 2761ae08745Sheppo nodev, /* devo_reset */ 2771ae08745Sheppo &vdc_cb_ops, /* devo_cb_ops */ 2781ae08745Sheppo NULL, /* devo_bus_ops */ 2791ae08745Sheppo nulldev /* devo_power */ 2801ae08745Sheppo }; 2811ae08745Sheppo 2821ae08745Sheppo static struct modldrv modldrv = { 2831ae08745Sheppo &mod_driverops, 2841ae08745Sheppo "virtual disk client %I%", 2851ae08745Sheppo &vdc_ops, 2861ae08745Sheppo }; 2871ae08745Sheppo 2881ae08745Sheppo static struct modlinkage modlinkage = { 2891ae08745Sheppo MODREV_1, 2901ae08745Sheppo &modldrv, 2911ae08745Sheppo NULL 2921ae08745Sheppo }; 2931ae08745Sheppo 2941ae08745Sheppo /* -------------------------------------------------------------------------- */ 2951ae08745Sheppo 2961ae08745Sheppo /* 2971ae08745Sheppo * Device Driver housekeeping and setup 2981ae08745Sheppo */ 2991ae08745Sheppo 3001ae08745Sheppo int 3011ae08745Sheppo _init(void) 3021ae08745Sheppo { 3031ae08745Sheppo int status; 3041ae08745Sheppo 3051ae08745Sheppo if ((status = ddi_soft_state_init(&vdc_state, sizeof (vdc_t), 1)) != 0) 3061ae08745Sheppo return (status); 3071ae08745Sheppo if ((status = mod_install(&modlinkage)) != 0) 3081ae08745Sheppo ddi_soft_state_fini(&vdc_state); 3094bac2208Snarayan vdc_efi_init(vd_process_ioctl); 3101ae08745Sheppo return (status); 3111ae08745Sheppo } 3121ae08745Sheppo 3131ae08745Sheppo int 3141ae08745Sheppo _info(struct modinfo *modinfop) 3151ae08745Sheppo { 3161ae08745Sheppo return (mod_info(&modlinkage, modinfop)); 3171ae08745Sheppo } 3181ae08745Sheppo 3191ae08745Sheppo int 3201ae08745Sheppo _fini(void) 3211ae08745Sheppo { 3221ae08745Sheppo int status; 3231ae08745Sheppo 3241ae08745Sheppo if ((status = mod_remove(&modlinkage)) != 0) 3251ae08745Sheppo return (status); 3264bac2208Snarayan vdc_efi_fini(); 3271ae08745Sheppo ddi_soft_state_fini(&vdc_state); 3281ae08745Sheppo return (0); 3291ae08745Sheppo } 3301ae08745Sheppo 3311ae08745Sheppo static int 3321ae08745Sheppo vdc_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp) 3331ae08745Sheppo { 3341ae08745Sheppo _NOTE(ARGUNUSED(dip)) 3351ae08745Sheppo 336*3af08d82Slm66018 int instance = SDUNIT((dev_t)arg); 3371ae08745Sheppo vdc_t *vdc = NULL; 3381ae08745Sheppo 3391ae08745Sheppo switch (cmd) { 3401ae08745Sheppo case DDI_INFO_DEVT2DEVINFO: 3411ae08745Sheppo if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) { 3421ae08745Sheppo *resultp = NULL; 3431ae08745Sheppo return (DDI_FAILURE); 3441ae08745Sheppo } 3451ae08745Sheppo *resultp = vdc->dip; 3461ae08745Sheppo return (DDI_SUCCESS); 3471ae08745Sheppo case DDI_INFO_DEVT2INSTANCE: 3481ae08745Sheppo *resultp = (void *)(uintptr_t)instance; 3491ae08745Sheppo return (DDI_SUCCESS); 3501ae08745Sheppo default: 3511ae08745Sheppo *resultp = NULL; 3521ae08745Sheppo return (DDI_FAILURE); 3531ae08745Sheppo } 3541ae08745Sheppo } 3551ae08745Sheppo 3561ae08745Sheppo static int 3571ae08745Sheppo vdc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 3581ae08745Sheppo { 3591ae08745Sheppo int instance; 3601ae08745Sheppo int rv; 3611ae08745Sheppo vdc_t *vdc = NULL; 3621ae08745Sheppo 3631ae08745Sheppo switch (cmd) { 3641ae08745Sheppo case DDI_DETACH: 3651ae08745Sheppo /* the real work happens below */ 3661ae08745Sheppo break; 3671ae08745Sheppo case DDI_SUSPEND: 3681ae08745Sheppo /* nothing to do for this non-device */ 3691ae08745Sheppo return (DDI_SUCCESS); 3701ae08745Sheppo default: 3711ae08745Sheppo return (DDI_FAILURE); 3721ae08745Sheppo } 3731ae08745Sheppo 3741ae08745Sheppo ASSERT(cmd == DDI_DETACH); 3751ae08745Sheppo instance = ddi_get_instance(dip); 376*3af08d82Slm66018 DMSGX(1, "[%d] Entered\n", instance); 3771ae08745Sheppo 3781ae08745Sheppo if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) { 379e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't get state structure", instance); 3801ae08745Sheppo return (DDI_FAILURE); 3811ae08745Sheppo } 3821ae08745Sheppo 383*3af08d82Slm66018 if (vdc->open_count) { 384*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Cannot detach: device is open", instance); 3851ae08745Sheppo return (DDI_FAILURE); 3861ae08745Sheppo } 3871ae08745Sheppo 388*3af08d82Slm66018 DMSG(vdc, 0, "[%d] proceeding...\n", instance); 389*3af08d82Slm66018 390*3af08d82Slm66018 /* mark instance as detaching */ 391*3af08d82Slm66018 vdc->lifecycle = VDC_LC_DETACHING; 3921ae08745Sheppo 3931ae08745Sheppo /* 3941ae08745Sheppo * try and disable callbacks to prevent another handshake 3951ae08745Sheppo */ 3961ae08745Sheppo rv = ldc_set_cb_mode(vdc->ldc_handle, LDC_CB_DISABLE); 397*3af08d82Slm66018 DMSG(vdc, 0, "callback disabled (rv=%d)\n", rv); 3981ae08745Sheppo 3991ae08745Sheppo if (vdc->initialized & VDC_THREAD) { 400*3af08d82Slm66018 mutex_enter(&vdc->read_lock); 401*3af08d82Slm66018 if ((vdc->read_state == VDC_READ_WAITING) || 402*3af08d82Slm66018 (vdc->read_state == VDC_READ_RESET)) { 403*3af08d82Slm66018 vdc->read_state = VDC_READ_RESET; 404*3af08d82Slm66018 cv_signal(&vdc->read_cv); 4051ae08745Sheppo } 406*3af08d82Slm66018 407*3af08d82Slm66018 mutex_exit(&vdc->read_lock); 408*3af08d82Slm66018 409*3af08d82Slm66018 /* wake up any thread waiting for connection to come online */ 410*3af08d82Slm66018 mutex_enter(&vdc->lock); 411*3af08d82Slm66018 if (vdc->state == VDC_STATE_INIT_WAITING) { 412*3af08d82Slm66018 DMSG(vdc, 0, 413*3af08d82Slm66018 "[%d] write reset - move to resetting state...\n", 414*3af08d82Slm66018 instance); 415*3af08d82Slm66018 vdc->state = VDC_STATE_RESETTING; 416*3af08d82Slm66018 cv_signal(&vdc->initwait_cv); 417*3af08d82Slm66018 } 418*3af08d82Slm66018 mutex_exit(&vdc->lock); 419*3af08d82Slm66018 420*3af08d82Slm66018 /* now wait until state transitions to VDC_STATE_DETACH */ 421*3af08d82Slm66018 thread_join(vdc->msg_proc_thr->t_did); 422*3af08d82Slm66018 ASSERT(vdc->state == VDC_STATE_DETACH); 423*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Reset thread exit and join ..\n", 424*3af08d82Slm66018 vdc->instance); 4251ae08745Sheppo } 4261ae08745Sheppo 4271ae08745Sheppo mutex_enter(&vdc->lock); 4281ae08745Sheppo 4291ae08745Sheppo if (vdc->initialized & VDC_DRING) 4301ae08745Sheppo vdc_destroy_descriptor_ring(vdc); 4311ae08745Sheppo 4321ae08745Sheppo if (vdc->initialized & VDC_LDC) 4331ae08745Sheppo vdc_terminate_ldc(vdc); 4341ae08745Sheppo 4351ae08745Sheppo mutex_exit(&vdc->lock); 4361ae08745Sheppo 4371ae08745Sheppo if (vdc->initialized & VDC_MINOR) { 4381ae08745Sheppo ddi_prop_remove_all(dip); 4391ae08745Sheppo ddi_remove_minor_node(dip, NULL); 4401ae08745Sheppo } 4411ae08745Sheppo 4421ae08745Sheppo if (vdc->initialized & VDC_LOCKS) { 4431ae08745Sheppo mutex_destroy(&vdc->lock); 444*3af08d82Slm66018 mutex_destroy(&vdc->read_lock); 445*3af08d82Slm66018 cv_destroy(&vdc->initwait_cv); 446*3af08d82Slm66018 cv_destroy(&vdc->dring_free_cv); 447*3af08d82Slm66018 cv_destroy(&vdc->membind_cv); 448*3af08d82Slm66018 cv_destroy(&vdc->sync_pending_cv); 449*3af08d82Slm66018 cv_destroy(&vdc->sync_blocked_cv); 450*3af08d82Slm66018 cv_destroy(&vdc->read_cv); 451*3af08d82Slm66018 cv_destroy(&vdc->running_cv); 4521ae08745Sheppo } 4531ae08745Sheppo 4541ae08745Sheppo if (vdc->minfo) 4551ae08745Sheppo kmem_free(vdc->minfo, sizeof (struct dk_minfo)); 4561ae08745Sheppo 4571ae08745Sheppo if (vdc->cinfo) 4581ae08745Sheppo kmem_free(vdc->cinfo, sizeof (struct dk_cinfo)); 4591ae08745Sheppo 4601ae08745Sheppo if (vdc->vtoc) 4611ae08745Sheppo kmem_free(vdc->vtoc, sizeof (struct vtoc)); 4621ae08745Sheppo 4630a55fbb7Slm66018 if (vdc->label) 4640a55fbb7Slm66018 kmem_free(vdc->label, DK_LABEL_SIZE); 4650a55fbb7Slm66018 4664bac2208Snarayan if (vdc->devid) { 4674bac2208Snarayan ddi_devid_unregister(dip); 4684bac2208Snarayan ddi_devid_free(vdc->devid); 4694bac2208Snarayan } 4704bac2208Snarayan 4711ae08745Sheppo if (vdc->initialized & VDC_SOFT_STATE) 4721ae08745Sheppo ddi_soft_state_free(vdc_state, instance); 4731ae08745Sheppo 474*3af08d82Slm66018 DMSG(vdc, 0, "[%d] End %p\n", instance, (void *)vdc); 4751ae08745Sheppo 4761ae08745Sheppo return (DDI_SUCCESS); 4771ae08745Sheppo } 4781ae08745Sheppo 4791ae08745Sheppo 4801ae08745Sheppo static int 4811ae08745Sheppo vdc_do_attach(dev_info_t *dip) 4821ae08745Sheppo { 4831ae08745Sheppo int instance; 4841ae08745Sheppo vdc_t *vdc = NULL; 4851ae08745Sheppo int status; 4861ae08745Sheppo 4871ae08745Sheppo ASSERT(dip != NULL); 4881ae08745Sheppo 4891ae08745Sheppo instance = ddi_get_instance(dip); 4901ae08745Sheppo if (ddi_soft_state_zalloc(vdc_state, instance) != DDI_SUCCESS) { 491e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't alloc state structure", 492e1ebb9ecSlm66018 instance); 4931ae08745Sheppo return (DDI_FAILURE); 4941ae08745Sheppo } 4951ae08745Sheppo 4961ae08745Sheppo if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) { 497e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't get state structure", instance); 4981ae08745Sheppo return (DDI_FAILURE); 4991ae08745Sheppo } 5001ae08745Sheppo 5011ae08745Sheppo /* 5021ae08745Sheppo * We assign the value to initialized in this case to zero out the 5031ae08745Sheppo * variable and then set bits in it to indicate what has been done 5041ae08745Sheppo */ 5051ae08745Sheppo vdc->initialized = VDC_SOFT_STATE; 5061ae08745Sheppo 5071ae08745Sheppo vdc_hz_timeout = drv_usectohz(vdc_usec_timeout); 508*3af08d82Slm66018 509*3af08d82Slm66018 vdc_hz_min_ldc_delay = drv_usectohz(vdc_min_timeout_ldc); 510*3af08d82Slm66018 vdc_hz_max_ldc_delay = drv_usectohz(vdc_max_timeout_ldc); 5111ae08745Sheppo 5121ae08745Sheppo vdc->dip = dip; 5131ae08745Sheppo vdc->instance = instance; 514*3af08d82Slm66018 vdc->open_count = 0; 5151ae08745Sheppo vdc->vdisk_type = VD_DISK_TYPE_UNK; 5164bac2208Snarayan vdc->vdisk_label = VD_DISK_LABEL_UNK; 517*3af08d82Slm66018 vdc->state = VDC_STATE_INIT; 518*3af08d82Slm66018 vdc->lifecycle = VDC_LC_ATTACHING; 5191ae08745Sheppo vdc->ldc_state = 0; 5201ae08745Sheppo vdc->session_id = 0; 5211ae08745Sheppo vdc->block_size = DEV_BSIZE; 5228e6a2a04Slm66018 vdc->max_xfer_sz = maxphys / DEV_BSIZE; 5231ae08745Sheppo 5241ae08745Sheppo vdc->vtoc = NULL; 5251ae08745Sheppo vdc->cinfo = NULL; 5261ae08745Sheppo vdc->minfo = NULL; 5271ae08745Sheppo 5281ae08745Sheppo mutex_init(&vdc->lock, NULL, MUTEX_DRIVER, NULL); 529*3af08d82Slm66018 cv_init(&vdc->initwait_cv, NULL, CV_DRIVER, NULL); 530*3af08d82Slm66018 cv_init(&vdc->dring_free_cv, NULL, CV_DRIVER, NULL); 531*3af08d82Slm66018 cv_init(&vdc->membind_cv, NULL, CV_DRIVER, NULL); 532*3af08d82Slm66018 cv_init(&vdc->running_cv, NULL, CV_DRIVER, NULL); 533*3af08d82Slm66018 534*3af08d82Slm66018 vdc->threads_pending = 0; 535*3af08d82Slm66018 vdc->sync_op_pending = B_FALSE; 536*3af08d82Slm66018 vdc->sync_op_blocked = B_FALSE; 537*3af08d82Slm66018 cv_init(&vdc->sync_pending_cv, NULL, CV_DRIVER, NULL); 538*3af08d82Slm66018 cv_init(&vdc->sync_blocked_cv, NULL, CV_DRIVER, NULL); 539*3af08d82Slm66018 540*3af08d82Slm66018 /* init blocking msg read functionality */ 541*3af08d82Slm66018 mutex_init(&vdc->read_lock, NULL, MUTEX_DRIVER, NULL); 542*3af08d82Slm66018 cv_init(&vdc->read_cv, NULL, CV_DRIVER, NULL); 543*3af08d82Slm66018 vdc->read_state = VDC_READ_IDLE; 544*3af08d82Slm66018 5451ae08745Sheppo vdc->initialized |= VDC_LOCKS; 5461ae08745Sheppo 547*3af08d82Slm66018 /* initialise LDC channel which will be used to communicate with vds */ 548*3af08d82Slm66018 if ((status = vdc_do_ldc_init(vdc)) != 0) { 549*3af08d82Slm66018 cmn_err(CE_NOTE, "[%d] Couldn't initialize LDC", instance); 550*3af08d82Slm66018 goto return_status; 551*3af08d82Slm66018 } 552*3af08d82Slm66018 553*3af08d82Slm66018 /* initialize the thread responsible for managing state with server */ 554*3af08d82Slm66018 vdc->msg_proc_thr = thread_create(NULL, 0, vdc_process_msg_thread, 5551ae08745Sheppo vdc, 0, &p0, TS_RUN, minclsyspri); 556*3af08d82Slm66018 if (vdc->msg_proc_thr == NULL) { 5571ae08745Sheppo cmn_err(CE_NOTE, "[%d] Failed to create msg processing thread", 5581ae08745Sheppo instance); 5591ae08745Sheppo return (DDI_FAILURE); 5601ae08745Sheppo } 561*3af08d82Slm66018 5621ae08745Sheppo vdc->initialized |= VDC_THREAD; 5631ae08745Sheppo 564e1ebb9ecSlm66018 atomic_inc_32(&vdc_instance_count); 5651ae08745Sheppo 5660a55fbb7Slm66018 /* 5670a55fbb7Slm66018 * Once the handshake is complete, we can use the DRing to send 5680a55fbb7Slm66018 * requests to the vDisk server to calculate the geometry and 5690a55fbb7Slm66018 * VTOC of the "disk" 5700a55fbb7Slm66018 */ 5710a55fbb7Slm66018 status = vdc_setup_disk_layout(vdc); 5720a55fbb7Slm66018 if (status != 0) { 573*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to discover disk layout (err%d)", 5740a55fbb7Slm66018 vdc->instance, status); 575*3af08d82Slm66018 goto return_status; 5761ae08745Sheppo } 5771ae08745Sheppo 5781ae08745Sheppo /* 5791ae08745Sheppo * Now that we have the device info we can create the 5801ae08745Sheppo * device nodes and properties 5811ae08745Sheppo */ 5821ae08745Sheppo status = vdc_create_device_nodes(vdc); 5831ae08745Sheppo if (status) { 584*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to create device nodes", 5851ae08745Sheppo instance); 586*3af08d82Slm66018 goto return_status; 5871ae08745Sheppo } 5881ae08745Sheppo status = vdc_create_device_nodes_props(vdc); 5891ae08745Sheppo if (status) { 590*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to create device nodes" 5910a55fbb7Slm66018 " properties (%d)", instance, status); 592*3af08d82Slm66018 goto return_status; 5931ae08745Sheppo } 5941ae08745Sheppo 5954bac2208Snarayan /* 5964bac2208Snarayan * Setup devid 5974bac2208Snarayan */ 5984bac2208Snarayan if (vdc_setup_devid(vdc)) { 599*3af08d82Slm66018 DMSG(vdc, 0, "[%d] No device id available\n", instance); 6004bac2208Snarayan } 6014bac2208Snarayan 6021ae08745Sheppo ddi_report_dev(dip); 603*3af08d82Slm66018 vdc->lifecycle = VDC_LC_ONLINE; 604*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Attach tasks successful\n", instance); 6051ae08745Sheppo 606*3af08d82Slm66018 return_status: 607*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Attach completed\n", instance); 6081ae08745Sheppo return (status); 6091ae08745Sheppo } 6101ae08745Sheppo 6111ae08745Sheppo static int 6121ae08745Sheppo vdc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 6131ae08745Sheppo { 6141ae08745Sheppo int status; 6151ae08745Sheppo 6161ae08745Sheppo switch (cmd) { 6171ae08745Sheppo case DDI_ATTACH: 6181ae08745Sheppo if ((status = vdc_do_attach(dip)) != 0) 6191ae08745Sheppo (void) vdc_detach(dip, DDI_DETACH); 6201ae08745Sheppo return (status); 6211ae08745Sheppo case DDI_RESUME: 6221ae08745Sheppo /* nothing to do for this non-device */ 6231ae08745Sheppo return (DDI_SUCCESS); 6241ae08745Sheppo default: 6251ae08745Sheppo return (DDI_FAILURE); 6261ae08745Sheppo } 6271ae08745Sheppo } 6281ae08745Sheppo 6291ae08745Sheppo static int 6301ae08745Sheppo vdc_do_ldc_init(vdc_t *vdc) 6311ae08745Sheppo { 6321ae08745Sheppo int status = 0; 6331ae08745Sheppo ldc_status_t ldc_state; 6341ae08745Sheppo ldc_attr_t ldc_attr; 6351ae08745Sheppo uint64_t ldc_id = 0; 6361ae08745Sheppo dev_info_t *dip = NULL; 6371ae08745Sheppo 6381ae08745Sheppo ASSERT(vdc != NULL); 6391ae08745Sheppo 6401ae08745Sheppo dip = vdc->dip; 6411ae08745Sheppo vdc->initialized |= VDC_LDC; 6421ae08745Sheppo 6431ae08745Sheppo if ((status = vdc_get_ldc_id(dip, &ldc_id)) != 0) { 644*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to get LDC channel ID property", 645e1ebb9ecSlm66018 vdc->instance); 6461ae08745Sheppo return (EIO); 6471ae08745Sheppo } 6481ae08745Sheppo vdc->ldc_id = ldc_id; 6491ae08745Sheppo 6501ae08745Sheppo ldc_attr.devclass = LDC_DEV_BLK; 6511ae08745Sheppo ldc_attr.instance = vdc->instance; 6521ae08745Sheppo ldc_attr.mode = LDC_MODE_UNRELIABLE; /* unreliable transport */ 653e1ebb9ecSlm66018 ldc_attr.mtu = VD_LDC_MTU; 6541ae08745Sheppo 6551ae08745Sheppo if ((vdc->initialized & VDC_LDC_INIT) == 0) { 6561ae08745Sheppo status = ldc_init(ldc_id, &ldc_attr, &vdc->ldc_handle); 6571ae08745Sheppo if (status != 0) { 658*3af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_init(chan %ld) returned %d", 6591ae08745Sheppo vdc->instance, ldc_id, status); 6601ae08745Sheppo return (status); 6611ae08745Sheppo } 6621ae08745Sheppo vdc->initialized |= VDC_LDC_INIT; 6631ae08745Sheppo } 6641ae08745Sheppo status = ldc_status(vdc->ldc_handle, &ldc_state); 6651ae08745Sheppo if (status != 0) { 666*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Cannot discover LDC status [err=%d]", 667e1ebb9ecSlm66018 vdc->instance, status); 6681ae08745Sheppo return (status); 6691ae08745Sheppo } 6701ae08745Sheppo vdc->ldc_state = ldc_state; 6711ae08745Sheppo 6721ae08745Sheppo if ((vdc->initialized & VDC_LDC_CB) == 0) { 6731ae08745Sheppo status = ldc_reg_callback(vdc->ldc_handle, vdc_handle_cb, 6741ae08745Sheppo (caddr_t)vdc); 6751ae08745Sheppo if (status != 0) { 676*3af08d82Slm66018 DMSG(vdc, 0, "[%d] LDC callback reg. failed (%d)", 677e1ebb9ecSlm66018 vdc->instance, status); 6781ae08745Sheppo return (status); 6791ae08745Sheppo } 6801ae08745Sheppo vdc->initialized |= VDC_LDC_CB; 6811ae08745Sheppo } 6821ae08745Sheppo 6831ae08745Sheppo vdc->initialized |= VDC_LDC; 6841ae08745Sheppo 6851ae08745Sheppo /* 6861ae08745Sheppo * At this stage we have initialised LDC, we will now try and open 6871ae08745Sheppo * the connection. 6881ae08745Sheppo */ 6891ae08745Sheppo if (vdc->ldc_state == LDC_INIT) { 6901ae08745Sheppo status = ldc_open(vdc->ldc_handle); 6911ae08745Sheppo if (status != 0) { 692*3af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_open(chan %ld) returned %d", 6931ae08745Sheppo vdc->instance, vdc->ldc_id, status); 6941ae08745Sheppo return (status); 6951ae08745Sheppo } 6961ae08745Sheppo vdc->initialized |= VDC_LDC_OPEN; 6971ae08745Sheppo } 6981ae08745Sheppo 6991ae08745Sheppo return (status); 7001ae08745Sheppo } 7011ae08745Sheppo 7021ae08745Sheppo static int 7031ae08745Sheppo vdc_start_ldc_connection(vdc_t *vdc) 7041ae08745Sheppo { 7051ae08745Sheppo int status = 0; 7061ae08745Sheppo 7071ae08745Sheppo ASSERT(vdc != NULL); 7081ae08745Sheppo 709*3af08d82Slm66018 ASSERT(MUTEX_HELD(&vdc->lock)); 7101ae08745Sheppo 7110a55fbb7Slm66018 status = vdc_do_ldc_up(vdc); 7121ae08745Sheppo 713*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Finished bringing up LDC\n", vdc->instance); 7141ae08745Sheppo 715*3af08d82Slm66018 return (status); 716*3af08d82Slm66018 } 717*3af08d82Slm66018 718*3af08d82Slm66018 static int 719*3af08d82Slm66018 vdc_stop_ldc_connection(vdc_t *vdcp) 720*3af08d82Slm66018 { 721*3af08d82Slm66018 int status; 722*3af08d82Slm66018 723*3af08d82Slm66018 DMSG(vdcp, 0, ": Resetting connection to vDisk server : state %d\n", 724*3af08d82Slm66018 vdcp->state); 725*3af08d82Slm66018 726*3af08d82Slm66018 status = ldc_down(vdcp->ldc_handle); 727*3af08d82Slm66018 DMSG(vdcp, 0, "ldc_down() = %d\n", status); 728*3af08d82Slm66018 729*3af08d82Slm66018 vdcp->initialized &= ~VDC_HANDSHAKE; 730*3af08d82Slm66018 DMSG(vdcp, 0, "initialized=%x\n", vdcp->initialized); 7311ae08745Sheppo 7321ae08745Sheppo return (status); 7331ae08745Sheppo } 7341ae08745Sheppo 7354bac2208Snarayan static int 7364bac2208Snarayan vdc_create_device_nodes_efi(vdc_t *vdc) 7374bac2208Snarayan { 7384bac2208Snarayan ddi_remove_minor_node(vdc->dip, "h"); 7394bac2208Snarayan ddi_remove_minor_node(vdc->dip, "h,raw"); 7404bac2208Snarayan 7414bac2208Snarayan if (ddi_create_minor_node(vdc->dip, "wd", S_IFBLK, 7424bac2208Snarayan VD_MAKE_DEV(vdc->instance, VD_EFI_WD_SLICE), 7434bac2208Snarayan DDI_NT_BLOCK, 0) != DDI_SUCCESS) { 7444bac2208Snarayan cmn_err(CE_NOTE, "[%d] Couldn't add block node 'wd'", 7454bac2208Snarayan vdc->instance); 7464bac2208Snarayan return (EIO); 7474bac2208Snarayan } 7484bac2208Snarayan 7494bac2208Snarayan /* if any device node is created we set this flag */ 7504bac2208Snarayan vdc->initialized |= VDC_MINOR; 7514bac2208Snarayan 7524bac2208Snarayan if (ddi_create_minor_node(vdc->dip, "wd,raw", S_IFCHR, 7534bac2208Snarayan VD_MAKE_DEV(vdc->instance, VD_EFI_WD_SLICE), 7544bac2208Snarayan DDI_NT_BLOCK, 0) != DDI_SUCCESS) { 7554bac2208Snarayan cmn_err(CE_NOTE, "[%d] Couldn't add block node 'wd,raw'", 7564bac2208Snarayan vdc->instance); 7574bac2208Snarayan return (EIO); 7584bac2208Snarayan } 7594bac2208Snarayan 7604bac2208Snarayan return (0); 7614bac2208Snarayan } 7624bac2208Snarayan 7634bac2208Snarayan static int 7644bac2208Snarayan vdc_create_device_nodes_vtoc(vdc_t *vdc) 7654bac2208Snarayan { 7664bac2208Snarayan ddi_remove_minor_node(vdc->dip, "wd"); 7674bac2208Snarayan ddi_remove_minor_node(vdc->dip, "wd,raw"); 7684bac2208Snarayan 7694bac2208Snarayan if (ddi_create_minor_node(vdc->dip, "h", S_IFBLK, 7704bac2208Snarayan VD_MAKE_DEV(vdc->instance, VD_EFI_WD_SLICE), 7714bac2208Snarayan DDI_NT_BLOCK, 0) != DDI_SUCCESS) { 7724bac2208Snarayan cmn_err(CE_NOTE, "[%d] Couldn't add block node 'h'", 7734bac2208Snarayan vdc->instance); 7744bac2208Snarayan return (EIO); 7754bac2208Snarayan } 7764bac2208Snarayan 7774bac2208Snarayan /* if any device node is created we set this flag */ 7784bac2208Snarayan vdc->initialized |= VDC_MINOR; 7794bac2208Snarayan 7804bac2208Snarayan if (ddi_create_minor_node(vdc->dip, "h,raw", S_IFCHR, 7814bac2208Snarayan VD_MAKE_DEV(vdc->instance, VD_EFI_WD_SLICE), 7824bac2208Snarayan DDI_NT_BLOCK, 0) != DDI_SUCCESS) { 7834bac2208Snarayan cmn_err(CE_NOTE, "[%d] Couldn't add block node 'h,raw'", 7844bac2208Snarayan vdc->instance); 7854bac2208Snarayan return (EIO); 7864bac2208Snarayan } 7874bac2208Snarayan 7884bac2208Snarayan return (0); 7894bac2208Snarayan } 7901ae08745Sheppo 7911ae08745Sheppo /* 7921ae08745Sheppo * Function: 7931ae08745Sheppo * vdc_create_device_nodes 7941ae08745Sheppo * 7951ae08745Sheppo * Description: 7961ae08745Sheppo * This function creates the block and character device nodes under 7971ae08745Sheppo * /devices along with the node properties. It is called as part of 7981ae08745Sheppo * the attach(9E) of the instance during the handshake with vds after 7991ae08745Sheppo * vds has sent the attributes to vdc. 8001ae08745Sheppo * 8011ae08745Sheppo * If the device is of type VD_DISK_TYPE_SLICE then the minor node 8021ae08745Sheppo * of 2 is used in keeping with the Solaris convention that slice 2 8031ae08745Sheppo * refers to a whole disk. Slices start at 'a' 8041ae08745Sheppo * 8051ae08745Sheppo * Parameters: 8061ae08745Sheppo * vdc - soft state pointer 8071ae08745Sheppo * 8081ae08745Sheppo * Return Values 8091ae08745Sheppo * 0 - Success 8101ae08745Sheppo * EIO - Failed to create node 8111ae08745Sheppo * EINVAL - Unknown type of disk exported 8121ae08745Sheppo */ 8131ae08745Sheppo static int 8141ae08745Sheppo vdc_create_device_nodes(vdc_t *vdc) 8151ae08745Sheppo { 8164bac2208Snarayan char name[sizeof ("s,raw")]; 8171ae08745Sheppo dev_info_t *dip = NULL; 8184bac2208Snarayan int instance, status; 8191ae08745Sheppo int num_slices = 1; 8201ae08745Sheppo int i; 8211ae08745Sheppo 8221ae08745Sheppo ASSERT(vdc != NULL); 8231ae08745Sheppo 8241ae08745Sheppo instance = vdc->instance; 8251ae08745Sheppo dip = vdc->dip; 8261ae08745Sheppo 8271ae08745Sheppo switch (vdc->vdisk_type) { 8281ae08745Sheppo case VD_DISK_TYPE_DISK: 8291ae08745Sheppo num_slices = V_NUMPAR; 8301ae08745Sheppo break; 8311ae08745Sheppo case VD_DISK_TYPE_SLICE: 8321ae08745Sheppo num_slices = 1; 8331ae08745Sheppo break; 8341ae08745Sheppo case VD_DISK_TYPE_UNK: 8351ae08745Sheppo default: 8361ae08745Sheppo return (EINVAL); 8371ae08745Sheppo } 8381ae08745Sheppo 8394bac2208Snarayan /* 8404bac2208Snarayan * Minor nodes are different for EFI disks: EFI disks do not have 8414bac2208Snarayan * a minor node 'g' for the minor number corresponding to slice 8424bac2208Snarayan * VD_EFI_WD_SLICE (slice 7) instead they have a minor node 'wd' 8434bac2208Snarayan * representing the whole disk. 8444bac2208Snarayan */ 8451ae08745Sheppo for (i = 0; i < num_slices; i++) { 8464bac2208Snarayan 8474bac2208Snarayan if (i == VD_EFI_WD_SLICE) { 8484bac2208Snarayan if (vdc->vdisk_label == VD_DISK_LABEL_EFI) 8494bac2208Snarayan status = vdc_create_device_nodes_efi(vdc); 8504bac2208Snarayan else 8514bac2208Snarayan status = vdc_create_device_nodes_vtoc(vdc); 8524bac2208Snarayan if (status != 0) 8534bac2208Snarayan return (status); 8544bac2208Snarayan continue; 8554bac2208Snarayan } 8564bac2208Snarayan 8571ae08745Sheppo (void) snprintf(name, sizeof (name), "%c", 'a' + i); 8581ae08745Sheppo if (ddi_create_minor_node(dip, name, S_IFBLK, 8591ae08745Sheppo VD_MAKE_DEV(instance, i), DDI_NT_BLOCK, 0) != DDI_SUCCESS) { 860e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't add block node '%s'", 861e1ebb9ecSlm66018 instance, name); 8621ae08745Sheppo return (EIO); 8631ae08745Sheppo } 8641ae08745Sheppo 8651ae08745Sheppo /* if any device node is created we set this flag */ 8661ae08745Sheppo vdc->initialized |= VDC_MINOR; 8671ae08745Sheppo 8681ae08745Sheppo (void) snprintf(name, sizeof (name), "%c%s", 8691ae08745Sheppo 'a' + i, ",raw"); 8701ae08745Sheppo if (ddi_create_minor_node(dip, name, S_IFCHR, 8711ae08745Sheppo VD_MAKE_DEV(instance, i), DDI_NT_BLOCK, 0) != DDI_SUCCESS) { 872e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't add raw node '%s'", 873e1ebb9ecSlm66018 instance, name); 8741ae08745Sheppo return (EIO); 8751ae08745Sheppo } 8761ae08745Sheppo } 8771ae08745Sheppo 8781ae08745Sheppo return (0); 8791ae08745Sheppo } 8801ae08745Sheppo 8811ae08745Sheppo /* 8821ae08745Sheppo * Function: 8831ae08745Sheppo * vdc_create_device_nodes_props 8841ae08745Sheppo * 8851ae08745Sheppo * Description: 8861ae08745Sheppo * This function creates the block and character device nodes under 8871ae08745Sheppo * /devices along with the node properties. It is called as part of 8881ae08745Sheppo * the attach(9E) of the instance during the handshake with vds after 8891ae08745Sheppo * vds has sent the attributes to vdc. 8901ae08745Sheppo * 8911ae08745Sheppo * Parameters: 8921ae08745Sheppo * vdc - soft state pointer 8931ae08745Sheppo * 8941ae08745Sheppo * Return Values 8951ae08745Sheppo * 0 - Success 8961ae08745Sheppo * EIO - Failed to create device node property 8971ae08745Sheppo * EINVAL - Unknown type of disk exported 8981ae08745Sheppo */ 8991ae08745Sheppo static int 9001ae08745Sheppo vdc_create_device_nodes_props(vdc_t *vdc) 9011ae08745Sheppo { 9021ae08745Sheppo dev_info_t *dip = NULL; 9031ae08745Sheppo int instance; 9041ae08745Sheppo int num_slices = 1; 9051ae08745Sheppo int64_t size = 0; 9061ae08745Sheppo dev_t dev; 9071ae08745Sheppo int rv; 9081ae08745Sheppo int i; 9091ae08745Sheppo 9101ae08745Sheppo ASSERT(vdc != NULL); 9111ae08745Sheppo 9121ae08745Sheppo instance = vdc->instance; 9131ae08745Sheppo dip = vdc->dip; 9141ae08745Sheppo 9151ae08745Sheppo if ((vdc->vtoc == NULL) || (vdc->vtoc->v_sanity != VTOC_SANE)) { 916*3af08d82Slm66018 DMSG(vdc, 0, "![%d] Could not create device node property." 9171ae08745Sheppo " No VTOC available", instance); 9181ae08745Sheppo return (ENXIO); 9191ae08745Sheppo } 9201ae08745Sheppo 9211ae08745Sheppo switch (vdc->vdisk_type) { 9221ae08745Sheppo case VD_DISK_TYPE_DISK: 9231ae08745Sheppo num_slices = V_NUMPAR; 9241ae08745Sheppo break; 9251ae08745Sheppo case VD_DISK_TYPE_SLICE: 9261ae08745Sheppo num_slices = 1; 9271ae08745Sheppo break; 9281ae08745Sheppo case VD_DISK_TYPE_UNK: 9291ae08745Sheppo default: 9301ae08745Sheppo return (EINVAL); 9311ae08745Sheppo } 9321ae08745Sheppo 9331ae08745Sheppo for (i = 0; i < num_slices; i++) { 9341ae08745Sheppo dev = makedevice(ddi_driver_major(dip), 9351ae08745Sheppo VD_MAKE_DEV(instance, i)); 9361ae08745Sheppo 9371ae08745Sheppo size = vdc->vtoc->v_part[i].p_size * vdc->vtoc->v_sectorsz; 938*3af08d82Slm66018 DMSG(vdc, 0, "[%d] sz %ld (%ld Mb) p_size %lx\n", 939e1ebb9ecSlm66018 instance, size, size / (1024 * 1024), 9401ae08745Sheppo vdc->vtoc->v_part[i].p_size); 9411ae08745Sheppo 9421ae08745Sheppo rv = ddi_prop_update_int64(dev, dip, VDC_SIZE_PROP_NAME, size); 9431ae08745Sheppo if (rv != DDI_PROP_SUCCESS) { 944e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't add '%s' prop of [%ld]", 945e1ebb9ecSlm66018 instance, VDC_SIZE_PROP_NAME, size); 9461ae08745Sheppo return (EIO); 9471ae08745Sheppo } 9481ae08745Sheppo 9491ae08745Sheppo rv = ddi_prop_update_int64(dev, dip, VDC_NBLOCKS_PROP_NAME, 9501ae08745Sheppo lbtodb(size)); 9511ae08745Sheppo if (rv != DDI_PROP_SUCCESS) { 952e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't add '%s' prop [%llu]", 9531ae08745Sheppo instance, VDC_NBLOCKS_PROP_NAME, lbtodb(size)); 9541ae08745Sheppo return (EIO); 9551ae08745Sheppo } 9561ae08745Sheppo } 9571ae08745Sheppo 9581ae08745Sheppo return (0); 9591ae08745Sheppo } 9601ae08745Sheppo 9611ae08745Sheppo static int 9621ae08745Sheppo vdc_open(dev_t *dev, int flag, int otyp, cred_t *cred) 9631ae08745Sheppo { 9641ae08745Sheppo _NOTE(ARGUNUSED(cred)) 9651ae08745Sheppo 9661ae08745Sheppo int instance; 9671ae08745Sheppo vdc_t *vdc; 9681ae08745Sheppo 9691ae08745Sheppo ASSERT(dev != NULL); 970*3af08d82Slm66018 instance = SDUNIT(*dev); 9711ae08745Sheppo 9721ae08745Sheppo if ((otyp != OTYP_CHR) && (otyp != OTYP_BLK)) 9731ae08745Sheppo return (EINVAL); 9741ae08745Sheppo 9751ae08745Sheppo if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) { 976e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't get state structure", instance); 9771ae08745Sheppo return (ENXIO); 9781ae08745Sheppo } 9791ae08745Sheppo 980*3af08d82Slm66018 DMSG(vdc, 0, "minor = %d flag = %x, otyp = %x\n", 981*3af08d82Slm66018 getminor(*dev), flag, otyp); 9821ae08745Sheppo 9831ae08745Sheppo mutex_enter(&vdc->lock); 984*3af08d82Slm66018 vdc->open_count++; 9851ae08745Sheppo mutex_exit(&vdc->lock); 9861ae08745Sheppo 9871ae08745Sheppo return (0); 9881ae08745Sheppo } 9891ae08745Sheppo 9901ae08745Sheppo static int 9911ae08745Sheppo vdc_close(dev_t dev, int flag, int otyp, cred_t *cred) 9921ae08745Sheppo { 9931ae08745Sheppo _NOTE(ARGUNUSED(cred)) 9941ae08745Sheppo 9951ae08745Sheppo int instance; 9961ae08745Sheppo vdc_t *vdc; 9971ae08745Sheppo 998*3af08d82Slm66018 instance = SDUNIT(dev); 9991ae08745Sheppo 10001ae08745Sheppo if ((otyp != OTYP_CHR) && (otyp != OTYP_BLK)) 10011ae08745Sheppo return (EINVAL); 10021ae08745Sheppo 10031ae08745Sheppo if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) { 1004e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't get state structure", instance); 10051ae08745Sheppo return (ENXIO); 10061ae08745Sheppo } 10071ae08745Sheppo 1008*3af08d82Slm66018 DMSG(vdc, 0, "[%d] flag = %x, otyp = %x\n", instance, flag, otyp); 10091ae08745Sheppo if (vdc->dkio_flush_pending) { 1010*3af08d82Slm66018 DMSG(vdc, 0, 1011*3af08d82Slm66018 "[%d] Cannot detach: %d outstanding DKIO flushes\n", 1012e1ebb9ecSlm66018 instance, vdc->dkio_flush_pending); 10131ae08745Sheppo return (EBUSY); 10141ae08745Sheppo } 10151ae08745Sheppo 10161ae08745Sheppo /* 10171ae08745Sheppo * Should not need the mutex here, since the framework should protect 10181ae08745Sheppo * against more opens on this device, but just in case. 10191ae08745Sheppo */ 10201ae08745Sheppo mutex_enter(&vdc->lock); 1021*3af08d82Slm66018 vdc->open_count--; 10221ae08745Sheppo mutex_exit(&vdc->lock); 10231ae08745Sheppo 10241ae08745Sheppo return (0); 10251ae08745Sheppo } 10261ae08745Sheppo 10271ae08745Sheppo static int 10281ae08745Sheppo vdc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) 10291ae08745Sheppo { 10301ae08745Sheppo _NOTE(ARGUNUSED(credp)) 10311ae08745Sheppo _NOTE(ARGUNUSED(rvalp)) 10321ae08745Sheppo 10331ae08745Sheppo return (vd_process_ioctl(dev, cmd, (caddr_t)arg, mode)); 10341ae08745Sheppo } 10351ae08745Sheppo 10361ae08745Sheppo static int 10371ae08745Sheppo vdc_print(dev_t dev, char *str) 10381ae08745Sheppo { 1039*3af08d82Slm66018 cmn_err(CE_NOTE, "vdc%d: %s", SDUNIT(dev), str); 10401ae08745Sheppo return (0); 10411ae08745Sheppo } 10421ae08745Sheppo 10431ae08745Sheppo static int 10441ae08745Sheppo vdc_dump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk) 10451ae08745Sheppo { 1046d10e4ef2Snarayan int rv; 1047d10e4ef2Snarayan size_t nbytes = nblk * DEV_BSIZE; 1048*3af08d82Slm66018 int instance = SDUNIT(dev); 1049d10e4ef2Snarayan vdc_t *vdc = NULL; 10501ae08745Sheppo 10511ae08745Sheppo if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) { 1052e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't get state structure", instance); 10531ae08745Sheppo return (ENXIO); 10541ae08745Sheppo } 10551ae08745Sheppo 1056*3af08d82Slm66018 DMSG(vdc, 2, "[%d] dump %ld bytes at block 0x%lx : addr=0x%p\n", 1057*3af08d82Slm66018 instance, nbytes, blkno, (void *)addr); 1058*3af08d82Slm66018 rv = vdc_send_request(vdc, VD_OP_BWRITE, addr, nbytes, 1059*3af08d82Slm66018 SDPART(dev), blkno, CB_STRATEGY, 0, VIO_write_dir); 1060*3af08d82Slm66018 if (rv) { 1061*3af08d82Slm66018 DMSG(vdc, 0, "Failed to do a disk dump (err=%d)\n", rv); 10621ae08745Sheppo return (rv); 10631ae08745Sheppo } 10641ae08745Sheppo 1065*3af08d82Slm66018 if (ddi_in_panic()) 1066*3af08d82Slm66018 (void) vdc_drain_response(vdc); 1067*3af08d82Slm66018 1068*3af08d82Slm66018 DMSG(vdc, 0, "[%d] End\n", instance); 1069*3af08d82Slm66018 1070*3af08d82Slm66018 return (0); 1071*3af08d82Slm66018 } 1072*3af08d82Slm66018 10731ae08745Sheppo /* -------------------------------------------------------------------------- */ 10741ae08745Sheppo 10751ae08745Sheppo /* 10761ae08745Sheppo * Disk access routines 10771ae08745Sheppo * 10781ae08745Sheppo */ 10791ae08745Sheppo 10801ae08745Sheppo /* 10811ae08745Sheppo * vdc_strategy() 10821ae08745Sheppo * 10831ae08745Sheppo * Return Value: 10841ae08745Sheppo * 0: As per strategy(9E), the strategy() function must return 0 10851ae08745Sheppo * [ bioerror(9f) sets b_flags to the proper error code ] 10861ae08745Sheppo */ 10871ae08745Sheppo static int 10881ae08745Sheppo vdc_strategy(struct buf *buf) 10891ae08745Sheppo { 10901ae08745Sheppo int rv = -1; 10911ae08745Sheppo vdc_t *vdc = NULL; 1092*3af08d82Slm66018 int instance = SDUNIT(buf->b_edev); 10931ae08745Sheppo int op = (buf->b_flags & B_READ) ? VD_OP_BREAD : VD_OP_BWRITE; 10941ae08745Sheppo 10951ae08745Sheppo if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) { 1096e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't get state structure", instance); 10971ae08745Sheppo bioerror(buf, ENXIO); 10981ae08745Sheppo biodone(buf); 10991ae08745Sheppo return (0); 11001ae08745Sheppo } 11011ae08745Sheppo 1102*3af08d82Slm66018 DMSG(vdc, 2, "[%d] %s %ld bytes at block %llx : b_addr=0x%p\n", 1103*3af08d82Slm66018 instance, (buf->b_flags & B_READ) ? "Read" : "Write", 1104*3af08d82Slm66018 buf->b_bcount, buf->b_lblkno, (void *)buf->b_un.b_addr); 1105d10e4ef2Snarayan DTRACE_IO2(vstart, buf_t *, buf, vdc_t *, vdc); 1106d10e4ef2Snarayan 11071ae08745Sheppo bp_mapin(buf); 11081ae08745Sheppo 1109*3af08d82Slm66018 rv = vdc_send_request(vdc, op, (caddr_t)buf->b_un.b_addr, 1110*3af08d82Slm66018 buf->b_bcount, SDPART(buf->b_edev), buf->b_lblkno, 1111*3af08d82Slm66018 CB_STRATEGY, buf, (op == VD_OP_BREAD) ? VIO_read_dir : 1112*3af08d82Slm66018 VIO_write_dir); 1113*3af08d82Slm66018 1114*3af08d82Slm66018 ASSERT(rv == 0 || rv == EINVAL); 11151ae08745Sheppo 1116d10e4ef2Snarayan /* 1117d10e4ef2Snarayan * If the request was successfully sent, the strategy call returns and 1118d10e4ef2Snarayan * the ACK handler calls the bioxxx functions when the vDisk server is 1119d10e4ef2Snarayan * done. 1120d10e4ef2Snarayan */ 1121d10e4ef2Snarayan if (rv) { 1122*3af08d82Slm66018 DMSG(vdc, 0, "Failed to read/write (err=%d)\n", rv); 11231ae08745Sheppo bioerror(buf, rv); 11241ae08745Sheppo biodone(buf); 1125d10e4ef2Snarayan } 1126d10e4ef2Snarayan 11271ae08745Sheppo return (0); 11281ae08745Sheppo } 11291ae08745Sheppo 11301ae08745Sheppo 11311ae08745Sheppo static int 11321ae08745Sheppo vdc_read(dev_t dev, struct uio *uio, cred_t *cred) 11331ae08745Sheppo { 11341ae08745Sheppo _NOTE(ARGUNUSED(cred)) 11351ae08745Sheppo 1136*3af08d82Slm66018 DMSGX(1, "[%d] Entered", SDUNIT(dev)); 11371ae08745Sheppo return (physio(vdc_strategy, NULL, dev, B_READ, minphys, uio)); 11381ae08745Sheppo } 11391ae08745Sheppo 11401ae08745Sheppo static int 11411ae08745Sheppo vdc_write(dev_t dev, struct uio *uio, cred_t *cred) 11421ae08745Sheppo { 11431ae08745Sheppo _NOTE(ARGUNUSED(cred)) 11441ae08745Sheppo 1145*3af08d82Slm66018 DMSGX(1, "[%d] Entered", SDUNIT(dev)); 11461ae08745Sheppo return (physio(vdc_strategy, NULL, dev, B_WRITE, minphys, uio)); 11471ae08745Sheppo } 11481ae08745Sheppo 11491ae08745Sheppo static int 11501ae08745Sheppo vdc_aread(dev_t dev, struct aio_req *aio, cred_t *cred) 11511ae08745Sheppo { 11521ae08745Sheppo _NOTE(ARGUNUSED(cred)) 11531ae08745Sheppo 1154*3af08d82Slm66018 DMSGX(1, "[%d] Entered", SDUNIT(dev)); 11551ae08745Sheppo return (aphysio(vdc_strategy, anocancel, dev, B_READ, minphys, aio)); 11561ae08745Sheppo } 11571ae08745Sheppo 11581ae08745Sheppo static int 11591ae08745Sheppo vdc_awrite(dev_t dev, struct aio_req *aio, cred_t *cred) 11601ae08745Sheppo { 11611ae08745Sheppo _NOTE(ARGUNUSED(cred)) 11621ae08745Sheppo 1163*3af08d82Slm66018 DMSGX(1, "[%d] Entered", SDUNIT(dev)); 11641ae08745Sheppo return (aphysio(vdc_strategy, anocancel, dev, B_WRITE, minphys, aio)); 11651ae08745Sheppo } 11661ae08745Sheppo 11671ae08745Sheppo 11681ae08745Sheppo /* -------------------------------------------------------------------------- */ 11691ae08745Sheppo 11701ae08745Sheppo /* 11711ae08745Sheppo * Handshake support 11721ae08745Sheppo */ 11731ae08745Sheppo 11741ae08745Sheppo 11750a55fbb7Slm66018 /* 11760a55fbb7Slm66018 * Function: 11770a55fbb7Slm66018 * vdc_init_ver_negotiation() 11780a55fbb7Slm66018 * 11790a55fbb7Slm66018 * Description: 11800a55fbb7Slm66018 * 11810a55fbb7Slm66018 * Arguments: 11820a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 11830a55fbb7Slm66018 * 11840a55fbb7Slm66018 * Return Code: 11850a55fbb7Slm66018 * 0 - Success 11860a55fbb7Slm66018 */ 11871ae08745Sheppo static int 11880a55fbb7Slm66018 vdc_init_ver_negotiation(vdc_t *vdc, vio_ver_t ver) 11891ae08745Sheppo { 11901ae08745Sheppo vio_ver_msg_t pkt; 11911ae08745Sheppo size_t msglen = sizeof (pkt); 11921ae08745Sheppo int status = -1; 11931ae08745Sheppo 11941ae08745Sheppo ASSERT(vdc != NULL); 11951ae08745Sheppo ASSERT(mutex_owned(&vdc->lock)); 11961ae08745Sheppo 1197*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Entered.\n", vdc->instance); 1198e1ebb9ecSlm66018 11991ae08745Sheppo /* 12001ae08745Sheppo * set the Session ID to a unique value 12011ae08745Sheppo * (the lower 32 bits of the clock tick) 12021ae08745Sheppo */ 12031ae08745Sheppo vdc->session_id = ((uint32_t)gettick() & 0xffffffff); 1204*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Set SID to 0x%lx\n", vdc->instance, vdc->session_id); 12051ae08745Sheppo 12061ae08745Sheppo pkt.tag.vio_msgtype = VIO_TYPE_CTRL; 12071ae08745Sheppo pkt.tag.vio_subtype = VIO_SUBTYPE_INFO; 12081ae08745Sheppo pkt.tag.vio_subtype_env = VIO_VER_INFO; 12091ae08745Sheppo pkt.tag.vio_sid = vdc->session_id; 12101ae08745Sheppo pkt.dev_class = VDEV_DISK; 12110a55fbb7Slm66018 pkt.ver_major = ver.major; 12120a55fbb7Slm66018 pkt.ver_minor = ver.minor; 12131ae08745Sheppo 12140a55fbb7Slm66018 status = vdc_send(vdc, (caddr_t)&pkt, &msglen); 1215*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Ver info sent (status = %d)\n", 1216*3af08d82Slm66018 vdc->instance, status); 12171ae08745Sheppo if ((status != 0) || (msglen != sizeof (vio_ver_msg_t))) { 1218*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to send Ver negotiation info: " 1219e1ebb9ecSlm66018 "id(%lx) rv(%d) size(%ld)", 1220e1ebb9ecSlm66018 vdc->instance, vdc->ldc_handle, 12211ae08745Sheppo status, msglen); 12221ae08745Sheppo if (msglen != sizeof (vio_ver_msg_t)) 12231ae08745Sheppo status = ENOMSG; 12241ae08745Sheppo } 12251ae08745Sheppo 12261ae08745Sheppo return (status); 12271ae08745Sheppo } 12281ae08745Sheppo 12290a55fbb7Slm66018 /* 12300a55fbb7Slm66018 * Function: 1231*3af08d82Slm66018 * vdc_ver_negotiation() 1232*3af08d82Slm66018 * 1233*3af08d82Slm66018 * Description: 1234*3af08d82Slm66018 * 1235*3af08d82Slm66018 * Arguments: 1236*3af08d82Slm66018 * vdcp - soft state pointer for this instance of the device driver. 1237*3af08d82Slm66018 * 1238*3af08d82Slm66018 * Return Code: 1239*3af08d82Slm66018 * 0 - Success 1240*3af08d82Slm66018 */ 1241*3af08d82Slm66018 static int 1242*3af08d82Slm66018 vdc_ver_negotiation(vdc_t *vdcp) 1243*3af08d82Slm66018 { 1244*3af08d82Slm66018 vio_msg_t vio_msg; 1245*3af08d82Slm66018 int status; 1246*3af08d82Slm66018 1247*3af08d82Slm66018 if (status = vdc_init_ver_negotiation(vdcp, vdc_version[0])) 1248*3af08d82Slm66018 return (status); 1249*3af08d82Slm66018 1250*3af08d82Slm66018 /* release lock and wait for response */ 1251*3af08d82Slm66018 mutex_exit(&vdcp->lock); 1252*3af08d82Slm66018 status = vdc_wait_for_response(vdcp, &vio_msg); 1253*3af08d82Slm66018 mutex_enter(&vdcp->lock); 1254*3af08d82Slm66018 if (status) { 1255*3af08d82Slm66018 DMSG(vdcp, 0, 1256*3af08d82Slm66018 "[%d] Failed waiting for Ver negotiation response, rv(%d)", 1257*3af08d82Slm66018 vdcp->instance, status); 1258*3af08d82Slm66018 return (status); 1259*3af08d82Slm66018 } 1260*3af08d82Slm66018 1261*3af08d82Slm66018 /* check type and sub_type ... */ 1262*3af08d82Slm66018 if (vio_msg.tag.vio_msgtype != VIO_TYPE_CTRL || 1263*3af08d82Slm66018 vio_msg.tag.vio_subtype == VIO_SUBTYPE_INFO) { 1264*3af08d82Slm66018 DMSG(vdcp, 0, "[%d] Invalid ver negotiation response\n", 1265*3af08d82Slm66018 vdcp->instance); 1266*3af08d82Slm66018 return (EPROTO); 1267*3af08d82Slm66018 } 1268*3af08d82Slm66018 1269*3af08d82Slm66018 return (vdc_handle_ver_msg(vdcp, (vio_ver_msg_t *)&vio_msg)); 1270*3af08d82Slm66018 } 1271*3af08d82Slm66018 1272*3af08d82Slm66018 /* 1273*3af08d82Slm66018 * Function: 12740a55fbb7Slm66018 * vdc_init_attr_negotiation() 12750a55fbb7Slm66018 * 12760a55fbb7Slm66018 * Description: 12770a55fbb7Slm66018 * 12780a55fbb7Slm66018 * Arguments: 12790a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 12800a55fbb7Slm66018 * 12810a55fbb7Slm66018 * Return Code: 12820a55fbb7Slm66018 * 0 - Success 12830a55fbb7Slm66018 */ 12841ae08745Sheppo static int 12851ae08745Sheppo vdc_init_attr_negotiation(vdc_t *vdc) 12861ae08745Sheppo { 12871ae08745Sheppo vd_attr_msg_t pkt; 12881ae08745Sheppo size_t msglen = sizeof (pkt); 12891ae08745Sheppo int status; 12901ae08745Sheppo 12911ae08745Sheppo ASSERT(vdc != NULL); 12921ae08745Sheppo ASSERT(mutex_owned(&vdc->lock)); 12931ae08745Sheppo 1294*3af08d82Slm66018 DMSG(vdc, 0, "[%d] entered\n", vdc->instance); 12951ae08745Sheppo 12961ae08745Sheppo /* fill in tag */ 12971ae08745Sheppo pkt.tag.vio_msgtype = VIO_TYPE_CTRL; 12981ae08745Sheppo pkt.tag.vio_subtype = VIO_SUBTYPE_INFO; 12991ae08745Sheppo pkt.tag.vio_subtype_env = VIO_ATTR_INFO; 13001ae08745Sheppo pkt.tag.vio_sid = vdc->session_id; 13011ae08745Sheppo /* fill in payload */ 13021ae08745Sheppo pkt.max_xfer_sz = vdc->max_xfer_sz; 13031ae08745Sheppo pkt.vdisk_block_size = vdc->block_size; 13041ae08745Sheppo pkt.xfer_mode = VIO_DRING_MODE; 13051ae08745Sheppo pkt.operations = 0; /* server will set bits of valid operations */ 13061ae08745Sheppo pkt.vdisk_type = 0; /* server will set to valid device type */ 13071ae08745Sheppo pkt.vdisk_size = 0; /* server will set to valid size */ 13081ae08745Sheppo 13090a55fbb7Slm66018 status = vdc_send(vdc, (caddr_t)&pkt, &msglen); 1310*3af08d82Slm66018 DMSG(vdc, 0, "Attr info sent (status = %d)\n", status); 13111ae08745Sheppo 13121ae08745Sheppo if ((status != 0) || (msglen != sizeof (vio_ver_msg_t))) { 1313*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to send Attr negotiation info: " 1314e1ebb9ecSlm66018 "id(%lx) rv(%d) size(%ld)", 1315e1ebb9ecSlm66018 vdc->instance, vdc->ldc_handle, 13161ae08745Sheppo status, msglen); 13171ae08745Sheppo if (msglen != sizeof (vio_ver_msg_t)) 13181ae08745Sheppo status = ENOMSG; 13191ae08745Sheppo } 13201ae08745Sheppo 13211ae08745Sheppo return (status); 13221ae08745Sheppo } 13231ae08745Sheppo 13240a55fbb7Slm66018 /* 13250a55fbb7Slm66018 * Function: 1326*3af08d82Slm66018 * vdc_attr_negotiation() 1327*3af08d82Slm66018 * 1328*3af08d82Slm66018 * Description: 1329*3af08d82Slm66018 * 1330*3af08d82Slm66018 * Arguments: 1331*3af08d82Slm66018 * vdc - soft state pointer for this instance of the device driver. 1332*3af08d82Slm66018 * 1333*3af08d82Slm66018 * Return Code: 1334*3af08d82Slm66018 * 0 - Success 1335*3af08d82Slm66018 */ 1336*3af08d82Slm66018 static int 1337*3af08d82Slm66018 vdc_attr_negotiation(vdc_t *vdcp) 1338*3af08d82Slm66018 { 1339*3af08d82Slm66018 int status; 1340*3af08d82Slm66018 vio_msg_t vio_msg; 1341*3af08d82Slm66018 1342*3af08d82Slm66018 if (status = vdc_init_attr_negotiation(vdcp)) 1343*3af08d82Slm66018 return (status); 1344*3af08d82Slm66018 1345*3af08d82Slm66018 /* release lock and wait for response */ 1346*3af08d82Slm66018 mutex_exit(&vdcp->lock); 1347*3af08d82Slm66018 status = vdc_wait_for_response(vdcp, &vio_msg); 1348*3af08d82Slm66018 mutex_enter(&vdcp->lock); 1349*3af08d82Slm66018 if (status) { 1350*3af08d82Slm66018 DMSG(vdcp, 0, 1351*3af08d82Slm66018 "[%d] Failed waiting for Attr negotiation response, rv(%d)", 1352*3af08d82Slm66018 vdcp->instance, status); 1353*3af08d82Slm66018 return (status); 1354*3af08d82Slm66018 } 1355*3af08d82Slm66018 1356*3af08d82Slm66018 /* check type and sub_type ... */ 1357*3af08d82Slm66018 if (vio_msg.tag.vio_msgtype != VIO_TYPE_CTRL || 1358*3af08d82Slm66018 vio_msg.tag.vio_subtype == VIO_SUBTYPE_INFO) { 1359*3af08d82Slm66018 DMSG(vdcp, 0, "[%d] Invalid attr negotiation response\n", 1360*3af08d82Slm66018 vdcp->instance); 1361*3af08d82Slm66018 return (EPROTO); 1362*3af08d82Slm66018 } 1363*3af08d82Slm66018 1364*3af08d82Slm66018 return (vdc_handle_attr_msg(vdcp, (vd_attr_msg_t *)&vio_msg)); 1365*3af08d82Slm66018 } 1366*3af08d82Slm66018 1367*3af08d82Slm66018 1368*3af08d82Slm66018 /* 1369*3af08d82Slm66018 * Function: 13700a55fbb7Slm66018 * vdc_init_dring_negotiate() 13710a55fbb7Slm66018 * 13720a55fbb7Slm66018 * Description: 13730a55fbb7Slm66018 * 13740a55fbb7Slm66018 * Arguments: 13750a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 13760a55fbb7Slm66018 * 13770a55fbb7Slm66018 * Return Code: 13780a55fbb7Slm66018 * 0 - Success 13790a55fbb7Slm66018 */ 13801ae08745Sheppo static int 13811ae08745Sheppo vdc_init_dring_negotiate(vdc_t *vdc) 13821ae08745Sheppo { 13831ae08745Sheppo vio_dring_reg_msg_t pkt; 13841ae08745Sheppo size_t msglen = sizeof (pkt); 13851ae08745Sheppo int status = -1; 1386*3af08d82Slm66018 int retry; 1387*3af08d82Slm66018 int nretries = 10; 13881ae08745Sheppo 13891ae08745Sheppo ASSERT(vdc != NULL); 13901ae08745Sheppo ASSERT(mutex_owned(&vdc->lock)); 13911ae08745Sheppo 1392*3af08d82Slm66018 for (retry = 0; retry < nretries; retry++) { 13931ae08745Sheppo status = vdc_init_descriptor_ring(vdc); 1394*3af08d82Slm66018 if (status != EAGAIN) 1395*3af08d82Slm66018 break; 1396*3af08d82Slm66018 drv_usecwait(vdc_min_timeout_ldc); 1397*3af08d82Slm66018 } 1398*3af08d82Slm66018 13991ae08745Sheppo if (status != 0) { 1400*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to init DRing (status = %d)\n", 14011ae08745Sheppo vdc->instance, status); 14021ae08745Sheppo return (status); 14031ae08745Sheppo } 1404*3af08d82Slm66018 1405*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Init of descriptor ring completed (status = %d)\n", 1406e1ebb9ecSlm66018 vdc->instance, status); 14071ae08745Sheppo 14081ae08745Sheppo /* fill in tag */ 14091ae08745Sheppo pkt.tag.vio_msgtype = VIO_TYPE_CTRL; 14101ae08745Sheppo pkt.tag.vio_subtype = VIO_SUBTYPE_INFO; 14111ae08745Sheppo pkt.tag.vio_subtype_env = VIO_DRING_REG; 14121ae08745Sheppo pkt.tag.vio_sid = vdc->session_id; 14131ae08745Sheppo /* fill in payload */ 14141ae08745Sheppo pkt.dring_ident = 0; 1415e1ebb9ecSlm66018 pkt.num_descriptors = vdc->dring_len; 1416e1ebb9ecSlm66018 pkt.descriptor_size = vdc->dring_entry_size; 14171ae08745Sheppo pkt.options = (VIO_TX_DRING | VIO_RX_DRING); 14181ae08745Sheppo pkt.ncookies = vdc->dring_cookie_count; 14191ae08745Sheppo pkt.cookie[0] = vdc->dring_cookie[0]; /* for now just one cookie */ 14201ae08745Sheppo 14210a55fbb7Slm66018 status = vdc_send(vdc, (caddr_t)&pkt, &msglen); 14221ae08745Sheppo if (status != 0) { 1423*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to register DRing (err = %d)", 1424e1ebb9ecSlm66018 vdc->instance, status); 14251ae08745Sheppo } 14261ae08745Sheppo 14271ae08745Sheppo return (status); 14281ae08745Sheppo } 14291ae08745Sheppo 14301ae08745Sheppo 1431*3af08d82Slm66018 /* 1432*3af08d82Slm66018 * Function: 1433*3af08d82Slm66018 * vdc_dring_negotiation() 1434*3af08d82Slm66018 * 1435*3af08d82Slm66018 * Description: 1436*3af08d82Slm66018 * 1437*3af08d82Slm66018 * Arguments: 1438*3af08d82Slm66018 * vdc - soft state pointer for this instance of the device driver. 1439*3af08d82Slm66018 * 1440*3af08d82Slm66018 * Return Code: 1441*3af08d82Slm66018 * 0 - Success 1442*3af08d82Slm66018 */ 1443*3af08d82Slm66018 static int 1444*3af08d82Slm66018 vdc_dring_negotiation(vdc_t *vdcp) 1445*3af08d82Slm66018 { 1446*3af08d82Slm66018 int status; 1447*3af08d82Slm66018 vio_msg_t vio_msg; 1448*3af08d82Slm66018 1449*3af08d82Slm66018 if (status = vdc_init_dring_negotiate(vdcp)) 1450*3af08d82Slm66018 return (status); 1451*3af08d82Slm66018 1452*3af08d82Slm66018 /* release lock and wait for response */ 1453*3af08d82Slm66018 mutex_exit(&vdcp->lock); 1454*3af08d82Slm66018 status = vdc_wait_for_response(vdcp, &vio_msg); 1455*3af08d82Slm66018 mutex_enter(&vdcp->lock); 1456*3af08d82Slm66018 if (status) { 1457*3af08d82Slm66018 DMSG(vdcp, 0, 1458*3af08d82Slm66018 "[%d] Failed waiting for Dring negotiation response," 1459*3af08d82Slm66018 " rv(%d)", vdcp->instance, status); 1460*3af08d82Slm66018 return (status); 1461*3af08d82Slm66018 } 1462*3af08d82Slm66018 1463*3af08d82Slm66018 /* check type and sub_type ... */ 1464*3af08d82Slm66018 if (vio_msg.tag.vio_msgtype != VIO_TYPE_CTRL || 1465*3af08d82Slm66018 vio_msg.tag.vio_subtype == VIO_SUBTYPE_INFO) { 1466*3af08d82Slm66018 DMSG(vdcp, 0, "[%d] Invalid Dring negotiation response\n", 1467*3af08d82Slm66018 vdcp->instance); 1468*3af08d82Slm66018 return (EPROTO); 1469*3af08d82Slm66018 } 1470*3af08d82Slm66018 1471*3af08d82Slm66018 return (vdc_handle_dring_reg_msg(vdcp, 1472*3af08d82Slm66018 (vio_dring_reg_msg_t *)&vio_msg)); 1473*3af08d82Slm66018 } 1474*3af08d82Slm66018 1475*3af08d82Slm66018 1476*3af08d82Slm66018 /* 1477*3af08d82Slm66018 * Function: 1478*3af08d82Slm66018 * vdc_send_rdx() 1479*3af08d82Slm66018 * 1480*3af08d82Slm66018 * Description: 1481*3af08d82Slm66018 * 1482*3af08d82Slm66018 * Arguments: 1483*3af08d82Slm66018 * vdc - soft state pointer for this instance of the device driver. 1484*3af08d82Slm66018 * 1485*3af08d82Slm66018 * Return Code: 1486*3af08d82Slm66018 * 0 - Success 1487*3af08d82Slm66018 */ 1488*3af08d82Slm66018 static int 1489*3af08d82Slm66018 vdc_send_rdx(vdc_t *vdcp) 1490*3af08d82Slm66018 { 1491*3af08d82Slm66018 vio_msg_t msg; 1492*3af08d82Slm66018 size_t msglen = sizeof (vio_msg_t); 1493*3af08d82Slm66018 int status; 1494*3af08d82Slm66018 1495*3af08d82Slm66018 /* 1496*3af08d82Slm66018 * Send an RDX message to vds to indicate we are ready 1497*3af08d82Slm66018 * to send data 1498*3af08d82Slm66018 */ 1499*3af08d82Slm66018 msg.tag.vio_msgtype = VIO_TYPE_CTRL; 1500*3af08d82Slm66018 msg.tag.vio_subtype = VIO_SUBTYPE_INFO; 1501*3af08d82Slm66018 msg.tag.vio_subtype_env = VIO_RDX; 1502*3af08d82Slm66018 msg.tag.vio_sid = vdcp->session_id; 1503*3af08d82Slm66018 status = vdc_send(vdcp, (caddr_t)&msg, &msglen); 1504*3af08d82Slm66018 if (status != 0) { 1505*3af08d82Slm66018 DMSG(vdcp, 0, "[%d] Failed to send RDX message (%d)", 1506*3af08d82Slm66018 vdcp->instance, status); 1507*3af08d82Slm66018 } 1508*3af08d82Slm66018 1509*3af08d82Slm66018 return (status); 1510*3af08d82Slm66018 } 1511*3af08d82Slm66018 1512*3af08d82Slm66018 /* 1513*3af08d82Slm66018 * Function: 1514*3af08d82Slm66018 * vdc_handle_rdx() 1515*3af08d82Slm66018 * 1516*3af08d82Slm66018 * Description: 1517*3af08d82Slm66018 * 1518*3af08d82Slm66018 * Arguments: 1519*3af08d82Slm66018 * vdc - soft state pointer for this instance of the device driver. 1520*3af08d82Slm66018 * msgp - received msg 1521*3af08d82Slm66018 * 1522*3af08d82Slm66018 * Return Code: 1523*3af08d82Slm66018 * 0 - Success 1524*3af08d82Slm66018 */ 1525*3af08d82Slm66018 static int 1526*3af08d82Slm66018 vdc_handle_rdx(vdc_t *vdcp, vio_rdx_msg_t *msgp) 1527*3af08d82Slm66018 { 1528*3af08d82Slm66018 _NOTE(ARGUNUSED(vdcp)) 1529*3af08d82Slm66018 _NOTE(ARGUNUSED(msgp)) 1530*3af08d82Slm66018 1531*3af08d82Slm66018 ASSERT(msgp->tag.vio_msgtype == VIO_TYPE_CTRL); 1532*3af08d82Slm66018 ASSERT(msgp->tag.vio_subtype == VIO_SUBTYPE_ACK); 1533*3af08d82Slm66018 ASSERT(msgp->tag.vio_subtype_env == VIO_RDX); 1534*3af08d82Slm66018 1535*3af08d82Slm66018 DMSG(vdcp, 1, "[%d] Got an RDX msg", vdcp->instance); 1536*3af08d82Slm66018 1537*3af08d82Slm66018 return (0); 1538*3af08d82Slm66018 } 1539*3af08d82Slm66018 1540*3af08d82Slm66018 /* 1541*3af08d82Slm66018 * Function: 1542*3af08d82Slm66018 * vdc_rdx_exchange() 1543*3af08d82Slm66018 * 1544*3af08d82Slm66018 * Description: 1545*3af08d82Slm66018 * 1546*3af08d82Slm66018 * Arguments: 1547*3af08d82Slm66018 * vdc - soft state pointer for this instance of the device driver. 1548*3af08d82Slm66018 * 1549*3af08d82Slm66018 * Return Code: 1550*3af08d82Slm66018 * 0 - Success 1551*3af08d82Slm66018 */ 1552*3af08d82Slm66018 static int 1553*3af08d82Slm66018 vdc_rdx_exchange(vdc_t *vdcp) 1554*3af08d82Slm66018 { 1555*3af08d82Slm66018 int status; 1556*3af08d82Slm66018 vio_msg_t vio_msg; 1557*3af08d82Slm66018 1558*3af08d82Slm66018 if (status = vdc_send_rdx(vdcp)) 1559*3af08d82Slm66018 return (status); 1560*3af08d82Slm66018 1561*3af08d82Slm66018 /* release lock and wait for response */ 1562*3af08d82Slm66018 mutex_exit(&vdcp->lock); 1563*3af08d82Slm66018 status = vdc_wait_for_response(vdcp, &vio_msg); 1564*3af08d82Slm66018 mutex_enter(&vdcp->lock); 1565*3af08d82Slm66018 if (status) { 1566*3af08d82Slm66018 DMSG(vdcp, 0, 1567*3af08d82Slm66018 "[%d] Failed waiting for RDX response," 1568*3af08d82Slm66018 " rv(%d)", vdcp->instance, status); 1569*3af08d82Slm66018 return (status); 1570*3af08d82Slm66018 } 1571*3af08d82Slm66018 1572*3af08d82Slm66018 /* check type and sub_type ... */ 1573*3af08d82Slm66018 if (vio_msg.tag.vio_msgtype != VIO_TYPE_CTRL || 1574*3af08d82Slm66018 vio_msg.tag.vio_subtype != VIO_SUBTYPE_ACK) { 1575*3af08d82Slm66018 DMSG(vdcp, 0, "[%d] Invalid RDX response\n", 1576*3af08d82Slm66018 vdcp->instance); 1577*3af08d82Slm66018 return (EPROTO); 1578*3af08d82Slm66018 } 1579*3af08d82Slm66018 1580*3af08d82Slm66018 return (vdc_handle_rdx(vdcp, (vio_rdx_msg_t *)&vio_msg)); 1581*3af08d82Slm66018 } 1582*3af08d82Slm66018 1583*3af08d82Slm66018 15841ae08745Sheppo /* -------------------------------------------------------------------------- */ 15851ae08745Sheppo 15861ae08745Sheppo /* 15871ae08745Sheppo * LDC helper routines 15881ae08745Sheppo */ 15891ae08745Sheppo 1590*3af08d82Slm66018 static int 1591*3af08d82Slm66018 vdc_recv(vdc_t *vdc, vio_msg_t *msgp, size_t *nbytesp) 1592*3af08d82Slm66018 { 1593*3af08d82Slm66018 int status; 1594*3af08d82Slm66018 boolean_t q_has_pkts = B_FALSE; 1595*3af08d82Slm66018 int delay_time; 1596*3af08d82Slm66018 size_t len; 1597*3af08d82Slm66018 1598*3af08d82Slm66018 mutex_enter(&vdc->read_lock); 1599*3af08d82Slm66018 1600*3af08d82Slm66018 if (vdc->read_state == VDC_READ_IDLE) 1601*3af08d82Slm66018 vdc->read_state = VDC_READ_WAITING; 1602*3af08d82Slm66018 1603*3af08d82Slm66018 while (vdc->read_state != VDC_READ_PENDING) { 1604*3af08d82Slm66018 1605*3af08d82Slm66018 /* detect if the connection has been reset */ 1606*3af08d82Slm66018 if (vdc->read_state == VDC_READ_RESET) { 1607*3af08d82Slm66018 status = ECONNRESET; 1608*3af08d82Slm66018 goto done; 1609*3af08d82Slm66018 } 1610*3af08d82Slm66018 1611*3af08d82Slm66018 cv_wait(&vdc->read_cv, &vdc->read_lock); 1612*3af08d82Slm66018 } 1613*3af08d82Slm66018 1614*3af08d82Slm66018 /* 1615*3af08d82Slm66018 * Until we get a blocking ldc read we have to retry 1616*3af08d82Slm66018 * until the entire LDC message has arrived before 1617*3af08d82Slm66018 * ldc_read() will succeed. Note we also bail out if 1618*3af08d82Slm66018 * the chanel is reset or goes away. 1619*3af08d82Slm66018 */ 1620*3af08d82Slm66018 delay_time = vdc_ldc_read_init_delay; 1621*3af08d82Slm66018 loop: 1622*3af08d82Slm66018 len = *nbytesp; 1623*3af08d82Slm66018 status = ldc_read(vdc->ldc_handle, (caddr_t)msgp, &len); 1624*3af08d82Slm66018 switch (status) { 1625*3af08d82Slm66018 case EAGAIN: 1626*3af08d82Slm66018 delay_time *= 2; 1627*3af08d82Slm66018 if (delay_time >= vdc_ldc_read_max_delay) 1628*3af08d82Slm66018 delay_time = vdc_ldc_read_max_delay; 1629*3af08d82Slm66018 delay(delay_time); 1630*3af08d82Slm66018 goto loop; 1631*3af08d82Slm66018 1632*3af08d82Slm66018 case 0: 1633*3af08d82Slm66018 if (len == 0) { 1634*3af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_read returned 0 bytes with " 1635*3af08d82Slm66018 "no error!\n", vdc->instance); 1636*3af08d82Slm66018 goto loop; 1637*3af08d82Slm66018 } 1638*3af08d82Slm66018 1639*3af08d82Slm66018 *nbytesp = len; 1640*3af08d82Slm66018 1641*3af08d82Slm66018 /* 1642*3af08d82Slm66018 * If there are pending messages, leave the 1643*3af08d82Slm66018 * read state as pending. Otherwise, set the state 1644*3af08d82Slm66018 * back to idle. 1645*3af08d82Slm66018 */ 1646*3af08d82Slm66018 status = ldc_chkq(vdc->ldc_handle, &q_has_pkts); 1647*3af08d82Slm66018 if (status == 0 && !q_has_pkts) 1648*3af08d82Slm66018 vdc->read_state = VDC_READ_IDLE; 1649*3af08d82Slm66018 1650*3af08d82Slm66018 break; 1651*3af08d82Slm66018 default: 1652*3af08d82Slm66018 DMSG(vdc, 0, "ldc_read returned %d\n", status); 1653*3af08d82Slm66018 break; 1654*3af08d82Slm66018 } 1655*3af08d82Slm66018 1656*3af08d82Slm66018 done: 1657*3af08d82Slm66018 mutex_exit(&vdc->read_lock); 1658*3af08d82Slm66018 1659*3af08d82Slm66018 return (status); 1660*3af08d82Slm66018 } 1661*3af08d82Slm66018 1662*3af08d82Slm66018 1663*3af08d82Slm66018 1664*3af08d82Slm66018 #ifdef DEBUG 1665*3af08d82Slm66018 void 1666*3af08d82Slm66018 vdc_decode_tag(vdc_t *vdcp, vio_msg_t *msg) 1667*3af08d82Slm66018 { 1668*3af08d82Slm66018 char *ms, *ss, *ses; 1669*3af08d82Slm66018 switch (msg->tag.vio_msgtype) { 1670*3af08d82Slm66018 #define Q(_s) case _s : ms = #_s; break; 1671*3af08d82Slm66018 Q(VIO_TYPE_CTRL) 1672*3af08d82Slm66018 Q(VIO_TYPE_DATA) 1673*3af08d82Slm66018 Q(VIO_TYPE_ERR) 1674*3af08d82Slm66018 #undef Q 1675*3af08d82Slm66018 default: ms = "unknown"; break; 1676*3af08d82Slm66018 } 1677*3af08d82Slm66018 1678*3af08d82Slm66018 switch (msg->tag.vio_subtype) { 1679*3af08d82Slm66018 #define Q(_s) case _s : ss = #_s; break; 1680*3af08d82Slm66018 Q(VIO_SUBTYPE_INFO) 1681*3af08d82Slm66018 Q(VIO_SUBTYPE_ACK) 1682*3af08d82Slm66018 Q(VIO_SUBTYPE_NACK) 1683*3af08d82Slm66018 #undef Q 1684*3af08d82Slm66018 default: ss = "unknown"; break; 1685*3af08d82Slm66018 } 1686*3af08d82Slm66018 1687*3af08d82Slm66018 switch (msg->tag.vio_subtype_env) { 1688*3af08d82Slm66018 #define Q(_s) case _s : ses = #_s; break; 1689*3af08d82Slm66018 Q(VIO_VER_INFO) 1690*3af08d82Slm66018 Q(VIO_ATTR_INFO) 1691*3af08d82Slm66018 Q(VIO_DRING_REG) 1692*3af08d82Slm66018 Q(VIO_DRING_UNREG) 1693*3af08d82Slm66018 Q(VIO_RDX) 1694*3af08d82Slm66018 Q(VIO_PKT_DATA) 1695*3af08d82Slm66018 Q(VIO_DESC_DATA) 1696*3af08d82Slm66018 Q(VIO_DRING_DATA) 1697*3af08d82Slm66018 #undef Q 1698*3af08d82Slm66018 default: ses = "unknown"; break; 1699*3af08d82Slm66018 } 1700*3af08d82Slm66018 1701*3af08d82Slm66018 DMSG(vdcp, 3, "(%x/%x/%x) message : (%s/%s/%s)\n", 1702*3af08d82Slm66018 msg->tag.vio_msgtype, msg->tag.vio_subtype, 1703*3af08d82Slm66018 msg->tag.vio_subtype_env, ms, ss, ses); 1704*3af08d82Slm66018 } 1705*3af08d82Slm66018 #endif 1706*3af08d82Slm66018 17071ae08745Sheppo /* 17081ae08745Sheppo * Function: 17091ae08745Sheppo * vdc_send() 17101ae08745Sheppo * 17111ae08745Sheppo * Description: 17121ae08745Sheppo * The function encapsulates the call to write a message using LDC. 17131ae08745Sheppo * If LDC indicates that the call failed due to the queue being full, 17141ae08745Sheppo * we retry the ldc_write() [ up to 'vdc_retries' time ], otherwise 17151ae08745Sheppo * we return the error returned by LDC. 17161ae08745Sheppo * 17171ae08745Sheppo * Arguments: 17181ae08745Sheppo * ldc_handle - LDC handle for the channel this instance of vdc uses 17191ae08745Sheppo * pkt - address of LDC message to be sent 17201ae08745Sheppo * msglen - the size of the message being sent. When the function 17211ae08745Sheppo * returns, this contains the number of bytes written. 17221ae08745Sheppo * 17231ae08745Sheppo * Return Code: 17241ae08745Sheppo * 0 - Success. 17251ae08745Sheppo * EINVAL - pkt or msglen were NULL 17261ae08745Sheppo * ECONNRESET - The connection was not up. 17271ae08745Sheppo * EWOULDBLOCK - LDC queue is full 17281ae08745Sheppo * xxx - other error codes returned by ldc_write 17291ae08745Sheppo */ 17301ae08745Sheppo static int 17310a55fbb7Slm66018 vdc_send(vdc_t *vdc, caddr_t pkt, size_t *msglen) 17321ae08745Sheppo { 17331ae08745Sheppo size_t size = 0; 17341ae08745Sheppo int status = 0; 1735*3af08d82Slm66018 clock_t delay_ticks; 17361ae08745Sheppo 17370a55fbb7Slm66018 ASSERT(vdc != NULL); 17380a55fbb7Slm66018 ASSERT(mutex_owned(&vdc->lock)); 17391ae08745Sheppo ASSERT(msglen != NULL); 17401ae08745Sheppo ASSERT(*msglen != 0); 17411ae08745Sheppo 1742*3af08d82Slm66018 #ifdef DEBUG 1743*3af08d82Slm66018 vdc_decode_tag(vdc, (vio_msg_t *)pkt); 1744*3af08d82Slm66018 #endif 1745*3af08d82Slm66018 /* 1746*3af08d82Slm66018 * Wait indefinitely to send if channel 1747*3af08d82Slm66018 * is busy, but bail out if we succeed or 1748*3af08d82Slm66018 * if the channel closes or is reset. 1749*3af08d82Slm66018 */ 1750*3af08d82Slm66018 delay_ticks = vdc_hz_min_ldc_delay; 17511ae08745Sheppo do { 17521ae08745Sheppo size = *msglen; 17530a55fbb7Slm66018 status = ldc_write(vdc->ldc_handle, pkt, &size); 1754*3af08d82Slm66018 if (status == EWOULDBLOCK) { 1755*3af08d82Slm66018 delay(delay_ticks); 1756*3af08d82Slm66018 /* geometric backoff */ 1757*3af08d82Slm66018 delay_ticks *= 2; 1758*3af08d82Slm66018 if (delay_ticks > vdc_hz_max_ldc_delay) 1759*3af08d82Slm66018 delay_ticks = vdc_hz_max_ldc_delay; 1760*3af08d82Slm66018 } 1761*3af08d82Slm66018 } while (status == EWOULDBLOCK); 17621ae08745Sheppo 17630a55fbb7Slm66018 /* if LDC had serious issues --- reset vdc state */ 17640a55fbb7Slm66018 if (status == EIO || status == ECONNRESET) { 1765*3af08d82Slm66018 /* LDC had serious issues --- reset vdc state */ 1766*3af08d82Slm66018 mutex_enter(&vdc->read_lock); 1767*3af08d82Slm66018 if ((vdc->read_state == VDC_READ_WAITING) || 1768*3af08d82Slm66018 (vdc->read_state == VDC_READ_RESET)) 1769*3af08d82Slm66018 cv_signal(&vdc->read_cv); 1770*3af08d82Slm66018 vdc->read_state = VDC_READ_RESET; 1771*3af08d82Slm66018 mutex_exit(&vdc->read_lock); 1772*3af08d82Slm66018 1773*3af08d82Slm66018 /* wake up any waiters in the reset thread */ 1774*3af08d82Slm66018 if (vdc->state == VDC_STATE_INIT_WAITING) { 1775*3af08d82Slm66018 DMSG(vdc, 0, "[%d] write reset - " 1776*3af08d82Slm66018 "vdc is resetting ..\n", vdc->instance); 1777*3af08d82Slm66018 vdc->state = VDC_STATE_RESETTING; 1778*3af08d82Slm66018 cv_signal(&vdc->initwait_cv); 1779*3af08d82Slm66018 } 1780*3af08d82Slm66018 1781*3af08d82Slm66018 return (ECONNRESET); 17820a55fbb7Slm66018 } 17830a55fbb7Slm66018 17841ae08745Sheppo /* return the last size written */ 17851ae08745Sheppo *msglen = size; 17861ae08745Sheppo 17871ae08745Sheppo return (status); 17881ae08745Sheppo } 17891ae08745Sheppo 17901ae08745Sheppo /* 17911ae08745Sheppo * Function: 17921ae08745Sheppo * vdc_get_ldc_id() 17931ae08745Sheppo * 17941ae08745Sheppo * Description: 17951ae08745Sheppo * This function gets the 'ldc-id' for this particular instance of vdc. 17961ae08745Sheppo * The id returned is the guest domain channel endpoint LDC uses for 17971ae08745Sheppo * communication with vds. 17981ae08745Sheppo * 17991ae08745Sheppo * Arguments: 18001ae08745Sheppo * dip - dev info pointer for this instance of the device driver. 18011ae08745Sheppo * ldc_id - pointer to variable used to return the 'ldc-id' found. 18021ae08745Sheppo * 18031ae08745Sheppo * Return Code: 18041ae08745Sheppo * 0 - Success. 18051ae08745Sheppo * ENOENT - Expected node or property did not exist. 18061ae08745Sheppo * ENXIO - Unexpected error communicating with MD framework 18071ae08745Sheppo */ 18081ae08745Sheppo static int 18091ae08745Sheppo vdc_get_ldc_id(dev_info_t *dip, uint64_t *ldc_id) 18101ae08745Sheppo { 18111ae08745Sheppo int status = ENOENT; 18121ae08745Sheppo char *node_name = NULL; 18131ae08745Sheppo md_t *mdp = NULL; 18141ae08745Sheppo int num_nodes; 18151ae08745Sheppo int num_vdevs; 18161ae08745Sheppo int num_chans; 18171ae08745Sheppo mde_cookie_t rootnode; 18181ae08745Sheppo mde_cookie_t *listp = NULL; 18191ae08745Sheppo mde_cookie_t *chanp = NULL; 18201ae08745Sheppo boolean_t found_inst = B_FALSE; 18211ae08745Sheppo int listsz; 18221ae08745Sheppo int idx; 18231ae08745Sheppo uint64_t md_inst; 18241ae08745Sheppo int obp_inst; 18251ae08745Sheppo int instance = ddi_get_instance(dip); 18261ae08745Sheppo 18271ae08745Sheppo ASSERT(ldc_id != NULL); 18281ae08745Sheppo *ldc_id = 0; 18291ae08745Sheppo 18301ae08745Sheppo /* 18311ae08745Sheppo * Get the OBP instance number for comparison with the MD instance 18321ae08745Sheppo * 18331ae08745Sheppo * The "cfg-handle" property of a vdc node in an MD contains the MD's 18341ae08745Sheppo * notion of "instance", or unique identifier, for that node; OBP 18351ae08745Sheppo * stores the value of the "cfg-handle" MD property as the value of 18361ae08745Sheppo * the "reg" property on the node in the device tree it builds from 18371ae08745Sheppo * the MD and passes to Solaris. Thus, we look up the devinfo node's 18381ae08745Sheppo * "reg" property value to uniquely identify this device instance. 18391ae08745Sheppo * If the "reg" property cannot be found, the device tree state is 18401ae08745Sheppo * presumably so broken that there is no point in continuing. 18411ae08745Sheppo */ 18421ae08745Sheppo if (!ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, OBP_REG)) { 18431ae08745Sheppo cmn_err(CE_WARN, "'%s' property does not exist", OBP_REG); 18441ae08745Sheppo return (ENOENT); 18451ae08745Sheppo } 18461ae08745Sheppo obp_inst = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 18471ae08745Sheppo OBP_REG, -1); 1848*3af08d82Slm66018 DMSGX(1, "[%d] OBP inst=%d\n", instance, obp_inst); 18491ae08745Sheppo 18501ae08745Sheppo /* 18511ae08745Sheppo * We now walk the MD nodes and if an instance of a vdc node matches 18521ae08745Sheppo * the instance got from OBP we get the ldc-id property. 18531ae08745Sheppo */ 18541ae08745Sheppo if ((mdp = md_get_handle()) == NULL) { 18551ae08745Sheppo cmn_err(CE_WARN, "unable to init machine description"); 18561ae08745Sheppo return (ENXIO); 18571ae08745Sheppo } 18581ae08745Sheppo 18591ae08745Sheppo num_nodes = md_node_count(mdp); 18601ae08745Sheppo ASSERT(num_nodes > 0); 18611ae08745Sheppo 18621ae08745Sheppo listsz = num_nodes * sizeof (mde_cookie_t); 18631ae08745Sheppo 18641ae08745Sheppo /* allocate memory for nodes */ 18651ae08745Sheppo listp = kmem_zalloc(listsz, KM_SLEEP); 18661ae08745Sheppo chanp = kmem_zalloc(listsz, KM_SLEEP); 18671ae08745Sheppo 18681ae08745Sheppo rootnode = md_root_node(mdp); 18691ae08745Sheppo ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE); 18701ae08745Sheppo 18711ae08745Sheppo /* 18721ae08745Sheppo * Search for all the virtual devices, we will then check to see which 18731ae08745Sheppo * ones are disk nodes. 18741ae08745Sheppo */ 18751ae08745Sheppo num_vdevs = md_scan_dag(mdp, rootnode, 18761ae08745Sheppo md_find_name(mdp, VDC_MD_VDEV_NAME), 18771ae08745Sheppo md_find_name(mdp, "fwd"), listp); 18781ae08745Sheppo 18791ae08745Sheppo if (num_vdevs <= 0) { 18801ae08745Sheppo cmn_err(CE_NOTE, "No '%s' node found", VDC_MD_VDEV_NAME); 18811ae08745Sheppo status = ENOENT; 18821ae08745Sheppo goto done; 18831ae08745Sheppo } 18841ae08745Sheppo 1885*3af08d82Slm66018 DMSGX(1, "[%d] num_vdevs=%d\n", instance, num_vdevs); 18861ae08745Sheppo for (idx = 0; idx < num_vdevs; idx++) { 18871ae08745Sheppo status = md_get_prop_str(mdp, listp[idx], "name", &node_name); 18881ae08745Sheppo if ((status != 0) || (node_name == NULL)) { 18891ae08745Sheppo cmn_err(CE_NOTE, "Unable to get name of node type '%s'" 18901ae08745Sheppo ": err %d", VDC_MD_VDEV_NAME, status); 18911ae08745Sheppo continue; 18921ae08745Sheppo } 18931ae08745Sheppo 1894*3af08d82Slm66018 DMSGX(1, "[%d] Found node '%s'\n", instance, node_name); 18951ae08745Sheppo if (strcmp(VDC_MD_DISK_NAME, node_name) == 0) { 18961ae08745Sheppo status = md_get_prop_val(mdp, listp[idx], 18971ae08745Sheppo VDC_MD_CFG_HDL, &md_inst); 1898*3af08d82Slm66018 DMSGX(1, "[%d] vdc inst in MD=%lx\n", 1899*3af08d82Slm66018 instance, md_inst); 19001ae08745Sheppo if ((status == 0) && (md_inst == obp_inst)) { 19011ae08745Sheppo found_inst = B_TRUE; 19021ae08745Sheppo break; 19031ae08745Sheppo } 19041ae08745Sheppo } 19051ae08745Sheppo } 19061ae08745Sheppo 19070a55fbb7Slm66018 if (!found_inst) { 1908*3af08d82Slm66018 DMSGX(0, "Unable to find correct '%s' node", VDC_MD_DISK_NAME); 19091ae08745Sheppo status = ENOENT; 19101ae08745Sheppo goto done; 19111ae08745Sheppo } 1912*3af08d82Slm66018 DMSGX(0, "[%d] MD inst=%lx\n", instance, md_inst); 19131ae08745Sheppo 19141ae08745Sheppo /* get the channels for this node */ 19151ae08745Sheppo num_chans = md_scan_dag(mdp, listp[idx], 19161ae08745Sheppo md_find_name(mdp, VDC_MD_CHAN_NAME), 19171ae08745Sheppo md_find_name(mdp, "fwd"), chanp); 19181ae08745Sheppo 19191ae08745Sheppo /* expecting at least one channel */ 19201ae08745Sheppo if (num_chans <= 0) { 19211ae08745Sheppo cmn_err(CE_NOTE, "No '%s' node for '%s' port", 19221ae08745Sheppo VDC_MD_CHAN_NAME, VDC_MD_VDEV_NAME); 19231ae08745Sheppo status = ENOENT; 19241ae08745Sheppo goto done; 19251ae08745Sheppo 19261ae08745Sheppo } else if (num_chans != 1) { 1927*3af08d82Slm66018 DMSGX(0, "[%d] Expected 1 '%s' node for '%s' port, found %d\n", 1928e1ebb9ecSlm66018 instance, VDC_MD_CHAN_NAME, VDC_MD_VDEV_NAME, 19291ae08745Sheppo num_chans); 19301ae08745Sheppo } 19311ae08745Sheppo 19321ae08745Sheppo /* 19331ae08745Sheppo * We use the first channel found (index 0), irrespective of how 19341ae08745Sheppo * many are there in total. 19351ae08745Sheppo */ 19361ae08745Sheppo if (md_get_prop_val(mdp, chanp[0], VDC_ID_PROP, ldc_id) != 0) { 19371ae08745Sheppo cmn_err(CE_NOTE, "Channel '%s' property not found", 19381ae08745Sheppo VDC_ID_PROP); 19391ae08745Sheppo status = ENOENT; 19401ae08745Sheppo } 19411ae08745Sheppo 1942*3af08d82Slm66018 DMSGX(0, "[%d] LDC id is 0x%lx\n", instance, *ldc_id); 19431ae08745Sheppo 19441ae08745Sheppo done: 19451ae08745Sheppo if (chanp) 19461ae08745Sheppo kmem_free(chanp, listsz); 19471ae08745Sheppo if (listp) 19481ae08745Sheppo kmem_free(listp, listsz); 19491ae08745Sheppo 19501ae08745Sheppo (void) md_fini_handle(mdp); 19511ae08745Sheppo 19521ae08745Sheppo return (status); 19531ae08745Sheppo } 19541ae08745Sheppo 19550a55fbb7Slm66018 static int 19560a55fbb7Slm66018 vdc_do_ldc_up(vdc_t *vdc) 19570a55fbb7Slm66018 { 19580a55fbb7Slm66018 int status; 1959*3af08d82Slm66018 ldc_status_t ldc_state; 19600a55fbb7Slm66018 1961*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Bringing up channel %lx\n", 1962*3af08d82Slm66018 vdc->instance, vdc->ldc_id); 1963*3af08d82Slm66018 1964*3af08d82Slm66018 if (vdc->lifecycle == VDC_LC_DETACHING) 1965*3af08d82Slm66018 return (EINVAL); 19660a55fbb7Slm66018 19670a55fbb7Slm66018 if ((status = ldc_up(vdc->ldc_handle)) != 0) { 19680a55fbb7Slm66018 switch (status) { 19690a55fbb7Slm66018 case ECONNREFUSED: /* listener not ready at other end */ 1970*3af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_up(%lx,...) return %d\n", 1971e1ebb9ecSlm66018 vdc->instance, vdc->ldc_id, status); 19720a55fbb7Slm66018 status = 0; 19730a55fbb7Slm66018 break; 19740a55fbb7Slm66018 default: 1975*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to bring up LDC: " 1976*3af08d82Slm66018 "channel=%ld, err=%d", vdc->instance, vdc->ldc_id, 1977*3af08d82Slm66018 status); 1978*3af08d82Slm66018 break; 1979*3af08d82Slm66018 } 1980*3af08d82Slm66018 } 1981*3af08d82Slm66018 1982*3af08d82Slm66018 if (ldc_status(vdc->ldc_handle, &ldc_state) == 0) { 1983*3af08d82Slm66018 vdc->ldc_state = ldc_state; 1984*3af08d82Slm66018 if (ldc_state == LDC_UP) { 1985*3af08d82Slm66018 DMSG(vdc, 0, "[%d] LDC channel already up\n", 1986*3af08d82Slm66018 vdc->instance); 1987*3af08d82Slm66018 vdc->seq_num = 1; 1988*3af08d82Slm66018 vdc->seq_num_reply = 0; 19890a55fbb7Slm66018 } 19900a55fbb7Slm66018 } 19910a55fbb7Slm66018 19920a55fbb7Slm66018 return (status); 19930a55fbb7Slm66018 } 19940a55fbb7Slm66018 19950a55fbb7Slm66018 /* 19960a55fbb7Slm66018 * Function: 19970a55fbb7Slm66018 * vdc_terminate_ldc() 19980a55fbb7Slm66018 * 19990a55fbb7Slm66018 * Description: 20000a55fbb7Slm66018 * 20010a55fbb7Slm66018 * Arguments: 20020a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 20030a55fbb7Slm66018 * 20040a55fbb7Slm66018 * Return Code: 20050a55fbb7Slm66018 * None 20060a55fbb7Slm66018 */ 20071ae08745Sheppo static void 20081ae08745Sheppo vdc_terminate_ldc(vdc_t *vdc) 20091ae08745Sheppo { 20101ae08745Sheppo int instance = ddi_get_instance(vdc->dip); 20111ae08745Sheppo 20121ae08745Sheppo ASSERT(vdc != NULL); 20131ae08745Sheppo ASSERT(mutex_owned(&vdc->lock)); 20141ae08745Sheppo 2015*3af08d82Slm66018 DMSG(vdc, 0, "[%d] initialized=%x\n", instance, vdc->initialized); 20161ae08745Sheppo 20171ae08745Sheppo if (vdc->initialized & VDC_LDC_OPEN) { 2018*3af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_close()\n", instance); 20191ae08745Sheppo (void) ldc_close(vdc->ldc_handle); 20201ae08745Sheppo } 20211ae08745Sheppo if (vdc->initialized & VDC_LDC_CB) { 2022*3af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_unreg_callback()\n", instance); 20231ae08745Sheppo (void) ldc_unreg_callback(vdc->ldc_handle); 20241ae08745Sheppo } 20251ae08745Sheppo if (vdc->initialized & VDC_LDC) { 2026*3af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_fini()\n", instance); 20271ae08745Sheppo (void) ldc_fini(vdc->ldc_handle); 20281ae08745Sheppo vdc->ldc_handle = NULL; 20291ae08745Sheppo } 20301ae08745Sheppo 20311ae08745Sheppo vdc->initialized &= ~(VDC_LDC | VDC_LDC_CB | VDC_LDC_OPEN); 20321ae08745Sheppo } 20331ae08745Sheppo 20341ae08745Sheppo /* -------------------------------------------------------------------------- */ 20351ae08745Sheppo 20361ae08745Sheppo /* 20371ae08745Sheppo * Descriptor Ring helper routines 20381ae08745Sheppo */ 20391ae08745Sheppo 20400a55fbb7Slm66018 /* 20410a55fbb7Slm66018 * Function: 20420a55fbb7Slm66018 * vdc_init_descriptor_ring() 20430a55fbb7Slm66018 * 20440a55fbb7Slm66018 * Description: 20450a55fbb7Slm66018 * 20460a55fbb7Slm66018 * Arguments: 20470a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 20480a55fbb7Slm66018 * 20490a55fbb7Slm66018 * Return Code: 20500a55fbb7Slm66018 * 0 - Success 20510a55fbb7Slm66018 */ 20521ae08745Sheppo static int 20531ae08745Sheppo vdc_init_descriptor_ring(vdc_t *vdc) 20541ae08745Sheppo { 20551ae08745Sheppo vd_dring_entry_t *dep = NULL; /* DRing Entry pointer */ 20560a55fbb7Slm66018 int status = 0; 20571ae08745Sheppo int i; 20581ae08745Sheppo 2059*3af08d82Slm66018 DMSG(vdc, 0, "[%d] initialized=%x\n", vdc->instance, vdc->initialized); 20601ae08745Sheppo 20611ae08745Sheppo ASSERT(vdc != NULL); 20621ae08745Sheppo ASSERT(mutex_owned(&vdc->lock)); 20631ae08745Sheppo ASSERT(vdc->ldc_handle != NULL); 20641ae08745Sheppo 2065e1ebb9ecSlm66018 /* ensure we have enough room to store max sized block */ 2066e1ebb9ecSlm66018 ASSERT(maxphys <= VD_MAX_BLOCK_SIZE); 2067e1ebb9ecSlm66018 20680a55fbb7Slm66018 if ((vdc->initialized & VDC_DRING_INIT) == 0) { 2069*3af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_mem_dring_create\n", vdc->instance); 2070e1ebb9ecSlm66018 /* 2071e1ebb9ecSlm66018 * Calculate the maximum block size we can transmit using one 2072e1ebb9ecSlm66018 * Descriptor Ring entry from the attributes returned by the 2073e1ebb9ecSlm66018 * vDisk server. This is subject to a minimum of 'maxphys' 2074e1ebb9ecSlm66018 * as we do not have the capability to split requests over 2075e1ebb9ecSlm66018 * multiple DRing entries. 2076e1ebb9ecSlm66018 */ 2077e1ebb9ecSlm66018 if ((vdc->max_xfer_sz * vdc->block_size) < maxphys) { 2078*3af08d82Slm66018 DMSG(vdc, 0, "[%d] using minimum DRing size\n", 2079e1ebb9ecSlm66018 vdc->instance); 2080e1ebb9ecSlm66018 vdc->dring_max_cookies = maxphys / PAGESIZE; 2081e1ebb9ecSlm66018 } else { 2082e1ebb9ecSlm66018 vdc->dring_max_cookies = 2083e1ebb9ecSlm66018 (vdc->max_xfer_sz * vdc->block_size) / PAGESIZE; 2084e1ebb9ecSlm66018 } 2085e1ebb9ecSlm66018 vdc->dring_entry_size = (sizeof (vd_dring_entry_t) + 2086e1ebb9ecSlm66018 (sizeof (ldc_mem_cookie_t) * 2087e1ebb9ecSlm66018 (vdc->dring_max_cookies - 1))); 2088e1ebb9ecSlm66018 vdc->dring_len = VD_DRING_LEN; 2089e1ebb9ecSlm66018 2090e1ebb9ecSlm66018 status = ldc_mem_dring_create(vdc->dring_len, 2091e1ebb9ecSlm66018 vdc->dring_entry_size, &vdc->ldc_dring_hdl); 20921ae08745Sheppo if ((vdc->ldc_dring_hdl == NULL) || (status != 0)) { 2093*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Descriptor ring creation failed", 2094e1ebb9ecSlm66018 vdc->instance); 20951ae08745Sheppo return (status); 20961ae08745Sheppo } 20970a55fbb7Slm66018 vdc->initialized |= VDC_DRING_INIT; 20980a55fbb7Slm66018 } 20991ae08745Sheppo 21000a55fbb7Slm66018 if ((vdc->initialized & VDC_DRING_BOUND) == 0) { 2101*3af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_mem_dring_bind\n", vdc->instance); 21020a55fbb7Slm66018 vdc->dring_cookie = 21030a55fbb7Slm66018 kmem_zalloc(sizeof (ldc_mem_cookie_t), KM_SLEEP); 21041ae08745Sheppo 21051ae08745Sheppo status = ldc_mem_dring_bind(vdc->ldc_handle, vdc->ldc_dring_hdl, 21064bac2208Snarayan LDC_SHADOW_MAP|LDC_DIRECT_MAP, LDC_MEM_RW, 21070a55fbb7Slm66018 &vdc->dring_cookie[0], 21081ae08745Sheppo &vdc->dring_cookie_count); 21091ae08745Sheppo if (status != 0) { 2110*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to bind descriptor ring " 2111*3af08d82Slm66018 "(%lx) to channel (%lx) status=%d\n", 2112*3af08d82Slm66018 vdc->instance, vdc->ldc_dring_hdl, 2113*3af08d82Slm66018 vdc->ldc_handle, status); 21141ae08745Sheppo return (status); 21151ae08745Sheppo } 21161ae08745Sheppo ASSERT(vdc->dring_cookie_count == 1); 21171ae08745Sheppo vdc->initialized |= VDC_DRING_BOUND; 21180a55fbb7Slm66018 } 21191ae08745Sheppo 21201ae08745Sheppo status = ldc_mem_dring_info(vdc->ldc_dring_hdl, &vdc->dring_mem_info); 21211ae08745Sheppo if (status != 0) { 2122*3af08d82Slm66018 DMSG(vdc, 0, 2123*3af08d82Slm66018 "[%d] Failed to get info for descriptor ring (%lx)\n", 2124e1ebb9ecSlm66018 vdc->instance, vdc->ldc_dring_hdl); 21251ae08745Sheppo return (status); 21261ae08745Sheppo } 21271ae08745Sheppo 21280a55fbb7Slm66018 if ((vdc->initialized & VDC_DRING_LOCAL) == 0) { 2129*3af08d82Slm66018 DMSG(vdc, 0, "[%d] local dring\n", vdc->instance); 21300a55fbb7Slm66018 21311ae08745Sheppo /* Allocate the local copy of this dring */ 21320a55fbb7Slm66018 vdc->local_dring = 2133e1ebb9ecSlm66018 kmem_zalloc(vdc->dring_len * sizeof (vdc_local_desc_t), 21341ae08745Sheppo KM_SLEEP); 21351ae08745Sheppo vdc->initialized |= VDC_DRING_LOCAL; 21360a55fbb7Slm66018 } 21371ae08745Sheppo 21381ae08745Sheppo /* 21390a55fbb7Slm66018 * Mark all DRing entries as free and initialize the private 21400a55fbb7Slm66018 * descriptor's memory handles. If any entry is initialized, 21410a55fbb7Slm66018 * we need to free it later so we set the bit in 'initialized' 21420a55fbb7Slm66018 * at the start. 21431ae08745Sheppo */ 21441ae08745Sheppo vdc->initialized |= VDC_DRING_ENTRY; 2145e1ebb9ecSlm66018 for (i = 0; i < vdc->dring_len; i++) { 21461ae08745Sheppo dep = VDC_GET_DRING_ENTRY_PTR(vdc, i); 21471ae08745Sheppo dep->hdr.dstate = VIO_DESC_FREE; 21481ae08745Sheppo 21491ae08745Sheppo status = ldc_mem_alloc_handle(vdc->ldc_handle, 21501ae08745Sheppo &vdc->local_dring[i].desc_mhdl); 21511ae08745Sheppo if (status != 0) { 2152*3af08d82Slm66018 DMSG(vdc, 0, "![%d] Failed to alloc mem handle for" 21531ae08745Sheppo " descriptor %d", vdc->instance, i); 21541ae08745Sheppo return (status); 21551ae08745Sheppo } 2156*3af08d82Slm66018 vdc->local_dring[i].is_free = B_TRUE; 21571ae08745Sheppo vdc->local_dring[i].dep = dep; 21581ae08745Sheppo } 21591ae08745Sheppo 2160*3af08d82Slm66018 /* Initialize the starting index */ 2161*3af08d82Slm66018 vdc->dring_curr_idx = 0; 21621ae08745Sheppo 21631ae08745Sheppo return (status); 21641ae08745Sheppo } 21651ae08745Sheppo 21660a55fbb7Slm66018 /* 21670a55fbb7Slm66018 * Function: 21680a55fbb7Slm66018 * vdc_destroy_descriptor_ring() 21690a55fbb7Slm66018 * 21700a55fbb7Slm66018 * Description: 21710a55fbb7Slm66018 * 21720a55fbb7Slm66018 * Arguments: 21730a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 21740a55fbb7Slm66018 * 21750a55fbb7Slm66018 * Return Code: 21760a55fbb7Slm66018 * None 21770a55fbb7Slm66018 */ 21781ae08745Sheppo static void 21791ae08745Sheppo vdc_destroy_descriptor_ring(vdc_t *vdc) 21801ae08745Sheppo { 21810a55fbb7Slm66018 vdc_local_desc_t *ldep = NULL; /* Local Dring Entry Pointer */ 21821ae08745Sheppo ldc_mem_handle_t mhdl = NULL; 2183*3af08d82Slm66018 ldc_mem_info_t minfo; 21841ae08745Sheppo int status = -1; 21851ae08745Sheppo int i; /* loop */ 21861ae08745Sheppo 21871ae08745Sheppo ASSERT(vdc != NULL); 21881ae08745Sheppo ASSERT(mutex_owned(&vdc->lock)); 21891ae08745Sheppo 2190*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Entered\n", vdc->instance); 21911ae08745Sheppo 21921ae08745Sheppo if (vdc->initialized & VDC_DRING_ENTRY) { 2193*3af08d82Slm66018 DMSG(vdc, 0, 2194*3af08d82Slm66018 "[%d] Removing Local DRing entries\n", vdc->instance); 2195e1ebb9ecSlm66018 for (i = 0; i < vdc->dring_len; i++) { 21960a55fbb7Slm66018 ldep = &vdc->local_dring[i]; 21970a55fbb7Slm66018 mhdl = ldep->desc_mhdl; 21981ae08745Sheppo 21990a55fbb7Slm66018 if (mhdl == NULL) 22000a55fbb7Slm66018 continue; 22010a55fbb7Slm66018 2202*3af08d82Slm66018 if ((status = ldc_mem_info(mhdl, &minfo)) != 0) { 2203*3af08d82Slm66018 DMSG(vdc, 0, 2204*3af08d82Slm66018 "ldc_mem_info returned an error: %d\n", 2205*3af08d82Slm66018 status); 2206*3af08d82Slm66018 2207*3af08d82Slm66018 /* 2208*3af08d82Slm66018 * This must mean that the mem handle 2209*3af08d82Slm66018 * is not valid. Clear it out so that 2210*3af08d82Slm66018 * no one tries to use it. 2211*3af08d82Slm66018 */ 2212*3af08d82Slm66018 ldep->desc_mhdl = NULL; 2213*3af08d82Slm66018 continue; 2214*3af08d82Slm66018 } 2215*3af08d82Slm66018 2216*3af08d82Slm66018 if (minfo.status == LDC_BOUND) { 2217*3af08d82Slm66018 (void) ldc_mem_unbind_handle(mhdl); 2218*3af08d82Slm66018 } 2219*3af08d82Slm66018 22201ae08745Sheppo (void) ldc_mem_free_handle(mhdl); 2221*3af08d82Slm66018 2222*3af08d82Slm66018 ldep->desc_mhdl = NULL; 22231ae08745Sheppo } 22241ae08745Sheppo vdc->initialized &= ~VDC_DRING_ENTRY; 22251ae08745Sheppo } 22261ae08745Sheppo 22271ae08745Sheppo if (vdc->initialized & VDC_DRING_LOCAL) { 2228*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Freeing Local DRing\n", vdc->instance); 22291ae08745Sheppo kmem_free(vdc->local_dring, 2230e1ebb9ecSlm66018 vdc->dring_len * sizeof (vdc_local_desc_t)); 22311ae08745Sheppo vdc->initialized &= ~VDC_DRING_LOCAL; 22321ae08745Sheppo } 22331ae08745Sheppo 22341ae08745Sheppo if (vdc->initialized & VDC_DRING_BOUND) { 2235*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Unbinding DRing\n", vdc->instance); 22361ae08745Sheppo status = ldc_mem_dring_unbind(vdc->ldc_dring_hdl); 22371ae08745Sheppo if (status == 0) { 22381ae08745Sheppo vdc->initialized &= ~VDC_DRING_BOUND; 22391ae08745Sheppo } else { 2240*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Error %d unbinding DRing %lx", 2241e1ebb9ecSlm66018 vdc->instance, status, vdc->ldc_dring_hdl); 22421ae08745Sheppo } 2243*3af08d82Slm66018 kmem_free(vdc->dring_cookie, sizeof (ldc_mem_cookie_t)); 22441ae08745Sheppo } 22451ae08745Sheppo 22461ae08745Sheppo if (vdc->initialized & VDC_DRING_INIT) { 2247*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Destroying DRing\n", vdc->instance); 22481ae08745Sheppo status = ldc_mem_dring_destroy(vdc->ldc_dring_hdl); 22491ae08745Sheppo if (status == 0) { 22501ae08745Sheppo vdc->ldc_dring_hdl = NULL; 22511ae08745Sheppo bzero(&vdc->dring_mem_info, sizeof (ldc_mem_info_t)); 22521ae08745Sheppo vdc->initialized &= ~VDC_DRING_INIT; 22531ae08745Sheppo } else { 2254*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Error %d destroying DRing (%lx)", 2255e1ebb9ecSlm66018 vdc->instance, status, vdc->ldc_dring_hdl); 22561ae08745Sheppo } 22571ae08745Sheppo } 22581ae08745Sheppo } 22591ae08745Sheppo 22601ae08745Sheppo /* 2261*3af08d82Slm66018 * Function: 2262*3af08d82Slm66018 * vdc_map_to_shared_ring() 22631ae08745Sheppo * 22641ae08745Sheppo * Description: 2265*3af08d82Slm66018 * Copy contents of the local descriptor to the shared 2266*3af08d82Slm66018 * memory descriptor. 22671ae08745Sheppo * 2268*3af08d82Slm66018 * Arguments: 2269*3af08d82Slm66018 * vdcp - soft state pointer for this instance of the device driver. 2270*3af08d82Slm66018 * idx - descriptor ring index 2271*3af08d82Slm66018 * 2272*3af08d82Slm66018 * Return Code: 2273*3af08d82Slm66018 * None 22741ae08745Sheppo */ 22751ae08745Sheppo static int 2276*3af08d82Slm66018 vdc_map_to_shared_dring(vdc_t *vdcp, int idx) 22771ae08745Sheppo { 2278*3af08d82Slm66018 vdc_local_desc_t *ldep; 2279*3af08d82Slm66018 vd_dring_entry_t *dep; 2280*3af08d82Slm66018 int rv; 22811ae08745Sheppo 2282*3af08d82Slm66018 ldep = &(vdcp->local_dring[idx]); 22831ae08745Sheppo 2284*3af08d82Slm66018 /* for now leave in the old pop_mem_hdl stuff */ 2285*3af08d82Slm66018 if (ldep->nbytes > 0) { 2286*3af08d82Slm66018 rv = vdc_populate_mem_hdl(vdcp, ldep); 2287*3af08d82Slm66018 if (rv) { 2288*3af08d82Slm66018 DMSG(vdcp, 0, "[%d] Cannot populate mem handle\n", 2289*3af08d82Slm66018 vdcp->instance); 2290*3af08d82Slm66018 return (rv); 2291*3af08d82Slm66018 } 2292*3af08d82Slm66018 } 22931ae08745Sheppo 2294*3af08d82Slm66018 /* 2295*3af08d82Slm66018 * fill in the data details into the DRing 2296*3af08d82Slm66018 */ 2297d10e4ef2Snarayan dep = ldep->dep; 22981ae08745Sheppo ASSERT(dep != NULL); 22991ae08745Sheppo 2300*3af08d82Slm66018 dep->payload.req_id = VDC_GET_NEXT_REQ_ID(vdcp); 2301*3af08d82Slm66018 dep->payload.operation = ldep->operation; 2302*3af08d82Slm66018 dep->payload.addr = ldep->offset; 2303*3af08d82Slm66018 dep->payload.nbytes = ldep->nbytes; 2304*3af08d82Slm66018 dep->payload.status = -1; /* vds will set valid value */ 2305*3af08d82Slm66018 dep->payload.slice = ldep->slice; 2306*3af08d82Slm66018 dep->hdr.dstate = VIO_DESC_READY; 2307*3af08d82Slm66018 dep->hdr.ack = 1; /* request an ACK for every message */ 23081ae08745Sheppo 2309*3af08d82Slm66018 return (0); 23101ae08745Sheppo } 23111ae08745Sheppo 23121ae08745Sheppo /* 23131ae08745Sheppo * Function: 2314*3af08d82Slm66018 * vdc_send_request 2315*3af08d82Slm66018 * 2316*3af08d82Slm66018 * Description: 2317*3af08d82Slm66018 * This routine writes the data to be transmitted to vds into the 2318*3af08d82Slm66018 * descriptor, notifies vds that the ring has been updated and 2319*3af08d82Slm66018 * then waits for the request to be processed. 2320*3af08d82Slm66018 * 2321*3af08d82Slm66018 * Arguments: 2322*3af08d82Slm66018 * vdcp - the soft state pointer 2323*3af08d82Slm66018 * operation - operation we want vds to perform (VD_OP_XXX) 2324*3af08d82Slm66018 * addr - address of data buf to be read/written. 2325*3af08d82Slm66018 * nbytes - number of bytes to read/write 2326*3af08d82Slm66018 * slice - the disk slice this request is for 2327*3af08d82Slm66018 * offset - relative disk offset 2328*3af08d82Slm66018 * cb_type - type of call - STRATEGY or SYNC 2329*3af08d82Slm66018 * cb_arg - parameter to be sent to server (depends on VD_OP_XXX type) 2330*3af08d82Slm66018 * . mode for ioctl(9e) 2331*3af08d82Slm66018 * . LP64 diskaddr_t (block I/O) 2332*3af08d82Slm66018 * dir - direction of operation (READ/WRITE/BOTH) 2333*3af08d82Slm66018 * 2334*3af08d82Slm66018 * Return Codes: 2335*3af08d82Slm66018 * 0 2336*3af08d82Slm66018 * EAGAIN 2337*3af08d82Slm66018 * EFAULT 2338*3af08d82Slm66018 * ENXIO 2339*3af08d82Slm66018 * EIO 2340*3af08d82Slm66018 */ 2341*3af08d82Slm66018 static int 2342*3af08d82Slm66018 vdc_send_request(vdc_t *vdcp, int operation, caddr_t addr, 2343*3af08d82Slm66018 size_t nbytes, int slice, diskaddr_t offset, int cb_type, 2344*3af08d82Slm66018 void *cb_arg, vio_desc_direction_t dir) 2345*3af08d82Slm66018 { 2346*3af08d82Slm66018 ASSERT(vdcp != NULL); 2347*3af08d82Slm66018 ASSERT(slice < V_NUMPAR); 2348*3af08d82Slm66018 2349*3af08d82Slm66018 mutex_enter(&vdcp->lock); 2350*3af08d82Slm66018 2351*3af08d82Slm66018 do { 2352*3af08d82Slm66018 while (vdcp->state != VDC_STATE_RUNNING) 2353*3af08d82Slm66018 cv_wait(&vdcp->running_cv, &vdcp->lock); 2354*3af08d82Slm66018 2355*3af08d82Slm66018 } while (vdc_populate_descriptor(vdcp, operation, addr, 2356*3af08d82Slm66018 nbytes, slice, offset, cb_type, cb_arg, dir)); 2357*3af08d82Slm66018 2358*3af08d82Slm66018 mutex_exit(&vdcp->lock); 2359*3af08d82Slm66018 return (0); 2360*3af08d82Slm66018 } 2361*3af08d82Slm66018 2362*3af08d82Slm66018 2363*3af08d82Slm66018 /* 2364*3af08d82Slm66018 * Function: 23651ae08745Sheppo * vdc_populate_descriptor 23661ae08745Sheppo * 23671ae08745Sheppo * Description: 23681ae08745Sheppo * This routine writes the data to be transmitted to vds into the 23691ae08745Sheppo * descriptor, notifies vds that the ring has been updated and 23701ae08745Sheppo * then waits for the request to be processed. 23711ae08745Sheppo * 23721ae08745Sheppo * Arguments: 2373*3af08d82Slm66018 * vdcp - the soft state pointer 23741ae08745Sheppo * operation - operation we want vds to perform (VD_OP_XXX) 2375*3af08d82Slm66018 * addr - address of data buf to be read/written. 2376*3af08d82Slm66018 * nbytes - number of bytes to read/write 2377*3af08d82Slm66018 * slice - the disk slice this request is for 2378*3af08d82Slm66018 * offset - relative disk offset 2379*3af08d82Slm66018 * cb_type - type of call - STRATEGY or SYNC 2380*3af08d82Slm66018 * cb_arg - parameter to be sent to server (depends on VD_OP_XXX type) 23811ae08745Sheppo * . mode for ioctl(9e) 23821ae08745Sheppo * . LP64 diskaddr_t (block I/O) 2383*3af08d82Slm66018 * dir - direction of operation (READ/WRITE/BOTH) 23841ae08745Sheppo * 23851ae08745Sheppo * Return Codes: 23861ae08745Sheppo * 0 23871ae08745Sheppo * EAGAIN 23881ae08745Sheppo * EFAULT 23891ae08745Sheppo * ENXIO 23901ae08745Sheppo * EIO 23911ae08745Sheppo */ 23921ae08745Sheppo static int 2393*3af08d82Slm66018 vdc_populate_descriptor(vdc_t *vdcp, int operation, caddr_t addr, 2394*3af08d82Slm66018 size_t nbytes, int slice, diskaddr_t offset, int cb_type, 2395*3af08d82Slm66018 void *cb_arg, vio_desc_direction_t dir) 23961ae08745Sheppo { 2397*3af08d82Slm66018 vdc_local_desc_t *local_dep = NULL; /* Local Dring Pointer */ 2398*3af08d82Slm66018 int idx; /* Index of DRing entry used */ 2399*3af08d82Slm66018 int next_idx; 24001ae08745Sheppo vio_dring_msg_t dmsg; 2401*3af08d82Slm66018 size_t msglen; 24028e6a2a04Slm66018 int rv; 24031ae08745Sheppo 2404*3af08d82Slm66018 ASSERT(MUTEX_HELD(&vdcp->lock)); 2405*3af08d82Slm66018 vdcp->threads_pending++; 2406*3af08d82Slm66018 loop: 2407*3af08d82Slm66018 DMSG(vdcp, 2, ": dring_curr_idx = %d\n", vdcp->dring_curr_idx); 24081ae08745Sheppo 2409*3af08d82Slm66018 /* Get next available D-Ring entry */ 2410*3af08d82Slm66018 idx = vdcp->dring_curr_idx; 2411*3af08d82Slm66018 local_dep = &(vdcp->local_dring[idx]); 24121ae08745Sheppo 2413*3af08d82Slm66018 if (!local_dep->is_free) { 2414*3af08d82Slm66018 DMSG(vdcp, 2, "[%d]: dring full - waiting for space\n", 2415*3af08d82Slm66018 vdcp->instance); 2416*3af08d82Slm66018 cv_wait(&vdcp->dring_free_cv, &vdcp->lock); 2417*3af08d82Slm66018 if (vdcp->state == VDC_STATE_RUNNING || 2418*3af08d82Slm66018 vdcp->state == VDC_STATE_HANDLE_PENDING) { 2419*3af08d82Slm66018 goto loop; 2420*3af08d82Slm66018 } 2421*3af08d82Slm66018 vdcp->threads_pending--; 2422*3af08d82Slm66018 return (ECONNRESET); 24231ae08745Sheppo } 24241ae08745Sheppo 2425*3af08d82Slm66018 next_idx = idx + 1; 2426*3af08d82Slm66018 if (next_idx >= vdcp->dring_len) 2427*3af08d82Slm66018 next_idx = 0; 2428*3af08d82Slm66018 vdcp->dring_curr_idx = next_idx; 24291ae08745Sheppo 2430*3af08d82Slm66018 ASSERT(local_dep->is_free); 24311ae08745Sheppo 2432*3af08d82Slm66018 local_dep->operation = operation; 2433d10e4ef2Snarayan local_dep->addr = addr; 2434*3af08d82Slm66018 local_dep->nbytes = nbytes; 2435*3af08d82Slm66018 local_dep->slice = slice; 2436*3af08d82Slm66018 local_dep->offset = offset; 2437*3af08d82Slm66018 local_dep->cb_type = cb_type; 2438*3af08d82Slm66018 local_dep->cb_arg = cb_arg; 2439*3af08d82Slm66018 local_dep->dir = dir; 2440*3af08d82Slm66018 2441*3af08d82Slm66018 local_dep->is_free = B_FALSE; 2442*3af08d82Slm66018 2443*3af08d82Slm66018 rv = vdc_map_to_shared_dring(vdcp, idx); 2444*3af08d82Slm66018 if (rv) { 2445*3af08d82Slm66018 DMSG(vdcp, 0, "[%d]: cannot bind memory - waiting ..\n", 2446*3af08d82Slm66018 vdcp->instance); 2447*3af08d82Slm66018 /* free the descriptor */ 2448*3af08d82Slm66018 local_dep->is_free = B_TRUE; 2449*3af08d82Slm66018 vdcp->dring_curr_idx = idx; 2450*3af08d82Slm66018 cv_wait(&vdcp->membind_cv, &vdcp->lock); 2451*3af08d82Slm66018 if (vdcp->state == VDC_STATE_RUNNING || 2452*3af08d82Slm66018 vdcp->state == VDC_STATE_HANDLE_PENDING) { 2453*3af08d82Slm66018 goto loop; 24541ae08745Sheppo } 2455*3af08d82Slm66018 vdcp->threads_pending--; 2456*3af08d82Slm66018 return (ECONNRESET); 24571ae08745Sheppo } 24581ae08745Sheppo 24591ae08745Sheppo /* 24601ae08745Sheppo * Send a msg with the DRing details to vds 24611ae08745Sheppo */ 24621ae08745Sheppo VIO_INIT_DRING_DATA_TAG(dmsg); 2463*3af08d82Slm66018 VDC_INIT_DRING_DATA_MSG_IDS(dmsg, vdcp); 2464*3af08d82Slm66018 dmsg.dring_ident = vdcp->dring_ident; 24651ae08745Sheppo dmsg.start_idx = idx; 24661ae08745Sheppo dmsg.end_idx = idx; 2467*3af08d82Slm66018 vdcp->seq_num++; 24681ae08745Sheppo 2469*3af08d82Slm66018 DTRACE_IO2(send, vio_dring_msg_t *, &dmsg, vdc_t *, vdcp); 2470d10e4ef2Snarayan 2471*3af08d82Slm66018 DMSG(vdcp, 2, "ident=0x%lx, st=%u, end=%u, seq=%ld\n", 2472*3af08d82Slm66018 vdcp->dring_ident, dmsg.start_idx, dmsg.end_idx, dmsg.seq_num); 24731ae08745Sheppo 2474*3af08d82Slm66018 /* 2475*3af08d82Slm66018 * note we're still holding the lock here to 2476*3af08d82Slm66018 * make sure the message goes out in order !!!... 2477*3af08d82Slm66018 */ 2478*3af08d82Slm66018 msglen = sizeof (dmsg); 2479*3af08d82Slm66018 rv = vdc_send(vdcp, (caddr_t)&dmsg, &msglen); 2480*3af08d82Slm66018 switch (rv) { 2481*3af08d82Slm66018 case ECONNRESET: 2482*3af08d82Slm66018 /* 2483*3af08d82Slm66018 * vdc_send initiates the reset on failure. 2484*3af08d82Slm66018 * Since the transaction has already been put 2485*3af08d82Slm66018 * on the local dring, it will automatically get 2486*3af08d82Slm66018 * retried when the channel is reset. Given that, 2487*3af08d82Slm66018 * it is ok to just return success even though the 2488*3af08d82Slm66018 * send failed. 2489*3af08d82Slm66018 */ 2490*3af08d82Slm66018 rv = 0; 2491*3af08d82Slm66018 break; 2492d10e4ef2Snarayan 2493*3af08d82Slm66018 case 0: /* EOK */ 2494*3af08d82Slm66018 DMSG(vdcp, 1, "sent via LDC: rv=%d\n", rv); 2495*3af08d82Slm66018 break; 2496d10e4ef2Snarayan 2497*3af08d82Slm66018 default: 2498*3af08d82Slm66018 goto cleanup_and_exit; 2499*3af08d82Slm66018 } 2500e1ebb9ecSlm66018 2501*3af08d82Slm66018 vdcp->threads_pending--; 2502*3af08d82Slm66018 return (rv); 2503*3af08d82Slm66018 2504*3af08d82Slm66018 cleanup_and_exit: 2505*3af08d82Slm66018 DMSG(vdcp, 0, "unexpected error, rv=%d\n", rv); 2506*3af08d82Slm66018 return (ENXIO); 25071ae08745Sheppo } 25081ae08745Sheppo 25091ae08745Sheppo /* 2510*3af08d82Slm66018 * Function: 2511*3af08d82Slm66018 * vdc_do_sync_op 2512*3af08d82Slm66018 * 2513*3af08d82Slm66018 * Description: 2514*3af08d82Slm66018 * Wrapper around vdc_populate_descriptor that blocks until the 2515*3af08d82Slm66018 * response to the message is available. 2516*3af08d82Slm66018 * 2517*3af08d82Slm66018 * Arguments: 2518*3af08d82Slm66018 * vdcp - the soft state pointer 2519*3af08d82Slm66018 * operation - operation we want vds to perform (VD_OP_XXX) 2520*3af08d82Slm66018 * addr - address of data buf to be read/written. 2521*3af08d82Slm66018 * nbytes - number of bytes to read/write 2522*3af08d82Slm66018 * slice - the disk slice this request is for 2523*3af08d82Slm66018 * offset - relative disk offset 2524*3af08d82Slm66018 * cb_type - type of call - STRATEGY or SYNC 2525*3af08d82Slm66018 * cb_arg - parameter to be sent to server (depends on VD_OP_XXX type) 2526*3af08d82Slm66018 * . mode for ioctl(9e) 2527*3af08d82Slm66018 * . LP64 diskaddr_t (block I/O) 2528*3af08d82Slm66018 * dir - direction of operation (READ/WRITE/BOTH) 2529*3af08d82Slm66018 * 2530*3af08d82Slm66018 * Return Codes: 2531*3af08d82Slm66018 * 0 2532*3af08d82Slm66018 * EAGAIN 2533*3af08d82Slm66018 * EFAULT 2534*3af08d82Slm66018 * ENXIO 2535*3af08d82Slm66018 * EIO 25360a55fbb7Slm66018 */ 2537*3af08d82Slm66018 static int 2538*3af08d82Slm66018 vdc_do_sync_op(vdc_t *vdcp, int operation, caddr_t addr, size_t nbytes, 2539*3af08d82Slm66018 int slice, diskaddr_t offset, int cb_type, void *cb_arg, 2540*3af08d82Slm66018 vio_desc_direction_t dir) 2541*3af08d82Slm66018 { 2542*3af08d82Slm66018 int status; 2543*3af08d82Slm66018 2544*3af08d82Slm66018 ASSERT(cb_type == CB_SYNC); 25451ae08745Sheppo 25461ae08745Sheppo /* 2547*3af08d82Slm66018 * Grab the lock, if blocked wait until the server 2548*3af08d82Slm66018 * response causes us to wake up again. 2549*3af08d82Slm66018 */ 2550*3af08d82Slm66018 mutex_enter(&vdcp->lock); 2551*3af08d82Slm66018 vdcp->sync_op_cnt++; 2552*3af08d82Slm66018 while (vdcp->sync_op_blocked && vdcp->state != VDC_STATE_DETACH) 2553*3af08d82Slm66018 cv_wait(&vdcp->sync_blocked_cv, &vdcp->lock); 2554*3af08d82Slm66018 2555*3af08d82Slm66018 if (vdcp->state == VDC_STATE_DETACH) { 2556*3af08d82Slm66018 cv_broadcast(&vdcp->sync_blocked_cv); 2557*3af08d82Slm66018 vdcp->sync_op_cnt--; 2558*3af08d82Slm66018 mutex_exit(&vdcp->lock); 2559*3af08d82Slm66018 return (ENXIO); 2560*3af08d82Slm66018 } 2561*3af08d82Slm66018 2562*3af08d82Slm66018 /* now block anyone other thread entering after us */ 2563*3af08d82Slm66018 vdcp->sync_op_blocked = B_TRUE; 2564*3af08d82Slm66018 vdcp->sync_op_pending = B_TRUE; 2565*3af08d82Slm66018 mutex_exit(&vdcp->lock); 2566*3af08d82Slm66018 2567*3af08d82Slm66018 /* 2568*3af08d82Slm66018 * No need to check return value - will return error only 2569*3af08d82Slm66018 * in the DETACH case and we can fall through 2570*3af08d82Slm66018 */ 2571*3af08d82Slm66018 (void) vdc_send_request(vdcp, operation, addr, 2572*3af08d82Slm66018 nbytes, slice, offset, cb_type, cb_arg, dir); 2573*3af08d82Slm66018 2574*3af08d82Slm66018 /* 2575*3af08d82Slm66018 * block until our transaction completes. 2576*3af08d82Slm66018 * Also anyone else waiting also gets to go next. 2577*3af08d82Slm66018 */ 2578*3af08d82Slm66018 mutex_enter(&vdcp->lock); 2579*3af08d82Slm66018 while (vdcp->sync_op_pending && vdcp->state != VDC_STATE_DETACH) 2580*3af08d82Slm66018 cv_wait(&vdcp->sync_pending_cv, &vdcp->lock); 2581*3af08d82Slm66018 2582*3af08d82Slm66018 DMSG(vdcp, 2, ": operation returned %d\n", vdcp->sync_op_status); 2583*3af08d82Slm66018 if (vdcp->state == VDC_STATE_DETACH) 2584*3af08d82Slm66018 status = ENXIO; 2585*3af08d82Slm66018 else 2586*3af08d82Slm66018 status = vdcp->sync_op_status; 2587*3af08d82Slm66018 vdcp->sync_op_status = 0; 2588*3af08d82Slm66018 vdcp->sync_op_blocked = B_FALSE; 2589*3af08d82Slm66018 vdcp->sync_op_cnt--; 2590*3af08d82Slm66018 2591*3af08d82Slm66018 /* signal the next waiting thread */ 2592*3af08d82Slm66018 cv_signal(&vdcp->sync_blocked_cv); 2593*3af08d82Slm66018 mutex_exit(&vdcp->lock); 2594*3af08d82Slm66018 2595*3af08d82Slm66018 return (status); 2596*3af08d82Slm66018 } 2597*3af08d82Slm66018 2598*3af08d82Slm66018 2599*3af08d82Slm66018 /* 2600*3af08d82Slm66018 * Function: 2601*3af08d82Slm66018 * vdc_drain_response() 2602*3af08d82Slm66018 * 2603*3af08d82Slm66018 * Description: 26041ae08745Sheppo * When a guest is panicking, the completion of requests needs to be 26051ae08745Sheppo * handled differently because interrupts are disabled and vdc 26061ae08745Sheppo * will not get messages. We have to poll for the messages instead. 2607*3af08d82Slm66018 * 2608*3af08d82Slm66018 * Arguments: 2609*3af08d82Slm66018 * vdc - soft state pointer for this instance of the device driver. 2610*3af08d82Slm66018 * 2611*3af08d82Slm66018 * Return Code: 2612*3af08d82Slm66018 * 0 - Success 26131ae08745Sheppo */ 2614*3af08d82Slm66018 static int 2615*3af08d82Slm66018 vdc_drain_response(vdc_t *vdc) 2616*3af08d82Slm66018 { 2617*3af08d82Slm66018 int rv, idx, retries; 2618*3af08d82Slm66018 size_t msglen; 2619*3af08d82Slm66018 vdc_local_desc_t *ldep = NULL; /* Local Dring Entry Pointer */ 2620*3af08d82Slm66018 vio_dring_msg_t dmsg; 2621*3af08d82Slm66018 2622*3af08d82Slm66018 mutex_enter(&vdc->lock); 2623*3af08d82Slm66018 26241ae08745Sheppo retries = 0; 26251ae08745Sheppo for (;;) { 26261ae08745Sheppo msglen = sizeof (dmsg); 2627*3af08d82Slm66018 rv = ldc_read(vdc->ldc_handle, (caddr_t)&dmsg, &msglen); 26288e6a2a04Slm66018 if (rv) { 26298e6a2a04Slm66018 rv = EINVAL; 26301ae08745Sheppo break; 26311ae08745Sheppo } 26321ae08745Sheppo 26331ae08745Sheppo /* 26341ae08745Sheppo * if there are no packets wait and check again 26351ae08745Sheppo */ 26368e6a2a04Slm66018 if ((rv == 0) && (msglen == 0)) { 26371ae08745Sheppo if (retries++ > vdc_dump_retries) { 26388e6a2a04Slm66018 rv = EAGAIN; 26391ae08745Sheppo break; 26401ae08745Sheppo } 26411ae08745Sheppo 2642d10e4ef2Snarayan drv_usecwait(vdc_usec_timeout_dump); 26431ae08745Sheppo continue; 26441ae08745Sheppo } 26451ae08745Sheppo 26461ae08745Sheppo /* 26471ae08745Sheppo * Ignore all messages that are not ACKs/NACKs to 26481ae08745Sheppo * DRing requests. 26491ae08745Sheppo */ 26501ae08745Sheppo if ((dmsg.tag.vio_msgtype != VIO_TYPE_DATA) || 26511ae08745Sheppo (dmsg.tag.vio_subtype_env != VIO_DRING_DATA)) { 2652*3af08d82Slm66018 DMSG(vdc, 0, "discard pkt: type=%d sub=%d env=%d\n", 26531ae08745Sheppo dmsg.tag.vio_msgtype, 26541ae08745Sheppo dmsg.tag.vio_subtype, 26551ae08745Sheppo dmsg.tag.vio_subtype_env); 26561ae08745Sheppo continue; 26571ae08745Sheppo } 26581ae08745Sheppo 26591ae08745Sheppo /* 2660*3af08d82Slm66018 * set the appropriate return value for the current request. 26611ae08745Sheppo */ 26621ae08745Sheppo switch (dmsg.tag.vio_subtype) { 26631ae08745Sheppo case VIO_SUBTYPE_ACK: 26648e6a2a04Slm66018 rv = 0; 26651ae08745Sheppo break; 26661ae08745Sheppo case VIO_SUBTYPE_NACK: 26678e6a2a04Slm66018 rv = EAGAIN; 26681ae08745Sheppo break; 26691ae08745Sheppo default: 26701ae08745Sheppo continue; 26711ae08745Sheppo } 26721ae08745Sheppo 2673*3af08d82Slm66018 idx = dmsg.start_idx; 2674*3af08d82Slm66018 if (idx >= vdc->dring_len) { 2675*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Bogus ack data : start %d\n", 2676e1ebb9ecSlm66018 vdc->instance, idx); 2677*3af08d82Slm66018 continue; 26781ae08745Sheppo } 2679*3af08d82Slm66018 ldep = &vdc->local_dring[idx]; 2680*3af08d82Slm66018 if (ldep->dep->hdr.dstate != VIO_DESC_DONE) { 2681*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Entry @ %d - state !DONE %d\n", 2682*3af08d82Slm66018 vdc->instance, idx, ldep->dep->hdr.dstate); 26831ae08745Sheppo continue; 26841ae08745Sheppo } 26851ae08745Sheppo 2686*3af08d82Slm66018 DMSG(vdc, 1, "[%d] Depopulating idx=%d state=%d\n", 2687*3af08d82Slm66018 vdc->instance, idx, ldep->dep->hdr.dstate); 2688*3af08d82Slm66018 rv = vdc_depopulate_descriptor(vdc, idx); 2689*3af08d82Slm66018 if (rv) { 2690*3af08d82Slm66018 DMSG(vdc, 0, 2691*3af08d82Slm66018 "[%d] Entry @ %d - depopulate failed ..\n", 2692*3af08d82Slm66018 vdc->instance, idx); 26931ae08745Sheppo } 26941ae08745Sheppo 2695*3af08d82Slm66018 /* if this is the last descriptor - break out of loop */ 2696*3af08d82Slm66018 if ((idx + 1) % vdc->dring_len == vdc->dring_curr_idx) 2697*3af08d82Slm66018 break; 2698*3af08d82Slm66018 } 2699*3af08d82Slm66018 2700*3af08d82Slm66018 mutex_exit(&vdc->lock); 2701*3af08d82Slm66018 DMSG(vdc, 0, "End idx=%d\n", idx); 2702*3af08d82Slm66018 2703*3af08d82Slm66018 return (rv); 27041ae08745Sheppo } 27051ae08745Sheppo 27061ae08745Sheppo 27070a55fbb7Slm66018 /* 27080a55fbb7Slm66018 * Function: 27090a55fbb7Slm66018 * vdc_depopulate_descriptor() 27100a55fbb7Slm66018 * 27110a55fbb7Slm66018 * Description: 27120a55fbb7Slm66018 * 27130a55fbb7Slm66018 * Arguments: 27140a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 27150a55fbb7Slm66018 * idx - Index of the Descriptor Ring entry being modified 27160a55fbb7Slm66018 * 27170a55fbb7Slm66018 * Return Code: 27180a55fbb7Slm66018 * 0 - Success 27190a55fbb7Slm66018 */ 27201ae08745Sheppo static int 27211ae08745Sheppo vdc_depopulate_descriptor(vdc_t *vdc, uint_t idx) 27221ae08745Sheppo { 27231ae08745Sheppo vd_dring_entry_t *dep = NULL; /* Dring Entry Pointer */ 27241ae08745Sheppo vdc_local_desc_t *ldep = NULL; /* Local Dring Entry Pointer */ 27251ae08745Sheppo int status = ENXIO; 27268e6a2a04Slm66018 int operation; 27278e6a2a04Slm66018 int rv = 0; 27281ae08745Sheppo 27291ae08745Sheppo ASSERT(vdc != NULL); 2730e1ebb9ecSlm66018 ASSERT(idx < vdc->dring_len); 27311ae08745Sheppo ldep = &vdc->local_dring[idx]; 27321ae08745Sheppo ASSERT(ldep != NULL); 2733*3af08d82Slm66018 ASSERT(MUTEX_HELD(&vdc->lock)); 2734*3af08d82Slm66018 2735*3af08d82Slm66018 DMSG(vdc, 2, ": idx = %d\n", idx); 27361ae08745Sheppo dep = ldep->dep; 27371ae08745Sheppo ASSERT(dep != NULL); 2738e1ebb9ecSlm66018 ASSERT((dep->hdr.dstate == VIO_DESC_DONE) || 2739e1ebb9ecSlm66018 (dep->payload.status == ECANCELED)); 27401ae08745Sheppo 2741e1ebb9ecSlm66018 VDC_MARK_DRING_ENTRY_FREE(vdc, idx); 2742*3af08d82Slm66018 2743*3af08d82Slm66018 ldep->is_free = B_TRUE; 2744*3af08d82Slm66018 DMSG(vdc, 2, ": is_free = %d\n", ldep->is_free); 27451ae08745Sheppo status = dep->payload.status; 27468e6a2a04Slm66018 operation = dep->payload.operation; 27471ae08745Sheppo 27484bac2208Snarayan /* the DKIO FLUSH operation never bind handles so we can return now */ 27494bac2208Snarayan if (operation == VD_OP_FLUSH) 27508e6a2a04Slm66018 return (status); 27518e6a2a04Slm66018 27521ae08745Sheppo /* 27531ae08745Sheppo * If the upper layer passed in a misaligned address we copied the 27541ae08745Sheppo * data into an aligned buffer before sending it to LDC - we now 27551ae08745Sheppo * copy it back to the original buffer. 27561ae08745Sheppo */ 27571ae08745Sheppo if (ldep->align_addr) { 27581ae08745Sheppo ASSERT(ldep->addr != NULL); 27591ae08745Sheppo ASSERT(dep->payload.nbytes > 0); 27601ae08745Sheppo 27611ae08745Sheppo bcopy(ldep->align_addr, ldep->addr, dep->payload.nbytes); 27621ae08745Sheppo kmem_free(ldep->align_addr, 2763d10e4ef2Snarayan sizeof (caddr_t) * P2ROUNDUP(dep->payload.nbytes, 8)); 27641ae08745Sheppo ldep->align_addr = NULL; 27651ae08745Sheppo } 27661ae08745Sheppo 27678e6a2a04Slm66018 rv = ldc_mem_unbind_handle(ldep->desc_mhdl); 27688e6a2a04Slm66018 if (rv != 0) { 2769*3af08d82Slm66018 DMSG(vdc, 0, "?[%d] unbind mhdl 0x%lx @ idx %d failed (%d)", 27708e6a2a04Slm66018 vdc->instance, ldep->desc_mhdl, idx, rv); 27718e6a2a04Slm66018 /* 27728e6a2a04Slm66018 * The error returned by the vDisk server is more informative 27738e6a2a04Slm66018 * and thus has a higher priority but if it isn't set we ensure 27748e6a2a04Slm66018 * that this function returns an error. 27758e6a2a04Slm66018 */ 27768e6a2a04Slm66018 if (status == 0) 27778e6a2a04Slm66018 status = EINVAL; 27781ae08745Sheppo } 27791ae08745Sheppo 2780*3af08d82Slm66018 cv_signal(&vdc->membind_cv); 2781*3af08d82Slm66018 cv_signal(&vdc->dring_free_cv); 2782*3af08d82Slm66018 27831ae08745Sheppo return (status); 27841ae08745Sheppo } 27851ae08745Sheppo 27860a55fbb7Slm66018 /* 27870a55fbb7Slm66018 * Function: 27880a55fbb7Slm66018 * vdc_populate_mem_hdl() 27890a55fbb7Slm66018 * 27900a55fbb7Slm66018 * Description: 27910a55fbb7Slm66018 * 27920a55fbb7Slm66018 * Arguments: 27930a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 27940a55fbb7Slm66018 * idx - Index of the Descriptor Ring entry being modified 27950a55fbb7Slm66018 * addr - virtual address being mapped in 27960a55fbb7Slm66018 * nybtes - number of bytes in 'addr' 27970a55fbb7Slm66018 * operation - the vDisk operation being performed (VD_OP_xxx) 27980a55fbb7Slm66018 * 27990a55fbb7Slm66018 * Return Code: 28000a55fbb7Slm66018 * 0 - Success 28010a55fbb7Slm66018 */ 28021ae08745Sheppo static int 2803*3af08d82Slm66018 vdc_populate_mem_hdl(vdc_t *vdcp, vdc_local_desc_t *ldep) 28041ae08745Sheppo { 28051ae08745Sheppo vd_dring_entry_t *dep = NULL; 28061ae08745Sheppo ldc_mem_handle_t mhdl; 28071ae08745Sheppo caddr_t vaddr; 2808*3af08d82Slm66018 size_t nbytes; 28094bac2208Snarayan uint8_t perm = LDC_MEM_RW; 28104bac2208Snarayan uint8_t maptype; 28111ae08745Sheppo int rv = 0; 28121ae08745Sheppo int i; 28131ae08745Sheppo 2814*3af08d82Slm66018 ASSERT(vdcp != NULL); 28151ae08745Sheppo 2816*3af08d82Slm66018 dep = ldep->dep; 28171ae08745Sheppo mhdl = ldep->desc_mhdl; 28181ae08745Sheppo 2819*3af08d82Slm66018 switch (ldep->dir) { 2820*3af08d82Slm66018 case VIO_read_dir: 28211ae08745Sheppo perm = LDC_MEM_W; 28221ae08745Sheppo break; 28231ae08745Sheppo 2824*3af08d82Slm66018 case VIO_write_dir: 28251ae08745Sheppo perm = LDC_MEM_R; 28261ae08745Sheppo break; 28271ae08745Sheppo 2828*3af08d82Slm66018 case VIO_both_dir: 28291ae08745Sheppo perm = LDC_MEM_RW; 28301ae08745Sheppo break; 28311ae08745Sheppo 28321ae08745Sheppo default: 28331ae08745Sheppo ASSERT(0); /* catch bad programming in vdc */ 28341ae08745Sheppo } 28351ae08745Sheppo 28361ae08745Sheppo /* 28371ae08745Sheppo * LDC expects any addresses passed in to be 8-byte aligned. We need 28381ae08745Sheppo * to copy the contents of any misaligned buffers to a newly allocated 28391ae08745Sheppo * buffer and bind it instead (and copy the the contents back to the 28401ae08745Sheppo * original buffer passed in when depopulating the descriptor) 28411ae08745Sheppo */ 2842*3af08d82Slm66018 vaddr = ldep->addr; 2843*3af08d82Slm66018 nbytes = ldep->nbytes; 2844*3af08d82Slm66018 if (((uint64_t)vaddr & 0x7) != 0) { 2845d10e4ef2Snarayan ASSERT(ldep->align_addr == NULL); 28461ae08745Sheppo ldep->align_addr = 2847*3af08d82Slm66018 kmem_alloc(sizeof (caddr_t) * 2848*3af08d82Slm66018 P2ROUNDUP(nbytes, 8), KM_SLEEP); 2849*3af08d82Slm66018 DMSG(vdcp, 0, "[%d] Misaligned address %p reallocating " 2850*3af08d82Slm66018 "(buf=%p nb=%ld op=%d)\n", 2851*3af08d82Slm66018 vdcp->instance, (void *)vaddr, (void *)ldep->align_addr, 2852*3af08d82Slm66018 nbytes, ldep->operation); 2853*3af08d82Slm66018 if (perm != LDC_MEM_W) 2854*3af08d82Slm66018 bcopy(vaddr, ldep->align_addr, nbytes); 28551ae08745Sheppo vaddr = ldep->align_addr; 28561ae08745Sheppo } 28571ae08745Sheppo 28584bac2208Snarayan maptype = LDC_IO_MAP|LDC_SHADOW_MAP|LDC_DIRECT_MAP; 28591ae08745Sheppo rv = ldc_mem_bind_handle(mhdl, vaddr, P2ROUNDUP(nbytes, 8), 28604bac2208Snarayan maptype, perm, &dep->payload.cookie[0], 28611ae08745Sheppo &dep->payload.ncookies); 2862*3af08d82Slm66018 DMSG(vdcp, 2, "[%d] bound mem handle; ncookies=%d\n", 2863*3af08d82Slm66018 vdcp->instance, dep->payload.ncookies); 28641ae08745Sheppo if (rv != 0) { 2865*3af08d82Slm66018 DMSG(vdcp, 0, "[%d] Failed to bind LDC memory handle " 2866*3af08d82Slm66018 "(mhdl=%p, buf=%p, err=%d)\n", 2867*3af08d82Slm66018 vdcp->instance, (void *)mhdl, (void *)vaddr, rv); 28681ae08745Sheppo if (ldep->align_addr) { 28691ae08745Sheppo kmem_free(ldep->align_addr, 2870d10e4ef2Snarayan sizeof (caddr_t) * P2ROUNDUP(nbytes, 8)); 28711ae08745Sheppo ldep->align_addr = NULL; 28721ae08745Sheppo } 28731ae08745Sheppo return (EAGAIN); 28741ae08745Sheppo } 28751ae08745Sheppo 28761ae08745Sheppo /* 28771ae08745Sheppo * Get the other cookies (if any). 28781ae08745Sheppo */ 28791ae08745Sheppo for (i = 1; i < dep->payload.ncookies; i++) { 28801ae08745Sheppo rv = ldc_mem_nextcookie(mhdl, &dep->payload.cookie[i]); 28811ae08745Sheppo if (rv != 0) { 28821ae08745Sheppo (void) ldc_mem_unbind_handle(mhdl); 2883*3af08d82Slm66018 DMSG(vdcp, 0, "?[%d] Failed to get next cookie " 2884e1ebb9ecSlm66018 "(mhdl=%lx cnum=%d), err=%d", 2885*3af08d82Slm66018 vdcp->instance, mhdl, i, rv); 28861ae08745Sheppo if (ldep->align_addr) { 28871ae08745Sheppo kmem_free(ldep->align_addr, 28881ae08745Sheppo sizeof (caddr_t) * dep->payload.nbytes); 28891ae08745Sheppo ldep->align_addr = NULL; 28901ae08745Sheppo } 28911ae08745Sheppo return (EAGAIN); 28921ae08745Sheppo } 28931ae08745Sheppo } 28941ae08745Sheppo 28951ae08745Sheppo return (rv); 28961ae08745Sheppo } 28971ae08745Sheppo 28981ae08745Sheppo /* 28991ae08745Sheppo * Interrupt handlers for messages from LDC 29001ae08745Sheppo */ 29011ae08745Sheppo 29020a55fbb7Slm66018 /* 29030a55fbb7Slm66018 * Function: 29040a55fbb7Slm66018 * vdc_handle_cb() 29050a55fbb7Slm66018 * 29060a55fbb7Slm66018 * Description: 29070a55fbb7Slm66018 * 29080a55fbb7Slm66018 * Arguments: 29090a55fbb7Slm66018 * event - Type of event (LDC_EVT_xxx) that triggered the callback 29100a55fbb7Slm66018 * arg - soft state pointer for this instance of the device driver. 29110a55fbb7Slm66018 * 29120a55fbb7Slm66018 * Return Code: 29130a55fbb7Slm66018 * 0 - Success 29140a55fbb7Slm66018 */ 29151ae08745Sheppo static uint_t 29161ae08745Sheppo vdc_handle_cb(uint64_t event, caddr_t arg) 29171ae08745Sheppo { 29181ae08745Sheppo ldc_status_t ldc_state; 29191ae08745Sheppo int rv = 0; 29201ae08745Sheppo 29211ae08745Sheppo vdc_t *vdc = (vdc_t *)(void *)arg; 29221ae08745Sheppo 29231ae08745Sheppo ASSERT(vdc != NULL); 29241ae08745Sheppo 2925*3af08d82Slm66018 DMSG(vdc, 1, "evt=%lx seqID=%ld\n", event, vdc->seq_num); 29261ae08745Sheppo 29271ae08745Sheppo /* 29281ae08745Sheppo * Depending on the type of event that triggered this callback, 2929*3af08d82Slm66018 * we modify the handshake state or read the data. 29301ae08745Sheppo * 29311ae08745Sheppo * NOTE: not done as a switch() as event could be triggered by 29321ae08745Sheppo * a state change and a read request. Also the ordering of the 29331ae08745Sheppo * check for the event types is deliberate. 29341ae08745Sheppo */ 29351ae08745Sheppo if (event & LDC_EVT_UP) { 2936*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Received LDC_EVT_UP\n", vdc->instance); 2937*3af08d82Slm66018 2938*3af08d82Slm66018 mutex_enter(&vdc->lock); 29391ae08745Sheppo 29401ae08745Sheppo /* get LDC state */ 29411ae08745Sheppo rv = ldc_status(vdc->ldc_handle, &ldc_state); 29421ae08745Sheppo if (rv != 0) { 2943*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Couldn't get LDC status %d", 29441ae08745Sheppo vdc->instance, rv); 29451ae08745Sheppo return (LDC_SUCCESS); 29461ae08745Sheppo } 2947*3af08d82Slm66018 if (vdc->ldc_state != LDC_UP && ldc_state == LDC_UP) { 29481ae08745Sheppo /* 2949*3af08d82Slm66018 * Reset the transaction sequence numbers when 2950*3af08d82Slm66018 * LDC comes up. We then kick off the handshake 2951*3af08d82Slm66018 * negotiation with the vDisk server. 29521ae08745Sheppo */ 29530a55fbb7Slm66018 vdc->seq_num = 1; 29541ae08745Sheppo vdc->seq_num_reply = 0; 29551ae08745Sheppo vdc->ldc_state = ldc_state; 2956*3af08d82Slm66018 cv_signal(&vdc->initwait_cv); 2957*3af08d82Slm66018 } 2958*3af08d82Slm66018 29591ae08745Sheppo mutex_exit(&vdc->lock); 29601ae08745Sheppo } 29611ae08745Sheppo 29621ae08745Sheppo if (event & LDC_EVT_READ) { 2963*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Received LDC_EVT_READ\n", vdc->instance); 2964*3af08d82Slm66018 mutex_enter(&vdc->read_lock); 2965*3af08d82Slm66018 cv_signal(&vdc->read_cv); 2966*3af08d82Slm66018 vdc->read_state = VDC_READ_PENDING; 2967*3af08d82Slm66018 mutex_exit(&vdc->read_lock); 29681ae08745Sheppo 29691ae08745Sheppo /* that's all we have to do - no need to handle DOWN/RESET */ 29701ae08745Sheppo return (LDC_SUCCESS); 29711ae08745Sheppo } 29721ae08745Sheppo 2973*3af08d82Slm66018 if (event & (LDC_EVT_RESET|LDC_EVT_DOWN)) { 29740a55fbb7Slm66018 2975*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Received LDC RESET event\n", vdc->instance); 2976*3af08d82Slm66018 29770a55fbb7Slm66018 mutex_enter(&vdc->lock); 2978*3af08d82Slm66018 /* 2979*3af08d82Slm66018 * Need to wake up any readers so they will 2980*3af08d82Slm66018 * detect that a reset has occurred. 2981*3af08d82Slm66018 */ 2982*3af08d82Slm66018 mutex_enter(&vdc->read_lock); 2983*3af08d82Slm66018 if ((vdc->read_state == VDC_READ_WAITING) || 2984*3af08d82Slm66018 (vdc->read_state == VDC_READ_RESET)) 2985*3af08d82Slm66018 cv_signal(&vdc->read_cv); 2986*3af08d82Slm66018 vdc->read_state = VDC_READ_RESET; 2987*3af08d82Slm66018 mutex_exit(&vdc->read_lock); 29880a55fbb7Slm66018 2989*3af08d82Slm66018 /* wake up any threads waiting for connection to come up */ 2990*3af08d82Slm66018 if (vdc->state == VDC_STATE_INIT_WAITING) { 2991*3af08d82Slm66018 vdc->state = VDC_STATE_RESETTING; 2992*3af08d82Slm66018 cv_signal(&vdc->initwait_cv); 29931ae08745Sheppo } 29941ae08745Sheppo 29950a55fbb7Slm66018 mutex_exit(&vdc->lock); 29961ae08745Sheppo } 29971ae08745Sheppo 29981ae08745Sheppo if (event & ~(LDC_EVT_UP | LDC_EVT_RESET | LDC_EVT_DOWN | LDC_EVT_READ)) 2999*3af08d82Slm66018 DMSG(vdc, 0, "![%d] Unexpected LDC event (%lx) received", 30001ae08745Sheppo vdc->instance, event); 30011ae08745Sheppo 30021ae08745Sheppo return (LDC_SUCCESS); 30031ae08745Sheppo } 30041ae08745Sheppo 3005*3af08d82Slm66018 /* 3006*3af08d82Slm66018 * Function: 3007*3af08d82Slm66018 * vdc_wait_for_response() 3008*3af08d82Slm66018 * 3009*3af08d82Slm66018 * Description: 3010*3af08d82Slm66018 * Block waiting for a response from the server. If there is 3011*3af08d82Slm66018 * no data the thread block on the read_cv that is signalled 3012*3af08d82Slm66018 * by the callback when an EVT_READ occurs. 3013*3af08d82Slm66018 * 3014*3af08d82Slm66018 * Arguments: 3015*3af08d82Slm66018 * vdcp - soft state pointer for this instance of the device driver. 3016*3af08d82Slm66018 * 3017*3af08d82Slm66018 * Return Code: 3018*3af08d82Slm66018 * 0 - Success 3019*3af08d82Slm66018 */ 3020*3af08d82Slm66018 static int 3021*3af08d82Slm66018 vdc_wait_for_response(vdc_t *vdcp, vio_msg_t *msgp) 3022*3af08d82Slm66018 { 3023*3af08d82Slm66018 size_t nbytes = sizeof (*msgp); 3024*3af08d82Slm66018 int status; 3025*3af08d82Slm66018 3026*3af08d82Slm66018 ASSERT(vdcp != NULL); 3027*3af08d82Slm66018 3028*3af08d82Slm66018 DMSG(vdcp, 1, "[%d] Entered\n", vdcp->instance); 3029*3af08d82Slm66018 3030*3af08d82Slm66018 status = vdc_recv(vdcp, msgp, &nbytes); 3031*3af08d82Slm66018 DMSG(vdcp, 3, "vdc_read() done.. status=0x%x size=0x%x\n", 3032*3af08d82Slm66018 status, (int)nbytes); 3033*3af08d82Slm66018 if (status) { 3034*3af08d82Slm66018 DMSG(vdcp, 0, "?[%d] Error %d reading LDC msg\n", 3035*3af08d82Slm66018 vdcp->instance, status); 3036*3af08d82Slm66018 return (status); 3037*3af08d82Slm66018 } 3038*3af08d82Slm66018 3039*3af08d82Slm66018 if (nbytes < sizeof (vio_msg_tag_t)) { 3040*3af08d82Slm66018 DMSG(vdcp, 0, "?[%d] Expect %lu bytes; recv'd %lu\n", 3041*3af08d82Slm66018 vdcp->instance, sizeof (vio_msg_tag_t), nbytes); 3042*3af08d82Slm66018 return (ENOMSG); 3043*3af08d82Slm66018 } 3044*3af08d82Slm66018 3045*3af08d82Slm66018 DMSG(vdcp, 2, "[%d] (%x/%x/%x)\n", vdcp->instance, 3046*3af08d82Slm66018 msgp->tag.vio_msgtype, 3047*3af08d82Slm66018 msgp->tag.vio_subtype, 3048*3af08d82Slm66018 msgp->tag.vio_subtype_env); 3049*3af08d82Slm66018 3050*3af08d82Slm66018 /* 3051*3af08d82Slm66018 * Verify the Session ID of the message 3052*3af08d82Slm66018 * 3053*3af08d82Slm66018 * Every message after the Version has been negotiated should 3054*3af08d82Slm66018 * have the correct session ID set. 3055*3af08d82Slm66018 */ 3056*3af08d82Slm66018 if ((msgp->tag.vio_sid != vdcp->session_id) && 3057*3af08d82Slm66018 (msgp->tag.vio_subtype_env != VIO_VER_INFO)) { 3058*3af08d82Slm66018 DMSG(vdcp, 0, "[%d] Invalid SID: received 0x%x, " 3059*3af08d82Slm66018 "expected 0x%lx [seq num %lx @ %d]", 3060*3af08d82Slm66018 vdcp->instance, msgp->tag.vio_sid, 3061*3af08d82Slm66018 vdcp->session_id, 3062*3af08d82Slm66018 ((vio_dring_msg_t *)msgp)->seq_num, 3063*3af08d82Slm66018 ((vio_dring_msg_t *)msgp)->start_idx); 3064*3af08d82Slm66018 return (ENOMSG); 3065*3af08d82Slm66018 } 3066*3af08d82Slm66018 return (0); 3067*3af08d82Slm66018 } 3068*3af08d82Slm66018 3069*3af08d82Slm66018 3070*3af08d82Slm66018 /* 3071*3af08d82Slm66018 * Function: 3072*3af08d82Slm66018 * vdc_resubmit_backup_dring() 3073*3af08d82Slm66018 * 3074*3af08d82Slm66018 * Description: 3075*3af08d82Slm66018 * Resubmit each descriptor in the backed up dring to 3076*3af08d82Slm66018 * vDisk server. The Dring was backed up during connection 3077*3af08d82Slm66018 * reset. 3078*3af08d82Slm66018 * 3079*3af08d82Slm66018 * Arguments: 3080*3af08d82Slm66018 * vdcp - soft state pointer for this instance of the device driver. 3081*3af08d82Slm66018 * 3082*3af08d82Slm66018 * Return Code: 3083*3af08d82Slm66018 * 0 - Success 3084*3af08d82Slm66018 */ 3085*3af08d82Slm66018 static int 3086*3af08d82Slm66018 vdc_resubmit_backup_dring(vdc_t *vdcp) 3087*3af08d82Slm66018 { 3088*3af08d82Slm66018 int count; 3089*3af08d82Slm66018 int b_idx; 3090*3af08d82Slm66018 int rv; 3091*3af08d82Slm66018 int dring_size; 3092*3af08d82Slm66018 int status; 3093*3af08d82Slm66018 vio_msg_t vio_msg; 3094*3af08d82Slm66018 vdc_local_desc_t *curr_ldep; 3095*3af08d82Slm66018 3096*3af08d82Slm66018 ASSERT(MUTEX_NOT_HELD(&vdcp->lock)); 3097*3af08d82Slm66018 ASSERT(vdcp->state == VDC_STATE_HANDLE_PENDING); 3098*3af08d82Slm66018 3099*3af08d82Slm66018 DMSG(vdcp, 1, "restoring pending dring entries (len=%d, tail=%d)\n", 3100*3af08d82Slm66018 vdcp->local_dring_backup_len, vdcp->local_dring_backup_tail); 3101*3af08d82Slm66018 3102*3af08d82Slm66018 /* 3103*3af08d82Slm66018 * Walk the backup copy of the local descriptor ring and 3104*3af08d82Slm66018 * resubmit all the outstanding transactions. 3105*3af08d82Slm66018 */ 3106*3af08d82Slm66018 b_idx = vdcp->local_dring_backup_tail; 3107*3af08d82Slm66018 for (count = 0; count < vdcp->local_dring_backup_len; count++) { 3108*3af08d82Slm66018 3109*3af08d82Slm66018 curr_ldep = &(vdcp->local_dring_backup[b_idx]); 3110*3af08d82Slm66018 3111*3af08d82Slm66018 /* only resubmit oustanding transactions */ 3112*3af08d82Slm66018 if (!curr_ldep->is_free) { 3113*3af08d82Slm66018 3114*3af08d82Slm66018 DMSG(vdcp, 1, "resubmitting entry idx=%x\n", b_idx); 3115*3af08d82Slm66018 mutex_enter(&vdcp->lock); 3116*3af08d82Slm66018 rv = vdc_populate_descriptor(vdcp, curr_ldep->operation, 3117*3af08d82Slm66018 curr_ldep->addr, curr_ldep->nbytes, 3118*3af08d82Slm66018 curr_ldep->slice, curr_ldep->offset, 3119*3af08d82Slm66018 curr_ldep->cb_type, curr_ldep->cb_arg, 3120*3af08d82Slm66018 curr_ldep->dir); 3121*3af08d82Slm66018 mutex_exit(&vdcp->lock); 3122*3af08d82Slm66018 if (rv) { 3123*3af08d82Slm66018 DMSG(vdcp, 1, "[%d] cannot resubmit entry %d\n", 3124*3af08d82Slm66018 vdcp->instance, b_idx); 3125*3af08d82Slm66018 return (rv); 3126*3af08d82Slm66018 } 3127*3af08d82Slm66018 3128*3af08d82Slm66018 /* Wait for the response message. */ 3129*3af08d82Slm66018 DMSG(vdcp, 1, "waiting for response to idx=%x\n", 3130*3af08d82Slm66018 b_idx); 3131*3af08d82Slm66018 status = vdc_wait_for_response(vdcp, &vio_msg); 3132*3af08d82Slm66018 if (status) { 3133*3af08d82Slm66018 DMSG(vdcp, 1, "[%d] wait_for_response " 3134*3af08d82Slm66018 "returned err=%d\n", vdcp->instance, 3135*3af08d82Slm66018 status); 3136*3af08d82Slm66018 return (status); 3137*3af08d82Slm66018 } 3138*3af08d82Slm66018 3139*3af08d82Slm66018 DMSG(vdcp, 1, "processing msg for idx=%x\n", b_idx); 3140*3af08d82Slm66018 status = vdc_process_data_msg(vdcp, &vio_msg); 3141*3af08d82Slm66018 if (status) { 3142*3af08d82Slm66018 DMSG(vdcp, 1, "[%d] process_data_msg " 3143*3af08d82Slm66018 "returned err=%d\n", vdcp->instance, 3144*3af08d82Slm66018 status); 3145*3af08d82Slm66018 return (status); 3146*3af08d82Slm66018 } 3147*3af08d82Slm66018 } 3148*3af08d82Slm66018 3149*3af08d82Slm66018 /* get the next element to submit */ 3150*3af08d82Slm66018 if (++b_idx >= vdcp->local_dring_backup_len) 3151*3af08d82Slm66018 b_idx = 0; 3152*3af08d82Slm66018 } 3153*3af08d82Slm66018 3154*3af08d82Slm66018 /* all done - now clear up pending dring copy */ 3155*3af08d82Slm66018 dring_size = vdcp->local_dring_backup_len * 3156*3af08d82Slm66018 sizeof (vdcp->local_dring_backup[0]); 3157*3af08d82Slm66018 3158*3af08d82Slm66018 (void) kmem_free(vdcp->local_dring_backup, dring_size); 3159*3af08d82Slm66018 3160*3af08d82Slm66018 vdcp->local_dring_backup = NULL; 3161*3af08d82Slm66018 3162*3af08d82Slm66018 return (0); 3163*3af08d82Slm66018 } 3164*3af08d82Slm66018 3165*3af08d82Slm66018 /* 3166*3af08d82Slm66018 * Function: 3167*3af08d82Slm66018 * vdc_backup_local_dring() 3168*3af08d82Slm66018 * 3169*3af08d82Slm66018 * Description: 3170*3af08d82Slm66018 * Backup the current dring in the event of a reset. The Dring 3171*3af08d82Slm66018 * transactions will be resubmitted to the server when the 3172*3af08d82Slm66018 * connection is restored. 3173*3af08d82Slm66018 * 3174*3af08d82Slm66018 * Arguments: 3175*3af08d82Slm66018 * vdcp - soft state pointer for this instance of the device driver. 3176*3af08d82Slm66018 * 3177*3af08d82Slm66018 * Return Code: 3178*3af08d82Slm66018 * NONE 3179*3af08d82Slm66018 */ 3180*3af08d82Slm66018 static void 3181*3af08d82Slm66018 vdc_backup_local_dring(vdc_t *vdcp) 3182*3af08d82Slm66018 { 3183*3af08d82Slm66018 int dring_size; 3184*3af08d82Slm66018 3185*3af08d82Slm66018 ASSERT(vdcp->state == VDC_STATE_RESETTING); 3186*3af08d82Slm66018 3187*3af08d82Slm66018 /* 3188*3af08d82Slm66018 * If the backup dring is stil around, it means 3189*3af08d82Slm66018 * that the last restore did not complete. However, 3190*3af08d82Slm66018 * since we never got back into the running state, 3191*3af08d82Slm66018 * the backup copy we have is still valid. 3192*3af08d82Slm66018 */ 3193*3af08d82Slm66018 if (vdcp->local_dring_backup != NULL) { 3194*3af08d82Slm66018 DMSG(vdcp, 1, "reusing local descriptor ring backup " 3195*3af08d82Slm66018 "(len=%d, tail=%d)\n", vdcp->local_dring_backup_len, 3196*3af08d82Slm66018 vdcp->local_dring_backup_tail); 3197*3af08d82Slm66018 return; 3198*3af08d82Slm66018 } 3199*3af08d82Slm66018 3200*3af08d82Slm66018 DMSG(vdcp, 1, "backing up the local descriptor ring (len=%d, " 3201*3af08d82Slm66018 "tail=%d)\n", vdcp->dring_len, vdcp->dring_curr_idx); 3202*3af08d82Slm66018 3203*3af08d82Slm66018 dring_size = vdcp->dring_len * sizeof (vdcp->local_dring[0]); 3204*3af08d82Slm66018 3205*3af08d82Slm66018 vdcp->local_dring_backup = kmem_alloc(dring_size, KM_SLEEP); 3206*3af08d82Slm66018 bcopy(vdcp->local_dring, vdcp->local_dring_backup, dring_size); 3207*3af08d82Slm66018 3208*3af08d82Slm66018 vdcp->local_dring_backup_tail = vdcp->dring_curr_idx; 3209*3af08d82Slm66018 vdcp->local_dring_backup_len = vdcp->dring_len; 3210*3af08d82Slm66018 } 3211*3af08d82Slm66018 32121ae08745Sheppo /* -------------------------------------------------------------------------- */ 32131ae08745Sheppo 32141ae08745Sheppo /* 32151ae08745Sheppo * The following functions process the incoming messages from vds 32161ae08745Sheppo */ 32171ae08745Sheppo 32180a55fbb7Slm66018 /* 32190a55fbb7Slm66018 * Function: 32200a55fbb7Slm66018 * vdc_process_msg_thread() 32210a55fbb7Slm66018 * 32220a55fbb7Slm66018 * Description: 32230a55fbb7Slm66018 * 3224*3af08d82Slm66018 * Main VDC message processing thread. Each vDisk instance 3225*3af08d82Slm66018 * consists of a copy of this thread. This thread triggers 3226*3af08d82Slm66018 * all the handshakes and data exchange with the server. It 3227*3af08d82Slm66018 * also handles all channel resets 3228*3af08d82Slm66018 * 32290a55fbb7Slm66018 * Arguments: 32300a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 32310a55fbb7Slm66018 * 32320a55fbb7Slm66018 * Return Code: 32330a55fbb7Slm66018 * None 32340a55fbb7Slm66018 */ 32351ae08745Sheppo static void 3236*3af08d82Slm66018 vdc_process_msg_thread(vdc_t *vdcp) 32371ae08745Sheppo { 32381ae08745Sheppo int status; 32391ae08745Sheppo 3240*3af08d82Slm66018 mutex_enter(&vdcp->lock); 32411ae08745Sheppo 32421ae08745Sheppo for (;;) { 32431ae08745Sheppo 3244*3af08d82Slm66018 #define Q(_s) (vdcp->state == _s) ? #_s : 3245*3af08d82Slm66018 DMSG(vdcp, 3, "state = %d (%s)\n", vdcp->state, 3246*3af08d82Slm66018 Q(VDC_STATE_INIT) 3247*3af08d82Slm66018 Q(VDC_STATE_INIT_WAITING) 3248*3af08d82Slm66018 Q(VDC_STATE_NEGOTIATE) 3249*3af08d82Slm66018 Q(VDC_STATE_HANDLE_PENDING) 3250*3af08d82Slm66018 Q(VDC_STATE_RUNNING) 3251*3af08d82Slm66018 Q(VDC_STATE_RESETTING) 3252*3af08d82Slm66018 Q(VDC_STATE_DETACH) 3253*3af08d82Slm66018 "UNKNOWN"); 32541ae08745Sheppo 3255*3af08d82Slm66018 switch (vdcp->state) { 3256*3af08d82Slm66018 case VDC_STATE_INIT: 3257*3af08d82Slm66018 3258*3af08d82Slm66018 /* Check if have re-initializing repeatedly */ 3259*3af08d82Slm66018 if (vdcp->hshake_cnt++ > VDC_RETRIES) { 3260*3af08d82Slm66018 vdcp->state = VDC_STATE_DETACH; 3261*3af08d82Slm66018 break; 3262*3af08d82Slm66018 } 3263*3af08d82Slm66018 3264*3af08d82Slm66018 /* Bring up connection with vds via LDC */ 3265*3af08d82Slm66018 status = vdc_start_ldc_connection(vdcp); 3266*3af08d82Slm66018 switch (status) { 3267*3af08d82Slm66018 case EINVAL: 3268*3af08d82Slm66018 DMSG(vdcp, 0, "[%d] Could not start LDC", 3269*3af08d82Slm66018 vdcp->instance); 3270*3af08d82Slm66018 vdcp->state = VDC_STATE_DETACH; 3271*3af08d82Slm66018 break; 3272*3af08d82Slm66018 case 0: 3273*3af08d82Slm66018 vdcp->state = VDC_STATE_INIT_WAITING; 3274*3af08d82Slm66018 break; 3275*3af08d82Slm66018 default: 3276*3af08d82Slm66018 vdcp->state = VDC_STATE_INIT_WAITING; 3277*3af08d82Slm66018 break; 3278*3af08d82Slm66018 } 3279*3af08d82Slm66018 break; 3280*3af08d82Slm66018 3281*3af08d82Slm66018 case VDC_STATE_INIT_WAITING: 3282*3af08d82Slm66018 3283*3af08d82Slm66018 /* 3284*3af08d82Slm66018 * Let the callback event move us on 3285*3af08d82Slm66018 * when channel is open to server 3286*3af08d82Slm66018 */ 3287*3af08d82Slm66018 while (vdcp->ldc_state != LDC_UP) { 3288*3af08d82Slm66018 cv_wait(&vdcp->initwait_cv, &vdcp->lock); 3289*3af08d82Slm66018 if (vdcp->state != VDC_STATE_INIT_WAITING) { 3290*3af08d82Slm66018 DMSG(vdcp, 0, 3291*3af08d82Slm66018 "state moved to %d out from under us...\n", 3292*3af08d82Slm66018 vdcp->state); 3293*3af08d82Slm66018 3294*3af08d82Slm66018 break; 3295*3af08d82Slm66018 } 3296*3af08d82Slm66018 } 3297*3af08d82Slm66018 if (vdcp->state == VDC_STATE_INIT_WAITING && 3298*3af08d82Slm66018 vdcp->ldc_state == LDC_UP) { 3299*3af08d82Slm66018 vdcp->state = VDC_STATE_NEGOTIATE; 3300*3af08d82Slm66018 } 3301*3af08d82Slm66018 break; 3302*3af08d82Slm66018 3303*3af08d82Slm66018 case VDC_STATE_NEGOTIATE: 3304*3af08d82Slm66018 switch (status = vdc_ver_negotiation(vdcp)) { 3305*3af08d82Slm66018 case 0: 3306*3af08d82Slm66018 break; 3307*3af08d82Slm66018 default: 3308*3af08d82Slm66018 DMSG(vdcp, 0, "ver negotiate failed (%d)..\n", 3309*3af08d82Slm66018 status); 3310*3af08d82Slm66018 goto reset; 3311*3af08d82Slm66018 } 3312*3af08d82Slm66018 3313*3af08d82Slm66018 switch (status = vdc_attr_negotiation(vdcp)) { 3314*3af08d82Slm66018 case 0: 3315*3af08d82Slm66018 break; 3316*3af08d82Slm66018 default: 3317*3af08d82Slm66018 DMSG(vdcp, 0, "attr negotiate failed (%d)..\n", 3318*3af08d82Slm66018 status); 3319*3af08d82Slm66018 goto reset; 3320*3af08d82Slm66018 } 3321*3af08d82Slm66018 3322*3af08d82Slm66018 switch (status = vdc_dring_negotiation(vdcp)) { 3323*3af08d82Slm66018 case 0: 3324*3af08d82Slm66018 break; 3325*3af08d82Slm66018 default: 3326*3af08d82Slm66018 DMSG(vdcp, 0, "dring negotiate failed (%d)..\n", 3327*3af08d82Slm66018 status); 3328*3af08d82Slm66018 goto reset; 3329*3af08d82Slm66018 } 3330*3af08d82Slm66018 3331*3af08d82Slm66018 switch (status = vdc_rdx_exchange(vdcp)) { 3332*3af08d82Slm66018 case 0: 3333*3af08d82Slm66018 vdcp->state = VDC_STATE_HANDLE_PENDING; 3334*3af08d82Slm66018 goto done; 3335*3af08d82Slm66018 default: 3336*3af08d82Slm66018 DMSG(vdcp, 0, "RDX xchg failed ..(%d)\n", 3337*3af08d82Slm66018 status); 3338*3af08d82Slm66018 goto reset; 3339*3af08d82Slm66018 } 3340*3af08d82Slm66018 reset: 3341*3af08d82Slm66018 DMSG(vdcp, 0, "negotiation failed: resetting (%d)\n", 3342*3af08d82Slm66018 status); 3343*3af08d82Slm66018 vdcp->state = VDC_STATE_RESETTING; 3344*3af08d82Slm66018 done: 3345*3af08d82Slm66018 DMSG(vdcp, 0, "negotiation complete (state=0x%x)...\n", 3346*3af08d82Slm66018 vdcp->state); 3347*3af08d82Slm66018 break; 3348*3af08d82Slm66018 3349*3af08d82Slm66018 case VDC_STATE_HANDLE_PENDING: 3350*3af08d82Slm66018 3351*3af08d82Slm66018 mutex_exit(&vdcp->lock); 3352*3af08d82Slm66018 status = vdc_resubmit_backup_dring(vdcp); 3353*3af08d82Slm66018 mutex_enter(&vdcp->lock); 3354*3af08d82Slm66018 3355*3af08d82Slm66018 if (status) 3356*3af08d82Slm66018 vdcp->state = VDC_STATE_RESETTING; 3357*3af08d82Slm66018 else 3358*3af08d82Slm66018 vdcp->state = VDC_STATE_RUNNING; 3359*3af08d82Slm66018 3360*3af08d82Slm66018 break; 3361*3af08d82Slm66018 3362*3af08d82Slm66018 /* enter running state */ 3363*3af08d82Slm66018 case VDC_STATE_RUNNING: 3364*3af08d82Slm66018 /* 3365*3af08d82Slm66018 * Signal anyone waiting for the connection 3366*3af08d82Slm66018 * to come on line. 3367*3af08d82Slm66018 */ 3368*3af08d82Slm66018 vdcp->hshake_cnt = 0; 3369*3af08d82Slm66018 cv_broadcast(&vdcp->running_cv); 3370*3af08d82Slm66018 mutex_exit(&vdcp->lock); 3371*3af08d82Slm66018 3372*3af08d82Slm66018 for (;;) { 3373*3af08d82Slm66018 vio_msg_t msg; 3374*3af08d82Slm66018 status = vdc_wait_for_response(vdcp, &msg); 3375*3af08d82Slm66018 if (status) break; 3376*3af08d82Slm66018 3377*3af08d82Slm66018 DMSG(vdcp, 1, "[%d] new pkt(s) available\n", 3378*3af08d82Slm66018 vdcp->instance); 3379*3af08d82Slm66018 status = vdc_process_data_msg(vdcp, &msg); 33801ae08745Sheppo if (status) { 3381*3af08d82Slm66018 DMSG(vdcp, 1, "[%d] process_data_msg " 3382*3af08d82Slm66018 "returned err=%d\n", vdcp->instance, 3383*3af08d82Slm66018 status); 33841ae08745Sheppo break; 33851ae08745Sheppo } 33861ae08745Sheppo 3387*3af08d82Slm66018 } 3388e1ebb9ecSlm66018 3389*3af08d82Slm66018 mutex_enter(&vdcp->lock); 3390*3af08d82Slm66018 3391*3af08d82Slm66018 vdcp->state = VDC_STATE_RESETTING; 3392*3af08d82Slm66018 break; 3393*3af08d82Slm66018 3394*3af08d82Slm66018 case VDC_STATE_RESETTING: 3395*3af08d82Slm66018 DMSG(vdcp, 0, "Initiating channel reset " 3396*3af08d82Slm66018 "(pending = %d)\n", (int)vdcp->threads_pending); 3397*3af08d82Slm66018 3398*3af08d82Slm66018 if (vdcp->self_reset) { 3399*3af08d82Slm66018 DMSG(vdcp, 0, 3400*3af08d82Slm66018 "[%d] calling stop_ldc_connection.\n", 3401*3af08d82Slm66018 vdcp->instance); 3402*3af08d82Slm66018 status = vdc_stop_ldc_connection(vdcp); 3403*3af08d82Slm66018 vdcp->self_reset = B_FALSE; 34041ae08745Sheppo } 34051ae08745Sheppo 34061ae08745Sheppo /* 3407*3af08d82Slm66018 * Wait for all threads currently waiting 3408*3af08d82Slm66018 * for a free dring entry to use. 34091ae08745Sheppo */ 3410*3af08d82Slm66018 while (vdcp->threads_pending) { 3411*3af08d82Slm66018 cv_broadcast(&vdcp->membind_cv); 3412*3af08d82Slm66018 cv_broadcast(&vdcp->dring_free_cv); 3413*3af08d82Slm66018 mutex_exit(&vdcp->lock); 3414*3af08d82Slm66018 /* let them wake up */ 3415*3af08d82Slm66018 drv_usecwait(vdc_min_timeout_ldc); 3416*3af08d82Slm66018 mutex_enter(&vdcp->lock); 34171ae08745Sheppo } 34181ae08745Sheppo 3419*3af08d82Slm66018 ASSERT(vdcp->threads_pending == 0); 34201ae08745Sheppo 3421*3af08d82Slm66018 /* Sanity check that no thread is receiving */ 3422*3af08d82Slm66018 ASSERT(vdcp->read_state != VDC_READ_WAITING); 34230a55fbb7Slm66018 3424*3af08d82Slm66018 vdcp->read_state = VDC_READ_IDLE; 3425*3af08d82Slm66018 3426*3af08d82Slm66018 vdc_backup_local_dring(vdcp); 3427*3af08d82Slm66018 3428*3af08d82Slm66018 /* cleanup the old d-ring */ 3429*3af08d82Slm66018 vdc_destroy_descriptor_ring(vdcp); 3430*3af08d82Slm66018 3431*3af08d82Slm66018 /* go and start again */ 3432*3af08d82Slm66018 vdcp->state = VDC_STATE_INIT; 3433*3af08d82Slm66018 34340a55fbb7Slm66018 break; 34350a55fbb7Slm66018 3436*3af08d82Slm66018 case VDC_STATE_DETACH: 3437*3af08d82Slm66018 DMSG(vdcp, 0, "[%d] Reset thread exit cleanup ..\n", 3438*3af08d82Slm66018 vdcp->instance); 3439*3af08d82Slm66018 3440*3af08d82Slm66018 while (vdcp->sync_op_pending) { 3441*3af08d82Slm66018 cv_signal(&vdcp->sync_pending_cv); 3442*3af08d82Slm66018 cv_signal(&vdcp->sync_blocked_cv); 3443*3af08d82Slm66018 mutex_exit(&vdcp->lock); 3444*3af08d82Slm66018 drv_usecwait(vdc_min_timeout_ldc); 3445*3af08d82Slm66018 mutex_enter(&vdcp->lock); 34460a55fbb7Slm66018 } 34471ae08745Sheppo 3448*3af08d82Slm66018 cv_signal(&vdcp->running_cv); 3449*3af08d82Slm66018 mutex_exit(&vdcp->lock); 3450*3af08d82Slm66018 3451*3af08d82Slm66018 DMSG(vdcp, 0, "[%d] Msg processing thread exiting ..\n", 3452*3af08d82Slm66018 vdcp->instance); 3453*3af08d82Slm66018 thread_exit(); 3454*3af08d82Slm66018 break; 3455*3af08d82Slm66018 } 3456*3af08d82Slm66018 } 34570a55fbb7Slm66018 } 34580a55fbb7Slm66018 34590a55fbb7Slm66018 34600a55fbb7Slm66018 /* 34610a55fbb7Slm66018 * Function: 34620a55fbb7Slm66018 * vdc_process_data_msg() 34630a55fbb7Slm66018 * 34640a55fbb7Slm66018 * Description: 34650a55fbb7Slm66018 * This function is called by the message processing thread each time 34660a55fbb7Slm66018 * a message with a msgtype of VIO_TYPE_DATA is received. It will either 34670a55fbb7Slm66018 * be an ACK or NACK from vds[1] which vdc handles as follows. 34680a55fbb7Slm66018 * ACK - wake up the waiting thread 34690a55fbb7Slm66018 * NACK - resend any messages necessary 34700a55fbb7Slm66018 * 34710a55fbb7Slm66018 * [1] Although the message format allows it, vds should not send a 34720a55fbb7Slm66018 * VIO_SUBTYPE_INFO message to vdc asking it to read data; if for 34730a55fbb7Slm66018 * some bizarre reason it does, vdc will reset the connection. 34740a55fbb7Slm66018 * 34750a55fbb7Slm66018 * Arguments: 34760a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 34770a55fbb7Slm66018 * msg - the LDC message sent by vds 34780a55fbb7Slm66018 * 34790a55fbb7Slm66018 * Return Code: 34800a55fbb7Slm66018 * 0 - Success. 34810a55fbb7Slm66018 * > 0 - error value returned by LDC 34820a55fbb7Slm66018 */ 34830a55fbb7Slm66018 static int 3484*3af08d82Slm66018 vdc_process_data_msg(vdc_t *vdcp, vio_msg_t *msg) 34850a55fbb7Slm66018 { 34860a55fbb7Slm66018 int status = 0; 3487*3af08d82Slm66018 vio_dring_msg_t *dring_msg; 3488d10e4ef2Snarayan vdc_local_desc_t *ldep = NULL; 3489*3af08d82Slm66018 int start, end; 3490*3af08d82Slm66018 int idx; 34910a55fbb7Slm66018 3492*3af08d82Slm66018 dring_msg = (vio_dring_msg_t *)msg; 34930a55fbb7Slm66018 3494*3af08d82Slm66018 ASSERT(msg->tag.vio_msgtype == VIO_TYPE_DATA); 3495*3af08d82Slm66018 ASSERT(vdcp != NULL); 3496*3af08d82Slm66018 3497*3af08d82Slm66018 mutex_enter(&vdcp->lock); 34980a55fbb7Slm66018 34990a55fbb7Slm66018 /* 35000a55fbb7Slm66018 * Check to see if the message has bogus data 35010a55fbb7Slm66018 */ 3502e1ebb9ecSlm66018 idx = start = dring_msg->start_idx; 35030a55fbb7Slm66018 end = dring_msg->end_idx; 3504*3af08d82Slm66018 if ((start >= vdcp->dring_len) || 3505*3af08d82Slm66018 (end >= vdcp->dring_len) || (end < -1)) { 3506*3af08d82Slm66018 DMSG(vdcp, 0, "[%d] Bogus ACK data : start %d, end %d\n", 3507*3af08d82Slm66018 vdcp->instance, start, end); 3508*3af08d82Slm66018 mutex_exit(&vdcp->lock); 3509e1ebb9ecSlm66018 return (EINVAL); 35100a55fbb7Slm66018 } 35110a55fbb7Slm66018 35120a55fbb7Slm66018 /* 35130a55fbb7Slm66018 * Verify that the sequence number is what vdc expects. 35140a55fbb7Slm66018 */ 3515*3af08d82Slm66018 switch (vdc_verify_seq_num(vdcp, dring_msg)) { 3516e1ebb9ecSlm66018 case VDC_SEQ_NUM_TODO: 3517e1ebb9ecSlm66018 break; /* keep processing this message */ 3518e1ebb9ecSlm66018 case VDC_SEQ_NUM_SKIP: 3519*3af08d82Slm66018 mutex_exit(&vdcp->lock); 3520e1ebb9ecSlm66018 return (0); 3521e1ebb9ecSlm66018 case VDC_SEQ_NUM_INVALID: 3522*3af08d82Slm66018 mutex_exit(&vdcp->lock); 3523*3af08d82Slm66018 DMSG(vdcp, 0, "[%d] invalid seqno\n", vdcp->instance); 35240a55fbb7Slm66018 return (ENXIO); 35250a55fbb7Slm66018 } 35260a55fbb7Slm66018 3527*3af08d82Slm66018 if (msg->tag.vio_subtype == VIO_SUBTYPE_NACK) { 3528*3af08d82Slm66018 DMSG(vdcp, 0, "[%d] DATA NACK\n", vdcp->instance); 3529e1ebb9ecSlm66018 VDC_DUMP_DRING_MSG(dring_msg); 3530*3af08d82Slm66018 mutex_exit(&vdcp->lock); 3531e1ebb9ecSlm66018 return (EIO); 35320a55fbb7Slm66018 3533*3af08d82Slm66018 } else if (msg->tag.vio_subtype == VIO_SUBTYPE_INFO) { 3534*3af08d82Slm66018 mutex_exit(&vdcp->lock); 3535e1ebb9ecSlm66018 return (EPROTO); 3536e1ebb9ecSlm66018 } 3537e1ebb9ecSlm66018 3538*3af08d82Slm66018 DTRACE_IO2(recv, vio_dring_msg_t, dring_msg, vdc_t *, vdcp); 3539*3af08d82Slm66018 DMSG(vdcp, 1, ": start %d end %d\n", start, end); 3540*3af08d82Slm66018 ASSERT(start == end); 3541*3af08d82Slm66018 3542*3af08d82Slm66018 ldep = &vdcp->local_dring[idx]; 3543*3af08d82Slm66018 3544*3af08d82Slm66018 DMSG(vdcp, 1, ": state 0x%x - cb_type 0x%x\n", 3545*3af08d82Slm66018 ldep->dep->hdr.dstate, ldep->cb_type); 3546*3af08d82Slm66018 3547e1ebb9ecSlm66018 if (ldep->dep->hdr.dstate == VIO_DESC_DONE) { 3548*3af08d82Slm66018 struct buf *bufp; 3549e1ebb9ecSlm66018 3550*3af08d82Slm66018 switch (ldep->cb_type) { 3551*3af08d82Slm66018 case CB_SYNC: 3552*3af08d82Slm66018 ASSERT(vdcp->sync_op_pending); 3553d10e4ef2Snarayan 3554*3af08d82Slm66018 status = vdc_depopulate_descriptor(vdcp, idx); 3555*3af08d82Slm66018 vdcp->sync_op_status = status; 3556*3af08d82Slm66018 vdcp->sync_op_pending = B_FALSE; 3557*3af08d82Slm66018 cv_signal(&vdcp->sync_pending_cv); 3558*3af08d82Slm66018 break; 35594bac2208Snarayan 3560*3af08d82Slm66018 case CB_STRATEGY: 3561*3af08d82Slm66018 bufp = ldep->cb_arg; 3562*3af08d82Slm66018 ASSERT(bufp != NULL); 3563*3af08d82Slm66018 status = ldep->dep->payload.status; /* Future:ntoh */ 3564*3af08d82Slm66018 if (status != 0) { 3565*3af08d82Slm66018 DMSG(vdcp, 1, "strategy status=%d\n", status); 3566*3af08d82Slm66018 bioerror(bufp, status); 3567d10e4ef2Snarayan } 3568*3af08d82Slm66018 status = vdc_depopulate_descriptor(vdcp, idx); 3569*3af08d82Slm66018 biodone(bufp); 3570*3af08d82Slm66018 break; 3571*3af08d82Slm66018 3572*3af08d82Slm66018 default: 3573*3af08d82Slm66018 ASSERT(0); 35740a55fbb7Slm66018 } 3575*3af08d82Slm66018 } 3576*3af08d82Slm66018 3577*3af08d82Slm66018 /* let the arrival signal propogate */ 3578*3af08d82Slm66018 mutex_exit(&vdcp->lock); 35790a55fbb7Slm66018 3580e1ebb9ecSlm66018 /* probe gives the count of how many entries were processed */ 3581*3af08d82Slm66018 DTRACE_IO2(processed, int, 1, vdc_t *, vdcp); 35820a55fbb7Slm66018 3583*3af08d82Slm66018 return (0); 35840a55fbb7Slm66018 } 35850a55fbb7Slm66018 35860a55fbb7Slm66018 /* 35870a55fbb7Slm66018 * Function: 35880a55fbb7Slm66018 * vdc_process_err_msg() 35890a55fbb7Slm66018 * 35900a55fbb7Slm66018 * NOTE: No error messages are used as part of the vDisk protocol 35910a55fbb7Slm66018 */ 35920a55fbb7Slm66018 static int 35930a55fbb7Slm66018 vdc_process_err_msg(vdc_t *vdc, vio_msg_t msg) 35940a55fbb7Slm66018 { 35950a55fbb7Slm66018 _NOTE(ARGUNUSED(vdc)) 35960a55fbb7Slm66018 _NOTE(ARGUNUSED(msg)) 35970a55fbb7Slm66018 35980a55fbb7Slm66018 ASSERT(msg.tag.vio_msgtype == VIO_TYPE_ERR); 3599*3af08d82Slm66018 DMSG(vdc, 1, "[%d] Got an ERR msg", vdc->instance); 36000a55fbb7Slm66018 36010a55fbb7Slm66018 return (ENOTSUP); 36020a55fbb7Slm66018 } 36030a55fbb7Slm66018 36040a55fbb7Slm66018 /* 36050a55fbb7Slm66018 * Function: 36060a55fbb7Slm66018 * vdc_handle_ver_msg() 36070a55fbb7Slm66018 * 36080a55fbb7Slm66018 * Description: 36090a55fbb7Slm66018 * 36100a55fbb7Slm66018 * Arguments: 36110a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 36120a55fbb7Slm66018 * ver_msg - LDC message sent by vDisk server 36130a55fbb7Slm66018 * 36140a55fbb7Slm66018 * Return Code: 36150a55fbb7Slm66018 * 0 - Success 36160a55fbb7Slm66018 */ 36170a55fbb7Slm66018 static int 36180a55fbb7Slm66018 vdc_handle_ver_msg(vdc_t *vdc, vio_ver_msg_t *ver_msg) 36190a55fbb7Slm66018 { 36200a55fbb7Slm66018 int status = 0; 36210a55fbb7Slm66018 36220a55fbb7Slm66018 ASSERT(vdc != NULL); 36230a55fbb7Slm66018 ASSERT(mutex_owned(&vdc->lock)); 36240a55fbb7Slm66018 36250a55fbb7Slm66018 if (ver_msg->tag.vio_subtype_env != VIO_VER_INFO) { 36260a55fbb7Slm66018 return (EPROTO); 36270a55fbb7Slm66018 } 36280a55fbb7Slm66018 36290a55fbb7Slm66018 if (ver_msg->dev_class != VDEV_DISK_SERVER) { 36300a55fbb7Slm66018 return (EINVAL); 36310a55fbb7Slm66018 } 36320a55fbb7Slm66018 36330a55fbb7Slm66018 switch (ver_msg->tag.vio_subtype) { 36340a55fbb7Slm66018 case VIO_SUBTYPE_ACK: 36350a55fbb7Slm66018 /* 36360a55fbb7Slm66018 * We check to see if the version returned is indeed supported 36370a55fbb7Slm66018 * (The server may have also adjusted the minor number downwards 36380a55fbb7Slm66018 * and if so 'ver_msg' will contain the actual version agreed) 36390a55fbb7Slm66018 */ 36400a55fbb7Slm66018 if (vdc_is_supported_version(ver_msg)) { 36410a55fbb7Slm66018 vdc->ver.major = ver_msg->ver_major; 36420a55fbb7Slm66018 vdc->ver.minor = ver_msg->ver_minor; 36430a55fbb7Slm66018 ASSERT(vdc->ver.major > 0); 36440a55fbb7Slm66018 } else { 36450a55fbb7Slm66018 status = EPROTO; 36460a55fbb7Slm66018 } 36470a55fbb7Slm66018 break; 36480a55fbb7Slm66018 36490a55fbb7Slm66018 case VIO_SUBTYPE_NACK: 36500a55fbb7Slm66018 /* 36510a55fbb7Slm66018 * call vdc_is_supported_version() which will return the next 36520a55fbb7Slm66018 * supported version (if any) in 'ver_msg' 36530a55fbb7Slm66018 */ 36540a55fbb7Slm66018 (void) vdc_is_supported_version(ver_msg); 36550a55fbb7Slm66018 if (ver_msg->ver_major > 0) { 36560a55fbb7Slm66018 size_t len = sizeof (*ver_msg); 36570a55fbb7Slm66018 36580a55fbb7Slm66018 ASSERT(vdc->ver.major > 0); 36590a55fbb7Slm66018 36600a55fbb7Slm66018 /* reset the necessary fields and resend */ 36610a55fbb7Slm66018 ver_msg->tag.vio_subtype = VIO_SUBTYPE_INFO; 36620a55fbb7Slm66018 ver_msg->dev_class = VDEV_DISK; 36630a55fbb7Slm66018 36640a55fbb7Slm66018 status = vdc_send(vdc, (caddr_t)ver_msg, &len); 3665*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Resend VER info (LDC status = %d)\n", 36660a55fbb7Slm66018 vdc->instance, status); 36670a55fbb7Slm66018 if (len != sizeof (*ver_msg)) 36680a55fbb7Slm66018 status = EBADMSG; 36690a55fbb7Slm66018 } else { 3670*3af08d82Slm66018 DMSG(vdc, 0, "[%d] No common version with " 36710a55fbb7Slm66018 "vDisk server", vdc->instance); 36720a55fbb7Slm66018 status = ENOTSUP; 36730a55fbb7Slm66018 } 36740a55fbb7Slm66018 36750a55fbb7Slm66018 break; 36761ae08745Sheppo case VIO_SUBTYPE_INFO: 36771ae08745Sheppo /* 36781ae08745Sheppo * Handle the case where vds starts handshake 36791ae08745Sheppo * (for now only vdc is the instigatior) 36801ae08745Sheppo */ 36811ae08745Sheppo status = ENOTSUP; 36821ae08745Sheppo break; 36831ae08745Sheppo 36841ae08745Sheppo default: 36850a55fbb7Slm66018 status = EINVAL; 36861ae08745Sheppo break; 36871ae08745Sheppo } 36881ae08745Sheppo 36890a55fbb7Slm66018 return (status); 36900a55fbb7Slm66018 } 36910a55fbb7Slm66018 36920a55fbb7Slm66018 /* 36930a55fbb7Slm66018 * Function: 36940a55fbb7Slm66018 * vdc_handle_attr_msg() 36950a55fbb7Slm66018 * 36960a55fbb7Slm66018 * Description: 36970a55fbb7Slm66018 * 36980a55fbb7Slm66018 * Arguments: 36990a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 37000a55fbb7Slm66018 * attr_msg - LDC message sent by vDisk server 37010a55fbb7Slm66018 * 37020a55fbb7Slm66018 * Return Code: 37030a55fbb7Slm66018 * 0 - Success 37040a55fbb7Slm66018 */ 37050a55fbb7Slm66018 static int 37060a55fbb7Slm66018 vdc_handle_attr_msg(vdc_t *vdc, vd_attr_msg_t *attr_msg) 37070a55fbb7Slm66018 { 37080a55fbb7Slm66018 int status = 0; 37090a55fbb7Slm66018 37100a55fbb7Slm66018 ASSERT(vdc != NULL); 37110a55fbb7Slm66018 ASSERT(mutex_owned(&vdc->lock)); 37120a55fbb7Slm66018 37130a55fbb7Slm66018 if (attr_msg->tag.vio_subtype_env != VIO_ATTR_INFO) { 37140a55fbb7Slm66018 return (EPROTO); 37150a55fbb7Slm66018 } 37160a55fbb7Slm66018 37170a55fbb7Slm66018 switch (attr_msg->tag.vio_subtype) { 37181ae08745Sheppo case VIO_SUBTYPE_ACK: 37191ae08745Sheppo /* 37201ae08745Sheppo * We now verify the attributes sent by vds. 37211ae08745Sheppo */ 37221ae08745Sheppo vdc->vdisk_size = attr_msg->vdisk_size; 37231ae08745Sheppo vdc->vdisk_type = attr_msg->vdisk_type; 37241ae08745Sheppo 3725*3af08d82Slm66018 DMSG(vdc, 0, "[%d] max_xfer_sz: sent %lx acked %lx\n", 3726e1ebb9ecSlm66018 vdc->instance, vdc->max_xfer_sz, attr_msg->max_xfer_sz); 3727*3af08d82Slm66018 DMSG(vdc, 0, "[%d] vdisk_block_size: sent %lx acked %x\n", 3728e1ebb9ecSlm66018 vdc->instance, vdc->block_size, 3729e1ebb9ecSlm66018 attr_msg->vdisk_block_size); 3730e1ebb9ecSlm66018 37311ae08745Sheppo /* 3732e1ebb9ecSlm66018 * We don't know at compile time what the vDisk server will 3733e1ebb9ecSlm66018 * think are good values but we apply an large (arbitrary) 3734e1ebb9ecSlm66018 * upper bound to prevent memory exhaustion in vdc if it was 3735e1ebb9ecSlm66018 * allocating a DRing based of huge values sent by the server. 3736e1ebb9ecSlm66018 * We probably will never exceed this except if the message 3737e1ebb9ecSlm66018 * was garbage. 37381ae08745Sheppo */ 3739e1ebb9ecSlm66018 if ((attr_msg->max_xfer_sz * attr_msg->vdisk_block_size) <= 3740e1ebb9ecSlm66018 (PAGESIZE * DEV_BSIZE)) { 3741e1ebb9ecSlm66018 vdc->max_xfer_sz = attr_msg->max_xfer_sz; 3742e1ebb9ecSlm66018 vdc->block_size = attr_msg->vdisk_block_size; 3743e1ebb9ecSlm66018 } else { 3744*3af08d82Slm66018 DMSG(vdc, 0, "[%d] vds block transfer size too big;" 3745e1ebb9ecSlm66018 " using max supported by vdc", vdc->instance); 37461ae08745Sheppo } 37471ae08745Sheppo 37481ae08745Sheppo if ((attr_msg->xfer_mode != VIO_DRING_MODE) || 37491ae08745Sheppo (attr_msg->vdisk_size > INT64_MAX) || 37501ae08745Sheppo (attr_msg->vdisk_type > VD_DISK_TYPE_DISK)) { 3751*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Invalid attributes from vds", 3752e1ebb9ecSlm66018 vdc->instance); 37531ae08745Sheppo status = EINVAL; 37541ae08745Sheppo break; 37551ae08745Sheppo } 37561ae08745Sheppo 37571ae08745Sheppo break; 37581ae08745Sheppo 37591ae08745Sheppo case VIO_SUBTYPE_NACK: 37601ae08745Sheppo /* 37611ae08745Sheppo * vds could not handle the attributes we sent so we 37621ae08745Sheppo * stop negotiating. 37631ae08745Sheppo */ 37641ae08745Sheppo status = EPROTO; 37651ae08745Sheppo break; 37661ae08745Sheppo 37671ae08745Sheppo case VIO_SUBTYPE_INFO: 37681ae08745Sheppo /* 37691ae08745Sheppo * Handle the case where vds starts the handshake 37701ae08745Sheppo * (for now; vdc is the only supported instigatior) 37711ae08745Sheppo */ 37721ae08745Sheppo status = ENOTSUP; 37731ae08745Sheppo break; 37741ae08745Sheppo 37751ae08745Sheppo default: 37761ae08745Sheppo status = ENOTSUP; 37771ae08745Sheppo break; 37781ae08745Sheppo } 37791ae08745Sheppo 37800a55fbb7Slm66018 return (status); 37811ae08745Sheppo } 37821ae08745Sheppo 37830a55fbb7Slm66018 /* 37840a55fbb7Slm66018 * Function: 37850a55fbb7Slm66018 * vdc_handle_dring_reg_msg() 37860a55fbb7Slm66018 * 37870a55fbb7Slm66018 * Description: 37880a55fbb7Slm66018 * 37890a55fbb7Slm66018 * Arguments: 37900a55fbb7Slm66018 * vdc - soft state pointer for this instance of the driver. 37910a55fbb7Slm66018 * dring_msg - LDC message sent by vDisk server 37920a55fbb7Slm66018 * 37930a55fbb7Slm66018 * Return Code: 37940a55fbb7Slm66018 * 0 - Success 37950a55fbb7Slm66018 */ 37960a55fbb7Slm66018 static int 37970a55fbb7Slm66018 vdc_handle_dring_reg_msg(vdc_t *vdc, vio_dring_reg_msg_t *dring_msg) 37980a55fbb7Slm66018 { 37990a55fbb7Slm66018 int status = 0; 38001ae08745Sheppo 38010a55fbb7Slm66018 ASSERT(vdc != NULL); 38020a55fbb7Slm66018 ASSERT(mutex_owned(&vdc->lock)); 38030a55fbb7Slm66018 38040a55fbb7Slm66018 if (dring_msg->tag.vio_subtype_env != VIO_DRING_REG) { 38050a55fbb7Slm66018 return (EPROTO); 38060a55fbb7Slm66018 } 38070a55fbb7Slm66018 38080a55fbb7Slm66018 switch (dring_msg->tag.vio_subtype) { 38090a55fbb7Slm66018 case VIO_SUBTYPE_ACK: 38101ae08745Sheppo /* save the received dring_ident */ 38111ae08745Sheppo vdc->dring_ident = dring_msg->dring_ident; 3812*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Received dring ident=0x%lx\n", 3813e1ebb9ecSlm66018 vdc->instance, vdc->dring_ident); 38141ae08745Sheppo break; 38151ae08745Sheppo 38161ae08745Sheppo case VIO_SUBTYPE_NACK: 38171ae08745Sheppo /* 38181ae08745Sheppo * vds could not handle the DRing info we sent so we 38191ae08745Sheppo * stop negotiating. 38201ae08745Sheppo */ 3821*3af08d82Slm66018 DMSG(vdc, 0, "[%d] server could not register DRing\n", 3822*3af08d82Slm66018 vdc->instance); 38231ae08745Sheppo status = EPROTO; 38241ae08745Sheppo break; 38251ae08745Sheppo 38261ae08745Sheppo case VIO_SUBTYPE_INFO: 38271ae08745Sheppo /* 38281ae08745Sheppo * Handle the case where vds starts handshake 38291ae08745Sheppo * (for now only vdc is the instigatior) 38301ae08745Sheppo */ 38311ae08745Sheppo status = ENOTSUP; 38321ae08745Sheppo break; 38331ae08745Sheppo default: 38341ae08745Sheppo status = ENOTSUP; 38351ae08745Sheppo } 38361ae08745Sheppo 38371ae08745Sheppo return (status); 38381ae08745Sheppo } 38391ae08745Sheppo 38401ae08745Sheppo /* 38411ae08745Sheppo * Function: 38421ae08745Sheppo * vdc_verify_seq_num() 38431ae08745Sheppo * 38441ae08745Sheppo * Description: 3845e1ebb9ecSlm66018 * This functions verifies that the sequence number sent back by the vDisk 3846e1ebb9ecSlm66018 * server with the latest message is what is expected (i.e. it is greater 3847e1ebb9ecSlm66018 * than the last seq num sent by the vDisk server and less than or equal 3848e1ebb9ecSlm66018 * to the last seq num generated by vdc). 3849e1ebb9ecSlm66018 * 3850e1ebb9ecSlm66018 * It then checks the request ID to see if any requests need processing 3851e1ebb9ecSlm66018 * in the DRing. 38521ae08745Sheppo * 38531ae08745Sheppo * Arguments: 38541ae08745Sheppo * vdc - soft state pointer for this instance of the driver. 38551ae08745Sheppo * dring_msg - pointer to the LDC message sent by vds 38561ae08745Sheppo * 38571ae08745Sheppo * Return Code: 3858e1ebb9ecSlm66018 * VDC_SEQ_NUM_TODO - Message needs to be processed 3859e1ebb9ecSlm66018 * VDC_SEQ_NUM_SKIP - Message has already been processed 3860e1ebb9ecSlm66018 * VDC_SEQ_NUM_INVALID - The seq numbers are so out of sync, 3861e1ebb9ecSlm66018 * vdc cannot deal with them 38621ae08745Sheppo */ 3863e1ebb9ecSlm66018 static int 3864e1ebb9ecSlm66018 vdc_verify_seq_num(vdc_t *vdc, vio_dring_msg_t *dring_msg) 38651ae08745Sheppo { 38661ae08745Sheppo ASSERT(vdc != NULL); 38671ae08745Sheppo ASSERT(dring_msg != NULL); 3868d10e4ef2Snarayan ASSERT(mutex_owned(&vdc->lock)); 38691ae08745Sheppo 38701ae08745Sheppo /* 38711ae08745Sheppo * Check to see if the messages were responded to in the correct 3872e1ebb9ecSlm66018 * order by vds. 38731ae08745Sheppo */ 3874e1ebb9ecSlm66018 if ((dring_msg->seq_num <= vdc->seq_num_reply) || 3875e1ebb9ecSlm66018 (dring_msg->seq_num > vdc->seq_num)) { 3876*3af08d82Slm66018 DMSG(vdc, 0, "?[%d] Bogus sequence_number %lu: " 3877e1ebb9ecSlm66018 "%lu > expected <= %lu (last proc req %lu sent %lu)\n", 3878e1ebb9ecSlm66018 vdc->instance, dring_msg->seq_num, 3879e1ebb9ecSlm66018 vdc->seq_num_reply, vdc->seq_num, 3880e1ebb9ecSlm66018 vdc->req_id_proc, vdc->req_id); 3881e1ebb9ecSlm66018 return (VDC_SEQ_NUM_INVALID); 38821ae08745Sheppo } 3883e1ebb9ecSlm66018 vdc->seq_num_reply = dring_msg->seq_num; 38841ae08745Sheppo 3885e1ebb9ecSlm66018 if (vdc->req_id_proc < vdc->req_id) 3886e1ebb9ecSlm66018 return (VDC_SEQ_NUM_TODO); 3887e1ebb9ecSlm66018 else 3888e1ebb9ecSlm66018 return (VDC_SEQ_NUM_SKIP); 38891ae08745Sheppo } 38901ae08745Sheppo 38910a55fbb7Slm66018 38920a55fbb7Slm66018 /* 38930a55fbb7Slm66018 * Function: 38940a55fbb7Slm66018 * vdc_is_supported_version() 38950a55fbb7Slm66018 * 38960a55fbb7Slm66018 * Description: 38970a55fbb7Slm66018 * This routine checks if the major/minor version numbers specified in 38980a55fbb7Slm66018 * 'ver_msg' are supported. If not it finds the next version that is 38990a55fbb7Slm66018 * in the supported version list 'vdc_version[]' and sets the fields in 39000a55fbb7Slm66018 * 'ver_msg' to those values 39010a55fbb7Slm66018 * 39020a55fbb7Slm66018 * Arguments: 39030a55fbb7Slm66018 * ver_msg - LDC message sent by vDisk server 39040a55fbb7Slm66018 * 39050a55fbb7Slm66018 * Return Code: 39060a55fbb7Slm66018 * B_TRUE - Success 39070a55fbb7Slm66018 * B_FALSE - Version not supported 39080a55fbb7Slm66018 */ 39090a55fbb7Slm66018 static boolean_t 39100a55fbb7Slm66018 vdc_is_supported_version(vio_ver_msg_t *ver_msg) 39110a55fbb7Slm66018 { 39120a55fbb7Slm66018 int vdc_num_versions = sizeof (vdc_version) / sizeof (vdc_version[0]); 39130a55fbb7Slm66018 39140a55fbb7Slm66018 for (int i = 0; i < vdc_num_versions; i++) { 39150a55fbb7Slm66018 ASSERT(vdc_version[i].major > 0); 39160a55fbb7Slm66018 ASSERT((i == 0) || 39170a55fbb7Slm66018 (vdc_version[i].major < vdc_version[i-1].major)); 39180a55fbb7Slm66018 39190a55fbb7Slm66018 /* 39200a55fbb7Slm66018 * If the major versions match, adjust the minor version, if 39210a55fbb7Slm66018 * necessary, down to the highest value supported by this 39220a55fbb7Slm66018 * client. The server should support all minor versions lower 39230a55fbb7Slm66018 * than the value it sent 39240a55fbb7Slm66018 */ 39250a55fbb7Slm66018 if (ver_msg->ver_major == vdc_version[i].major) { 39260a55fbb7Slm66018 if (ver_msg->ver_minor > vdc_version[i].minor) { 3927*3af08d82Slm66018 DMSGX(0, 3928*3af08d82Slm66018 "Adjusting minor version from %u to %u", 39290a55fbb7Slm66018 ver_msg->ver_minor, vdc_version[i].minor); 39300a55fbb7Slm66018 ver_msg->ver_minor = vdc_version[i].minor; 39310a55fbb7Slm66018 } 39320a55fbb7Slm66018 return (B_TRUE); 39330a55fbb7Slm66018 } 39340a55fbb7Slm66018 39350a55fbb7Slm66018 /* 39360a55fbb7Slm66018 * If the message contains a higher major version number, set 39370a55fbb7Slm66018 * the message's major/minor versions to the current values 39380a55fbb7Slm66018 * and return false, so this message will get resent with 39390a55fbb7Slm66018 * these values, and the server will potentially try again 39400a55fbb7Slm66018 * with the same or a lower version 39410a55fbb7Slm66018 */ 39420a55fbb7Slm66018 if (ver_msg->ver_major > vdc_version[i].major) { 39430a55fbb7Slm66018 ver_msg->ver_major = vdc_version[i].major; 39440a55fbb7Slm66018 ver_msg->ver_minor = vdc_version[i].minor; 3945*3af08d82Slm66018 DMSGX(0, "Suggesting major/minor (0x%x/0x%x)\n", 39460a55fbb7Slm66018 ver_msg->ver_major, ver_msg->ver_minor); 39470a55fbb7Slm66018 39480a55fbb7Slm66018 return (B_FALSE); 39490a55fbb7Slm66018 } 39500a55fbb7Slm66018 39510a55fbb7Slm66018 /* 39520a55fbb7Slm66018 * Otherwise, the message's major version is less than the 39530a55fbb7Slm66018 * current major version, so continue the loop to the next 39540a55fbb7Slm66018 * (lower) supported version 39550a55fbb7Slm66018 */ 39560a55fbb7Slm66018 } 39570a55fbb7Slm66018 39580a55fbb7Slm66018 /* 39590a55fbb7Slm66018 * No common version was found; "ground" the version pair in the 39600a55fbb7Slm66018 * message to terminate negotiation 39610a55fbb7Slm66018 */ 39620a55fbb7Slm66018 ver_msg->ver_major = 0; 39630a55fbb7Slm66018 ver_msg->ver_minor = 0; 39640a55fbb7Slm66018 39650a55fbb7Slm66018 return (B_FALSE); 39660a55fbb7Slm66018 } 39671ae08745Sheppo /* -------------------------------------------------------------------------- */ 39681ae08745Sheppo 39691ae08745Sheppo /* 39701ae08745Sheppo * DKIO(7) support 39711ae08745Sheppo */ 39721ae08745Sheppo 39731ae08745Sheppo typedef struct vdc_dk_arg { 39741ae08745Sheppo struct dk_callback dkc; 39751ae08745Sheppo int mode; 39761ae08745Sheppo dev_t dev; 39771ae08745Sheppo vdc_t *vdc; 39781ae08745Sheppo } vdc_dk_arg_t; 39791ae08745Sheppo 39801ae08745Sheppo /* 39811ae08745Sheppo * Function: 39821ae08745Sheppo * vdc_dkio_flush_cb() 39831ae08745Sheppo * 39841ae08745Sheppo * Description: 39851ae08745Sheppo * This routine is a callback for DKIOCFLUSHWRITECACHE which can be called 39861ae08745Sheppo * by kernel code. 39871ae08745Sheppo * 39881ae08745Sheppo * Arguments: 39891ae08745Sheppo * arg - a pointer to a vdc_dk_arg_t structure. 39901ae08745Sheppo */ 39911ae08745Sheppo void 39921ae08745Sheppo vdc_dkio_flush_cb(void *arg) 39931ae08745Sheppo { 39941ae08745Sheppo struct vdc_dk_arg *dk_arg = (struct vdc_dk_arg *)arg; 39951ae08745Sheppo struct dk_callback *dkc = NULL; 39961ae08745Sheppo vdc_t *vdc = NULL; 39971ae08745Sheppo int rv; 39981ae08745Sheppo 39991ae08745Sheppo if (dk_arg == NULL) { 4000*3af08d82Slm66018 cmn_err(CE_NOTE, "?[Unk] DKIOCFLUSHWRITECACHE arg is NULL\n"); 40011ae08745Sheppo return; 40021ae08745Sheppo } 40031ae08745Sheppo dkc = &dk_arg->dkc; 40041ae08745Sheppo vdc = dk_arg->vdc; 40051ae08745Sheppo ASSERT(vdc != NULL); 40061ae08745Sheppo 4007*3af08d82Slm66018 rv = vdc_do_sync_op(vdc, VD_OP_FLUSH, NULL, 0, 4008*3af08d82Slm66018 SDPART(dk_arg->dev), 0, CB_SYNC, 0, VIO_both_dir); 40091ae08745Sheppo if (rv != 0) { 4010*3af08d82Slm66018 DMSG(vdc, 0, "[%d] DKIOCFLUSHWRITECACHE failed %d : model %x\n", 4011e1ebb9ecSlm66018 vdc->instance, rv, 40121ae08745Sheppo ddi_model_convert_from(dk_arg->mode & FMODELS)); 40131ae08745Sheppo } 40141ae08745Sheppo 40151ae08745Sheppo /* 40161ae08745Sheppo * Trigger the call back to notify the caller the the ioctl call has 40171ae08745Sheppo * been completed. 40181ae08745Sheppo */ 40191ae08745Sheppo if ((dk_arg->mode & FKIOCTL) && 40201ae08745Sheppo (dkc != NULL) && 40211ae08745Sheppo (dkc->dkc_callback != NULL)) { 40221ae08745Sheppo ASSERT(dkc->dkc_cookie != NULL); 40238e6a2a04Slm66018 (*dkc->dkc_callback)(dkc->dkc_cookie, rv); 40241ae08745Sheppo } 40251ae08745Sheppo 40261ae08745Sheppo /* Indicate that one less DKIO write flush is outstanding */ 40271ae08745Sheppo mutex_enter(&vdc->lock); 40281ae08745Sheppo vdc->dkio_flush_pending--; 40291ae08745Sheppo ASSERT(vdc->dkio_flush_pending >= 0); 40301ae08745Sheppo mutex_exit(&vdc->lock); 40318e6a2a04Slm66018 40328e6a2a04Slm66018 /* free the mem that was allocated when the callback was dispatched */ 40338e6a2a04Slm66018 kmem_free(arg, sizeof (vdc_dk_arg_t)); 40341ae08745Sheppo } 40351ae08745Sheppo 40361ae08745Sheppo /* 40371ae08745Sheppo * This structure is used in the DKIO(7I) array below. 40381ae08745Sheppo */ 40391ae08745Sheppo typedef struct vdc_dk_ioctl { 40401ae08745Sheppo uint8_t op; /* VD_OP_XXX value */ 40411ae08745Sheppo int cmd; /* Solaris ioctl operation number */ 40421ae08745Sheppo size_t nbytes; /* size of structure to be copied */ 40430a55fbb7Slm66018 40440a55fbb7Slm66018 /* function to convert between vDisk and Solaris structure formats */ 4045d10e4ef2Snarayan int (*convert)(vdc_t *vdc, void *vd_buf, void *ioctl_arg, 4046d10e4ef2Snarayan int mode, int dir); 40471ae08745Sheppo } vdc_dk_ioctl_t; 40481ae08745Sheppo 40491ae08745Sheppo /* 40501ae08745Sheppo * Subset of DKIO(7I) operations currently supported 40511ae08745Sheppo */ 40521ae08745Sheppo static vdc_dk_ioctl_t dk_ioctl[] = { 40530a55fbb7Slm66018 {VD_OP_FLUSH, DKIOCFLUSHWRITECACHE, sizeof (int), 40540a55fbb7Slm66018 vdc_null_copy_func}, 40550a55fbb7Slm66018 {VD_OP_GET_WCE, DKIOCGETWCE, sizeof (int), 40564bac2208Snarayan vdc_get_wce_convert}, 40570a55fbb7Slm66018 {VD_OP_SET_WCE, DKIOCSETWCE, sizeof (int), 40584bac2208Snarayan vdc_set_wce_convert}, 40590a55fbb7Slm66018 {VD_OP_GET_VTOC, DKIOCGVTOC, sizeof (vd_vtoc_t), 40600a55fbb7Slm66018 vdc_get_vtoc_convert}, 40610a55fbb7Slm66018 {VD_OP_SET_VTOC, DKIOCSVTOC, sizeof (vd_vtoc_t), 40620a55fbb7Slm66018 vdc_set_vtoc_convert}, 40630a55fbb7Slm66018 {VD_OP_GET_DISKGEOM, DKIOCGGEOM, sizeof (vd_geom_t), 40640a55fbb7Slm66018 vdc_get_geom_convert}, 40650a55fbb7Slm66018 {VD_OP_GET_DISKGEOM, DKIOCG_PHYGEOM, sizeof (vd_geom_t), 40660a55fbb7Slm66018 vdc_get_geom_convert}, 40670a55fbb7Slm66018 {VD_OP_GET_DISKGEOM, DKIOCG_VIRTGEOM, sizeof (vd_geom_t), 40680a55fbb7Slm66018 vdc_get_geom_convert}, 40690a55fbb7Slm66018 {VD_OP_SET_DISKGEOM, DKIOCSGEOM, sizeof (vd_geom_t), 40700a55fbb7Slm66018 vdc_set_geom_convert}, 40714bac2208Snarayan {VD_OP_GET_EFI, DKIOCGETEFI, 0, 40724bac2208Snarayan vdc_get_efi_convert}, 40734bac2208Snarayan {VD_OP_SET_EFI, DKIOCSETEFI, 0, 40744bac2208Snarayan vdc_set_efi_convert}, 40750a55fbb7Slm66018 40760a55fbb7Slm66018 /* 40770a55fbb7Slm66018 * These particular ioctls are not sent to the server - vdc fakes up 40780a55fbb7Slm66018 * the necessary info. 40790a55fbb7Slm66018 */ 40800a55fbb7Slm66018 {0, DKIOCINFO, sizeof (struct dk_cinfo), vdc_null_copy_func}, 40810a55fbb7Slm66018 {0, DKIOCGMEDIAINFO, sizeof (struct dk_minfo), vdc_null_copy_func}, 40820a55fbb7Slm66018 {0, USCSICMD, sizeof (struct uscsi_cmd), vdc_null_copy_func}, 40830a55fbb7Slm66018 {0, DKIOCREMOVABLE, 0, vdc_null_copy_func}, 40840a55fbb7Slm66018 {0, CDROMREADOFFSET, 0, vdc_null_copy_func} 40851ae08745Sheppo }; 40861ae08745Sheppo 40871ae08745Sheppo /* 40881ae08745Sheppo * Function: 40891ae08745Sheppo * vd_process_ioctl() 40901ae08745Sheppo * 40911ae08745Sheppo * Description: 40920a55fbb7Slm66018 * This routine processes disk specific ioctl calls 40931ae08745Sheppo * 40941ae08745Sheppo * Arguments: 40951ae08745Sheppo * dev - the device number 40961ae08745Sheppo * cmd - the operation [dkio(7I)] to be processed 40971ae08745Sheppo * arg - pointer to user provided structure 40981ae08745Sheppo * (contains data to be set or reference parameter for get) 40991ae08745Sheppo * mode - bit flag, indicating open settings, 32/64 bit type, etc 41001ae08745Sheppo * 41011ae08745Sheppo * Return Code: 41021ae08745Sheppo * 0 41031ae08745Sheppo * EFAULT 41041ae08745Sheppo * ENXIO 41051ae08745Sheppo * EIO 41061ae08745Sheppo * ENOTSUP 41071ae08745Sheppo */ 41081ae08745Sheppo static int 41091ae08745Sheppo vd_process_ioctl(dev_t dev, int cmd, caddr_t arg, int mode) 41101ae08745Sheppo { 4111*3af08d82Slm66018 int instance = SDUNIT(dev); 41121ae08745Sheppo vdc_t *vdc = NULL; 41131ae08745Sheppo int rv = -1; 41141ae08745Sheppo int idx = 0; /* index into dk_ioctl[] */ 41151ae08745Sheppo size_t len = 0; /* #bytes to send to vds */ 41161ae08745Sheppo size_t alloc_len = 0; /* #bytes to allocate mem for */ 41171ae08745Sheppo caddr_t mem_p = NULL; 41181ae08745Sheppo size_t nioctls = (sizeof (dk_ioctl)) / (sizeof (dk_ioctl[0])); 4119d10e4ef2Snarayan struct vtoc vtoc_saved; 4120*3af08d82Slm66018 vdc_dk_ioctl_t *iop; 41211ae08745Sheppo 41221ae08745Sheppo vdc = ddi_get_soft_state(vdc_state, instance); 41231ae08745Sheppo if (vdc == NULL) { 41241ae08745Sheppo cmn_err(CE_NOTE, "![%d] Could not get soft state structure", 41251ae08745Sheppo instance); 41261ae08745Sheppo return (ENXIO); 41271ae08745Sheppo } 41281ae08745Sheppo 4129*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Processing ioctl(%x) for dev %lx : model %x\n", 4130*3af08d82Slm66018 instance, cmd, dev, ddi_model_convert_from(mode & FMODELS)); 41311ae08745Sheppo 41321ae08745Sheppo /* 41331ae08745Sheppo * Validate the ioctl operation to be performed. 41341ae08745Sheppo * 41351ae08745Sheppo * If we have looped through the array without finding a match then we 41361ae08745Sheppo * don't support this ioctl. 41371ae08745Sheppo */ 41381ae08745Sheppo for (idx = 0; idx < nioctls; idx++) { 41391ae08745Sheppo if (cmd == dk_ioctl[idx].cmd) 41401ae08745Sheppo break; 41411ae08745Sheppo } 41421ae08745Sheppo 41431ae08745Sheppo if (idx >= nioctls) { 4144*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Unsupported ioctl (0x%x)\n", 4145e1ebb9ecSlm66018 vdc->instance, cmd); 41461ae08745Sheppo return (ENOTSUP); 41471ae08745Sheppo } 41481ae08745Sheppo 4149*3af08d82Slm66018 iop = &(dk_ioctl[idx]); 4150*3af08d82Slm66018 41514bac2208Snarayan if (cmd == DKIOCGETEFI || cmd == DKIOCSETEFI) { 41524bac2208Snarayan /* size is not fixed for EFI ioctls, it depends on ioctl arg */ 41534bac2208Snarayan dk_efi_t dk_efi; 41544bac2208Snarayan 41554bac2208Snarayan rv = ddi_copyin(arg, &dk_efi, sizeof (dk_efi_t), mode); 41564bac2208Snarayan if (rv != 0) 41574bac2208Snarayan return (EFAULT); 41584bac2208Snarayan 41594bac2208Snarayan len = sizeof (vd_efi_t) - 1 + dk_efi.dki_length; 41604bac2208Snarayan } else { 4161*3af08d82Slm66018 len = iop->nbytes; 41624bac2208Snarayan } 41631ae08745Sheppo 41641ae08745Sheppo /* 41650a55fbb7Slm66018 * Deal with the ioctls which the server does not provide. vdc can 41660a55fbb7Slm66018 * fake these up and return immediately 41671ae08745Sheppo */ 41681ae08745Sheppo switch (cmd) { 41691ae08745Sheppo case CDROMREADOFFSET: 41701ae08745Sheppo case DKIOCREMOVABLE: 41710a55fbb7Slm66018 case USCSICMD: 41721ae08745Sheppo return (ENOTTY); 41731ae08745Sheppo 41741ae08745Sheppo case DKIOCINFO: 41751ae08745Sheppo { 41761ae08745Sheppo struct dk_cinfo cinfo; 41771ae08745Sheppo if (vdc->cinfo == NULL) 41781ae08745Sheppo return (ENXIO); 41791ae08745Sheppo 41801ae08745Sheppo bcopy(vdc->cinfo, &cinfo, sizeof (struct dk_cinfo)); 4181*3af08d82Slm66018 cinfo.dki_partition = SDPART(dev); 41821ae08745Sheppo 41831ae08745Sheppo rv = ddi_copyout(&cinfo, (void *)arg, 41841ae08745Sheppo sizeof (struct dk_cinfo), mode); 41851ae08745Sheppo if (rv != 0) 41861ae08745Sheppo return (EFAULT); 41871ae08745Sheppo 41881ae08745Sheppo return (0); 41891ae08745Sheppo } 41901ae08745Sheppo 41911ae08745Sheppo case DKIOCGMEDIAINFO: 41928e6a2a04Slm66018 { 41931ae08745Sheppo if (vdc->minfo == NULL) 41941ae08745Sheppo return (ENXIO); 41951ae08745Sheppo 41961ae08745Sheppo rv = ddi_copyout(vdc->minfo, (void *)arg, 41971ae08745Sheppo sizeof (struct dk_minfo), mode); 41981ae08745Sheppo if (rv != 0) 41991ae08745Sheppo return (EFAULT); 42001ae08745Sheppo 42011ae08745Sheppo return (0); 42021ae08745Sheppo } 42031ae08745Sheppo 42048e6a2a04Slm66018 case DKIOCFLUSHWRITECACHE: 42058e6a2a04Slm66018 { 42068e6a2a04Slm66018 struct dk_callback *dkc = (struct dk_callback *)arg; 42078e6a2a04Slm66018 vdc_dk_arg_t *dkarg = NULL; 42088e6a2a04Slm66018 4209*3af08d82Slm66018 DMSG(vdc, 1, "[%d] Flush W$: mode %x\n", 4210*3af08d82Slm66018 instance, mode); 42118e6a2a04Slm66018 42128e6a2a04Slm66018 /* 42138e6a2a04Slm66018 * If the backing device is not a 'real' disk then the 42148e6a2a04Slm66018 * W$ operation request to the vDisk server will fail 42158e6a2a04Slm66018 * so we might as well save the cycles and return now. 42168e6a2a04Slm66018 */ 42178e6a2a04Slm66018 if (vdc->vdisk_type != VD_DISK_TYPE_DISK) 42188e6a2a04Slm66018 return (ENOTTY); 42198e6a2a04Slm66018 42208e6a2a04Slm66018 /* 42218e6a2a04Slm66018 * If arg is NULL, then there is no callback function 42228e6a2a04Slm66018 * registered and the call operates synchronously; we 42238e6a2a04Slm66018 * break and continue with the rest of the function and 42248e6a2a04Slm66018 * wait for vds to return (i.e. after the request to 42258e6a2a04Slm66018 * vds returns successfully, all writes completed prior 42268e6a2a04Slm66018 * to the ioctl will have been flushed from the disk 42278e6a2a04Slm66018 * write cache to persistent media. 42288e6a2a04Slm66018 * 42298e6a2a04Slm66018 * If a callback function is registered, we dispatch 42308e6a2a04Slm66018 * the request on a task queue and return immediately. 42318e6a2a04Slm66018 * The callback will deal with informing the calling 42328e6a2a04Slm66018 * thread that the flush request is completed. 42338e6a2a04Slm66018 */ 42348e6a2a04Slm66018 if (dkc == NULL) 42358e6a2a04Slm66018 break; 42368e6a2a04Slm66018 42378e6a2a04Slm66018 dkarg = kmem_zalloc(sizeof (vdc_dk_arg_t), KM_SLEEP); 42388e6a2a04Slm66018 42398e6a2a04Slm66018 dkarg->mode = mode; 42408e6a2a04Slm66018 dkarg->dev = dev; 42418e6a2a04Slm66018 bcopy(dkc, &dkarg->dkc, sizeof (*dkc)); 42428e6a2a04Slm66018 42438e6a2a04Slm66018 mutex_enter(&vdc->lock); 42448e6a2a04Slm66018 vdc->dkio_flush_pending++; 42458e6a2a04Slm66018 dkarg->vdc = vdc; 42468e6a2a04Slm66018 mutex_exit(&vdc->lock); 42478e6a2a04Slm66018 42488e6a2a04Slm66018 /* put the request on a task queue */ 42498e6a2a04Slm66018 rv = taskq_dispatch(system_taskq, vdc_dkio_flush_cb, 42508e6a2a04Slm66018 (void *)dkarg, DDI_SLEEP); 4251*3af08d82Slm66018 if (rv == NULL) { 4252*3af08d82Slm66018 /* clean up if dispatch fails */ 4253*3af08d82Slm66018 mutex_enter(&vdc->lock); 4254*3af08d82Slm66018 vdc->dkio_flush_pending--; 4255*3af08d82Slm66018 kmem_free(dkarg, sizeof (vdc_dk_arg_t)); 4256*3af08d82Slm66018 } 42578e6a2a04Slm66018 42588e6a2a04Slm66018 return (rv == NULL ? ENOMEM : 0); 42598e6a2a04Slm66018 } 42608e6a2a04Slm66018 } 42618e6a2a04Slm66018 42621ae08745Sheppo /* catch programming error in vdc - should be a VD_OP_XXX ioctl */ 4263*3af08d82Slm66018 ASSERT(iop->op != 0); 42641ae08745Sheppo 42651ae08745Sheppo /* LDC requires that the memory being mapped is 8-byte aligned */ 42661ae08745Sheppo alloc_len = P2ROUNDUP(len, sizeof (uint64_t)); 4267*3af08d82Slm66018 DMSG(vdc, 1, "[%d] struct size %ld alloc %ld\n", 4268*3af08d82Slm66018 instance, len, alloc_len); 42691ae08745Sheppo 42700a55fbb7Slm66018 ASSERT(alloc_len != 0); /* sanity check */ 42711ae08745Sheppo mem_p = kmem_zalloc(alloc_len, KM_SLEEP); 42721ae08745Sheppo 4273d10e4ef2Snarayan if (cmd == DKIOCSVTOC) { 4274d10e4ef2Snarayan /* 4275d10e4ef2Snarayan * Save a copy of the current VTOC so that we can roll back 4276d10e4ef2Snarayan * if the setting of the new VTOC fails. 4277d10e4ef2Snarayan */ 4278d10e4ef2Snarayan bcopy(vdc->vtoc, &vtoc_saved, sizeof (struct vtoc)); 4279d10e4ef2Snarayan } 4280d10e4ef2Snarayan 42810a55fbb7Slm66018 /* 42820a55fbb7Slm66018 * Call the conversion function for this ioctl whhich if necessary 42830a55fbb7Slm66018 * converts from the Solaris format to the format ARC'ed 42840a55fbb7Slm66018 * as part of the vDisk protocol (FWARC 2006/195) 42850a55fbb7Slm66018 */ 4286*3af08d82Slm66018 ASSERT(iop->convert != NULL); 4287*3af08d82Slm66018 rv = (iop->convert)(vdc, arg, mem_p, mode, VD_COPYIN); 42881ae08745Sheppo if (rv != 0) { 4289*3af08d82Slm66018 DMSG(vdc, 0, "[%d] convert func returned %d for ioctl 0x%x\n", 4290e1ebb9ecSlm66018 instance, rv, cmd); 42911ae08745Sheppo if (mem_p != NULL) 42921ae08745Sheppo kmem_free(mem_p, alloc_len); 42930a55fbb7Slm66018 return (rv); 42941ae08745Sheppo } 42951ae08745Sheppo 42961ae08745Sheppo /* 42971ae08745Sheppo * send request to vds to service the ioctl. 42981ae08745Sheppo */ 4299*3af08d82Slm66018 rv = vdc_do_sync_op(vdc, iop->op, mem_p, alloc_len, 4300*3af08d82Slm66018 SDPART(dev), 0, CB_SYNC, (void*)(uint64_t)mode, 4301*3af08d82Slm66018 VIO_both_dir); 4302*3af08d82Slm66018 43031ae08745Sheppo if (rv != 0) { 43041ae08745Sheppo /* 43051ae08745Sheppo * This is not necessarily an error. The ioctl could 43061ae08745Sheppo * be returning a value such as ENOTTY to indicate 43071ae08745Sheppo * that the ioctl is not applicable. 43081ae08745Sheppo */ 4309*3af08d82Slm66018 DMSG(vdc, 0, "[%d] vds returned %d for ioctl 0x%x\n", 4310e1ebb9ecSlm66018 instance, rv, cmd); 43111ae08745Sheppo if (mem_p != NULL) 43121ae08745Sheppo kmem_free(mem_p, alloc_len); 4313d10e4ef2Snarayan 4314d10e4ef2Snarayan if (cmd == DKIOCSVTOC) { 4315d10e4ef2Snarayan /* update of the VTOC has failed, roll back */ 4316d10e4ef2Snarayan bcopy(&vtoc_saved, vdc->vtoc, sizeof (struct vtoc)); 4317d10e4ef2Snarayan } 4318d10e4ef2Snarayan 43191ae08745Sheppo return (rv); 43201ae08745Sheppo } 43211ae08745Sheppo 43221ae08745Sheppo if (cmd == DKIOCSVTOC) { 4323d10e4ef2Snarayan /* 43244bac2208Snarayan * The VTOC has been changed. We need to update the device 43254bac2208Snarayan * nodes to handle the case where an EFI label has been 43264bac2208Snarayan * changed to a VTOC label. We also try and update the device 4327d10e4ef2Snarayan * node properties. Failing to set the properties should 4328d10e4ef2Snarayan * not cause an error to be return the caller though. 4329d10e4ef2Snarayan */ 43304bac2208Snarayan vdc->vdisk_label = VD_DISK_LABEL_VTOC; 43314bac2208Snarayan (void) vdc_create_device_nodes_vtoc(vdc); 43324bac2208Snarayan 43331ae08745Sheppo if (vdc_create_device_nodes_props(vdc)) { 4334*3af08d82Slm66018 DMSG(vdc, 0, "![%d] Failed to update device nodes" 4335d10e4ef2Snarayan " properties", vdc->instance); 43361ae08745Sheppo } 43374bac2208Snarayan 43384bac2208Snarayan } else if (cmd == DKIOCSETEFI) { 43394bac2208Snarayan /* 43404bac2208Snarayan * The EFI has been changed. We need to update the device 43414bac2208Snarayan * nodes to handle the case where a VTOC label has been 43424bac2208Snarayan * changed to an EFI label. We also try and update the device 43434bac2208Snarayan * node properties. Failing to set the properties should 43444bac2208Snarayan * not cause an error to be return the caller though. 43454bac2208Snarayan */ 43464bac2208Snarayan struct dk_gpt *efi; 43474bac2208Snarayan size_t efi_len; 43484bac2208Snarayan 43494bac2208Snarayan vdc->vdisk_label = VD_DISK_LABEL_EFI; 43504bac2208Snarayan (void) vdc_create_device_nodes_efi(vdc); 43514bac2208Snarayan 43524bac2208Snarayan rv = vdc_efi_alloc_and_read(dev, &efi, &efi_len); 43534bac2208Snarayan 43544bac2208Snarayan if (rv == 0) { 43554bac2208Snarayan vdc_store_efi(vdc, efi); 43564bac2208Snarayan rv = vdc_create_device_nodes_props(vdc); 43574bac2208Snarayan vd_efi_free(efi, efi_len); 43584bac2208Snarayan } 43594bac2208Snarayan 43604bac2208Snarayan if (rv) { 4361*3af08d82Slm66018 DMSG(vdc, 0, "![%d] Failed to update device nodes" 43624bac2208Snarayan " properties", vdc->instance); 43634bac2208Snarayan } 43641ae08745Sheppo } 43651ae08745Sheppo 43661ae08745Sheppo /* 43670a55fbb7Slm66018 * Call the conversion function (if it exists) for this ioctl 43680a55fbb7Slm66018 * which converts from the format ARC'ed as part of the vDisk 43690a55fbb7Slm66018 * protocol (FWARC 2006/195) back to a format understood by 43700a55fbb7Slm66018 * the rest of Solaris. 43711ae08745Sheppo */ 4372*3af08d82Slm66018 rv = (iop->convert)(vdc, mem_p, arg, mode, VD_COPYOUT); 43730a55fbb7Slm66018 if (rv != 0) { 4374*3af08d82Slm66018 DMSG(vdc, 0, "[%d] convert func returned %d for ioctl 0x%x\n", 4375e1ebb9ecSlm66018 instance, rv, cmd); 43761ae08745Sheppo if (mem_p != NULL) 43771ae08745Sheppo kmem_free(mem_p, alloc_len); 43780a55fbb7Slm66018 return (rv); 43791ae08745Sheppo } 43801ae08745Sheppo 43811ae08745Sheppo if (mem_p != NULL) 43821ae08745Sheppo kmem_free(mem_p, alloc_len); 43831ae08745Sheppo 43841ae08745Sheppo return (rv); 43851ae08745Sheppo } 43861ae08745Sheppo 43871ae08745Sheppo /* 43881ae08745Sheppo * Function: 43890a55fbb7Slm66018 * 43900a55fbb7Slm66018 * Description: 43910a55fbb7Slm66018 * This is an empty conversion function used by ioctl calls which 43920a55fbb7Slm66018 * do not need to convert the data being passed in/out to userland 43930a55fbb7Slm66018 */ 43940a55fbb7Slm66018 static int 4395d10e4ef2Snarayan vdc_null_copy_func(vdc_t *vdc, void *from, void *to, int mode, int dir) 43960a55fbb7Slm66018 { 4397d10e4ef2Snarayan _NOTE(ARGUNUSED(vdc)) 43980a55fbb7Slm66018 _NOTE(ARGUNUSED(from)) 43990a55fbb7Slm66018 _NOTE(ARGUNUSED(to)) 44000a55fbb7Slm66018 _NOTE(ARGUNUSED(mode)) 44010a55fbb7Slm66018 _NOTE(ARGUNUSED(dir)) 44020a55fbb7Slm66018 44030a55fbb7Slm66018 return (0); 44040a55fbb7Slm66018 } 44050a55fbb7Slm66018 44064bac2208Snarayan static int 44074bac2208Snarayan vdc_get_wce_convert(vdc_t *vdc, void *from, void *to, 44084bac2208Snarayan int mode, int dir) 44094bac2208Snarayan { 44104bac2208Snarayan _NOTE(ARGUNUSED(vdc)) 44114bac2208Snarayan 44124bac2208Snarayan if (dir == VD_COPYIN) 44134bac2208Snarayan return (0); /* nothing to do */ 44144bac2208Snarayan 44154bac2208Snarayan if (ddi_copyout(from, to, sizeof (int), mode) != 0) 44164bac2208Snarayan return (EFAULT); 44174bac2208Snarayan 44184bac2208Snarayan return (0); 44194bac2208Snarayan } 44204bac2208Snarayan 44214bac2208Snarayan static int 44224bac2208Snarayan vdc_set_wce_convert(vdc_t *vdc, void *from, void *to, 44234bac2208Snarayan int mode, int dir) 44244bac2208Snarayan { 44254bac2208Snarayan _NOTE(ARGUNUSED(vdc)) 44264bac2208Snarayan 44274bac2208Snarayan if (dir == VD_COPYOUT) 44284bac2208Snarayan return (0); /* nothing to do */ 44294bac2208Snarayan 44304bac2208Snarayan if (ddi_copyin(from, to, sizeof (int), mode) != 0) 44314bac2208Snarayan return (EFAULT); 44324bac2208Snarayan 44334bac2208Snarayan return (0); 44344bac2208Snarayan } 44354bac2208Snarayan 44360a55fbb7Slm66018 /* 44370a55fbb7Slm66018 * Function: 44380a55fbb7Slm66018 * vdc_get_vtoc_convert() 44390a55fbb7Slm66018 * 44400a55fbb7Slm66018 * Description: 4441d10e4ef2Snarayan * This routine performs the necessary convertions from the DKIOCGVTOC 4442d10e4ef2Snarayan * Solaris structure to the format defined in FWARC 2006/195. 4443d10e4ef2Snarayan * 4444d10e4ef2Snarayan * In the struct vtoc definition, the timestamp field is marked as not 4445d10e4ef2Snarayan * supported so it is not part of vDisk protocol (FWARC 2006/195). 4446d10e4ef2Snarayan * However SVM uses that field to check it can write into the VTOC, 4447d10e4ef2Snarayan * so we fake up the info of that field. 44480a55fbb7Slm66018 * 44490a55fbb7Slm66018 * Arguments: 4450d10e4ef2Snarayan * vdc - the vDisk client 44510a55fbb7Slm66018 * from - the buffer containing the data to be copied from 44520a55fbb7Slm66018 * to - the buffer to be copied to 44530a55fbb7Slm66018 * mode - flags passed to ioctl() call 44540a55fbb7Slm66018 * dir - the "direction" of the copy - VD_COPYIN or VD_COPYOUT 44550a55fbb7Slm66018 * 44560a55fbb7Slm66018 * Return Code: 44570a55fbb7Slm66018 * 0 - Success 44580a55fbb7Slm66018 * ENXIO - incorrect buffer passed in. 4459d10e4ef2Snarayan * EFAULT - ddi_copyout routine encountered an error. 44600a55fbb7Slm66018 */ 44610a55fbb7Slm66018 static int 4462d10e4ef2Snarayan vdc_get_vtoc_convert(vdc_t *vdc, void *from, void *to, int mode, int dir) 44630a55fbb7Slm66018 { 4464d10e4ef2Snarayan int i; 44650a55fbb7Slm66018 void *tmp_mem = NULL; 44660a55fbb7Slm66018 void *tmp_memp; 44670a55fbb7Slm66018 struct vtoc vt; 44680a55fbb7Slm66018 struct vtoc32 vt32; 44690a55fbb7Slm66018 int copy_len = 0; 44700a55fbb7Slm66018 int rv = 0; 44710a55fbb7Slm66018 44720a55fbb7Slm66018 if (dir != VD_COPYOUT) 44730a55fbb7Slm66018 return (0); /* nothing to do */ 44740a55fbb7Slm66018 44750a55fbb7Slm66018 if ((from == NULL) || (to == NULL)) 44760a55fbb7Slm66018 return (ENXIO); 44770a55fbb7Slm66018 44780a55fbb7Slm66018 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) 44790a55fbb7Slm66018 copy_len = sizeof (struct vtoc32); 44800a55fbb7Slm66018 else 44810a55fbb7Slm66018 copy_len = sizeof (struct vtoc); 44820a55fbb7Slm66018 44830a55fbb7Slm66018 tmp_mem = kmem_alloc(copy_len, KM_SLEEP); 44840a55fbb7Slm66018 44850a55fbb7Slm66018 VD_VTOC2VTOC((vd_vtoc_t *)from, &vt); 4486d10e4ef2Snarayan 4487d10e4ef2Snarayan /* fake the VTOC timestamp field */ 4488d10e4ef2Snarayan for (i = 0; i < V_NUMPAR; i++) { 4489d10e4ef2Snarayan vt.timestamp[i] = vdc->vtoc->timestamp[i]; 4490d10e4ef2Snarayan } 4491d10e4ef2Snarayan 44920a55fbb7Slm66018 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 44930a55fbb7Slm66018 vtoctovtoc32(vt, vt32); 44940a55fbb7Slm66018 tmp_memp = &vt32; 44950a55fbb7Slm66018 } else { 44960a55fbb7Slm66018 tmp_memp = &vt; 44970a55fbb7Slm66018 } 44980a55fbb7Slm66018 rv = ddi_copyout(tmp_memp, to, copy_len, mode); 44990a55fbb7Slm66018 if (rv != 0) 45000a55fbb7Slm66018 rv = EFAULT; 45010a55fbb7Slm66018 45020a55fbb7Slm66018 kmem_free(tmp_mem, copy_len); 45030a55fbb7Slm66018 return (rv); 45040a55fbb7Slm66018 } 45050a55fbb7Slm66018 45060a55fbb7Slm66018 /* 45070a55fbb7Slm66018 * Function: 45080a55fbb7Slm66018 * vdc_set_vtoc_convert() 45090a55fbb7Slm66018 * 45100a55fbb7Slm66018 * Description: 4511d10e4ef2Snarayan * This routine performs the necessary convertions from the DKIOCSVTOC 4512d10e4ef2Snarayan * Solaris structure to the format defined in FWARC 2006/195. 45130a55fbb7Slm66018 * 45140a55fbb7Slm66018 * Arguments: 4515d10e4ef2Snarayan * vdc - the vDisk client 45160a55fbb7Slm66018 * from - Buffer with data 45170a55fbb7Slm66018 * to - Buffer where data is to be copied to 45180a55fbb7Slm66018 * mode - flags passed to ioctl 45190a55fbb7Slm66018 * dir - direction of copy (in or out) 45200a55fbb7Slm66018 * 45210a55fbb7Slm66018 * Return Code: 45220a55fbb7Slm66018 * 0 - Success 45230a55fbb7Slm66018 * ENXIO - Invalid buffer passed in 45240a55fbb7Slm66018 * EFAULT - ddi_copyin of data failed 45250a55fbb7Slm66018 */ 45260a55fbb7Slm66018 static int 4527d10e4ef2Snarayan vdc_set_vtoc_convert(vdc_t *vdc, void *from, void *to, int mode, int dir) 45280a55fbb7Slm66018 { 45290a55fbb7Slm66018 void *tmp_mem = NULL; 45300a55fbb7Slm66018 struct vtoc vt; 45310a55fbb7Slm66018 struct vtoc *vtp = &vt; 45320a55fbb7Slm66018 vd_vtoc_t vtvd; 45330a55fbb7Slm66018 int copy_len = 0; 45340a55fbb7Slm66018 int rv = 0; 45350a55fbb7Slm66018 45360a55fbb7Slm66018 if (dir != VD_COPYIN) 45370a55fbb7Slm66018 return (0); /* nothing to do */ 45380a55fbb7Slm66018 45390a55fbb7Slm66018 if ((from == NULL) || (to == NULL)) 45400a55fbb7Slm66018 return (ENXIO); 45410a55fbb7Slm66018 45420a55fbb7Slm66018 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) 45430a55fbb7Slm66018 copy_len = sizeof (struct vtoc32); 45440a55fbb7Slm66018 else 45450a55fbb7Slm66018 copy_len = sizeof (struct vtoc); 45460a55fbb7Slm66018 45470a55fbb7Slm66018 tmp_mem = kmem_alloc(copy_len, KM_SLEEP); 45480a55fbb7Slm66018 45490a55fbb7Slm66018 rv = ddi_copyin(from, tmp_mem, copy_len, mode); 45500a55fbb7Slm66018 if (rv != 0) { 45510a55fbb7Slm66018 kmem_free(tmp_mem, copy_len); 45520a55fbb7Slm66018 return (EFAULT); 45530a55fbb7Slm66018 } 45540a55fbb7Slm66018 45550a55fbb7Slm66018 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 45560a55fbb7Slm66018 vtoc32tovtoc((*(struct vtoc32 *)tmp_mem), vt); 45570a55fbb7Slm66018 } else { 45580a55fbb7Slm66018 vtp = tmp_mem; 45590a55fbb7Slm66018 } 45600a55fbb7Slm66018 4561d10e4ef2Snarayan /* 4562d10e4ef2Snarayan * The VTOC is being changed, then vdc needs to update the copy 4563d10e4ef2Snarayan * it saved in the soft state structure. 4564d10e4ef2Snarayan */ 4565d10e4ef2Snarayan bcopy(vtp, vdc->vtoc, sizeof (struct vtoc)); 4566d10e4ef2Snarayan 45670a55fbb7Slm66018 VTOC2VD_VTOC(vtp, &vtvd); 45680a55fbb7Slm66018 bcopy(&vtvd, to, sizeof (vd_vtoc_t)); 45690a55fbb7Slm66018 kmem_free(tmp_mem, copy_len); 45700a55fbb7Slm66018 45710a55fbb7Slm66018 return (0); 45720a55fbb7Slm66018 } 45730a55fbb7Slm66018 45740a55fbb7Slm66018 /* 45750a55fbb7Slm66018 * Function: 45760a55fbb7Slm66018 * vdc_get_geom_convert() 45770a55fbb7Slm66018 * 45780a55fbb7Slm66018 * Description: 4579d10e4ef2Snarayan * This routine performs the necessary convertions from the DKIOCGGEOM, 4580d10e4ef2Snarayan * DKIOCG_PHYSGEOM and DKIOG_VIRTGEOM Solaris structures to the format 4581d10e4ef2Snarayan * defined in FWARC 2006/195 45820a55fbb7Slm66018 * 45830a55fbb7Slm66018 * Arguments: 4584d10e4ef2Snarayan * vdc - the vDisk client 45850a55fbb7Slm66018 * from - Buffer with data 45860a55fbb7Slm66018 * to - Buffer where data is to be copied to 45870a55fbb7Slm66018 * mode - flags passed to ioctl 45880a55fbb7Slm66018 * dir - direction of copy (in or out) 45890a55fbb7Slm66018 * 45900a55fbb7Slm66018 * Return Code: 45910a55fbb7Slm66018 * 0 - Success 45920a55fbb7Slm66018 * ENXIO - Invalid buffer passed in 4593d10e4ef2Snarayan * EFAULT - ddi_copyout of data failed 45940a55fbb7Slm66018 */ 45950a55fbb7Slm66018 static int 4596d10e4ef2Snarayan vdc_get_geom_convert(vdc_t *vdc, void *from, void *to, int mode, int dir) 45970a55fbb7Slm66018 { 4598d10e4ef2Snarayan _NOTE(ARGUNUSED(vdc)) 4599d10e4ef2Snarayan 46000a55fbb7Slm66018 struct dk_geom geom; 46010a55fbb7Slm66018 int copy_len = sizeof (struct dk_geom); 46020a55fbb7Slm66018 int rv = 0; 46030a55fbb7Slm66018 46040a55fbb7Slm66018 if (dir != VD_COPYOUT) 46050a55fbb7Slm66018 return (0); /* nothing to do */ 46060a55fbb7Slm66018 46070a55fbb7Slm66018 if ((from == NULL) || (to == NULL)) 46080a55fbb7Slm66018 return (ENXIO); 46090a55fbb7Slm66018 46100a55fbb7Slm66018 VD_GEOM2DK_GEOM((vd_geom_t *)from, &geom); 46110a55fbb7Slm66018 rv = ddi_copyout(&geom, to, copy_len, mode); 46120a55fbb7Slm66018 if (rv != 0) 46130a55fbb7Slm66018 rv = EFAULT; 46140a55fbb7Slm66018 46150a55fbb7Slm66018 return (rv); 46160a55fbb7Slm66018 } 46170a55fbb7Slm66018 46180a55fbb7Slm66018 /* 46190a55fbb7Slm66018 * Function: 46200a55fbb7Slm66018 * vdc_set_geom_convert() 46210a55fbb7Slm66018 * 46220a55fbb7Slm66018 * Description: 4623d10e4ef2Snarayan * This routine performs the necessary convertions from the DKIOCSGEOM 4624d10e4ef2Snarayan * Solaris structure to the format defined in FWARC 2006/195. 46250a55fbb7Slm66018 * 46260a55fbb7Slm66018 * Arguments: 4627d10e4ef2Snarayan * vdc - the vDisk client 46280a55fbb7Slm66018 * from - Buffer with data 46290a55fbb7Slm66018 * to - Buffer where data is to be copied to 46300a55fbb7Slm66018 * mode - flags passed to ioctl 46310a55fbb7Slm66018 * dir - direction of copy (in or out) 46320a55fbb7Slm66018 * 46330a55fbb7Slm66018 * Return Code: 46340a55fbb7Slm66018 * 0 - Success 46350a55fbb7Slm66018 * ENXIO - Invalid buffer passed in 46360a55fbb7Slm66018 * EFAULT - ddi_copyin of data failed 46370a55fbb7Slm66018 */ 46380a55fbb7Slm66018 static int 4639d10e4ef2Snarayan vdc_set_geom_convert(vdc_t *vdc, void *from, void *to, int mode, int dir) 46400a55fbb7Slm66018 { 4641d10e4ef2Snarayan _NOTE(ARGUNUSED(vdc)) 4642d10e4ef2Snarayan 46430a55fbb7Slm66018 vd_geom_t vdgeom; 46440a55fbb7Slm66018 void *tmp_mem = NULL; 46450a55fbb7Slm66018 int copy_len = sizeof (struct dk_geom); 46460a55fbb7Slm66018 int rv = 0; 46470a55fbb7Slm66018 46480a55fbb7Slm66018 if (dir != VD_COPYIN) 46490a55fbb7Slm66018 return (0); /* nothing to do */ 46500a55fbb7Slm66018 46510a55fbb7Slm66018 if ((from == NULL) || (to == NULL)) 46520a55fbb7Slm66018 return (ENXIO); 46530a55fbb7Slm66018 46540a55fbb7Slm66018 tmp_mem = kmem_alloc(copy_len, KM_SLEEP); 46550a55fbb7Slm66018 46560a55fbb7Slm66018 rv = ddi_copyin(from, tmp_mem, copy_len, mode); 46570a55fbb7Slm66018 if (rv != 0) { 46580a55fbb7Slm66018 kmem_free(tmp_mem, copy_len); 46590a55fbb7Slm66018 return (EFAULT); 46600a55fbb7Slm66018 } 46610a55fbb7Slm66018 DK_GEOM2VD_GEOM((struct dk_geom *)tmp_mem, &vdgeom); 46620a55fbb7Slm66018 bcopy(&vdgeom, to, sizeof (vdgeom)); 46630a55fbb7Slm66018 kmem_free(tmp_mem, copy_len); 46640a55fbb7Slm66018 46650a55fbb7Slm66018 return (0); 46660a55fbb7Slm66018 } 46670a55fbb7Slm66018 46684bac2208Snarayan static int 46694bac2208Snarayan vdc_get_efi_convert(vdc_t *vdc, void *from, void *to, int mode, int dir) 46704bac2208Snarayan { 46714bac2208Snarayan _NOTE(ARGUNUSED(vdc)) 46724bac2208Snarayan 46734bac2208Snarayan vd_efi_t *vd_efi; 46744bac2208Snarayan dk_efi_t dk_efi; 46754bac2208Snarayan int rv = 0; 46764bac2208Snarayan void *uaddr; 46774bac2208Snarayan 46784bac2208Snarayan if ((from == NULL) || (to == NULL)) 46794bac2208Snarayan return (ENXIO); 46804bac2208Snarayan 46814bac2208Snarayan if (dir == VD_COPYIN) { 46824bac2208Snarayan 46834bac2208Snarayan vd_efi = (vd_efi_t *)to; 46844bac2208Snarayan 46854bac2208Snarayan rv = ddi_copyin(from, &dk_efi, sizeof (dk_efi_t), mode); 46864bac2208Snarayan if (rv != 0) 46874bac2208Snarayan return (EFAULT); 46884bac2208Snarayan 46894bac2208Snarayan vd_efi->lba = dk_efi.dki_lba; 46904bac2208Snarayan vd_efi->length = dk_efi.dki_length; 46914bac2208Snarayan bzero(vd_efi->data, vd_efi->length); 46924bac2208Snarayan 46934bac2208Snarayan } else { 46944bac2208Snarayan 46954bac2208Snarayan rv = ddi_copyin(to, &dk_efi, sizeof (dk_efi_t), mode); 46964bac2208Snarayan if (rv != 0) 46974bac2208Snarayan return (EFAULT); 46984bac2208Snarayan 46994bac2208Snarayan uaddr = dk_efi.dki_data; 47004bac2208Snarayan 47014bac2208Snarayan dk_efi.dki_data = kmem_alloc(dk_efi.dki_length, KM_SLEEP); 47024bac2208Snarayan 47034bac2208Snarayan VD_EFI2DK_EFI((vd_efi_t *)from, &dk_efi); 47044bac2208Snarayan 47054bac2208Snarayan rv = ddi_copyout(dk_efi.dki_data, uaddr, dk_efi.dki_length, 47064bac2208Snarayan mode); 47074bac2208Snarayan if (rv != 0) 47084bac2208Snarayan return (EFAULT); 47094bac2208Snarayan 47104bac2208Snarayan kmem_free(dk_efi.dki_data, dk_efi.dki_length); 47114bac2208Snarayan } 47124bac2208Snarayan 47134bac2208Snarayan return (0); 47144bac2208Snarayan } 47154bac2208Snarayan 47164bac2208Snarayan static int 47174bac2208Snarayan vdc_set_efi_convert(vdc_t *vdc, void *from, void *to, int mode, int dir) 47184bac2208Snarayan { 47194bac2208Snarayan _NOTE(ARGUNUSED(vdc)) 47204bac2208Snarayan 47214bac2208Snarayan dk_efi_t dk_efi; 47224bac2208Snarayan void *uaddr; 47234bac2208Snarayan 47244bac2208Snarayan if (dir == VD_COPYOUT) 47254bac2208Snarayan return (0); /* nothing to do */ 47264bac2208Snarayan 47274bac2208Snarayan if ((from == NULL) || (to == NULL)) 47284bac2208Snarayan return (ENXIO); 47294bac2208Snarayan 47304bac2208Snarayan if (ddi_copyin(from, &dk_efi, sizeof (dk_efi_t), mode) != 0) 47314bac2208Snarayan return (EFAULT); 47324bac2208Snarayan 47334bac2208Snarayan uaddr = dk_efi.dki_data; 47344bac2208Snarayan 47354bac2208Snarayan dk_efi.dki_data = kmem_alloc(dk_efi.dki_length, KM_SLEEP); 47364bac2208Snarayan 47374bac2208Snarayan if (ddi_copyin(uaddr, dk_efi.dki_data, dk_efi.dki_length, mode) != 0) 47384bac2208Snarayan return (EFAULT); 47394bac2208Snarayan 47404bac2208Snarayan DK_EFI2VD_EFI(&dk_efi, (vd_efi_t *)to); 47414bac2208Snarayan 47424bac2208Snarayan kmem_free(dk_efi.dki_data, dk_efi.dki_length); 47434bac2208Snarayan 47444bac2208Snarayan return (0); 47454bac2208Snarayan } 47464bac2208Snarayan 47470a55fbb7Slm66018 /* 47480a55fbb7Slm66018 * Function: 47491ae08745Sheppo * vdc_create_fake_geometry() 47501ae08745Sheppo * 47511ae08745Sheppo * Description: 47521ae08745Sheppo * This routine fakes up the disk info needed for some DKIO ioctls. 47531ae08745Sheppo * - DKIOCINFO 47541ae08745Sheppo * - DKIOCGMEDIAINFO 47551ae08745Sheppo * 47561ae08745Sheppo * [ just like lofi(7D) and ramdisk(7D) ] 47571ae08745Sheppo * 47581ae08745Sheppo * Arguments: 47591ae08745Sheppo * vdc - soft state pointer for this instance of the device driver. 47601ae08745Sheppo * 47611ae08745Sheppo * Return Code: 47621ae08745Sheppo * 0 - Success 47631ae08745Sheppo */ 47641ae08745Sheppo static int 47651ae08745Sheppo vdc_create_fake_geometry(vdc_t *vdc) 47661ae08745Sheppo { 47670a55fbb7Slm66018 int rv = 0; 47680a55fbb7Slm66018 47691ae08745Sheppo ASSERT(vdc != NULL); 47701ae08745Sheppo 47711ae08745Sheppo /* 47721ae08745Sheppo * DKIOCINFO support 47731ae08745Sheppo */ 47741ae08745Sheppo vdc->cinfo = kmem_zalloc(sizeof (struct dk_cinfo), KM_SLEEP); 47751ae08745Sheppo 47761ae08745Sheppo (void) strcpy(vdc->cinfo->dki_cname, VDC_DRIVER_NAME); 47771ae08745Sheppo (void) strcpy(vdc->cinfo->dki_dname, VDC_DRIVER_NAME); 47788e6a2a04Slm66018 /* max_xfer_sz is #blocks so we don't need to divide by DEV_BSIZE */ 47798e6a2a04Slm66018 vdc->cinfo->dki_maxtransfer = vdc->max_xfer_sz; 47801ae08745Sheppo vdc->cinfo->dki_ctype = DKC_SCSI_CCS; 47811ae08745Sheppo vdc->cinfo->dki_flags = DKI_FMTVOL; 47821ae08745Sheppo vdc->cinfo->dki_cnum = 0; 47831ae08745Sheppo vdc->cinfo->dki_addr = 0; 47841ae08745Sheppo vdc->cinfo->dki_space = 0; 47851ae08745Sheppo vdc->cinfo->dki_prio = 0; 47861ae08745Sheppo vdc->cinfo->dki_vec = 0; 47871ae08745Sheppo vdc->cinfo->dki_unit = vdc->instance; 47881ae08745Sheppo vdc->cinfo->dki_slave = 0; 47891ae08745Sheppo /* 47901ae08745Sheppo * The partition number will be created on the fly depending on the 47911ae08745Sheppo * actual slice (i.e. minor node) that is used to request the data. 47921ae08745Sheppo */ 47931ae08745Sheppo vdc->cinfo->dki_partition = 0; 47941ae08745Sheppo 47951ae08745Sheppo /* 47961ae08745Sheppo * DKIOCGMEDIAINFO support 47971ae08745Sheppo */ 47980a55fbb7Slm66018 if (vdc->minfo == NULL) 47991ae08745Sheppo vdc->minfo = kmem_zalloc(sizeof (struct dk_minfo), KM_SLEEP); 48001ae08745Sheppo vdc->minfo->dki_media_type = DK_FIXED_DISK; 48014bac2208Snarayan vdc->minfo->dki_capacity = vdc->vdisk_size; 48021ae08745Sheppo vdc->minfo->dki_lbsize = DEV_BSIZE; 48031ae08745Sheppo 48040a55fbb7Slm66018 return (rv); 48050a55fbb7Slm66018 } 48060a55fbb7Slm66018 48070a55fbb7Slm66018 /* 48080a55fbb7Slm66018 * Function: 48090a55fbb7Slm66018 * vdc_setup_disk_layout() 48100a55fbb7Slm66018 * 48110a55fbb7Slm66018 * Description: 48120a55fbb7Slm66018 * This routine discovers all the necessary details about the "disk" 48130a55fbb7Slm66018 * by requesting the data that is available from the vDisk server and by 48140a55fbb7Slm66018 * faking up the rest of the data. 48150a55fbb7Slm66018 * 48160a55fbb7Slm66018 * Arguments: 48170a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 48180a55fbb7Slm66018 * 48190a55fbb7Slm66018 * Return Code: 48200a55fbb7Slm66018 * 0 - Success 48210a55fbb7Slm66018 */ 48220a55fbb7Slm66018 static int 48230a55fbb7Slm66018 vdc_setup_disk_layout(vdc_t *vdc) 48240a55fbb7Slm66018 { 4825d10e4ef2Snarayan buf_t *buf; /* BREAD requests need to be in a buf_t structure */ 48260a55fbb7Slm66018 dev_t dev; 48270a55fbb7Slm66018 int slice = 0; 48280a55fbb7Slm66018 int rv; 48290a55fbb7Slm66018 48300a55fbb7Slm66018 ASSERT(vdc != NULL); 48310a55fbb7Slm66018 48320a55fbb7Slm66018 rv = vdc_create_fake_geometry(vdc); 48330a55fbb7Slm66018 if (rv != 0) { 4834*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to create disk geometry (err%d)", 48350a55fbb7Slm66018 vdc->instance, rv); 48360a55fbb7Slm66018 } 48370a55fbb7Slm66018 48380a55fbb7Slm66018 if (vdc->vtoc == NULL) 48390a55fbb7Slm66018 vdc->vtoc = kmem_zalloc(sizeof (struct vtoc), KM_SLEEP); 48400a55fbb7Slm66018 48410a55fbb7Slm66018 dev = makedevice(ddi_driver_major(vdc->dip), 48420a55fbb7Slm66018 VD_MAKE_DEV(vdc->instance, 0)); 48430a55fbb7Slm66018 rv = vd_process_ioctl(dev, DKIOCGVTOC, (caddr_t)vdc->vtoc, FKIOCTL); 48444bac2208Snarayan 48454bac2208Snarayan if (rv && rv != ENOTSUP) { 4846*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to get VTOC (err=%d)", 48470a55fbb7Slm66018 vdc->instance, rv); 48480a55fbb7Slm66018 return (rv); 48490a55fbb7Slm66018 } 48500a55fbb7Slm66018 48514bac2208Snarayan if (rv == ENOTSUP) { 48524bac2208Snarayan /* 48534bac2208Snarayan * If the device does not support VTOC then we try 48544bac2208Snarayan * to read an EFI label. 48554bac2208Snarayan */ 48564bac2208Snarayan struct dk_gpt *efi; 48574bac2208Snarayan size_t efi_len; 48584bac2208Snarayan 48594bac2208Snarayan rv = vdc_efi_alloc_and_read(dev, &efi, &efi_len); 48604bac2208Snarayan 48614bac2208Snarayan if (rv) { 4862*3af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to get EFI (err=%d)", 48634bac2208Snarayan vdc->instance, rv); 48644bac2208Snarayan return (rv); 48654bac2208Snarayan } 48664bac2208Snarayan 48674bac2208Snarayan vdc->vdisk_label = VD_DISK_LABEL_EFI; 48684bac2208Snarayan vdc_store_efi(vdc, efi); 48694bac2208Snarayan vd_efi_free(efi, efi_len); 48704bac2208Snarayan 48714bac2208Snarayan return (0); 48724bac2208Snarayan } 48734bac2208Snarayan 48744bac2208Snarayan vdc->vdisk_label = VD_DISK_LABEL_VTOC; 48754bac2208Snarayan 48760a55fbb7Slm66018 /* 4877*3af08d82Slm66018 * FUTURE: This could be default way for reading the VTOC 4878*3af08d82Slm66018 * from the disk as supposed to sending the VD_OP_GET_VTOC 4879*3af08d82Slm66018 * to the server. Currently this is a sanity check. 4880*3af08d82Slm66018 * 48810a55fbb7Slm66018 * find the slice that represents the entire "disk" and use that to 48820a55fbb7Slm66018 * read the disk label. The convention in Solaris is that slice 2 4883d10e4ef2Snarayan * represents the whole disk so we check that it is, otherwise we 48840a55fbb7Slm66018 * default to slice 0 48850a55fbb7Slm66018 */ 48860a55fbb7Slm66018 if ((vdc->vdisk_type == VD_DISK_TYPE_DISK) && 48870a55fbb7Slm66018 (vdc->vtoc->v_part[2].p_tag == V_BACKUP)) { 48880a55fbb7Slm66018 slice = 2; 48890a55fbb7Slm66018 } else { 48900a55fbb7Slm66018 slice = 0; 48910a55fbb7Slm66018 } 4892d10e4ef2Snarayan 4893d10e4ef2Snarayan /* 4894d10e4ef2Snarayan * Read disk label from start of disk 4895d10e4ef2Snarayan */ 4896d10e4ef2Snarayan vdc->label = kmem_zalloc(DK_LABEL_SIZE, KM_SLEEP); 4897d10e4ef2Snarayan buf = kmem_alloc(sizeof (buf_t), KM_SLEEP); 4898d10e4ef2Snarayan bioinit(buf); 4899d10e4ef2Snarayan buf->b_un.b_addr = (caddr_t)vdc->label; 4900d10e4ef2Snarayan buf->b_bcount = DK_LABEL_SIZE; 4901d10e4ef2Snarayan buf->b_flags = B_BUSY | B_READ; 4902d10e4ef2Snarayan buf->b_dev = dev; 4903*3af08d82Slm66018 rv = vdc_send_request(vdc, VD_OP_BREAD, (caddr_t)vdc->label, 4904*3af08d82Slm66018 DK_LABEL_SIZE, slice, 0, CB_STRATEGY, buf, VIO_read_dir); 4905*3af08d82Slm66018 if (rv) { 4906*3af08d82Slm66018 DMSG(vdc, 1, "[%d] Failed to read disk block 0\n", 4907*3af08d82Slm66018 vdc->instance); 4908*3af08d82Slm66018 kmem_free(buf, sizeof (buf_t)); 4909*3af08d82Slm66018 return (rv); 4910*3af08d82Slm66018 } 4911d10e4ef2Snarayan rv = biowait(buf); 4912d10e4ef2Snarayan biofini(buf); 4913d10e4ef2Snarayan kmem_free(buf, sizeof (buf_t)); 49140a55fbb7Slm66018 49150a55fbb7Slm66018 return (rv); 49161ae08745Sheppo } 49174bac2208Snarayan 49184bac2208Snarayan /* 49194bac2208Snarayan * Function: 49204bac2208Snarayan * vdc_setup_devid() 49214bac2208Snarayan * 49224bac2208Snarayan * Description: 49234bac2208Snarayan * This routine discovers the devid of a vDisk. It requests the devid of 49244bac2208Snarayan * the underlying device from the vDisk server, builds an encapsulated 49254bac2208Snarayan * devid based on the retrieved devid and registers that new devid to 49264bac2208Snarayan * the vDisk. 49274bac2208Snarayan * 49284bac2208Snarayan * Arguments: 49294bac2208Snarayan * vdc - soft state pointer for this instance of the device driver. 49304bac2208Snarayan * 49314bac2208Snarayan * Return Code: 49324bac2208Snarayan * 0 - A devid was succesfully registered for the vDisk 49334bac2208Snarayan */ 49344bac2208Snarayan static int 49354bac2208Snarayan vdc_setup_devid(vdc_t *vdc) 49364bac2208Snarayan { 49374bac2208Snarayan int rv; 49384bac2208Snarayan vd_devid_t *vd_devid; 49394bac2208Snarayan size_t bufsize, bufid_len; 49404bac2208Snarayan 49414bac2208Snarayan /* 49424bac2208Snarayan * At first sight, we don't know the size of the devid that the 49434bac2208Snarayan * server will return but this size will be encoded into the 49444bac2208Snarayan * reply. So we do a first request using a default size then we 49454bac2208Snarayan * check if this size was large enough. If not then we do a second 49464bac2208Snarayan * request with the correct size returned by the server. Note that 49474bac2208Snarayan * ldc requires size to be 8-byte aligned. 49484bac2208Snarayan */ 49494bac2208Snarayan bufsize = P2ROUNDUP(VD_DEVID_SIZE(VD_DEVID_DEFAULT_LEN), 49504bac2208Snarayan sizeof (uint64_t)); 49514bac2208Snarayan vd_devid = kmem_zalloc(bufsize, KM_SLEEP); 49524bac2208Snarayan bufid_len = bufsize - sizeof (vd_efi_t) - 1; 49534bac2208Snarayan 4954*3af08d82Slm66018 rv = vdc_do_sync_op(vdc, VD_OP_GET_DEVID, (caddr_t)vd_devid, 4955*3af08d82Slm66018 bufsize, 0, 0, CB_SYNC, 0, VIO_both_dir); 4956*3af08d82Slm66018 4957*3af08d82Slm66018 DMSG(vdc, 2, "sync_op returned %d\n", rv); 4958*3af08d82Slm66018 49594bac2208Snarayan if (rv) { 49604bac2208Snarayan kmem_free(vd_devid, bufsize); 49614bac2208Snarayan return (rv); 49624bac2208Snarayan } 49634bac2208Snarayan 49644bac2208Snarayan if (vd_devid->length > bufid_len) { 49654bac2208Snarayan /* 49664bac2208Snarayan * The returned devid is larger than the buffer used. Try again 49674bac2208Snarayan * with a buffer with the right size. 49684bac2208Snarayan */ 49694bac2208Snarayan kmem_free(vd_devid, bufsize); 49704bac2208Snarayan bufsize = P2ROUNDUP(VD_DEVID_SIZE(vd_devid->length), 49714bac2208Snarayan sizeof (uint64_t)); 49724bac2208Snarayan vd_devid = kmem_zalloc(bufsize, KM_SLEEP); 49734bac2208Snarayan bufid_len = bufsize - sizeof (vd_efi_t) - 1; 49744bac2208Snarayan 4975*3af08d82Slm66018 rv = vdc_do_sync_op(vdc, VD_OP_GET_DEVID, 4976*3af08d82Slm66018 (caddr_t)vd_devid, bufsize, 0, 0, CB_SYNC, 0, 4977*3af08d82Slm66018 VIO_both_dir); 4978*3af08d82Slm66018 49794bac2208Snarayan if (rv) { 49804bac2208Snarayan kmem_free(vd_devid, bufsize); 49814bac2208Snarayan return (rv); 49824bac2208Snarayan } 49834bac2208Snarayan } 49844bac2208Snarayan 49854bac2208Snarayan /* 49864bac2208Snarayan * The virtual disk should have the same device id as the one associated 49874bac2208Snarayan * with the physical disk it is mapped on, otherwise sharing a disk 49884bac2208Snarayan * between a LDom and a non-LDom may not work (for example for a shared 49894bac2208Snarayan * SVM disk set). 49904bac2208Snarayan * 49914bac2208Snarayan * The DDI framework does not allow creating a device id with any 49924bac2208Snarayan * type so we first create a device id of type DEVID_ENCAP and then 49934bac2208Snarayan * we restore the orignal type of the physical device. 49944bac2208Snarayan */ 49954bac2208Snarayan 4996*3af08d82Slm66018 DMSG(vdc, 2, ": devid length = %d\n", vd_devid->length); 4997*3af08d82Slm66018 49984bac2208Snarayan /* build an encapsulated devid based on the returned devid */ 49994bac2208Snarayan if (ddi_devid_init(vdc->dip, DEVID_ENCAP, vd_devid->length, 50004bac2208Snarayan vd_devid->id, &vdc->devid) != DDI_SUCCESS) { 5001*3af08d82Slm66018 DMSG(vdc, 1, "[%d] Fail to created devid\n", vdc->instance); 50024bac2208Snarayan kmem_free(vd_devid, bufsize); 50034bac2208Snarayan return (1); 50044bac2208Snarayan } 50054bac2208Snarayan 50064bac2208Snarayan DEVID_FORMTYPE((impl_devid_t *)vdc->devid, vd_devid->type); 50074bac2208Snarayan 50084bac2208Snarayan ASSERT(ddi_devid_valid(vdc->devid) == DDI_SUCCESS); 50094bac2208Snarayan 50104bac2208Snarayan kmem_free(vd_devid, bufsize); 50114bac2208Snarayan 50124bac2208Snarayan if (ddi_devid_register(vdc->dip, vdc->devid) != DDI_SUCCESS) { 5013*3af08d82Slm66018 DMSG(vdc, 1, "[%d] Fail to register devid\n", vdc->instance); 50144bac2208Snarayan return (1); 50154bac2208Snarayan } 50164bac2208Snarayan 50174bac2208Snarayan return (0); 50184bac2208Snarayan } 50194bac2208Snarayan 50204bac2208Snarayan static void 50214bac2208Snarayan vdc_store_efi(vdc_t *vdc, struct dk_gpt *efi) 50224bac2208Snarayan { 50234bac2208Snarayan struct vtoc *vtoc = vdc->vtoc; 50244bac2208Snarayan 50254bac2208Snarayan vd_efi_to_vtoc(efi, vtoc); 50264bac2208Snarayan if (vdc->vdisk_type == VD_DISK_TYPE_SLICE) { 50274bac2208Snarayan /* 50284bac2208Snarayan * vd_efi_to_vtoc() will store information about the EFI Sun 50294bac2208Snarayan * reserved partition (representing the entire disk) into 50304bac2208Snarayan * partition 7. However single-slice device will only have 50314bac2208Snarayan * that single partition and the vdc driver expects to find 50324bac2208Snarayan * information about that partition in slice 0. So we need 50334bac2208Snarayan * to copy information from slice 7 to slice 0. 50344bac2208Snarayan */ 50354bac2208Snarayan vtoc->v_part[0].p_tag = vtoc->v_part[VD_EFI_WD_SLICE].p_tag; 50364bac2208Snarayan vtoc->v_part[0].p_flag = vtoc->v_part[VD_EFI_WD_SLICE].p_flag; 50374bac2208Snarayan vtoc->v_part[0].p_start = vtoc->v_part[VD_EFI_WD_SLICE].p_start; 50384bac2208Snarayan vtoc->v_part[0].p_size = vtoc->v_part[VD_EFI_WD_SLICE].p_size; 50394bac2208Snarayan } 50404bac2208Snarayan } 5041