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 /* 23edcc0754Sachartre * Copyright 2008 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> 782f5224aeSachartre #include <sys/var.h> 791ae08745Sheppo #include <sys/vtoc.h> 801ae08745Sheppo #include <sys/archsystm.h> 811ae08745Sheppo #include <sys/sysmacros.h> 821ae08745Sheppo 831ae08745Sheppo #include <sys/cdio.h> 841ae08745Sheppo #include <sys/dktp/fdisk.h> 8587a7269eSachartre #include <sys/dktp/dadkio.h> 862f5224aeSachartre #include <sys/mhd.h> 871ae08745Sheppo #include <sys/scsi/generic/sense.h> 882f5224aeSachartre #include <sys/scsi/impl/uscsi.h> 892f5224aeSachartre #include <sys/scsi/impl/services.h> 902f5224aeSachartre #include <sys/scsi/targets/sddef.h> 911ae08745Sheppo 921ae08745Sheppo #include <sys/ldoms.h> 931ae08745Sheppo #include <sys/ldc.h> 941ae08745Sheppo #include <sys/vio_common.h> 951ae08745Sheppo #include <sys/vio_mailbox.h> 9617cadca8Slm66018 #include <sys/vio_util.h> 971ae08745Sheppo #include <sys/vdsk_common.h> 981ae08745Sheppo #include <sys/vdsk_mailbox.h> 991ae08745Sheppo #include <sys/vdc.h> 1001ae08745Sheppo 1011ae08745Sheppo /* 1021ae08745Sheppo * function prototypes 1031ae08745Sheppo */ 1041ae08745Sheppo 1051ae08745Sheppo /* standard driver functions */ 1061ae08745Sheppo static int vdc_open(dev_t *dev, int flag, int otyp, cred_t *cred); 1071ae08745Sheppo static int vdc_close(dev_t dev, int flag, int otyp, cred_t *cred); 1081ae08745Sheppo static int vdc_strategy(struct buf *buf); 1091ae08745Sheppo static int vdc_print(dev_t dev, char *str); 1101ae08745Sheppo static int vdc_dump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk); 1111ae08745Sheppo static int vdc_read(dev_t dev, struct uio *uio, cred_t *cred); 1121ae08745Sheppo static int vdc_write(dev_t dev, struct uio *uio, cred_t *cred); 1131ae08745Sheppo static int vdc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 1141ae08745Sheppo cred_t *credp, int *rvalp); 1151ae08745Sheppo static int vdc_aread(dev_t dev, struct aio_req *aio, cred_t *cred); 1161ae08745Sheppo static int vdc_awrite(dev_t dev, struct aio_req *aio, cred_t *cred); 1171ae08745Sheppo 1181ae08745Sheppo static int vdc_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, 1191ae08745Sheppo void *arg, void **resultp); 1201ae08745Sheppo static int vdc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 1211ae08745Sheppo static int vdc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 1221ae08745Sheppo 1231ae08745Sheppo /* setup */ 1240d0c8d4bSnarayan static void vdc_min(struct buf *bufp); 1250a55fbb7Slm66018 static int vdc_send(vdc_t *vdc, caddr_t pkt, size_t *msglen); 126655fd6a9Sachartre static int vdc_do_ldc_init(vdc_t *vdc, md_t *mdp, mde_cookie_t vd_node); 1271ae08745Sheppo static int vdc_start_ldc_connection(vdc_t *vdc); 1281ae08745Sheppo static int vdc_create_device_nodes(vdc_t *vdc); 1294bac2208Snarayan static int vdc_create_device_nodes_efi(vdc_t *vdc); 1304bac2208Snarayan static int vdc_create_device_nodes_vtoc(vdc_t *vdc); 1311ae08745Sheppo static int vdc_create_device_nodes_props(vdc_t *vdc); 132655fd6a9Sachartre static int vdc_get_md_node(dev_info_t *dip, md_t **mdpp, 133655fd6a9Sachartre mde_cookie_t *vd_nodep, mde_cookie_t *vd_portp); 134655fd6a9Sachartre static int vdc_get_ldc_id(md_t *, mde_cookie_t, uint64_t *); 1350a55fbb7Slm66018 static int vdc_do_ldc_up(vdc_t *vdc); 1361ae08745Sheppo static void vdc_terminate_ldc(vdc_t *vdc); 1371ae08745Sheppo static int vdc_init_descriptor_ring(vdc_t *vdc); 1381ae08745Sheppo static void vdc_destroy_descriptor_ring(vdc_t *vdc); 1394bac2208Snarayan static int vdc_setup_devid(vdc_t *vdc); 140edcc0754Sachartre static void vdc_store_label_efi(vdc_t *, efi_gpt_t *, efi_gpe_t *); 14178fcd0a1Sachartre static void vdc_store_label_vtoc(vdc_t *, struct dk_geom *, struct vtoc *); 14278fcd0a1Sachartre static void vdc_store_label_unk(vdc_t *vdc); 14378fcd0a1Sachartre static boolean_t vdc_is_opened(vdc_t *vdc); 1441ae08745Sheppo 1451ae08745Sheppo /* handshake with vds */ 1460a55fbb7Slm66018 static int vdc_init_ver_negotiation(vdc_t *vdc, vio_ver_t ver); 1473af08d82Slm66018 static int vdc_ver_negotiation(vdc_t *vdcp); 1481ae08745Sheppo static int vdc_init_attr_negotiation(vdc_t *vdc); 1493af08d82Slm66018 static int vdc_attr_negotiation(vdc_t *vdcp); 1501ae08745Sheppo static int vdc_init_dring_negotiate(vdc_t *vdc); 1513af08d82Slm66018 static int vdc_dring_negotiation(vdc_t *vdcp); 1523af08d82Slm66018 static int vdc_send_rdx(vdc_t *vdcp); 1533af08d82Slm66018 static int vdc_rdx_exchange(vdc_t *vdcp); 1540a55fbb7Slm66018 static boolean_t vdc_is_supported_version(vio_ver_msg_t *ver_msg); 1551ae08745Sheppo 1560a55fbb7Slm66018 /* processing incoming messages from vDisk server */ 1571ae08745Sheppo static void vdc_process_msg_thread(vdc_t *vdc); 1583af08d82Slm66018 static int vdc_recv(vdc_t *vdc, vio_msg_t *msgp, size_t *nbytesp); 1593af08d82Slm66018 1600a55fbb7Slm66018 static uint_t vdc_handle_cb(uint64_t event, caddr_t arg); 1613af08d82Slm66018 static int vdc_process_data_msg(vdc_t *vdc, vio_msg_t *msg); 1620a55fbb7Slm66018 static int vdc_handle_ver_msg(vdc_t *vdc, vio_ver_msg_t *ver_msg); 1630a55fbb7Slm66018 static int vdc_handle_attr_msg(vdc_t *vdc, vd_attr_msg_t *attr_msg); 1640a55fbb7Slm66018 static int vdc_handle_dring_reg_msg(vdc_t *vdc, vio_dring_reg_msg_t *msg); 1653af08d82Slm66018 static int vdc_send_request(vdc_t *vdcp, int operation, 1663af08d82Slm66018 caddr_t addr, size_t nbytes, int slice, diskaddr_t offset, 1673af08d82Slm66018 int cb_type, void *cb_arg, vio_desc_direction_t dir); 1683af08d82Slm66018 static int vdc_map_to_shared_dring(vdc_t *vdcp, int idx); 1693af08d82Slm66018 static int vdc_populate_descriptor(vdc_t *vdcp, int operation, 1703af08d82Slm66018 caddr_t addr, size_t nbytes, int slice, diskaddr_t offset, 1713af08d82Slm66018 int cb_type, void *cb_arg, vio_desc_direction_t dir); 1722f5224aeSachartre static int vdc_do_sync_op(vdc_t *vdcp, int operation, caddr_t addr, 1732f5224aeSachartre size_t nbytes, int slice, diskaddr_t offset, int cb_type, 1742f5224aeSachartre void *cb_arg, vio_desc_direction_t dir, boolean_t); 1753af08d82Slm66018 1763af08d82Slm66018 static int vdc_wait_for_response(vdc_t *vdcp, vio_msg_t *msgp); 1773af08d82Slm66018 static int vdc_drain_response(vdc_t *vdcp); 1781ae08745Sheppo static int vdc_depopulate_descriptor(vdc_t *vdc, uint_t idx); 1793af08d82Slm66018 static int vdc_populate_mem_hdl(vdc_t *vdcp, vdc_local_desc_t *ldep); 180e1ebb9ecSlm66018 static int vdc_verify_seq_num(vdc_t *vdc, vio_dring_msg_t *dring_msg); 1811ae08745Sheppo 1821ae08745Sheppo /* dkio */ 1832f5224aeSachartre static int vd_process_ioctl(dev_t dev, int cmd, caddr_t arg, int mode, 1842f5224aeSachartre int *rvalp); 185edcc0754Sachartre static int vd_process_efi_ioctl(void *vdisk, int cmd, uintptr_t arg); 18678fcd0a1Sachartre static void vdc_create_fake_geometry(vdc_t *vdc); 18778fcd0a1Sachartre static int vdc_validate_geometry(vdc_t *vdc); 18878fcd0a1Sachartre static void vdc_validate(vdc_t *vdc); 18978fcd0a1Sachartre static void vdc_validate_task(void *arg); 190d10e4ef2Snarayan static int vdc_null_copy_func(vdc_t *vdc, void *from, void *to, 191d10e4ef2Snarayan int mode, int dir); 1924bac2208Snarayan static int vdc_get_wce_convert(vdc_t *vdc, void *from, void *to, 1934bac2208Snarayan int mode, int dir); 1944bac2208Snarayan static int vdc_set_wce_convert(vdc_t *vdc, void *from, void *to, 1954bac2208Snarayan int mode, int dir); 196d10e4ef2Snarayan static int vdc_get_vtoc_convert(vdc_t *vdc, void *from, void *to, 197d10e4ef2Snarayan int mode, int dir); 198d10e4ef2Snarayan static int vdc_set_vtoc_convert(vdc_t *vdc, void *from, void *to, 199d10e4ef2Snarayan int mode, int dir); 200d10e4ef2Snarayan static int vdc_get_geom_convert(vdc_t *vdc, void *from, void *to, 201d10e4ef2Snarayan int mode, int dir); 202d10e4ef2Snarayan static int vdc_set_geom_convert(vdc_t *vdc, void *from, void *to, 203d10e4ef2Snarayan int mode, int dir); 2044bac2208Snarayan static int vdc_get_efi_convert(vdc_t *vdc, void *from, void *to, 2054bac2208Snarayan int mode, int dir); 2064bac2208Snarayan static int vdc_set_efi_convert(vdc_t *vdc, void *from, void *to, 2074bac2208Snarayan int mode, int dir); 2081ae08745Sheppo 2092f5224aeSachartre static void vdc_ownership_update(vdc_t *vdc, int ownership_flags); 2102f5224aeSachartre static int vdc_access_set(vdc_t *vdc, uint64_t flags, int mode); 2112f5224aeSachartre static vdc_io_t *vdc_failfast_io_queue(vdc_t *vdc, struct buf *buf); 2122f5224aeSachartre static int vdc_failfast_check_resv(vdc_t *vdc); 2132f5224aeSachartre 2141ae08745Sheppo /* 2151ae08745Sheppo * Module variables 2161ae08745Sheppo */ 217e1ebb9ecSlm66018 218e1ebb9ecSlm66018 /* 219e1ebb9ecSlm66018 * Tunable variables to control how long vdc waits before timing out on 220e1ebb9ecSlm66018 * various operations 221e1ebb9ecSlm66018 */ 2223c96341aSnarayan static int vdc_hshake_retries = 3; 223e1ebb9ecSlm66018 224655fd6a9Sachartre static int vdc_timeout = 0; /* units: seconds */ 225655fd6a9Sachartre 2263af08d82Slm66018 static uint64_t vdc_hz_min_ldc_delay; 2273af08d82Slm66018 static uint64_t vdc_min_timeout_ldc = 1 * MILLISEC; 2283af08d82Slm66018 static uint64_t vdc_hz_max_ldc_delay; 2293af08d82Slm66018 static uint64_t vdc_max_timeout_ldc = 100 * MILLISEC; 2303af08d82Slm66018 2313af08d82Slm66018 static uint64_t vdc_ldc_read_init_delay = 1 * MILLISEC; 2323af08d82Slm66018 static uint64_t vdc_ldc_read_max_delay = 100 * MILLISEC; 233e1ebb9ecSlm66018 234e1ebb9ecSlm66018 /* values for dumping - need to run in a tighter loop */ 235e1ebb9ecSlm66018 static uint64_t vdc_usec_timeout_dump = 100 * MILLISEC; /* 0.1s units: ns */ 236e1ebb9ecSlm66018 static int vdc_dump_retries = 100; 237e1ebb9ecSlm66018 2382f5224aeSachartre static uint16_t vdc_scsi_timeout = 60; /* 60s units: seconds */ 2392f5224aeSachartre 2402f5224aeSachartre static uint64_t vdc_ownership_delay = 6 * MICROSEC; /* 6s units: usec */ 2412f5224aeSachartre 242e1ebb9ecSlm66018 /* Count of the number of vdc instances attached */ 243e1ebb9ecSlm66018 static volatile uint32_t vdc_instance_count = 0; 2441ae08745Sheppo 2452f5224aeSachartre /* Tunable to log all SCSI errors */ 2462f5224aeSachartre static boolean_t vdc_scsi_log_error = B_FALSE; 2472f5224aeSachartre 2481ae08745Sheppo /* Soft state pointer */ 2491ae08745Sheppo static void *vdc_state; 2501ae08745Sheppo 2513af08d82Slm66018 /* 2523af08d82Slm66018 * Controlling the verbosity of the error/debug messages 2533af08d82Slm66018 * 2543af08d82Slm66018 * vdc_msglevel - controls level of messages 2553af08d82Slm66018 * vdc_matchinst - 64-bit variable where each bit corresponds 2563af08d82Slm66018 * to the vdc instance the vdc_msglevel applies. 2573af08d82Slm66018 */ 2583af08d82Slm66018 int vdc_msglevel = 0x0; 2593af08d82Slm66018 uint64_t vdc_matchinst = 0ull; 2601ae08745Sheppo 2610a55fbb7Slm66018 /* 2620a55fbb7Slm66018 * Supported vDisk protocol version pairs. 2630a55fbb7Slm66018 * 2640a55fbb7Slm66018 * The first array entry is the latest and preferred version. 2650a55fbb7Slm66018 */ 26617cadca8Slm66018 static const vio_ver_t vdc_version[] = {{1, 1}}; 2671ae08745Sheppo 2681ae08745Sheppo static struct cb_ops vdc_cb_ops = { 2691ae08745Sheppo vdc_open, /* cb_open */ 2701ae08745Sheppo vdc_close, /* cb_close */ 2711ae08745Sheppo vdc_strategy, /* cb_strategy */ 2721ae08745Sheppo vdc_print, /* cb_print */ 2731ae08745Sheppo vdc_dump, /* cb_dump */ 2741ae08745Sheppo vdc_read, /* cb_read */ 2751ae08745Sheppo vdc_write, /* cb_write */ 2761ae08745Sheppo vdc_ioctl, /* cb_ioctl */ 2771ae08745Sheppo nodev, /* cb_devmap */ 2781ae08745Sheppo nodev, /* cb_mmap */ 2791ae08745Sheppo nodev, /* cb_segmap */ 2801ae08745Sheppo nochpoll, /* cb_chpoll */ 2811ae08745Sheppo ddi_prop_op, /* cb_prop_op */ 2821ae08745Sheppo NULL, /* cb_str */ 2831ae08745Sheppo D_MP | D_64BIT, /* cb_flag */ 2841ae08745Sheppo CB_REV, /* cb_rev */ 2851ae08745Sheppo vdc_aread, /* cb_aread */ 2861ae08745Sheppo vdc_awrite /* cb_awrite */ 2871ae08745Sheppo }; 2881ae08745Sheppo 2891ae08745Sheppo static struct dev_ops vdc_ops = { 2901ae08745Sheppo DEVO_REV, /* devo_rev */ 2911ae08745Sheppo 0, /* devo_refcnt */ 2921ae08745Sheppo vdc_getinfo, /* devo_getinfo */ 2931ae08745Sheppo nulldev, /* devo_identify */ 2941ae08745Sheppo nulldev, /* devo_probe */ 2951ae08745Sheppo vdc_attach, /* devo_attach */ 2961ae08745Sheppo vdc_detach, /* devo_detach */ 2971ae08745Sheppo nodev, /* devo_reset */ 2981ae08745Sheppo &vdc_cb_ops, /* devo_cb_ops */ 2991ae08745Sheppo NULL, /* devo_bus_ops */ 3001ae08745Sheppo nulldev /* devo_power */ 3011ae08745Sheppo }; 3021ae08745Sheppo 3031ae08745Sheppo static struct modldrv modldrv = { 3041ae08745Sheppo &mod_driverops, 305205eeb1aSlm66018 "virtual disk client", 3061ae08745Sheppo &vdc_ops, 3071ae08745Sheppo }; 3081ae08745Sheppo 3091ae08745Sheppo static struct modlinkage modlinkage = { 3101ae08745Sheppo MODREV_1, 3111ae08745Sheppo &modldrv, 3121ae08745Sheppo NULL 3131ae08745Sheppo }; 3141ae08745Sheppo 3151ae08745Sheppo /* -------------------------------------------------------------------------- */ 3161ae08745Sheppo 3171ae08745Sheppo /* 3181ae08745Sheppo * Device Driver housekeeping and setup 3191ae08745Sheppo */ 3201ae08745Sheppo 3211ae08745Sheppo int 3221ae08745Sheppo _init(void) 3231ae08745Sheppo { 3241ae08745Sheppo int status; 3251ae08745Sheppo 3261ae08745Sheppo if ((status = ddi_soft_state_init(&vdc_state, sizeof (vdc_t), 1)) != 0) 3271ae08745Sheppo return (status); 3281ae08745Sheppo if ((status = mod_install(&modlinkage)) != 0) 3291ae08745Sheppo ddi_soft_state_fini(&vdc_state); 3301ae08745Sheppo return (status); 3311ae08745Sheppo } 3321ae08745Sheppo 3331ae08745Sheppo int 3341ae08745Sheppo _info(struct modinfo *modinfop) 3351ae08745Sheppo { 3361ae08745Sheppo return (mod_info(&modlinkage, modinfop)); 3371ae08745Sheppo } 3381ae08745Sheppo 3391ae08745Sheppo int 3401ae08745Sheppo _fini(void) 3411ae08745Sheppo { 3421ae08745Sheppo int status; 3431ae08745Sheppo 3441ae08745Sheppo if ((status = mod_remove(&modlinkage)) != 0) 3451ae08745Sheppo return (status); 3461ae08745Sheppo ddi_soft_state_fini(&vdc_state); 3471ae08745Sheppo return (0); 3481ae08745Sheppo } 3491ae08745Sheppo 3501ae08745Sheppo static int 3511ae08745Sheppo vdc_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp) 3521ae08745Sheppo { 3531ae08745Sheppo _NOTE(ARGUNUSED(dip)) 3541ae08745Sheppo 3550d0c8d4bSnarayan int instance = VDCUNIT((dev_t)arg); 3561ae08745Sheppo vdc_t *vdc = NULL; 3571ae08745Sheppo 3581ae08745Sheppo switch (cmd) { 3591ae08745Sheppo case DDI_INFO_DEVT2DEVINFO: 3601ae08745Sheppo if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) { 3611ae08745Sheppo *resultp = NULL; 3621ae08745Sheppo return (DDI_FAILURE); 3631ae08745Sheppo } 3641ae08745Sheppo *resultp = vdc->dip; 3651ae08745Sheppo return (DDI_SUCCESS); 3661ae08745Sheppo case DDI_INFO_DEVT2INSTANCE: 3671ae08745Sheppo *resultp = (void *)(uintptr_t)instance; 3681ae08745Sheppo return (DDI_SUCCESS); 3691ae08745Sheppo default: 3701ae08745Sheppo *resultp = NULL; 3711ae08745Sheppo return (DDI_FAILURE); 3721ae08745Sheppo } 3731ae08745Sheppo } 3741ae08745Sheppo 3751ae08745Sheppo static int 3761ae08745Sheppo vdc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 3771ae08745Sheppo { 3782f5224aeSachartre kt_did_t failfast_tid, ownership_tid; 3791ae08745Sheppo int instance; 3801ae08745Sheppo int rv; 3811ae08745Sheppo vdc_t *vdc = NULL; 3821ae08745Sheppo 3831ae08745Sheppo switch (cmd) { 3841ae08745Sheppo case DDI_DETACH: 3851ae08745Sheppo /* the real work happens below */ 3861ae08745Sheppo break; 3871ae08745Sheppo case DDI_SUSPEND: 3881ae08745Sheppo /* nothing to do for this non-device */ 3891ae08745Sheppo return (DDI_SUCCESS); 3901ae08745Sheppo default: 3911ae08745Sheppo return (DDI_FAILURE); 3921ae08745Sheppo } 3931ae08745Sheppo 3941ae08745Sheppo ASSERT(cmd == DDI_DETACH); 3951ae08745Sheppo instance = ddi_get_instance(dip); 3963af08d82Slm66018 DMSGX(1, "[%d] Entered\n", instance); 3971ae08745Sheppo 3981ae08745Sheppo if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) { 399e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't get state structure", instance); 4001ae08745Sheppo return (DDI_FAILURE); 4011ae08745Sheppo } 4021ae08745Sheppo 4032f5224aeSachartre /* 4042f5224aeSachartre * This function is called when vdc is detached or if it has failed to 4052f5224aeSachartre * attach. In that case, the attach may have fail before the vdisk type 4062f5224aeSachartre * has been set so we can't call vdc_is_opened(). However as the attach 4072f5224aeSachartre * has failed, we know that the vdisk is not opened and we can safely 4082f5224aeSachartre * detach. 4092f5224aeSachartre */ 4102f5224aeSachartre if (vdc->vdisk_type != VD_DISK_TYPE_UNK && vdc_is_opened(vdc)) { 4113af08d82Slm66018 DMSG(vdc, 0, "[%d] Cannot detach: device is open", instance); 4121ae08745Sheppo return (DDI_FAILURE); 4131ae08745Sheppo } 4141ae08745Sheppo 41578fcd0a1Sachartre if (vdc->dkio_flush_pending) { 41678fcd0a1Sachartre DMSG(vdc, 0, 41778fcd0a1Sachartre "[%d] Cannot detach: %d outstanding DKIO flushes\n", 41878fcd0a1Sachartre instance, vdc->dkio_flush_pending); 41978fcd0a1Sachartre return (DDI_FAILURE); 42078fcd0a1Sachartre } 42178fcd0a1Sachartre 42278fcd0a1Sachartre if (vdc->validate_pending) { 42378fcd0a1Sachartre DMSG(vdc, 0, 42478fcd0a1Sachartre "[%d] Cannot detach: %d outstanding validate request\n", 42578fcd0a1Sachartre instance, vdc->validate_pending); 42678fcd0a1Sachartre return (DDI_FAILURE); 42778fcd0a1Sachartre } 42878fcd0a1Sachartre 4293af08d82Slm66018 DMSG(vdc, 0, "[%d] proceeding...\n", instance); 4303af08d82Slm66018 4312f5224aeSachartre /* If we took ownership, release ownership */ 4322f5224aeSachartre mutex_enter(&vdc->ownership_lock); 4332f5224aeSachartre if (vdc->ownership & VDC_OWNERSHIP_GRANTED) { 4342f5224aeSachartre rv = vdc_access_set(vdc, VD_ACCESS_SET_CLEAR, FKIOCTL); 4352f5224aeSachartre if (rv == 0) { 4362f5224aeSachartre vdc_ownership_update(vdc, VDC_OWNERSHIP_NONE); 4372f5224aeSachartre } 4382f5224aeSachartre } 4392f5224aeSachartre mutex_exit(&vdc->ownership_lock); 4402f5224aeSachartre 4413af08d82Slm66018 /* mark instance as detaching */ 4423af08d82Slm66018 vdc->lifecycle = VDC_LC_DETACHING; 4431ae08745Sheppo 4441ae08745Sheppo /* 4451ae08745Sheppo * try and disable callbacks to prevent another handshake 4461ae08745Sheppo */ 4471ae08745Sheppo rv = ldc_set_cb_mode(vdc->ldc_handle, LDC_CB_DISABLE); 4483af08d82Slm66018 DMSG(vdc, 0, "callback disabled (rv=%d)\n", rv); 4491ae08745Sheppo 4501ae08745Sheppo if (vdc->initialized & VDC_THREAD) { 4513af08d82Slm66018 mutex_enter(&vdc->read_lock); 4523af08d82Slm66018 if ((vdc->read_state == VDC_READ_WAITING) || 4533af08d82Slm66018 (vdc->read_state == VDC_READ_RESET)) { 4543af08d82Slm66018 vdc->read_state = VDC_READ_RESET; 4553af08d82Slm66018 cv_signal(&vdc->read_cv); 4561ae08745Sheppo } 4573af08d82Slm66018 4583af08d82Slm66018 mutex_exit(&vdc->read_lock); 4593af08d82Slm66018 4603af08d82Slm66018 /* wake up any thread waiting for connection to come online */ 4613af08d82Slm66018 mutex_enter(&vdc->lock); 4623af08d82Slm66018 if (vdc->state == VDC_STATE_INIT_WAITING) { 4633af08d82Slm66018 DMSG(vdc, 0, 4643af08d82Slm66018 "[%d] write reset - move to resetting state...\n", 4653af08d82Slm66018 instance); 4663af08d82Slm66018 vdc->state = VDC_STATE_RESETTING; 4673af08d82Slm66018 cv_signal(&vdc->initwait_cv); 4683af08d82Slm66018 } 4693af08d82Slm66018 mutex_exit(&vdc->lock); 4703af08d82Slm66018 4713af08d82Slm66018 /* now wait until state transitions to VDC_STATE_DETACH */ 4723af08d82Slm66018 thread_join(vdc->msg_proc_thr->t_did); 4733af08d82Slm66018 ASSERT(vdc->state == VDC_STATE_DETACH); 4743af08d82Slm66018 DMSG(vdc, 0, "[%d] Reset thread exit and join ..\n", 4753af08d82Slm66018 vdc->instance); 4761ae08745Sheppo } 4771ae08745Sheppo 4781ae08745Sheppo mutex_enter(&vdc->lock); 4791ae08745Sheppo 4801ae08745Sheppo if (vdc->initialized & VDC_DRING) 4811ae08745Sheppo vdc_destroy_descriptor_ring(vdc); 4821ae08745Sheppo 4831ae08745Sheppo if (vdc->initialized & VDC_LDC) 4841ae08745Sheppo vdc_terminate_ldc(vdc); 4851ae08745Sheppo 4862f5224aeSachartre if (vdc->failfast_thread) { 4872f5224aeSachartre failfast_tid = vdc->failfast_thread->t_did; 4882f5224aeSachartre vdc->failfast_interval = 0; 4892f5224aeSachartre cv_signal(&vdc->failfast_cv); 4902f5224aeSachartre } else { 4912f5224aeSachartre failfast_tid = 0; 4922f5224aeSachartre } 4932f5224aeSachartre 4942f5224aeSachartre if (vdc->ownership & VDC_OWNERSHIP_WANTED) { 4952f5224aeSachartre ownership_tid = vdc->ownership_thread->t_did; 4962f5224aeSachartre vdc->ownership = VDC_OWNERSHIP_NONE; 4972f5224aeSachartre cv_signal(&vdc->ownership_cv); 4982f5224aeSachartre } else { 4992f5224aeSachartre ownership_tid = 0; 5002f5224aeSachartre } 5012f5224aeSachartre 5021ae08745Sheppo mutex_exit(&vdc->lock); 5031ae08745Sheppo 5042f5224aeSachartre if (failfast_tid != 0) 5052f5224aeSachartre thread_join(failfast_tid); 5062f5224aeSachartre 5072f5224aeSachartre if (ownership_tid != 0) 5082f5224aeSachartre thread_join(ownership_tid); 5092f5224aeSachartre 5101ae08745Sheppo if (vdc->initialized & VDC_MINOR) { 5111ae08745Sheppo ddi_prop_remove_all(dip); 5121ae08745Sheppo ddi_remove_minor_node(dip, NULL); 5131ae08745Sheppo } 5141ae08745Sheppo 5151ae08745Sheppo if (vdc->initialized & VDC_LOCKS) { 5161ae08745Sheppo mutex_destroy(&vdc->lock); 5173af08d82Slm66018 mutex_destroy(&vdc->read_lock); 5182f5224aeSachartre mutex_destroy(&vdc->ownership_lock); 5193af08d82Slm66018 cv_destroy(&vdc->initwait_cv); 5203af08d82Slm66018 cv_destroy(&vdc->dring_free_cv); 5213af08d82Slm66018 cv_destroy(&vdc->membind_cv); 5223af08d82Slm66018 cv_destroy(&vdc->sync_pending_cv); 5233af08d82Slm66018 cv_destroy(&vdc->sync_blocked_cv); 5243af08d82Slm66018 cv_destroy(&vdc->read_cv); 5253af08d82Slm66018 cv_destroy(&vdc->running_cv); 5262f5224aeSachartre cv_destroy(&vdc->ownership_cv); 5272f5224aeSachartre cv_destroy(&vdc->failfast_cv); 5282f5224aeSachartre cv_destroy(&vdc->failfast_io_cv); 5291ae08745Sheppo } 5301ae08745Sheppo 5311ae08745Sheppo if (vdc->minfo) 5321ae08745Sheppo kmem_free(vdc->minfo, sizeof (struct dk_minfo)); 5331ae08745Sheppo 5341ae08745Sheppo if (vdc->cinfo) 5351ae08745Sheppo kmem_free(vdc->cinfo, sizeof (struct dk_cinfo)); 5361ae08745Sheppo 5371ae08745Sheppo if (vdc->vtoc) 5381ae08745Sheppo kmem_free(vdc->vtoc, sizeof (struct vtoc)); 5391ae08745Sheppo 54078fcd0a1Sachartre if (vdc->geom) 54178fcd0a1Sachartre kmem_free(vdc->geom, sizeof (struct dk_geom)); 5420a55fbb7Slm66018 5434bac2208Snarayan if (vdc->devid) { 5444bac2208Snarayan ddi_devid_unregister(dip); 5454bac2208Snarayan ddi_devid_free(vdc->devid); 5464bac2208Snarayan } 5474bac2208Snarayan 5481ae08745Sheppo if (vdc->initialized & VDC_SOFT_STATE) 5491ae08745Sheppo ddi_soft_state_free(vdc_state, instance); 5501ae08745Sheppo 5513af08d82Slm66018 DMSG(vdc, 0, "[%d] End %p\n", instance, (void *)vdc); 5521ae08745Sheppo 5531ae08745Sheppo return (DDI_SUCCESS); 5541ae08745Sheppo } 5551ae08745Sheppo 5561ae08745Sheppo 5571ae08745Sheppo static int 5581ae08745Sheppo vdc_do_attach(dev_info_t *dip) 5591ae08745Sheppo { 5601ae08745Sheppo int instance; 5611ae08745Sheppo vdc_t *vdc = NULL; 5621ae08745Sheppo int status; 563655fd6a9Sachartre md_t *mdp; 564655fd6a9Sachartre mde_cookie_t vd_node, vd_port; 5651ae08745Sheppo 5661ae08745Sheppo ASSERT(dip != NULL); 5671ae08745Sheppo 5681ae08745Sheppo instance = ddi_get_instance(dip); 5691ae08745Sheppo if (ddi_soft_state_zalloc(vdc_state, instance) != DDI_SUCCESS) { 570e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't alloc state structure", 571e1ebb9ecSlm66018 instance); 5721ae08745Sheppo return (DDI_FAILURE); 5731ae08745Sheppo } 5741ae08745Sheppo 5751ae08745Sheppo if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) { 576e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't get state structure", instance); 5771ae08745Sheppo return (DDI_FAILURE); 5781ae08745Sheppo } 5791ae08745Sheppo 5801ae08745Sheppo /* 5811ae08745Sheppo * We assign the value to initialized in this case to zero out the 5821ae08745Sheppo * variable and then set bits in it to indicate what has been done 5831ae08745Sheppo */ 5841ae08745Sheppo vdc->initialized = VDC_SOFT_STATE; 5851ae08745Sheppo 5863af08d82Slm66018 vdc_hz_min_ldc_delay = drv_usectohz(vdc_min_timeout_ldc); 5873af08d82Slm66018 vdc_hz_max_ldc_delay = drv_usectohz(vdc_max_timeout_ldc); 5881ae08745Sheppo 5891ae08745Sheppo vdc->dip = dip; 5901ae08745Sheppo vdc->instance = instance; 5911ae08745Sheppo vdc->vdisk_type = VD_DISK_TYPE_UNK; 5924bac2208Snarayan vdc->vdisk_label = VD_DISK_LABEL_UNK; 5933af08d82Slm66018 vdc->state = VDC_STATE_INIT; 5943af08d82Slm66018 vdc->lifecycle = VDC_LC_ATTACHING; 5951ae08745Sheppo vdc->ldc_state = 0; 5961ae08745Sheppo vdc->session_id = 0; 5971ae08745Sheppo vdc->block_size = DEV_BSIZE; 5988e6a2a04Slm66018 vdc->max_xfer_sz = maxphys / DEV_BSIZE; 5991ae08745Sheppo 60017cadca8Slm66018 /* 60117cadca8Slm66018 * We assume, for now, that the vDisk server will export 'read' 60217cadca8Slm66018 * operations to us at a minimum (this is needed because of checks 60317cadca8Slm66018 * in vdc for supported operations early in the handshake process). 60417cadca8Slm66018 * The vDisk server will return ENOTSUP if this is not the case. 60517cadca8Slm66018 * The value will be overwritten during the attribute exchange with 60617cadca8Slm66018 * the bitmask of operations exported by server. 60717cadca8Slm66018 */ 60817cadca8Slm66018 vdc->operations = VD_OP_MASK_READ; 60917cadca8Slm66018 6101ae08745Sheppo vdc->vtoc = NULL; 61178fcd0a1Sachartre vdc->geom = NULL; 6121ae08745Sheppo vdc->cinfo = NULL; 6131ae08745Sheppo vdc->minfo = NULL; 6141ae08745Sheppo 6151ae08745Sheppo mutex_init(&vdc->lock, NULL, MUTEX_DRIVER, NULL); 6163af08d82Slm66018 cv_init(&vdc->initwait_cv, NULL, CV_DRIVER, NULL); 6173af08d82Slm66018 cv_init(&vdc->dring_free_cv, NULL, CV_DRIVER, NULL); 6183af08d82Slm66018 cv_init(&vdc->membind_cv, NULL, CV_DRIVER, NULL); 6193af08d82Slm66018 cv_init(&vdc->running_cv, NULL, CV_DRIVER, NULL); 6203af08d82Slm66018 6213af08d82Slm66018 vdc->threads_pending = 0; 6223af08d82Slm66018 vdc->sync_op_pending = B_FALSE; 6233af08d82Slm66018 vdc->sync_op_blocked = B_FALSE; 6243af08d82Slm66018 cv_init(&vdc->sync_pending_cv, NULL, CV_DRIVER, NULL); 6253af08d82Slm66018 cv_init(&vdc->sync_blocked_cv, NULL, CV_DRIVER, NULL); 6263af08d82Slm66018 6272f5224aeSachartre mutex_init(&vdc->ownership_lock, NULL, MUTEX_DRIVER, NULL); 6282f5224aeSachartre cv_init(&vdc->ownership_cv, NULL, CV_DRIVER, NULL); 6292f5224aeSachartre cv_init(&vdc->failfast_cv, NULL, CV_DRIVER, NULL); 6302f5224aeSachartre cv_init(&vdc->failfast_io_cv, NULL, CV_DRIVER, NULL); 6312f5224aeSachartre 6323af08d82Slm66018 /* init blocking msg read functionality */ 6333af08d82Slm66018 mutex_init(&vdc->read_lock, NULL, MUTEX_DRIVER, NULL); 6343af08d82Slm66018 cv_init(&vdc->read_cv, NULL, CV_DRIVER, NULL); 6353af08d82Slm66018 vdc->read_state = VDC_READ_IDLE; 6363af08d82Slm66018 6371ae08745Sheppo vdc->initialized |= VDC_LOCKS; 6381ae08745Sheppo 639655fd6a9Sachartre /* get device and port MD node for this disk instance */ 640655fd6a9Sachartre if (vdc_get_md_node(dip, &mdp, &vd_node, &vd_port) != 0) { 641655fd6a9Sachartre cmn_err(CE_NOTE, "[%d] Could not get machine description node", 642655fd6a9Sachartre instance); 643655fd6a9Sachartre return (DDI_FAILURE); 644655fd6a9Sachartre } 645655fd6a9Sachartre 646655fd6a9Sachartre /* set the connection timeout */ 647655fd6a9Sachartre if (vd_port == NULL || (md_get_prop_val(mdp, vd_port, 648655fd6a9Sachartre VDC_MD_TIMEOUT, &vdc->ctimeout) != 0)) { 649655fd6a9Sachartre vdc->ctimeout = 0; 650655fd6a9Sachartre } 651655fd6a9Sachartre 6523af08d82Slm66018 /* initialise LDC channel which will be used to communicate with vds */ 653655fd6a9Sachartre status = vdc_do_ldc_init(vdc, mdp, vd_node); 654655fd6a9Sachartre 655655fd6a9Sachartre (void) md_fini_handle(mdp); 656655fd6a9Sachartre 657655fd6a9Sachartre if (status != 0) { 6583af08d82Slm66018 cmn_err(CE_NOTE, "[%d] Couldn't initialize LDC", instance); 6593af08d82Slm66018 goto return_status; 6603af08d82Slm66018 } 6613af08d82Slm66018 6623af08d82Slm66018 /* initialize the thread responsible for managing state with server */ 6633af08d82Slm66018 vdc->msg_proc_thr = thread_create(NULL, 0, vdc_process_msg_thread, 6641ae08745Sheppo vdc, 0, &p0, TS_RUN, minclsyspri); 6653af08d82Slm66018 if (vdc->msg_proc_thr == NULL) { 6661ae08745Sheppo cmn_err(CE_NOTE, "[%d] Failed to create msg processing thread", 6671ae08745Sheppo instance); 6681ae08745Sheppo return (DDI_FAILURE); 6691ae08745Sheppo } 6703af08d82Slm66018 6711ae08745Sheppo vdc->initialized |= VDC_THREAD; 6721ae08745Sheppo 673e1ebb9ecSlm66018 atomic_inc_32(&vdc_instance_count); 6741ae08745Sheppo 6750a55fbb7Slm66018 /* 67678fcd0a1Sachartre * Check the disk label. This will send requests and do the handshake. 67778fcd0a1Sachartre * We don't really care about the disk label now. What we really need is 67878fcd0a1Sachartre * the handshake do be done so that we know the type of the disk (slice 67978fcd0a1Sachartre * or full disk) and the appropriate device nodes can be created. 6800a55fbb7Slm66018 */ 68178fcd0a1Sachartre vdc->vdisk_label = VD_DISK_LABEL_UNK; 68278fcd0a1Sachartre vdc->vtoc = kmem_zalloc(sizeof (struct vtoc), KM_SLEEP); 68378fcd0a1Sachartre vdc->geom = kmem_zalloc(sizeof (struct dk_geom), KM_SLEEP); 68417cadca8Slm66018 vdc->minfo = kmem_zalloc(sizeof (struct dk_minfo), KM_SLEEP); 68578fcd0a1Sachartre 68678fcd0a1Sachartre mutex_enter(&vdc->lock); 68778fcd0a1Sachartre (void) vdc_validate_geometry(vdc); 68878fcd0a1Sachartre mutex_exit(&vdc->lock); 6891ae08745Sheppo 6901ae08745Sheppo /* 6911ae08745Sheppo * Now that we have the device info we can create the 6921ae08745Sheppo * device nodes and properties 6931ae08745Sheppo */ 6941ae08745Sheppo status = vdc_create_device_nodes(vdc); 6951ae08745Sheppo if (status) { 6963af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to create device nodes", 6971ae08745Sheppo instance); 6983af08d82Slm66018 goto return_status; 6991ae08745Sheppo } 7001ae08745Sheppo status = vdc_create_device_nodes_props(vdc); 7011ae08745Sheppo if (status) { 7023af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to create device nodes" 7030a55fbb7Slm66018 " properties (%d)", instance, status); 7043af08d82Slm66018 goto return_status; 7051ae08745Sheppo } 7061ae08745Sheppo 7074bac2208Snarayan /* 7084bac2208Snarayan * Setup devid 7094bac2208Snarayan */ 7104bac2208Snarayan if (vdc_setup_devid(vdc)) { 7113af08d82Slm66018 DMSG(vdc, 0, "[%d] No device id available\n", instance); 7124bac2208Snarayan } 7134bac2208Snarayan 7141ae08745Sheppo ddi_report_dev(dip); 7153af08d82Slm66018 vdc->lifecycle = VDC_LC_ONLINE; 7163af08d82Slm66018 DMSG(vdc, 0, "[%d] Attach tasks successful\n", instance); 7171ae08745Sheppo 7183af08d82Slm66018 return_status: 7193af08d82Slm66018 DMSG(vdc, 0, "[%d] Attach completed\n", instance); 7201ae08745Sheppo return (status); 7211ae08745Sheppo } 7221ae08745Sheppo 7231ae08745Sheppo static int 7241ae08745Sheppo vdc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 7251ae08745Sheppo { 7261ae08745Sheppo int status; 7271ae08745Sheppo 7281ae08745Sheppo switch (cmd) { 7291ae08745Sheppo case DDI_ATTACH: 7301ae08745Sheppo if ((status = vdc_do_attach(dip)) != 0) 7311ae08745Sheppo (void) vdc_detach(dip, DDI_DETACH); 7321ae08745Sheppo return (status); 7331ae08745Sheppo case DDI_RESUME: 7341ae08745Sheppo /* nothing to do for this non-device */ 7351ae08745Sheppo return (DDI_SUCCESS); 7361ae08745Sheppo default: 7371ae08745Sheppo return (DDI_FAILURE); 7381ae08745Sheppo } 7391ae08745Sheppo } 7401ae08745Sheppo 7411ae08745Sheppo static int 742655fd6a9Sachartre vdc_do_ldc_init(vdc_t *vdc, md_t *mdp, mde_cookie_t vd_node) 7431ae08745Sheppo { 7441ae08745Sheppo int status = 0; 7451ae08745Sheppo ldc_status_t ldc_state; 7461ae08745Sheppo ldc_attr_t ldc_attr; 7471ae08745Sheppo uint64_t ldc_id = 0; 7481ae08745Sheppo 7491ae08745Sheppo ASSERT(vdc != NULL); 7501ae08745Sheppo 7511ae08745Sheppo vdc->initialized |= VDC_LDC; 7521ae08745Sheppo 753655fd6a9Sachartre if ((status = vdc_get_ldc_id(mdp, vd_node, &ldc_id)) != 0) { 7543af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to get LDC channel ID property", 755e1ebb9ecSlm66018 vdc->instance); 7561ae08745Sheppo return (EIO); 7571ae08745Sheppo } 758655fd6a9Sachartre 759655fd6a9Sachartre DMSGX(0, "[%d] LDC id is 0x%lx\n", vdc->instance, ldc_id); 760655fd6a9Sachartre 7611ae08745Sheppo vdc->ldc_id = ldc_id; 7621ae08745Sheppo 7631ae08745Sheppo ldc_attr.devclass = LDC_DEV_BLK; 7641ae08745Sheppo ldc_attr.instance = vdc->instance; 7651ae08745Sheppo ldc_attr.mode = LDC_MODE_UNRELIABLE; /* unreliable transport */ 766e1ebb9ecSlm66018 ldc_attr.mtu = VD_LDC_MTU; 7671ae08745Sheppo 7681ae08745Sheppo if ((vdc->initialized & VDC_LDC_INIT) == 0) { 7691ae08745Sheppo status = ldc_init(ldc_id, &ldc_attr, &vdc->ldc_handle); 7701ae08745Sheppo if (status != 0) { 7713af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_init(chan %ld) returned %d", 7721ae08745Sheppo vdc->instance, ldc_id, status); 7731ae08745Sheppo return (status); 7741ae08745Sheppo } 7751ae08745Sheppo vdc->initialized |= VDC_LDC_INIT; 7761ae08745Sheppo } 7771ae08745Sheppo status = ldc_status(vdc->ldc_handle, &ldc_state); 7781ae08745Sheppo if (status != 0) { 7793af08d82Slm66018 DMSG(vdc, 0, "[%d] Cannot discover LDC status [err=%d]", 780e1ebb9ecSlm66018 vdc->instance, status); 7811ae08745Sheppo return (status); 7821ae08745Sheppo } 7831ae08745Sheppo vdc->ldc_state = ldc_state; 7841ae08745Sheppo 7851ae08745Sheppo if ((vdc->initialized & VDC_LDC_CB) == 0) { 7861ae08745Sheppo status = ldc_reg_callback(vdc->ldc_handle, vdc_handle_cb, 7871ae08745Sheppo (caddr_t)vdc); 7881ae08745Sheppo if (status != 0) { 7893af08d82Slm66018 DMSG(vdc, 0, "[%d] LDC callback reg. failed (%d)", 790e1ebb9ecSlm66018 vdc->instance, status); 7911ae08745Sheppo return (status); 7921ae08745Sheppo } 7931ae08745Sheppo vdc->initialized |= VDC_LDC_CB; 7941ae08745Sheppo } 7951ae08745Sheppo 7961ae08745Sheppo vdc->initialized |= VDC_LDC; 7971ae08745Sheppo 7981ae08745Sheppo /* 7991ae08745Sheppo * At this stage we have initialised LDC, we will now try and open 8001ae08745Sheppo * the connection. 8011ae08745Sheppo */ 8021ae08745Sheppo if (vdc->ldc_state == LDC_INIT) { 8031ae08745Sheppo status = ldc_open(vdc->ldc_handle); 8041ae08745Sheppo if (status != 0) { 8053af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_open(chan %ld) returned %d", 8061ae08745Sheppo vdc->instance, vdc->ldc_id, status); 8071ae08745Sheppo return (status); 8081ae08745Sheppo } 8091ae08745Sheppo vdc->initialized |= VDC_LDC_OPEN; 8101ae08745Sheppo } 8111ae08745Sheppo 8121ae08745Sheppo return (status); 8131ae08745Sheppo } 8141ae08745Sheppo 8151ae08745Sheppo static int 8161ae08745Sheppo vdc_start_ldc_connection(vdc_t *vdc) 8171ae08745Sheppo { 8181ae08745Sheppo int status = 0; 8191ae08745Sheppo 8201ae08745Sheppo ASSERT(vdc != NULL); 8211ae08745Sheppo 8223af08d82Slm66018 ASSERT(MUTEX_HELD(&vdc->lock)); 8231ae08745Sheppo 8240a55fbb7Slm66018 status = vdc_do_ldc_up(vdc); 8251ae08745Sheppo 8263af08d82Slm66018 DMSG(vdc, 0, "[%d] Finished bringing up LDC\n", vdc->instance); 8271ae08745Sheppo 8283af08d82Slm66018 return (status); 8293af08d82Slm66018 } 8303af08d82Slm66018 8313af08d82Slm66018 static int 8323af08d82Slm66018 vdc_stop_ldc_connection(vdc_t *vdcp) 8333af08d82Slm66018 { 8343af08d82Slm66018 int status; 8353af08d82Slm66018 8363af08d82Slm66018 DMSG(vdcp, 0, ": Resetting connection to vDisk server : state %d\n", 8373af08d82Slm66018 vdcp->state); 8383af08d82Slm66018 8393af08d82Slm66018 status = ldc_down(vdcp->ldc_handle); 8403af08d82Slm66018 DMSG(vdcp, 0, "ldc_down() = %d\n", status); 8413af08d82Slm66018 8423af08d82Slm66018 vdcp->initialized &= ~VDC_HANDSHAKE; 8433af08d82Slm66018 DMSG(vdcp, 0, "initialized=%x\n", vdcp->initialized); 8441ae08745Sheppo 8451ae08745Sheppo return (status); 8461ae08745Sheppo } 8471ae08745Sheppo 8484bac2208Snarayan static int 8494bac2208Snarayan vdc_create_device_nodes_efi(vdc_t *vdc) 8504bac2208Snarayan { 8514bac2208Snarayan ddi_remove_minor_node(vdc->dip, "h"); 8524bac2208Snarayan ddi_remove_minor_node(vdc->dip, "h,raw"); 8534bac2208Snarayan 8544bac2208Snarayan if (ddi_create_minor_node(vdc->dip, "wd", S_IFBLK, 8554bac2208Snarayan VD_MAKE_DEV(vdc->instance, VD_EFI_WD_SLICE), 8564bac2208Snarayan DDI_NT_BLOCK, 0) != DDI_SUCCESS) { 8574bac2208Snarayan cmn_err(CE_NOTE, "[%d] Couldn't add block node 'wd'", 8584bac2208Snarayan vdc->instance); 8594bac2208Snarayan return (EIO); 8604bac2208Snarayan } 8614bac2208Snarayan 8624bac2208Snarayan /* if any device node is created we set this flag */ 8634bac2208Snarayan vdc->initialized |= VDC_MINOR; 8644bac2208Snarayan 8654bac2208Snarayan if (ddi_create_minor_node(vdc->dip, "wd,raw", S_IFCHR, 8664bac2208Snarayan VD_MAKE_DEV(vdc->instance, VD_EFI_WD_SLICE), 8674bac2208Snarayan DDI_NT_BLOCK, 0) != DDI_SUCCESS) { 8684bac2208Snarayan cmn_err(CE_NOTE, "[%d] Couldn't add block node 'wd,raw'", 8694bac2208Snarayan vdc->instance); 8704bac2208Snarayan return (EIO); 8714bac2208Snarayan } 8724bac2208Snarayan 8734bac2208Snarayan return (0); 8744bac2208Snarayan } 8754bac2208Snarayan 8764bac2208Snarayan static int 8774bac2208Snarayan vdc_create_device_nodes_vtoc(vdc_t *vdc) 8784bac2208Snarayan { 8794bac2208Snarayan ddi_remove_minor_node(vdc->dip, "wd"); 8804bac2208Snarayan ddi_remove_minor_node(vdc->dip, "wd,raw"); 8814bac2208Snarayan 8824bac2208Snarayan if (ddi_create_minor_node(vdc->dip, "h", S_IFBLK, 8834bac2208Snarayan VD_MAKE_DEV(vdc->instance, VD_EFI_WD_SLICE), 8844bac2208Snarayan DDI_NT_BLOCK, 0) != DDI_SUCCESS) { 8854bac2208Snarayan cmn_err(CE_NOTE, "[%d] Couldn't add block node 'h'", 8864bac2208Snarayan vdc->instance); 8874bac2208Snarayan return (EIO); 8884bac2208Snarayan } 8894bac2208Snarayan 8904bac2208Snarayan /* if any device node is created we set this flag */ 8914bac2208Snarayan vdc->initialized |= VDC_MINOR; 8924bac2208Snarayan 8934bac2208Snarayan if (ddi_create_minor_node(vdc->dip, "h,raw", S_IFCHR, 8944bac2208Snarayan VD_MAKE_DEV(vdc->instance, VD_EFI_WD_SLICE), 8954bac2208Snarayan DDI_NT_BLOCK, 0) != DDI_SUCCESS) { 8964bac2208Snarayan cmn_err(CE_NOTE, "[%d] Couldn't add block node 'h,raw'", 8974bac2208Snarayan vdc->instance); 8984bac2208Snarayan return (EIO); 8994bac2208Snarayan } 9004bac2208Snarayan 9014bac2208Snarayan return (0); 9024bac2208Snarayan } 9031ae08745Sheppo 9041ae08745Sheppo /* 9051ae08745Sheppo * Function: 9061ae08745Sheppo * vdc_create_device_nodes 9071ae08745Sheppo * 9081ae08745Sheppo * Description: 9091ae08745Sheppo * This function creates the block and character device nodes under 9101ae08745Sheppo * /devices along with the node properties. It is called as part of 9111ae08745Sheppo * the attach(9E) of the instance during the handshake with vds after 9121ae08745Sheppo * vds has sent the attributes to vdc. 9131ae08745Sheppo * 9141ae08745Sheppo * If the device is of type VD_DISK_TYPE_SLICE then the minor node 9151ae08745Sheppo * of 2 is used in keeping with the Solaris convention that slice 2 9161ae08745Sheppo * refers to a whole disk. Slices start at 'a' 9171ae08745Sheppo * 9181ae08745Sheppo * Parameters: 9191ae08745Sheppo * vdc - soft state pointer 9201ae08745Sheppo * 9211ae08745Sheppo * Return Values 9221ae08745Sheppo * 0 - Success 9231ae08745Sheppo * EIO - Failed to create node 9241ae08745Sheppo * EINVAL - Unknown type of disk exported 9251ae08745Sheppo */ 9261ae08745Sheppo static int 9271ae08745Sheppo vdc_create_device_nodes(vdc_t *vdc) 9281ae08745Sheppo { 9294bac2208Snarayan char name[sizeof ("s,raw")]; 9301ae08745Sheppo dev_info_t *dip = NULL; 9314bac2208Snarayan int instance, status; 9321ae08745Sheppo int num_slices = 1; 9331ae08745Sheppo int i; 9341ae08745Sheppo 9351ae08745Sheppo ASSERT(vdc != NULL); 9361ae08745Sheppo 9371ae08745Sheppo instance = vdc->instance; 9381ae08745Sheppo dip = vdc->dip; 9391ae08745Sheppo 9401ae08745Sheppo switch (vdc->vdisk_type) { 9411ae08745Sheppo case VD_DISK_TYPE_DISK: 9421ae08745Sheppo num_slices = V_NUMPAR; 9431ae08745Sheppo break; 9441ae08745Sheppo case VD_DISK_TYPE_SLICE: 9451ae08745Sheppo num_slices = 1; 9461ae08745Sheppo break; 9471ae08745Sheppo case VD_DISK_TYPE_UNK: 9481ae08745Sheppo default: 9491ae08745Sheppo return (EINVAL); 9501ae08745Sheppo } 9511ae08745Sheppo 9524bac2208Snarayan /* 9534bac2208Snarayan * Minor nodes are different for EFI disks: EFI disks do not have 9544bac2208Snarayan * a minor node 'g' for the minor number corresponding to slice 9554bac2208Snarayan * VD_EFI_WD_SLICE (slice 7) instead they have a minor node 'wd' 9564bac2208Snarayan * representing the whole disk. 9574bac2208Snarayan */ 9581ae08745Sheppo for (i = 0; i < num_slices; i++) { 9594bac2208Snarayan 9604bac2208Snarayan if (i == VD_EFI_WD_SLICE) { 9614bac2208Snarayan if (vdc->vdisk_label == VD_DISK_LABEL_EFI) 9624bac2208Snarayan status = vdc_create_device_nodes_efi(vdc); 9634bac2208Snarayan else 9644bac2208Snarayan status = vdc_create_device_nodes_vtoc(vdc); 9654bac2208Snarayan if (status != 0) 9664bac2208Snarayan return (status); 9674bac2208Snarayan continue; 9684bac2208Snarayan } 9694bac2208Snarayan 9701ae08745Sheppo (void) snprintf(name, sizeof (name), "%c", 'a' + i); 9711ae08745Sheppo if (ddi_create_minor_node(dip, name, S_IFBLK, 9721ae08745Sheppo VD_MAKE_DEV(instance, i), DDI_NT_BLOCK, 0) != DDI_SUCCESS) { 973e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't add block node '%s'", 974e1ebb9ecSlm66018 instance, name); 9751ae08745Sheppo return (EIO); 9761ae08745Sheppo } 9771ae08745Sheppo 9781ae08745Sheppo /* if any device node is created we set this flag */ 9791ae08745Sheppo vdc->initialized |= VDC_MINOR; 9801ae08745Sheppo 98187a7269eSachartre (void) snprintf(name, sizeof (name), "%c%s", 'a' + i, ",raw"); 98287a7269eSachartre 9831ae08745Sheppo if (ddi_create_minor_node(dip, name, S_IFCHR, 9841ae08745Sheppo VD_MAKE_DEV(instance, i), DDI_NT_BLOCK, 0) != DDI_SUCCESS) { 985e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't add raw node '%s'", 986e1ebb9ecSlm66018 instance, name); 9871ae08745Sheppo return (EIO); 9881ae08745Sheppo } 9891ae08745Sheppo } 9901ae08745Sheppo 9911ae08745Sheppo return (0); 9921ae08745Sheppo } 9931ae08745Sheppo 9941ae08745Sheppo /* 9951ae08745Sheppo * Function: 9961ae08745Sheppo * vdc_create_device_nodes_props 9971ae08745Sheppo * 9981ae08745Sheppo * Description: 9991ae08745Sheppo * This function creates the block and character device nodes under 10001ae08745Sheppo * /devices along with the node properties. It is called as part of 10011ae08745Sheppo * the attach(9E) of the instance during the handshake with vds after 10021ae08745Sheppo * vds has sent the attributes to vdc. 10031ae08745Sheppo * 10041ae08745Sheppo * Parameters: 10051ae08745Sheppo * vdc - soft state pointer 10061ae08745Sheppo * 10071ae08745Sheppo * Return Values 10081ae08745Sheppo * 0 - Success 10091ae08745Sheppo * EIO - Failed to create device node property 10101ae08745Sheppo * EINVAL - Unknown type of disk exported 10111ae08745Sheppo */ 10121ae08745Sheppo static int 10131ae08745Sheppo vdc_create_device_nodes_props(vdc_t *vdc) 10141ae08745Sheppo { 10151ae08745Sheppo dev_info_t *dip = NULL; 10161ae08745Sheppo int instance; 10171ae08745Sheppo int num_slices = 1; 10181ae08745Sheppo int64_t size = 0; 10191ae08745Sheppo dev_t dev; 10201ae08745Sheppo int rv; 10211ae08745Sheppo int i; 10221ae08745Sheppo 10231ae08745Sheppo ASSERT(vdc != NULL); 10241ae08745Sheppo 10251ae08745Sheppo instance = vdc->instance; 10261ae08745Sheppo dip = vdc->dip; 10271ae08745Sheppo 10281ae08745Sheppo switch (vdc->vdisk_type) { 10291ae08745Sheppo case VD_DISK_TYPE_DISK: 10301ae08745Sheppo num_slices = V_NUMPAR; 10311ae08745Sheppo break; 10321ae08745Sheppo case VD_DISK_TYPE_SLICE: 10331ae08745Sheppo num_slices = 1; 10341ae08745Sheppo break; 10351ae08745Sheppo case VD_DISK_TYPE_UNK: 10361ae08745Sheppo default: 10371ae08745Sheppo return (EINVAL); 10381ae08745Sheppo } 10391ae08745Sheppo 104078fcd0a1Sachartre if (vdc->vdisk_label == VD_DISK_LABEL_UNK) { 104178fcd0a1Sachartre /* remove all properties */ 104278fcd0a1Sachartre for (i = 0; i < num_slices; i++) { 104378fcd0a1Sachartre dev = makedevice(ddi_driver_major(dip), 104478fcd0a1Sachartre VD_MAKE_DEV(instance, i)); 104578fcd0a1Sachartre (void) ddi_prop_remove(dev, dip, VDC_SIZE_PROP_NAME); 104678fcd0a1Sachartre (void) ddi_prop_remove(dev, dip, VDC_NBLOCKS_PROP_NAME); 104778fcd0a1Sachartre } 104878fcd0a1Sachartre return (0); 104978fcd0a1Sachartre } 105078fcd0a1Sachartre 10511ae08745Sheppo for (i = 0; i < num_slices; i++) { 10521ae08745Sheppo dev = makedevice(ddi_driver_major(dip), 10531ae08745Sheppo VD_MAKE_DEV(instance, i)); 10541ae08745Sheppo 1055edcc0754Sachartre size = vdc->slice[i].nblocks * vdc->block_size; 10563af08d82Slm66018 DMSG(vdc, 0, "[%d] sz %ld (%ld Mb) p_size %lx\n", 1057e1ebb9ecSlm66018 instance, size, size / (1024 * 1024), 1058edcc0754Sachartre vdc->slice[i].nblocks); 10591ae08745Sheppo 10601ae08745Sheppo rv = ddi_prop_update_int64(dev, dip, VDC_SIZE_PROP_NAME, size); 10611ae08745Sheppo if (rv != DDI_PROP_SUCCESS) { 1062e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't add '%s' prop of [%ld]", 1063e1ebb9ecSlm66018 instance, VDC_SIZE_PROP_NAME, size); 10641ae08745Sheppo return (EIO); 10651ae08745Sheppo } 10661ae08745Sheppo 10671ae08745Sheppo rv = ddi_prop_update_int64(dev, dip, VDC_NBLOCKS_PROP_NAME, 10681ae08745Sheppo lbtodb(size)); 10691ae08745Sheppo if (rv != DDI_PROP_SUCCESS) { 1070e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't add '%s' prop [%llu]", 10711ae08745Sheppo instance, VDC_NBLOCKS_PROP_NAME, lbtodb(size)); 10721ae08745Sheppo return (EIO); 10731ae08745Sheppo } 10741ae08745Sheppo } 10751ae08745Sheppo 10761ae08745Sheppo return (0); 10771ae08745Sheppo } 10781ae08745Sheppo 107978fcd0a1Sachartre /* 108078fcd0a1Sachartre * Function: 108178fcd0a1Sachartre * vdc_is_opened 108278fcd0a1Sachartre * 108378fcd0a1Sachartre * Description: 108478fcd0a1Sachartre * This function checks if any slice of a given virtual disk is 108578fcd0a1Sachartre * currently opened. 108678fcd0a1Sachartre * 108778fcd0a1Sachartre * Parameters: 108878fcd0a1Sachartre * vdc - soft state pointer 108978fcd0a1Sachartre * 109078fcd0a1Sachartre * Return Values 109178fcd0a1Sachartre * B_TRUE - at least one slice is opened. 109278fcd0a1Sachartre * B_FALSE - no slice is opened. 109378fcd0a1Sachartre */ 109478fcd0a1Sachartre static boolean_t 109578fcd0a1Sachartre vdc_is_opened(vdc_t *vdc) 109678fcd0a1Sachartre { 109778fcd0a1Sachartre int i, nslices; 109878fcd0a1Sachartre 109978fcd0a1Sachartre switch (vdc->vdisk_type) { 110078fcd0a1Sachartre case VD_DISK_TYPE_DISK: 110178fcd0a1Sachartre nslices = V_NUMPAR; 110278fcd0a1Sachartre break; 110378fcd0a1Sachartre case VD_DISK_TYPE_SLICE: 110478fcd0a1Sachartre nslices = 1; 110578fcd0a1Sachartre break; 110678fcd0a1Sachartre case VD_DISK_TYPE_UNK: 110778fcd0a1Sachartre default: 110878fcd0a1Sachartre ASSERT(0); 110978fcd0a1Sachartre } 111078fcd0a1Sachartre 111178fcd0a1Sachartre /* check if there's any layered open */ 111278fcd0a1Sachartre for (i = 0; i < nslices; i++) { 111378fcd0a1Sachartre if (vdc->open_lyr[i] > 0) 111478fcd0a1Sachartre return (B_TRUE); 111578fcd0a1Sachartre } 111678fcd0a1Sachartre 111778fcd0a1Sachartre /* check if there is any other kind of open */ 111878fcd0a1Sachartre for (i = 0; i < OTYPCNT; i++) { 111978fcd0a1Sachartre if (vdc->open[i] != 0) 112078fcd0a1Sachartre return (B_TRUE); 112178fcd0a1Sachartre } 112278fcd0a1Sachartre 112378fcd0a1Sachartre return (B_FALSE); 112478fcd0a1Sachartre } 112578fcd0a1Sachartre 112678fcd0a1Sachartre static int 112778fcd0a1Sachartre vdc_mark_opened(vdc_t *vdc, int slice, int flag, int otyp) 112878fcd0a1Sachartre { 112978fcd0a1Sachartre uint8_t slicemask; 113078fcd0a1Sachartre int i; 113178fcd0a1Sachartre 113278fcd0a1Sachartre ASSERT(otyp < OTYPCNT); 113378fcd0a1Sachartre ASSERT(slice < V_NUMPAR); 113478fcd0a1Sachartre ASSERT(MUTEX_HELD(&vdc->lock)); 113578fcd0a1Sachartre 113678fcd0a1Sachartre slicemask = 1 << slice; 113778fcd0a1Sachartre 113878fcd0a1Sachartre /* check if slice is already exclusively opened */ 113978fcd0a1Sachartre if (vdc->open_excl & slicemask) 114078fcd0a1Sachartre return (EBUSY); 114178fcd0a1Sachartre 114278fcd0a1Sachartre /* if open exclusive, check if slice is already opened */ 114378fcd0a1Sachartre if (flag & FEXCL) { 114478fcd0a1Sachartre if (vdc->open_lyr[slice] > 0) 114578fcd0a1Sachartre return (EBUSY); 114678fcd0a1Sachartre for (i = 0; i < OTYPCNT; i++) { 114778fcd0a1Sachartre if (vdc->open[i] & slicemask) 114878fcd0a1Sachartre return (EBUSY); 114978fcd0a1Sachartre } 115078fcd0a1Sachartre vdc->open_excl |= slicemask; 115178fcd0a1Sachartre } 115278fcd0a1Sachartre 115378fcd0a1Sachartre /* mark slice as opened */ 115478fcd0a1Sachartre if (otyp == OTYP_LYR) { 115578fcd0a1Sachartre vdc->open_lyr[slice]++; 115678fcd0a1Sachartre } else { 115778fcd0a1Sachartre vdc->open[otyp] |= slicemask; 115878fcd0a1Sachartre } 115978fcd0a1Sachartre 116078fcd0a1Sachartre return (0); 116178fcd0a1Sachartre } 116278fcd0a1Sachartre 116378fcd0a1Sachartre static void 116478fcd0a1Sachartre vdc_mark_closed(vdc_t *vdc, int slice, int flag, int otyp) 116578fcd0a1Sachartre { 116678fcd0a1Sachartre uint8_t slicemask; 116778fcd0a1Sachartre 116878fcd0a1Sachartre ASSERT(otyp < OTYPCNT); 116978fcd0a1Sachartre ASSERT(slice < V_NUMPAR); 117078fcd0a1Sachartre ASSERT(MUTEX_HELD(&vdc->lock)); 117178fcd0a1Sachartre 117278fcd0a1Sachartre slicemask = 1 << slice; 117378fcd0a1Sachartre 117478fcd0a1Sachartre if (otyp == OTYP_LYR) { 117578fcd0a1Sachartre ASSERT(vdc->open_lyr[slice] > 0); 117678fcd0a1Sachartre vdc->open_lyr[slice]--; 117778fcd0a1Sachartre } else { 117878fcd0a1Sachartre vdc->open[otyp] &= ~slicemask; 117978fcd0a1Sachartre } 118078fcd0a1Sachartre 118178fcd0a1Sachartre if (flag & FEXCL) 118278fcd0a1Sachartre vdc->open_excl &= ~slicemask; 118378fcd0a1Sachartre } 118478fcd0a1Sachartre 11851ae08745Sheppo static int 11861ae08745Sheppo vdc_open(dev_t *dev, int flag, int otyp, cred_t *cred) 11871ae08745Sheppo { 11881ae08745Sheppo _NOTE(ARGUNUSED(cred)) 11891ae08745Sheppo 11901ae08745Sheppo int instance; 119178fcd0a1Sachartre int slice, status = 0; 11921ae08745Sheppo vdc_t *vdc; 11931ae08745Sheppo 11941ae08745Sheppo ASSERT(dev != NULL); 11950d0c8d4bSnarayan instance = VDCUNIT(*dev); 11961ae08745Sheppo 119778fcd0a1Sachartre if (otyp >= OTYPCNT) 11981ae08745Sheppo return (EINVAL); 11991ae08745Sheppo 12001ae08745Sheppo if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) { 1201e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't get state structure", instance); 12021ae08745Sheppo return (ENXIO); 12031ae08745Sheppo } 12041ae08745Sheppo 12053af08d82Slm66018 DMSG(vdc, 0, "minor = %d flag = %x, otyp = %x\n", 12063af08d82Slm66018 getminor(*dev), flag, otyp); 12071ae08745Sheppo 120878fcd0a1Sachartre slice = VDCPART(*dev); 120978fcd0a1Sachartre 12101ae08745Sheppo mutex_enter(&vdc->lock); 121178fcd0a1Sachartre 121278fcd0a1Sachartre status = vdc_mark_opened(vdc, slice, flag, otyp); 121378fcd0a1Sachartre 121478fcd0a1Sachartre if (status != 0) { 121578fcd0a1Sachartre mutex_exit(&vdc->lock); 121678fcd0a1Sachartre return (status); 121778fcd0a1Sachartre } 121878fcd0a1Sachartre 121978fcd0a1Sachartre if (flag & (FNDELAY | FNONBLOCK)) { 122078fcd0a1Sachartre 122178fcd0a1Sachartre /* don't resubmit a validate request if there's already one */ 122278fcd0a1Sachartre if (vdc->validate_pending > 0) { 122378fcd0a1Sachartre mutex_exit(&vdc->lock); 122478fcd0a1Sachartre return (0); 122578fcd0a1Sachartre } 122678fcd0a1Sachartre 122778fcd0a1Sachartre /* call vdc_validate() asynchronously to avoid blocking */ 122878fcd0a1Sachartre if (taskq_dispatch(system_taskq, vdc_validate_task, 122978fcd0a1Sachartre (void *)vdc, TQ_NOSLEEP) == NULL) { 123078fcd0a1Sachartre vdc_mark_closed(vdc, slice, flag, otyp); 123178fcd0a1Sachartre mutex_exit(&vdc->lock); 123278fcd0a1Sachartre return (ENXIO); 123378fcd0a1Sachartre } 123478fcd0a1Sachartre 123578fcd0a1Sachartre vdc->validate_pending++; 123678fcd0a1Sachartre mutex_exit(&vdc->lock); 123778fcd0a1Sachartre return (0); 123878fcd0a1Sachartre } 123978fcd0a1Sachartre 12401ae08745Sheppo mutex_exit(&vdc->lock); 12411ae08745Sheppo 124278fcd0a1Sachartre vdc_validate(vdc); 124378fcd0a1Sachartre 124478fcd0a1Sachartre mutex_enter(&vdc->lock); 124578fcd0a1Sachartre 124678fcd0a1Sachartre if (vdc->vdisk_label == VD_DISK_LABEL_UNK || 1247edcc0754Sachartre vdc->slice[slice].nblocks == 0) { 124878fcd0a1Sachartre vdc_mark_closed(vdc, slice, flag, otyp); 124978fcd0a1Sachartre status = EIO; 125078fcd0a1Sachartre } 125178fcd0a1Sachartre 125278fcd0a1Sachartre mutex_exit(&vdc->lock); 125378fcd0a1Sachartre 125478fcd0a1Sachartre return (status); 12551ae08745Sheppo } 12561ae08745Sheppo 12571ae08745Sheppo static int 12581ae08745Sheppo vdc_close(dev_t dev, int flag, int otyp, cred_t *cred) 12591ae08745Sheppo { 12601ae08745Sheppo _NOTE(ARGUNUSED(cred)) 12611ae08745Sheppo 12621ae08745Sheppo int instance; 126378fcd0a1Sachartre int slice; 12642f5224aeSachartre int rv, rval; 12651ae08745Sheppo vdc_t *vdc; 12661ae08745Sheppo 12670d0c8d4bSnarayan instance = VDCUNIT(dev); 12681ae08745Sheppo 126978fcd0a1Sachartre if (otyp >= OTYPCNT) 12701ae08745Sheppo return (EINVAL); 12711ae08745Sheppo 12721ae08745Sheppo if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) { 1273e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't get state structure", instance); 12741ae08745Sheppo return (ENXIO); 12751ae08745Sheppo } 12761ae08745Sheppo 12773af08d82Slm66018 DMSG(vdc, 0, "[%d] flag = %x, otyp = %x\n", instance, flag, otyp); 12781ae08745Sheppo 127978fcd0a1Sachartre slice = VDCPART(dev); 128078fcd0a1Sachartre 12818259acd8Szk194757 /* 12828259acd8Szk194757 * Attempt to flush the W$ on a close operation. If this is 12838259acd8Szk194757 * not a supported IOCTL command or the backing device is read-only 12848259acd8Szk194757 * do not fail the close operation. 12858259acd8Szk194757 */ 12862f5224aeSachartre rv = vd_process_ioctl(dev, DKIOCFLUSHWRITECACHE, NULL, FKIOCTL, &rval); 12878259acd8Szk194757 12888259acd8Szk194757 if (rv != 0 && rv != ENOTSUP && rv != ENOTTY && rv != EROFS) { 12898259acd8Szk194757 DMSG(vdc, 0, "[%d] flush failed with error %d on close\n", 12908259acd8Szk194757 instance, rv); 12918259acd8Szk194757 return (EIO); 12928259acd8Szk194757 } 12938259acd8Szk194757 12941ae08745Sheppo mutex_enter(&vdc->lock); 129578fcd0a1Sachartre vdc_mark_closed(vdc, slice, flag, otyp); 12961ae08745Sheppo mutex_exit(&vdc->lock); 12971ae08745Sheppo 12981ae08745Sheppo return (0); 12991ae08745Sheppo } 13001ae08745Sheppo 13011ae08745Sheppo static int 13021ae08745Sheppo vdc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) 13031ae08745Sheppo { 13041ae08745Sheppo _NOTE(ARGUNUSED(credp)) 13051ae08745Sheppo 13062f5224aeSachartre return (vd_process_ioctl(dev, cmd, (caddr_t)arg, mode, rvalp)); 13071ae08745Sheppo } 13081ae08745Sheppo 13091ae08745Sheppo static int 13101ae08745Sheppo vdc_print(dev_t dev, char *str) 13111ae08745Sheppo { 13120d0c8d4bSnarayan cmn_err(CE_NOTE, "vdc%d: %s", VDCUNIT(dev), str); 13131ae08745Sheppo return (0); 13141ae08745Sheppo } 13151ae08745Sheppo 13161ae08745Sheppo static int 13171ae08745Sheppo vdc_dump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk) 13181ae08745Sheppo { 1319d10e4ef2Snarayan int rv; 1320d10e4ef2Snarayan size_t nbytes = nblk * DEV_BSIZE; 13210d0c8d4bSnarayan int instance = VDCUNIT(dev); 1322d10e4ef2Snarayan vdc_t *vdc = NULL; 13231ae08745Sheppo 13241ae08745Sheppo if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) { 1325e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't get state structure", instance); 13261ae08745Sheppo return (ENXIO); 13271ae08745Sheppo } 13281ae08745Sheppo 13293af08d82Slm66018 DMSG(vdc, 2, "[%d] dump %ld bytes at block 0x%lx : addr=0x%p\n", 13303af08d82Slm66018 instance, nbytes, blkno, (void *)addr); 13313af08d82Slm66018 rv = vdc_send_request(vdc, VD_OP_BWRITE, addr, nbytes, 13320d0c8d4bSnarayan VDCPART(dev), blkno, CB_STRATEGY, 0, VIO_write_dir); 13333af08d82Slm66018 if (rv) { 13343af08d82Slm66018 DMSG(vdc, 0, "Failed to do a disk dump (err=%d)\n", rv); 13351ae08745Sheppo return (rv); 13361ae08745Sheppo } 13371ae08745Sheppo 13383af08d82Slm66018 if (ddi_in_panic()) 13393af08d82Slm66018 (void) vdc_drain_response(vdc); 13403af08d82Slm66018 13413af08d82Slm66018 DMSG(vdc, 0, "[%d] End\n", instance); 13423af08d82Slm66018 13433af08d82Slm66018 return (0); 13443af08d82Slm66018 } 13453af08d82Slm66018 13461ae08745Sheppo /* -------------------------------------------------------------------------- */ 13471ae08745Sheppo 13481ae08745Sheppo /* 13491ae08745Sheppo * Disk access routines 13501ae08745Sheppo * 13511ae08745Sheppo */ 13521ae08745Sheppo 13531ae08745Sheppo /* 13541ae08745Sheppo * vdc_strategy() 13551ae08745Sheppo * 13561ae08745Sheppo * Return Value: 13571ae08745Sheppo * 0: As per strategy(9E), the strategy() function must return 0 13581ae08745Sheppo * [ bioerror(9f) sets b_flags to the proper error code ] 13591ae08745Sheppo */ 13601ae08745Sheppo static int 13611ae08745Sheppo vdc_strategy(struct buf *buf) 13621ae08745Sheppo { 13631ae08745Sheppo int rv = -1; 13641ae08745Sheppo vdc_t *vdc = NULL; 13650d0c8d4bSnarayan int instance = VDCUNIT(buf->b_edev); 13661ae08745Sheppo int op = (buf->b_flags & B_READ) ? VD_OP_BREAD : VD_OP_BWRITE; 136787a7269eSachartre int slice; 13681ae08745Sheppo 13691ae08745Sheppo if ((vdc = ddi_get_soft_state(vdc_state, instance)) == NULL) { 1370e1ebb9ecSlm66018 cmn_err(CE_NOTE, "[%d] Couldn't get state structure", instance); 13711ae08745Sheppo bioerror(buf, ENXIO); 13721ae08745Sheppo biodone(buf); 13731ae08745Sheppo return (0); 13741ae08745Sheppo } 13751ae08745Sheppo 13763af08d82Slm66018 DMSG(vdc, 2, "[%d] %s %ld bytes at block %llx : b_addr=0x%p\n", 13773af08d82Slm66018 instance, (buf->b_flags & B_READ) ? "Read" : "Write", 13783af08d82Slm66018 buf->b_bcount, buf->b_lblkno, (void *)buf->b_un.b_addr); 1379d10e4ef2Snarayan DTRACE_IO2(vstart, buf_t *, buf, vdc_t *, vdc); 1380d10e4ef2Snarayan 13811ae08745Sheppo bp_mapin(buf); 13821ae08745Sheppo 138387a7269eSachartre if ((long)buf->b_private == VD_SLICE_NONE) { 138487a7269eSachartre /* I/O using an absolute disk offset */ 138587a7269eSachartre slice = VD_SLICE_NONE; 138687a7269eSachartre } else { 138787a7269eSachartre slice = VDCPART(buf->b_edev); 138887a7269eSachartre } 138987a7269eSachartre 13903af08d82Slm66018 rv = vdc_send_request(vdc, op, (caddr_t)buf->b_un.b_addr, 139187a7269eSachartre buf->b_bcount, slice, buf->b_lblkno, 13923af08d82Slm66018 CB_STRATEGY, buf, (op == VD_OP_BREAD) ? VIO_read_dir : 13933af08d82Slm66018 VIO_write_dir); 13943af08d82Slm66018 1395d10e4ef2Snarayan /* 1396d10e4ef2Snarayan * If the request was successfully sent, the strategy call returns and 1397d10e4ef2Snarayan * the ACK handler calls the bioxxx functions when the vDisk server is 1398d10e4ef2Snarayan * done. 1399d10e4ef2Snarayan */ 1400d10e4ef2Snarayan if (rv) { 14013af08d82Slm66018 DMSG(vdc, 0, "Failed to read/write (err=%d)\n", rv); 14021ae08745Sheppo bioerror(buf, rv); 14031ae08745Sheppo biodone(buf); 1404d10e4ef2Snarayan } 1405d10e4ef2Snarayan 14061ae08745Sheppo return (0); 14071ae08745Sheppo } 14081ae08745Sheppo 14090d0c8d4bSnarayan /* 14100d0c8d4bSnarayan * Function: 14110d0c8d4bSnarayan * vdc_min 14120d0c8d4bSnarayan * 14130d0c8d4bSnarayan * Description: 14140d0c8d4bSnarayan * Routine to limit the size of a data transfer. Used in 14150d0c8d4bSnarayan * conjunction with physio(9F). 14160d0c8d4bSnarayan * 14170d0c8d4bSnarayan * Arguments: 14180d0c8d4bSnarayan * bp - pointer to the indicated buf(9S) struct. 14190d0c8d4bSnarayan * 14200d0c8d4bSnarayan */ 14210d0c8d4bSnarayan static void 14220d0c8d4bSnarayan vdc_min(struct buf *bufp) 14230d0c8d4bSnarayan { 14240d0c8d4bSnarayan vdc_t *vdc = NULL; 14250d0c8d4bSnarayan int instance = VDCUNIT(bufp->b_edev); 14260d0c8d4bSnarayan 14270d0c8d4bSnarayan vdc = ddi_get_soft_state(vdc_state, instance); 14280d0c8d4bSnarayan VERIFY(vdc != NULL); 14290d0c8d4bSnarayan 14300d0c8d4bSnarayan if (bufp->b_bcount > (vdc->max_xfer_sz * vdc->block_size)) { 14310d0c8d4bSnarayan bufp->b_bcount = vdc->max_xfer_sz * vdc->block_size; 14320d0c8d4bSnarayan } 14330d0c8d4bSnarayan } 14341ae08745Sheppo 14351ae08745Sheppo static int 14361ae08745Sheppo vdc_read(dev_t dev, struct uio *uio, cred_t *cred) 14371ae08745Sheppo { 14381ae08745Sheppo _NOTE(ARGUNUSED(cred)) 14391ae08745Sheppo 14400d0c8d4bSnarayan DMSGX(1, "[%d] Entered", VDCUNIT(dev)); 14410d0c8d4bSnarayan return (physio(vdc_strategy, NULL, dev, B_READ, vdc_min, uio)); 14421ae08745Sheppo } 14431ae08745Sheppo 14441ae08745Sheppo static int 14451ae08745Sheppo vdc_write(dev_t dev, struct uio *uio, cred_t *cred) 14461ae08745Sheppo { 14471ae08745Sheppo _NOTE(ARGUNUSED(cred)) 14481ae08745Sheppo 14490d0c8d4bSnarayan DMSGX(1, "[%d] Entered", VDCUNIT(dev)); 14500d0c8d4bSnarayan return (physio(vdc_strategy, NULL, dev, B_WRITE, vdc_min, uio)); 14511ae08745Sheppo } 14521ae08745Sheppo 14531ae08745Sheppo static int 14541ae08745Sheppo vdc_aread(dev_t dev, struct aio_req *aio, cred_t *cred) 14551ae08745Sheppo { 14561ae08745Sheppo _NOTE(ARGUNUSED(cred)) 14571ae08745Sheppo 14580d0c8d4bSnarayan DMSGX(1, "[%d] Entered", VDCUNIT(dev)); 14590d0c8d4bSnarayan return (aphysio(vdc_strategy, anocancel, dev, B_READ, vdc_min, aio)); 14601ae08745Sheppo } 14611ae08745Sheppo 14621ae08745Sheppo static int 14631ae08745Sheppo vdc_awrite(dev_t dev, struct aio_req *aio, cred_t *cred) 14641ae08745Sheppo { 14651ae08745Sheppo _NOTE(ARGUNUSED(cred)) 14661ae08745Sheppo 14670d0c8d4bSnarayan DMSGX(1, "[%d] Entered", VDCUNIT(dev)); 14680d0c8d4bSnarayan return (aphysio(vdc_strategy, anocancel, dev, B_WRITE, vdc_min, aio)); 14691ae08745Sheppo } 14701ae08745Sheppo 14711ae08745Sheppo 14721ae08745Sheppo /* -------------------------------------------------------------------------- */ 14731ae08745Sheppo 14741ae08745Sheppo /* 14751ae08745Sheppo * Handshake support 14761ae08745Sheppo */ 14771ae08745Sheppo 14781ae08745Sheppo 14790a55fbb7Slm66018 /* 14800a55fbb7Slm66018 * Function: 14810a55fbb7Slm66018 * vdc_init_ver_negotiation() 14820a55fbb7Slm66018 * 14830a55fbb7Slm66018 * Description: 14840a55fbb7Slm66018 * 14850a55fbb7Slm66018 * Arguments: 14860a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 14870a55fbb7Slm66018 * 14880a55fbb7Slm66018 * Return Code: 14890a55fbb7Slm66018 * 0 - Success 14900a55fbb7Slm66018 */ 14911ae08745Sheppo static int 14920a55fbb7Slm66018 vdc_init_ver_negotiation(vdc_t *vdc, vio_ver_t ver) 14931ae08745Sheppo { 14941ae08745Sheppo vio_ver_msg_t pkt; 14951ae08745Sheppo size_t msglen = sizeof (pkt); 14961ae08745Sheppo int status = -1; 14971ae08745Sheppo 14981ae08745Sheppo ASSERT(vdc != NULL); 14991ae08745Sheppo ASSERT(mutex_owned(&vdc->lock)); 15001ae08745Sheppo 15013af08d82Slm66018 DMSG(vdc, 0, "[%d] Entered.\n", vdc->instance); 1502e1ebb9ecSlm66018 15031ae08745Sheppo /* 15041ae08745Sheppo * set the Session ID to a unique value 15051ae08745Sheppo * (the lower 32 bits of the clock tick) 15061ae08745Sheppo */ 15071ae08745Sheppo vdc->session_id = ((uint32_t)gettick() & 0xffffffff); 15083af08d82Slm66018 DMSG(vdc, 0, "[%d] Set SID to 0x%lx\n", vdc->instance, vdc->session_id); 15091ae08745Sheppo 15101ae08745Sheppo pkt.tag.vio_msgtype = VIO_TYPE_CTRL; 15111ae08745Sheppo pkt.tag.vio_subtype = VIO_SUBTYPE_INFO; 15121ae08745Sheppo pkt.tag.vio_subtype_env = VIO_VER_INFO; 15131ae08745Sheppo pkt.tag.vio_sid = vdc->session_id; 15141ae08745Sheppo pkt.dev_class = VDEV_DISK; 15150a55fbb7Slm66018 pkt.ver_major = ver.major; 15160a55fbb7Slm66018 pkt.ver_minor = ver.minor; 15171ae08745Sheppo 15180a55fbb7Slm66018 status = vdc_send(vdc, (caddr_t)&pkt, &msglen); 15193af08d82Slm66018 DMSG(vdc, 0, "[%d] Ver info sent (status = %d)\n", 15203af08d82Slm66018 vdc->instance, status); 15211ae08745Sheppo if ((status != 0) || (msglen != sizeof (vio_ver_msg_t))) { 15223af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to send Ver negotiation info: " 152387a7269eSachartre "id(%lx) rv(%d) size(%ld)", vdc->instance, vdc->ldc_handle, 15241ae08745Sheppo status, msglen); 15251ae08745Sheppo if (msglen != sizeof (vio_ver_msg_t)) 15261ae08745Sheppo status = ENOMSG; 15271ae08745Sheppo } 15281ae08745Sheppo 15291ae08745Sheppo return (status); 15301ae08745Sheppo } 15311ae08745Sheppo 15320a55fbb7Slm66018 /* 15330a55fbb7Slm66018 * Function: 15343af08d82Slm66018 * vdc_ver_negotiation() 15353af08d82Slm66018 * 15363af08d82Slm66018 * Description: 15373af08d82Slm66018 * 15383af08d82Slm66018 * Arguments: 15393af08d82Slm66018 * vdcp - soft state pointer for this instance of the device driver. 15403af08d82Slm66018 * 15413af08d82Slm66018 * Return Code: 15423af08d82Slm66018 * 0 - Success 15433af08d82Slm66018 */ 15443af08d82Slm66018 static int 15453af08d82Slm66018 vdc_ver_negotiation(vdc_t *vdcp) 15463af08d82Slm66018 { 15473af08d82Slm66018 vio_msg_t vio_msg; 15483af08d82Slm66018 int status; 15493af08d82Slm66018 15503af08d82Slm66018 if (status = vdc_init_ver_negotiation(vdcp, vdc_version[0])) 15513af08d82Slm66018 return (status); 15523af08d82Slm66018 15533af08d82Slm66018 /* release lock and wait for response */ 15543af08d82Slm66018 mutex_exit(&vdcp->lock); 15553af08d82Slm66018 status = vdc_wait_for_response(vdcp, &vio_msg); 15563af08d82Slm66018 mutex_enter(&vdcp->lock); 15573af08d82Slm66018 if (status) { 15583af08d82Slm66018 DMSG(vdcp, 0, 15593af08d82Slm66018 "[%d] Failed waiting for Ver negotiation response, rv(%d)", 15603af08d82Slm66018 vdcp->instance, status); 15613af08d82Slm66018 return (status); 15623af08d82Slm66018 } 15633af08d82Slm66018 15643af08d82Slm66018 /* check type and sub_type ... */ 15653af08d82Slm66018 if (vio_msg.tag.vio_msgtype != VIO_TYPE_CTRL || 15663af08d82Slm66018 vio_msg.tag.vio_subtype == VIO_SUBTYPE_INFO) { 15673af08d82Slm66018 DMSG(vdcp, 0, "[%d] Invalid ver negotiation response\n", 15683af08d82Slm66018 vdcp->instance); 15693af08d82Slm66018 return (EPROTO); 15703af08d82Slm66018 } 15713af08d82Slm66018 15723af08d82Slm66018 return (vdc_handle_ver_msg(vdcp, (vio_ver_msg_t *)&vio_msg)); 15733af08d82Slm66018 } 15743af08d82Slm66018 15753af08d82Slm66018 /* 15763af08d82Slm66018 * Function: 15770a55fbb7Slm66018 * vdc_init_attr_negotiation() 15780a55fbb7Slm66018 * 15790a55fbb7Slm66018 * Description: 15800a55fbb7Slm66018 * 15810a55fbb7Slm66018 * Arguments: 15820a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 15830a55fbb7Slm66018 * 15840a55fbb7Slm66018 * Return Code: 15850a55fbb7Slm66018 * 0 - Success 15860a55fbb7Slm66018 */ 15871ae08745Sheppo static int 15881ae08745Sheppo vdc_init_attr_negotiation(vdc_t *vdc) 15891ae08745Sheppo { 15901ae08745Sheppo vd_attr_msg_t pkt; 15911ae08745Sheppo size_t msglen = sizeof (pkt); 15921ae08745Sheppo int status; 15931ae08745Sheppo 15941ae08745Sheppo ASSERT(vdc != NULL); 15951ae08745Sheppo ASSERT(mutex_owned(&vdc->lock)); 15961ae08745Sheppo 15973af08d82Slm66018 DMSG(vdc, 0, "[%d] entered\n", vdc->instance); 15981ae08745Sheppo 15991ae08745Sheppo /* fill in tag */ 16001ae08745Sheppo pkt.tag.vio_msgtype = VIO_TYPE_CTRL; 16011ae08745Sheppo pkt.tag.vio_subtype = VIO_SUBTYPE_INFO; 16021ae08745Sheppo pkt.tag.vio_subtype_env = VIO_ATTR_INFO; 16031ae08745Sheppo pkt.tag.vio_sid = vdc->session_id; 16041ae08745Sheppo /* fill in payload */ 16051ae08745Sheppo pkt.max_xfer_sz = vdc->max_xfer_sz; 16061ae08745Sheppo pkt.vdisk_block_size = vdc->block_size; 1607*f0ca1d9aSsb155480 pkt.xfer_mode = VIO_DRING_MODE_V1_0; 16081ae08745Sheppo pkt.operations = 0; /* server will set bits of valid operations */ 16091ae08745Sheppo pkt.vdisk_type = 0; /* server will set to valid device type */ 161017cadca8Slm66018 pkt.vdisk_media = 0; /* server will set to valid media type */ 16111ae08745Sheppo pkt.vdisk_size = 0; /* server will set to valid size */ 16121ae08745Sheppo 16130a55fbb7Slm66018 status = vdc_send(vdc, (caddr_t)&pkt, &msglen); 16143af08d82Slm66018 DMSG(vdc, 0, "Attr info sent (status = %d)\n", status); 16151ae08745Sheppo 16161ae08745Sheppo if ((status != 0) || (msglen != sizeof (vio_ver_msg_t))) { 16173af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to send Attr negotiation info: " 161887a7269eSachartre "id(%lx) rv(%d) size(%ld)", vdc->instance, vdc->ldc_handle, 16191ae08745Sheppo status, msglen); 16201ae08745Sheppo if (msglen != sizeof (vio_ver_msg_t)) 16211ae08745Sheppo status = ENOMSG; 16221ae08745Sheppo } 16231ae08745Sheppo 16241ae08745Sheppo return (status); 16251ae08745Sheppo } 16261ae08745Sheppo 16270a55fbb7Slm66018 /* 16280a55fbb7Slm66018 * Function: 16293af08d82Slm66018 * vdc_attr_negotiation() 16303af08d82Slm66018 * 16313af08d82Slm66018 * Description: 16323af08d82Slm66018 * 16333af08d82Slm66018 * Arguments: 16343af08d82Slm66018 * vdc - soft state pointer for this instance of the device driver. 16353af08d82Slm66018 * 16363af08d82Slm66018 * Return Code: 16373af08d82Slm66018 * 0 - Success 16383af08d82Slm66018 */ 16393af08d82Slm66018 static int 16403af08d82Slm66018 vdc_attr_negotiation(vdc_t *vdcp) 16413af08d82Slm66018 { 16423af08d82Slm66018 int status; 16433af08d82Slm66018 vio_msg_t vio_msg; 16443af08d82Slm66018 16453af08d82Slm66018 if (status = vdc_init_attr_negotiation(vdcp)) 16463af08d82Slm66018 return (status); 16473af08d82Slm66018 16483af08d82Slm66018 /* release lock and wait for response */ 16493af08d82Slm66018 mutex_exit(&vdcp->lock); 16503af08d82Slm66018 status = vdc_wait_for_response(vdcp, &vio_msg); 16513af08d82Slm66018 mutex_enter(&vdcp->lock); 16523af08d82Slm66018 if (status) { 16533af08d82Slm66018 DMSG(vdcp, 0, 16543af08d82Slm66018 "[%d] Failed waiting for Attr negotiation response, rv(%d)", 16553af08d82Slm66018 vdcp->instance, status); 16563af08d82Slm66018 return (status); 16573af08d82Slm66018 } 16583af08d82Slm66018 16593af08d82Slm66018 /* check type and sub_type ... */ 16603af08d82Slm66018 if (vio_msg.tag.vio_msgtype != VIO_TYPE_CTRL || 16613af08d82Slm66018 vio_msg.tag.vio_subtype == VIO_SUBTYPE_INFO) { 16623af08d82Slm66018 DMSG(vdcp, 0, "[%d] Invalid attr negotiation response\n", 16633af08d82Slm66018 vdcp->instance); 16643af08d82Slm66018 return (EPROTO); 16653af08d82Slm66018 } 16663af08d82Slm66018 16673af08d82Slm66018 return (vdc_handle_attr_msg(vdcp, (vd_attr_msg_t *)&vio_msg)); 16683af08d82Slm66018 } 16693af08d82Slm66018 16703af08d82Slm66018 16713af08d82Slm66018 /* 16723af08d82Slm66018 * Function: 16730a55fbb7Slm66018 * vdc_init_dring_negotiate() 16740a55fbb7Slm66018 * 16750a55fbb7Slm66018 * Description: 16760a55fbb7Slm66018 * 16770a55fbb7Slm66018 * Arguments: 16780a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 16790a55fbb7Slm66018 * 16800a55fbb7Slm66018 * Return Code: 16810a55fbb7Slm66018 * 0 - Success 16820a55fbb7Slm66018 */ 16831ae08745Sheppo static int 16841ae08745Sheppo vdc_init_dring_negotiate(vdc_t *vdc) 16851ae08745Sheppo { 16861ae08745Sheppo vio_dring_reg_msg_t pkt; 16871ae08745Sheppo size_t msglen = sizeof (pkt); 16881ae08745Sheppo int status = -1; 16893af08d82Slm66018 int retry; 16903af08d82Slm66018 int nretries = 10; 16911ae08745Sheppo 16921ae08745Sheppo ASSERT(vdc != NULL); 16931ae08745Sheppo ASSERT(mutex_owned(&vdc->lock)); 16941ae08745Sheppo 16953af08d82Slm66018 for (retry = 0; retry < nretries; retry++) { 16961ae08745Sheppo status = vdc_init_descriptor_ring(vdc); 16973af08d82Slm66018 if (status != EAGAIN) 16983af08d82Slm66018 break; 16993af08d82Slm66018 drv_usecwait(vdc_min_timeout_ldc); 17003af08d82Slm66018 } 17013af08d82Slm66018 17021ae08745Sheppo if (status != 0) { 17033af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to init DRing (status = %d)\n", 17041ae08745Sheppo vdc->instance, status); 17051ae08745Sheppo return (status); 17061ae08745Sheppo } 17073af08d82Slm66018 17083af08d82Slm66018 DMSG(vdc, 0, "[%d] Init of descriptor ring completed (status = %d)\n", 1709e1ebb9ecSlm66018 vdc->instance, status); 17101ae08745Sheppo 17111ae08745Sheppo /* fill in tag */ 17121ae08745Sheppo pkt.tag.vio_msgtype = VIO_TYPE_CTRL; 17131ae08745Sheppo pkt.tag.vio_subtype = VIO_SUBTYPE_INFO; 17141ae08745Sheppo pkt.tag.vio_subtype_env = VIO_DRING_REG; 17151ae08745Sheppo pkt.tag.vio_sid = vdc->session_id; 17161ae08745Sheppo /* fill in payload */ 17171ae08745Sheppo pkt.dring_ident = 0; 1718e1ebb9ecSlm66018 pkt.num_descriptors = vdc->dring_len; 1719e1ebb9ecSlm66018 pkt.descriptor_size = vdc->dring_entry_size; 17201ae08745Sheppo pkt.options = (VIO_TX_DRING | VIO_RX_DRING); 17211ae08745Sheppo pkt.ncookies = vdc->dring_cookie_count; 17221ae08745Sheppo pkt.cookie[0] = vdc->dring_cookie[0]; /* for now just one cookie */ 17231ae08745Sheppo 17240a55fbb7Slm66018 status = vdc_send(vdc, (caddr_t)&pkt, &msglen); 17251ae08745Sheppo if (status != 0) { 17263af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to register DRing (err = %d)", 1727e1ebb9ecSlm66018 vdc->instance, status); 17281ae08745Sheppo } 17291ae08745Sheppo 17301ae08745Sheppo return (status); 17311ae08745Sheppo } 17321ae08745Sheppo 17331ae08745Sheppo 17343af08d82Slm66018 /* 17353af08d82Slm66018 * Function: 17363af08d82Slm66018 * vdc_dring_negotiation() 17373af08d82Slm66018 * 17383af08d82Slm66018 * Description: 17393af08d82Slm66018 * 17403af08d82Slm66018 * Arguments: 17413af08d82Slm66018 * vdc - soft state pointer for this instance of the device driver. 17423af08d82Slm66018 * 17433af08d82Slm66018 * Return Code: 17443af08d82Slm66018 * 0 - Success 17453af08d82Slm66018 */ 17463af08d82Slm66018 static int 17473af08d82Slm66018 vdc_dring_negotiation(vdc_t *vdcp) 17483af08d82Slm66018 { 17493af08d82Slm66018 int status; 17503af08d82Slm66018 vio_msg_t vio_msg; 17513af08d82Slm66018 17523af08d82Slm66018 if (status = vdc_init_dring_negotiate(vdcp)) 17533af08d82Slm66018 return (status); 17543af08d82Slm66018 17553af08d82Slm66018 /* release lock and wait for response */ 17563af08d82Slm66018 mutex_exit(&vdcp->lock); 17573af08d82Slm66018 status = vdc_wait_for_response(vdcp, &vio_msg); 17583af08d82Slm66018 mutex_enter(&vdcp->lock); 17593af08d82Slm66018 if (status) { 17603af08d82Slm66018 DMSG(vdcp, 0, 17613af08d82Slm66018 "[%d] Failed waiting for Dring negotiation response," 17623af08d82Slm66018 " rv(%d)", vdcp->instance, status); 17633af08d82Slm66018 return (status); 17643af08d82Slm66018 } 17653af08d82Slm66018 17663af08d82Slm66018 /* check type and sub_type ... */ 17673af08d82Slm66018 if (vio_msg.tag.vio_msgtype != VIO_TYPE_CTRL || 17683af08d82Slm66018 vio_msg.tag.vio_subtype == VIO_SUBTYPE_INFO) { 17693af08d82Slm66018 DMSG(vdcp, 0, "[%d] Invalid Dring negotiation response\n", 17703af08d82Slm66018 vdcp->instance); 17713af08d82Slm66018 return (EPROTO); 17723af08d82Slm66018 } 17733af08d82Slm66018 17743af08d82Slm66018 return (vdc_handle_dring_reg_msg(vdcp, 17753af08d82Slm66018 (vio_dring_reg_msg_t *)&vio_msg)); 17763af08d82Slm66018 } 17773af08d82Slm66018 17783af08d82Slm66018 17793af08d82Slm66018 /* 17803af08d82Slm66018 * Function: 17813af08d82Slm66018 * vdc_send_rdx() 17823af08d82Slm66018 * 17833af08d82Slm66018 * Description: 17843af08d82Slm66018 * 17853af08d82Slm66018 * Arguments: 17863af08d82Slm66018 * vdc - soft state pointer for this instance of the device driver. 17873af08d82Slm66018 * 17883af08d82Slm66018 * Return Code: 17893af08d82Slm66018 * 0 - Success 17903af08d82Slm66018 */ 17913af08d82Slm66018 static int 17923af08d82Slm66018 vdc_send_rdx(vdc_t *vdcp) 17933af08d82Slm66018 { 17943af08d82Slm66018 vio_msg_t msg; 17953af08d82Slm66018 size_t msglen = sizeof (vio_msg_t); 17963af08d82Slm66018 int status; 17973af08d82Slm66018 17983af08d82Slm66018 /* 17993af08d82Slm66018 * Send an RDX message to vds to indicate we are ready 18003af08d82Slm66018 * to send data 18013af08d82Slm66018 */ 18023af08d82Slm66018 msg.tag.vio_msgtype = VIO_TYPE_CTRL; 18033af08d82Slm66018 msg.tag.vio_subtype = VIO_SUBTYPE_INFO; 18043af08d82Slm66018 msg.tag.vio_subtype_env = VIO_RDX; 18053af08d82Slm66018 msg.tag.vio_sid = vdcp->session_id; 18063af08d82Slm66018 status = vdc_send(vdcp, (caddr_t)&msg, &msglen); 18073af08d82Slm66018 if (status != 0) { 18083af08d82Slm66018 DMSG(vdcp, 0, "[%d] Failed to send RDX message (%d)", 18093af08d82Slm66018 vdcp->instance, status); 18103af08d82Slm66018 } 18113af08d82Slm66018 18123af08d82Slm66018 return (status); 18133af08d82Slm66018 } 18143af08d82Slm66018 18153af08d82Slm66018 /* 18163af08d82Slm66018 * Function: 18173af08d82Slm66018 * vdc_handle_rdx() 18183af08d82Slm66018 * 18193af08d82Slm66018 * Description: 18203af08d82Slm66018 * 18213af08d82Slm66018 * Arguments: 18223af08d82Slm66018 * vdc - soft state pointer for this instance of the device driver. 18233af08d82Slm66018 * msgp - received msg 18243af08d82Slm66018 * 18253af08d82Slm66018 * Return Code: 18263af08d82Slm66018 * 0 - Success 18273af08d82Slm66018 */ 18283af08d82Slm66018 static int 18293af08d82Slm66018 vdc_handle_rdx(vdc_t *vdcp, vio_rdx_msg_t *msgp) 18303af08d82Slm66018 { 18313af08d82Slm66018 _NOTE(ARGUNUSED(vdcp)) 18323af08d82Slm66018 _NOTE(ARGUNUSED(msgp)) 18333af08d82Slm66018 18343af08d82Slm66018 ASSERT(msgp->tag.vio_msgtype == VIO_TYPE_CTRL); 18353af08d82Slm66018 ASSERT(msgp->tag.vio_subtype == VIO_SUBTYPE_ACK); 18363af08d82Slm66018 ASSERT(msgp->tag.vio_subtype_env == VIO_RDX); 18373af08d82Slm66018 18383af08d82Slm66018 DMSG(vdcp, 1, "[%d] Got an RDX msg", vdcp->instance); 18393af08d82Slm66018 18403af08d82Slm66018 return (0); 18413af08d82Slm66018 } 18423af08d82Slm66018 18433af08d82Slm66018 /* 18443af08d82Slm66018 * Function: 18453af08d82Slm66018 * vdc_rdx_exchange() 18463af08d82Slm66018 * 18473af08d82Slm66018 * Description: 18483af08d82Slm66018 * 18493af08d82Slm66018 * Arguments: 18503af08d82Slm66018 * vdc - soft state pointer for this instance of the device driver. 18513af08d82Slm66018 * 18523af08d82Slm66018 * Return Code: 18533af08d82Slm66018 * 0 - Success 18543af08d82Slm66018 */ 18553af08d82Slm66018 static int 18563af08d82Slm66018 vdc_rdx_exchange(vdc_t *vdcp) 18573af08d82Slm66018 { 18583af08d82Slm66018 int status; 18593af08d82Slm66018 vio_msg_t vio_msg; 18603af08d82Slm66018 18613af08d82Slm66018 if (status = vdc_send_rdx(vdcp)) 18623af08d82Slm66018 return (status); 18633af08d82Slm66018 18643af08d82Slm66018 /* release lock and wait for response */ 18653af08d82Slm66018 mutex_exit(&vdcp->lock); 18663af08d82Slm66018 status = vdc_wait_for_response(vdcp, &vio_msg); 18673af08d82Slm66018 mutex_enter(&vdcp->lock); 18683af08d82Slm66018 if (status) { 186987a7269eSachartre DMSG(vdcp, 0, "[%d] Failed waiting for RDX response, rv(%d)", 187087a7269eSachartre vdcp->instance, status); 18713af08d82Slm66018 return (status); 18723af08d82Slm66018 } 18733af08d82Slm66018 18743af08d82Slm66018 /* check type and sub_type ... */ 18753af08d82Slm66018 if (vio_msg.tag.vio_msgtype != VIO_TYPE_CTRL || 18763af08d82Slm66018 vio_msg.tag.vio_subtype != VIO_SUBTYPE_ACK) { 187787a7269eSachartre DMSG(vdcp, 0, "[%d] Invalid RDX response\n", vdcp->instance); 18783af08d82Slm66018 return (EPROTO); 18793af08d82Slm66018 } 18803af08d82Slm66018 18813af08d82Slm66018 return (vdc_handle_rdx(vdcp, (vio_rdx_msg_t *)&vio_msg)); 18823af08d82Slm66018 } 18833af08d82Slm66018 18843af08d82Slm66018 18851ae08745Sheppo /* -------------------------------------------------------------------------- */ 18861ae08745Sheppo 18871ae08745Sheppo /* 18881ae08745Sheppo * LDC helper routines 18891ae08745Sheppo */ 18901ae08745Sheppo 18913af08d82Slm66018 static int 18923af08d82Slm66018 vdc_recv(vdc_t *vdc, vio_msg_t *msgp, size_t *nbytesp) 18933af08d82Slm66018 { 18943af08d82Slm66018 int status; 18953af08d82Slm66018 boolean_t q_has_pkts = B_FALSE; 189617cadca8Slm66018 uint64_t delay_time; 18973af08d82Slm66018 size_t len; 18983af08d82Slm66018 18993af08d82Slm66018 mutex_enter(&vdc->read_lock); 19003af08d82Slm66018 19013af08d82Slm66018 if (vdc->read_state == VDC_READ_IDLE) 19023af08d82Slm66018 vdc->read_state = VDC_READ_WAITING; 19033af08d82Slm66018 19043af08d82Slm66018 while (vdc->read_state != VDC_READ_PENDING) { 19053af08d82Slm66018 19063af08d82Slm66018 /* detect if the connection has been reset */ 19073af08d82Slm66018 if (vdc->read_state == VDC_READ_RESET) { 19083af08d82Slm66018 status = ECONNRESET; 19093af08d82Slm66018 goto done; 19103af08d82Slm66018 } 19113af08d82Slm66018 19123af08d82Slm66018 cv_wait(&vdc->read_cv, &vdc->read_lock); 19133af08d82Slm66018 } 19143af08d82Slm66018 19153af08d82Slm66018 /* 19163af08d82Slm66018 * Until we get a blocking ldc read we have to retry 19173af08d82Slm66018 * until the entire LDC message has arrived before 19183af08d82Slm66018 * ldc_read() will succeed. Note we also bail out if 1919eff7243fSlm66018 * the channel is reset or goes away. 19203af08d82Slm66018 */ 19213af08d82Slm66018 delay_time = vdc_ldc_read_init_delay; 19223af08d82Slm66018 loop: 19233af08d82Slm66018 len = *nbytesp; 19243af08d82Slm66018 status = ldc_read(vdc->ldc_handle, (caddr_t)msgp, &len); 19253af08d82Slm66018 switch (status) { 19263af08d82Slm66018 case EAGAIN: 19273af08d82Slm66018 delay_time *= 2; 19283af08d82Slm66018 if (delay_time >= vdc_ldc_read_max_delay) 19293af08d82Slm66018 delay_time = vdc_ldc_read_max_delay; 19303af08d82Slm66018 delay(delay_time); 19313af08d82Slm66018 goto loop; 19323af08d82Slm66018 19333af08d82Slm66018 case 0: 19343af08d82Slm66018 if (len == 0) { 193517cadca8Slm66018 DMSG(vdc, 1, "[%d] ldc_read returned 0 bytes with " 19363af08d82Slm66018 "no error!\n", vdc->instance); 19373af08d82Slm66018 goto loop; 19383af08d82Slm66018 } 19393af08d82Slm66018 19403af08d82Slm66018 *nbytesp = len; 19413af08d82Slm66018 19423af08d82Slm66018 /* 19433af08d82Slm66018 * If there are pending messages, leave the 19443af08d82Slm66018 * read state as pending. Otherwise, set the state 19453af08d82Slm66018 * back to idle. 19463af08d82Slm66018 */ 19473af08d82Slm66018 status = ldc_chkq(vdc->ldc_handle, &q_has_pkts); 19483af08d82Slm66018 if (status == 0 && !q_has_pkts) 19493af08d82Slm66018 vdc->read_state = VDC_READ_IDLE; 19503af08d82Slm66018 19513af08d82Slm66018 break; 19523af08d82Slm66018 default: 19533af08d82Slm66018 DMSG(vdc, 0, "ldc_read returned %d\n", status); 19543af08d82Slm66018 break; 19553af08d82Slm66018 } 19563af08d82Slm66018 19573af08d82Slm66018 done: 19583af08d82Slm66018 mutex_exit(&vdc->read_lock); 19593af08d82Slm66018 19603af08d82Slm66018 return (status); 19613af08d82Slm66018 } 19623af08d82Slm66018 19633af08d82Slm66018 19643af08d82Slm66018 19653af08d82Slm66018 #ifdef DEBUG 19663af08d82Slm66018 void 19673af08d82Slm66018 vdc_decode_tag(vdc_t *vdcp, vio_msg_t *msg) 19683af08d82Slm66018 { 19693af08d82Slm66018 char *ms, *ss, *ses; 19703af08d82Slm66018 switch (msg->tag.vio_msgtype) { 19713af08d82Slm66018 #define Q(_s) case _s : ms = #_s; break; 19723af08d82Slm66018 Q(VIO_TYPE_CTRL) 19733af08d82Slm66018 Q(VIO_TYPE_DATA) 19743af08d82Slm66018 Q(VIO_TYPE_ERR) 19753af08d82Slm66018 #undef Q 19763af08d82Slm66018 default: ms = "unknown"; break; 19773af08d82Slm66018 } 19783af08d82Slm66018 19793af08d82Slm66018 switch (msg->tag.vio_subtype) { 19803af08d82Slm66018 #define Q(_s) case _s : ss = #_s; break; 19813af08d82Slm66018 Q(VIO_SUBTYPE_INFO) 19823af08d82Slm66018 Q(VIO_SUBTYPE_ACK) 19833af08d82Slm66018 Q(VIO_SUBTYPE_NACK) 19843af08d82Slm66018 #undef Q 19853af08d82Slm66018 default: ss = "unknown"; break; 19863af08d82Slm66018 } 19873af08d82Slm66018 19883af08d82Slm66018 switch (msg->tag.vio_subtype_env) { 19893af08d82Slm66018 #define Q(_s) case _s : ses = #_s; break; 19903af08d82Slm66018 Q(VIO_VER_INFO) 19913af08d82Slm66018 Q(VIO_ATTR_INFO) 19923af08d82Slm66018 Q(VIO_DRING_REG) 19933af08d82Slm66018 Q(VIO_DRING_UNREG) 19943af08d82Slm66018 Q(VIO_RDX) 19953af08d82Slm66018 Q(VIO_PKT_DATA) 19963af08d82Slm66018 Q(VIO_DESC_DATA) 19973af08d82Slm66018 Q(VIO_DRING_DATA) 19983af08d82Slm66018 #undef Q 19993af08d82Slm66018 default: ses = "unknown"; break; 20003af08d82Slm66018 } 20013af08d82Slm66018 20023af08d82Slm66018 DMSG(vdcp, 3, "(%x/%x/%x) message : (%s/%s/%s)\n", 20033af08d82Slm66018 msg->tag.vio_msgtype, msg->tag.vio_subtype, 20043af08d82Slm66018 msg->tag.vio_subtype_env, ms, ss, ses); 20053af08d82Slm66018 } 20063af08d82Slm66018 #endif 20073af08d82Slm66018 20081ae08745Sheppo /* 20091ae08745Sheppo * Function: 20101ae08745Sheppo * vdc_send() 20111ae08745Sheppo * 20121ae08745Sheppo * Description: 20131ae08745Sheppo * The function encapsulates the call to write a message using LDC. 20141ae08745Sheppo * If LDC indicates that the call failed due to the queue being full, 201517cadca8Slm66018 * we retry the ldc_write(), otherwise we return the error returned by LDC. 20161ae08745Sheppo * 20171ae08745Sheppo * Arguments: 20181ae08745Sheppo * ldc_handle - LDC handle for the channel this instance of vdc uses 20191ae08745Sheppo * pkt - address of LDC message to be sent 20201ae08745Sheppo * msglen - the size of the message being sent. When the function 20211ae08745Sheppo * returns, this contains the number of bytes written. 20221ae08745Sheppo * 20231ae08745Sheppo * Return Code: 20241ae08745Sheppo * 0 - Success. 20251ae08745Sheppo * EINVAL - pkt or msglen were NULL 20261ae08745Sheppo * ECONNRESET - The connection was not up. 20271ae08745Sheppo * EWOULDBLOCK - LDC queue is full 20281ae08745Sheppo * xxx - other error codes returned by ldc_write 20291ae08745Sheppo */ 20301ae08745Sheppo static int 20310a55fbb7Slm66018 vdc_send(vdc_t *vdc, caddr_t pkt, size_t *msglen) 20321ae08745Sheppo { 20331ae08745Sheppo size_t size = 0; 20341ae08745Sheppo int status = 0; 20353af08d82Slm66018 clock_t delay_ticks; 20361ae08745Sheppo 20370a55fbb7Slm66018 ASSERT(vdc != NULL); 20380a55fbb7Slm66018 ASSERT(mutex_owned(&vdc->lock)); 20391ae08745Sheppo ASSERT(msglen != NULL); 20401ae08745Sheppo ASSERT(*msglen != 0); 20411ae08745Sheppo 20423af08d82Slm66018 #ifdef DEBUG 204317cadca8Slm66018 vdc_decode_tag(vdc, (vio_msg_t *)(uintptr_t)pkt); 20443af08d82Slm66018 #endif 20453af08d82Slm66018 /* 20463af08d82Slm66018 * Wait indefinitely to send if channel 20473af08d82Slm66018 * is busy, but bail out if we succeed or 20483af08d82Slm66018 * if the channel closes or is reset. 20493af08d82Slm66018 */ 20503af08d82Slm66018 delay_ticks = vdc_hz_min_ldc_delay; 20511ae08745Sheppo do { 20521ae08745Sheppo size = *msglen; 20530a55fbb7Slm66018 status = ldc_write(vdc->ldc_handle, pkt, &size); 20543af08d82Slm66018 if (status == EWOULDBLOCK) { 20553af08d82Slm66018 delay(delay_ticks); 20563af08d82Slm66018 /* geometric backoff */ 20573af08d82Slm66018 delay_ticks *= 2; 20583af08d82Slm66018 if (delay_ticks > vdc_hz_max_ldc_delay) 20593af08d82Slm66018 delay_ticks = vdc_hz_max_ldc_delay; 20603af08d82Slm66018 } 20613af08d82Slm66018 } while (status == EWOULDBLOCK); 20621ae08745Sheppo 20630a55fbb7Slm66018 /* if LDC had serious issues --- reset vdc state */ 20640a55fbb7Slm66018 if (status == EIO || status == ECONNRESET) { 20653af08d82Slm66018 /* LDC had serious issues --- reset vdc state */ 20663af08d82Slm66018 mutex_enter(&vdc->read_lock); 20673af08d82Slm66018 if ((vdc->read_state == VDC_READ_WAITING) || 20683af08d82Slm66018 (vdc->read_state == VDC_READ_RESET)) 20693af08d82Slm66018 cv_signal(&vdc->read_cv); 20703af08d82Slm66018 vdc->read_state = VDC_READ_RESET; 20713af08d82Slm66018 mutex_exit(&vdc->read_lock); 20723af08d82Slm66018 20733af08d82Slm66018 /* wake up any waiters in the reset thread */ 20743af08d82Slm66018 if (vdc->state == VDC_STATE_INIT_WAITING) { 20753af08d82Slm66018 DMSG(vdc, 0, "[%d] write reset - " 20763af08d82Slm66018 "vdc is resetting ..\n", vdc->instance); 20773af08d82Slm66018 vdc->state = VDC_STATE_RESETTING; 20783af08d82Slm66018 cv_signal(&vdc->initwait_cv); 20793af08d82Slm66018 } 20803af08d82Slm66018 20813af08d82Slm66018 return (ECONNRESET); 20820a55fbb7Slm66018 } 20830a55fbb7Slm66018 20841ae08745Sheppo /* return the last size written */ 20851ae08745Sheppo *msglen = size; 20861ae08745Sheppo 20871ae08745Sheppo return (status); 20881ae08745Sheppo } 20891ae08745Sheppo 20901ae08745Sheppo /* 20911ae08745Sheppo * Function: 2092655fd6a9Sachartre * vdc_get_md_node 20931ae08745Sheppo * 20941ae08745Sheppo * Description: 2095655fd6a9Sachartre * Get the MD, the device node and the port node for the given 2096655fd6a9Sachartre * disk instance. The caller is responsible for cleaning up the 2097655fd6a9Sachartre * reference to the returned MD (mdpp) by calling md_fini_handle(). 20981ae08745Sheppo * 20991ae08745Sheppo * Arguments: 21001ae08745Sheppo * dip - dev info pointer for this instance of the device driver. 2101655fd6a9Sachartre * mdpp - the returned MD. 2102655fd6a9Sachartre * vd_nodep - the returned device node. 2103655fd6a9Sachartre * vd_portp - the returned port node. The returned port node is NULL 2104655fd6a9Sachartre * if no port node is found. 21051ae08745Sheppo * 21061ae08745Sheppo * Return Code: 21071ae08745Sheppo * 0 - Success. 21081ae08745Sheppo * ENOENT - Expected node or property did not exist. 21091ae08745Sheppo * ENXIO - Unexpected error communicating with MD framework 21101ae08745Sheppo */ 21111ae08745Sheppo static int 2112655fd6a9Sachartre vdc_get_md_node(dev_info_t *dip, md_t **mdpp, mde_cookie_t *vd_nodep, 2113655fd6a9Sachartre mde_cookie_t *vd_portp) 21141ae08745Sheppo { 21151ae08745Sheppo int status = ENOENT; 21161ae08745Sheppo char *node_name = NULL; 21171ae08745Sheppo md_t *mdp = NULL; 21181ae08745Sheppo int num_nodes; 21191ae08745Sheppo int num_vdevs; 2120655fd6a9Sachartre int num_vports; 21211ae08745Sheppo mde_cookie_t rootnode; 21221ae08745Sheppo mde_cookie_t *listp = NULL; 21231ae08745Sheppo boolean_t found_inst = B_FALSE; 21241ae08745Sheppo int listsz; 21251ae08745Sheppo int idx; 21261ae08745Sheppo uint64_t md_inst; 21271ae08745Sheppo int obp_inst; 21281ae08745Sheppo int instance = ddi_get_instance(dip); 21291ae08745Sheppo 21301ae08745Sheppo /* 21311ae08745Sheppo * Get the OBP instance number for comparison with the MD instance 21321ae08745Sheppo * 21331ae08745Sheppo * The "cfg-handle" property of a vdc node in an MD contains the MD's 21341ae08745Sheppo * notion of "instance", or unique identifier, for that node; OBP 21351ae08745Sheppo * stores the value of the "cfg-handle" MD property as the value of 21361ae08745Sheppo * the "reg" property on the node in the device tree it builds from 21371ae08745Sheppo * the MD and passes to Solaris. Thus, we look up the devinfo node's 21381ae08745Sheppo * "reg" property value to uniquely identify this device instance. 21391ae08745Sheppo * If the "reg" property cannot be found, the device tree state is 21401ae08745Sheppo * presumably so broken that there is no point in continuing. 21411ae08745Sheppo */ 21421ae08745Sheppo if (!ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, OBP_REG)) { 21431ae08745Sheppo cmn_err(CE_WARN, "'%s' property does not exist", OBP_REG); 21441ae08745Sheppo return (ENOENT); 21451ae08745Sheppo } 21461ae08745Sheppo obp_inst = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 21471ae08745Sheppo OBP_REG, -1); 21483af08d82Slm66018 DMSGX(1, "[%d] OBP inst=%d\n", instance, obp_inst); 21491ae08745Sheppo 21501ae08745Sheppo /* 2151655fd6a9Sachartre * We now walk the MD nodes to find the node for this vdisk. 21521ae08745Sheppo */ 21531ae08745Sheppo if ((mdp = md_get_handle()) == NULL) { 21541ae08745Sheppo cmn_err(CE_WARN, "unable to init machine description"); 21551ae08745Sheppo return (ENXIO); 21561ae08745Sheppo } 21571ae08745Sheppo 21581ae08745Sheppo num_nodes = md_node_count(mdp); 21591ae08745Sheppo ASSERT(num_nodes > 0); 21601ae08745Sheppo 21611ae08745Sheppo listsz = num_nodes * sizeof (mde_cookie_t); 21621ae08745Sheppo 21631ae08745Sheppo /* allocate memory for nodes */ 21641ae08745Sheppo listp = kmem_zalloc(listsz, KM_SLEEP); 21651ae08745Sheppo 21661ae08745Sheppo rootnode = md_root_node(mdp); 21671ae08745Sheppo ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE); 21681ae08745Sheppo 21691ae08745Sheppo /* 21701ae08745Sheppo * Search for all the virtual devices, we will then check to see which 21711ae08745Sheppo * ones are disk nodes. 21721ae08745Sheppo */ 21731ae08745Sheppo num_vdevs = md_scan_dag(mdp, rootnode, 21741ae08745Sheppo md_find_name(mdp, VDC_MD_VDEV_NAME), 21751ae08745Sheppo md_find_name(mdp, "fwd"), listp); 21761ae08745Sheppo 21771ae08745Sheppo if (num_vdevs <= 0) { 21781ae08745Sheppo cmn_err(CE_NOTE, "No '%s' node found", VDC_MD_VDEV_NAME); 21791ae08745Sheppo status = ENOENT; 21801ae08745Sheppo goto done; 21811ae08745Sheppo } 21821ae08745Sheppo 21833af08d82Slm66018 DMSGX(1, "[%d] num_vdevs=%d\n", instance, num_vdevs); 21841ae08745Sheppo for (idx = 0; idx < num_vdevs; idx++) { 21851ae08745Sheppo status = md_get_prop_str(mdp, listp[idx], "name", &node_name); 21861ae08745Sheppo if ((status != 0) || (node_name == NULL)) { 21871ae08745Sheppo cmn_err(CE_NOTE, "Unable to get name of node type '%s'" 21881ae08745Sheppo ": err %d", VDC_MD_VDEV_NAME, status); 21891ae08745Sheppo continue; 21901ae08745Sheppo } 21911ae08745Sheppo 21923af08d82Slm66018 DMSGX(1, "[%d] Found node '%s'\n", instance, node_name); 21931ae08745Sheppo if (strcmp(VDC_MD_DISK_NAME, node_name) == 0) { 21941ae08745Sheppo status = md_get_prop_val(mdp, listp[idx], 21951ae08745Sheppo VDC_MD_CFG_HDL, &md_inst); 21963af08d82Slm66018 DMSGX(1, "[%d] vdc inst in MD=%lx\n", 21973af08d82Slm66018 instance, md_inst); 21981ae08745Sheppo if ((status == 0) && (md_inst == obp_inst)) { 21991ae08745Sheppo found_inst = B_TRUE; 22001ae08745Sheppo break; 22011ae08745Sheppo } 22021ae08745Sheppo } 22031ae08745Sheppo } 22041ae08745Sheppo 22050a55fbb7Slm66018 if (!found_inst) { 22063af08d82Slm66018 DMSGX(0, "Unable to find correct '%s' node", VDC_MD_DISK_NAME); 22071ae08745Sheppo status = ENOENT; 22081ae08745Sheppo goto done; 22091ae08745Sheppo } 22103af08d82Slm66018 DMSGX(0, "[%d] MD inst=%lx\n", instance, md_inst); 22111ae08745Sheppo 2212655fd6a9Sachartre *vd_nodep = listp[idx]; 2213655fd6a9Sachartre *mdpp = mdp; 2214655fd6a9Sachartre 2215655fd6a9Sachartre num_vports = md_scan_dag(mdp, *vd_nodep, 2216655fd6a9Sachartre md_find_name(mdp, VDC_MD_PORT_NAME), 2217655fd6a9Sachartre md_find_name(mdp, "fwd"), listp); 2218655fd6a9Sachartre 2219655fd6a9Sachartre if (num_vports != 1) { 2220655fd6a9Sachartre DMSGX(0, "Expected 1 '%s' node for '%s' port, found %d\n", 2221655fd6a9Sachartre VDC_MD_PORT_NAME, VDC_MD_VDEV_NAME, num_vports); 2222655fd6a9Sachartre } 2223655fd6a9Sachartre 2224655fd6a9Sachartre *vd_portp = (num_vports == 0)? NULL: listp[0]; 2225655fd6a9Sachartre 2226655fd6a9Sachartre done: 2227655fd6a9Sachartre kmem_free(listp, listsz); 2228655fd6a9Sachartre return (status); 2229655fd6a9Sachartre } 2230655fd6a9Sachartre 2231655fd6a9Sachartre /* 2232655fd6a9Sachartre * Function: 2233655fd6a9Sachartre * vdc_get_ldc_id() 2234655fd6a9Sachartre * 2235655fd6a9Sachartre * Description: 2236655fd6a9Sachartre * This function gets the 'ldc-id' for this particular instance of vdc. 2237655fd6a9Sachartre * The id returned is the guest domain channel endpoint LDC uses for 2238655fd6a9Sachartre * communication with vds. 2239655fd6a9Sachartre * 2240655fd6a9Sachartre * Arguments: 2241655fd6a9Sachartre * mdp - pointer to the machine description. 2242655fd6a9Sachartre * vd_node - the vdisk element from the MD. 2243655fd6a9Sachartre * ldc_id - pointer to variable used to return the 'ldc-id' found. 2244655fd6a9Sachartre * 2245655fd6a9Sachartre * Return Code: 2246655fd6a9Sachartre * 0 - Success. 2247655fd6a9Sachartre * ENOENT - Expected node or property did not exist. 2248655fd6a9Sachartre */ 2249655fd6a9Sachartre static int 2250655fd6a9Sachartre vdc_get_ldc_id(md_t *mdp, mde_cookie_t vd_node, uint64_t *ldc_id) 2251655fd6a9Sachartre { 2252655fd6a9Sachartre mde_cookie_t *chanp = NULL; 2253655fd6a9Sachartre int listsz; 2254655fd6a9Sachartre int num_chans; 2255655fd6a9Sachartre int num_nodes; 2256655fd6a9Sachartre int status = 0; 2257655fd6a9Sachartre 2258655fd6a9Sachartre num_nodes = md_node_count(mdp); 2259655fd6a9Sachartre ASSERT(num_nodes > 0); 2260655fd6a9Sachartre 2261655fd6a9Sachartre listsz = num_nodes * sizeof (mde_cookie_t); 2262655fd6a9Sachartre 2263655fd6a9Sachartre /* allocate memory for nodes */ 2264655fd6a9Sachartre chanp = kmem_zalloc(listsz, KM_SLEEP); 2265655fd6a9Sachartre 22661ae08745Sheppo /* get the channels for this node */ 2267655fd6a9Sachartre num_chans = md_scan_dag(mdp, vd_node, 22681ae08745Sheppo md_find_name(mdp, VDC_MD_CHAN_NAME), 22691ae08745Sheppo md_find_name(mdp, "fwd"), chanp); 22701ae08745Sheppo 22711ae08745Sheppo /* expecting at least one channel */ 22721ae08745Sheppo if (num_chans <= 0) { 22731ae08745Sheppo cmn_err(CE_NOTE, "No '%s' node for '%s' port", 22741ae08745Sheppo VDC_MD_CHAN_NAME, VDC_MD_VDEV_NAME); 22751ae08745Sheppo status = ENOENT; 22761ae08745Sheppo goto done; 22771ae08745Sheppo 22781ae08745Sheppo } else if (num_chans != 1) { 2279655fd6a9Sachartre DMSGX(0, "Expected 1 '%s' node for '%s' port, found %d\n", 2280655fd6a9Sachartre VDC_MD_CHAN_NAME, VDC_MD_VDEV_NAME, num_chans); 22811ae08745Sheppo } 22821ae08745Sheppo 22831ae08745Sheppo /* 22841ae08745Sheppo * We use the first channel found (index 0), irrespective of how 22851ae08745Sheppo * many are there in total. 22861ae08745Sheppo */ 2287655fd6a9Sachartre if (md_get_prop_val(mdp, chanp[0], VDC_MD_ID, ldc_id) != 0) { 2288655fd6a9Sachartre cmn_err(CE_NOTE, "Channel '%s' property not found", VDC_MD_ID); 22891ae08745Sheppo status = ENOENT; 22901ae08745Sheppo } 22911ae08745Sheppo 22921ae08745Sheppo done: 22931ae08745Sheppo kmem_free(chanp, listsz); 22941ae08745Sheppo return (status); 22951ae08745Sheppo } 22961ae08745Sheppo 22970a55fbb7Slm66018 static int 22980a55fbb7Slm66018 vdc_do_ldc_up(vdc_t *vdc) 22990a55fbb7Slm66018 { 23000a55fbb7Slm66018 int status; 23013af08d82Slm66018 ldc_status_t ldc_state; 23020a55fbb7Slm66018 23033af08d82Slm66018 DMSG(vdc, 0, "[%d] Bringing up channel %lx\n", 23043af08d82Slm66018 vdc->instance, vdc->ldc_id); 23053af08d82Slm66018 23063af08d82Slm66018 if (vdc->lifecycle == VDC_LC_DETACHING) 23073af08d82Slm66018 return (EINVAL); 23080a55fbb7Slm66018 23090a55fbb7Slm66018 if ((status = ldc_up(vdc->ldc_handle)) != 0) { 23100a55fbb7Slm66018 switch (status) { 23110a55fbb7Slm66018 case ECONNREFUSED: /* listener not ready at other end */ 23123af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_up(%lx,...) return %d\n", 2313e1ebb9ecSlm66018 vdc->instance, vdc->ldc_id, status); 23140a55fbb7Slm66018 status = 0; 23150a55fbb7Slm66018 break; 23160a55fbb7Slm66018 default: 23173af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to bring up LDC: " 23183af08d82Slm66018 "channel=%ld, err=%d", vdc->instance, vdc->ldc_id, 23193af08d82Slm66018 status); 23203af08d82Slm66018 break; 23213af08d82Slm66018 } 23223af08d82Slm66018 } 23233af08d82Slm66018 23243af08d82Slm66018 if (ldc_status(vdc->ldc_handle, &ldc_state) == 0) { 23253af08d82Slm66018 vdc->ldc_state = ldc_state; 23263af08d82Slm66018 if (ldc_state == LDC_UP) { 23273af08d82Slm66018 DMSG(vdc, 0, "[%d] LDC channel already up\n", 23283af08d82Slm66018 vdc->instance); 23293af08d82Slm66018 vdc->seq_num = 1; 23303af08d82Slm66018 vdc->seq_num_reply = 0; 23310a55fbb7Slm66018 } 23320a55fbb7Slm66018 } 23330a55fbb7Slm66018 23340a55fbb7Slm66018 return (status); 23350a55fbb7Slm66018 } 23360a55fbb7Slm66018 23370a55fbb7Slm66018 /* 23380a55fbb7Slm66018 * Function: 23390a55fbb7Slm66018 * vdc_terminate_ldc() 23400a55fbb7Slm66018 * 23410a55fbb7Slm66018 * Description: 23420a55fbb7Slm66018 * 23430a55fbb7Slm66018 * Arguments: 23440a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 23450a55fbb7Slm66018 * 23460a55fbb7Slm66018 * Return Code: 23470a55fbb7Slm66018 * None 23480a55fbb7Slm66018 */ 23491ae08745Sheppo static void 23501ae08745Sheppo vdc_terminate_ldc(vdc_t *vdc) 23511ae08745Sheppo { 23521ae08745Sheppo int instance = ddi_get_instance(vdc->dip); 23531ae08745Sheppo 23541ae08745Sheppo ASSERT(vdc != NULL); 23551ae08745Sheppo ASSERT(mutex_owned(&vdc->lock)); 23561ae08745Sheppo 23573af08d82Slm66018 DMSG(vdc, 0, "[%d] initialized=%x\n", instance, vdc->initialized); 23581ae08745Sheppo 23591ae08745Sheppo if (vdc->initialized & VDC_LDC_OPEN) { 23603af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_close()\n", instance); 23611ae08745Sheppo (void) ldc_close(vdc->ldc_handle); 23621ae08745Sheppo } 23631ae08745Sheppo if (vdc->initialized & VDC_LDC_CB) { 23643af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_unreg_callback()\n", instance); 23651ae08745Sheppo (void) ldc_unreg_callback(vdc->ldc_handle); 23661ae08745Sheppo } 23671ae08745Sheppo if (vdc->initialized & VDC_LDC) { 23683af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_fini()\n", instance); 23691ae08745Sheppo (void) ldc_fini(vdc->ldc_handle); 23701ae08745Sheppo vdc->ldc_handle = NULL; 23711ae08745Sheppo } 23721ae08745Sheppo 23731ae08745Sheppo vdc->initialized &= ~(VDC_LDC | VDC_LDC_CB | VDC_LDC_OPEN); 23741ae08745Sheppo } 23751ae08745Sheppo 23761ae08745Sheppo /* -------------------------------------------------------------------------- */ 23771ae08745Sheppo 23781ae08745Sheppo /* 23791ae08745Sheppo * Descriptor Ring helper routines 23801ae08745Sheppo */ 23811ae08745Sheppo 23820a55fbb7Slm66018 /* 23830a55fbb7Slm66018 * Function: 23840a55fbb7Slm66018 * vdc_init_descriptor_ring() 23850a55fbb7Slm66018 * 23860a55fbb7Slm66018 * Description: 23870a55fbb7Slm66018 * 23880a55fbb7Slm66018 * Arguments: 23890a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 23900a55fbb7Slm66018 * 23910a55fbb7Slm66018 * Return Code: 23920a55fbb7Slm66018 * 0 - Success 23930a55fbb7Slm66018 */ 23941ae08745Sheppo static int 23951ae08745Sheppo vdc_init_descriptor_ring(vdc_t *vdc) 23961ae08745Sheppo { 23971ae08745Sheppo vd_dring_entry_t *dep = NULL; /* DRing Entry pointer */ 23980a55fbb7Slm66018 int status = 0; 23991ae08745Sheppo int i; 24001ae08745Sheppo 24013af08d82Slm66018 DMSG(vdc, 0, "[%d] initialized=%x\n", vdc->instance, vdc->initialized); 24021ae08745Sheppo 24031ae08745Sheppo ASSERT(vdc != NULL); 24041ae08745Sheppo ASSERT(mutex_owned(&vdc->lock)); 24051ae08745Sheppo ASSERT(vdc->ldc_handle != NULL); 24061ae08745Sheppo 2407e1ebb9ecSlm66018 /* ensure we have enough room to store max sized block */ 2408e1ebb9ecSlm66018 ASSERT(maxphys <= VD_MAX_BLOCK_SIZE); 2409e1ebb9ecSlm66018 24100a55fbb7Slm66018 if ((vdc->initialized & VDC_DRING_INIT) == 0) { 24113af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_mem_dring_create\n", vdc->instance); 2412e1ebb9ecSlm66018 /* 2413e1ebb9ecSlm66018 * Calculate the maximum block size we can transmit using one 2414e1ebb9ecSlm66018 * Descriptor Ring entry from the attributes returned by the 2415e1ebb9ecSlm66018 * vDisk server. This is subject to a minimum of 'maxphys' 2416e1ebb9ecSlm66018 * as we do not have the capability to split requests over 2417e1ebb9ecSlm66018 * multiple DRing entries. 2418e1ebb9ecSlm66018 */ 2419e1ebb9ecSlm66018 if ((vdc->max_xfer_sz * vdc->block_size) < maxphys) { 24203af08d82Slm66018 DMSG(vdc, 0, "[%d] using minimum DRing size\n", 2421e1ebb9ecSlm66018 vdc->instance); 2422e1ebb9ecSlm66018 vdc->dring_max_cookies = maxphys / PAGESIZE; 2423e1ebb9ecSlm66018 } else { 2424e1ebb9ecSlm66018 vdc->dring_max_cookies = 2425e1ebb9ecSlm66018 (vdc->max_xfer_sz * vdc->block_size) / PAGESIZE; 2426e1ebb9ecSlm66018 } 2427e1ebb9ecSlm66018 vdc->dring_entry_size = (sizeof (vd_dring_entry_t) + 2428e1ebb9ecSlm66018 (sizeof (ldc_mem_cookie_t) * 2429e1ebb9ecSlm66018 (vdc->dring_max_cookies - 1))); 2430e1ebb9ecSlm66018 vdc->dring_len = VD_DRING_LEN; 2431e1ebb9ecSlm66018 2432e1ebb9ecSlm66018 status = ldc_mem_dring_create(vdc->dring_len, 2433e1ebb9ecSlm66018 vdc->dring_entry_size, &vdc->ldc_dring_hdl); 24341ae08745Sheppo if ((vdc->ldc_dring_hdl == NULL) || (status != 0)) { 24353af08d82Slm66018 DMSG(vdc, 0, "[%d] Descriptor ring creation failed", 2436e1ebb9ecSlm66018 vdc->instance); 24371ae08745Sheppo return (status); 24381ae08745Sheppo } 24390a55fbb7Slm66018 vdc->initialized |= VDC_DRING_INIT; 24400a55fbb7Slm66018 } 24411ae08745Sheppo 24420a55fbb7Slm66018 if ((vdc->initialized & VDC_DRING_BOUND) == 0) { 24433af08d82Slm66018 DMSG(vdc, 0, "[%d] ldc_mem_dring_bind\n", vdc->instance); 24440a55fbb7Slm66018 vdc->dring_cookie = 24450a55fbb7Slm66018 kmem_zalloc(sizeof (ldc_mem_cookie_t), KM_SLEEP); 24461ae08745Sheppo 24471ae08745Sheppo status = ldc_mem_dring_bind(vdc->ldc_handle, vdc->ldc_dring_hdl, 24484bac2208Snarayan LDC_SHADOW_MAP|LDC_DIRECT_MAP, LDC_MEM_RW, 24490a55fbb7Slm66018 &vdc->dring_cookie[0], 24501ae08745Sheppo &vdc->dring_cookie_count); 24511ae08745Sheppo if (status != 0) { 24523af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to bind descriptor ring " 24533af08d82Slm66018 "(%lx) to channel (%lx) status=%d\n", 24543af08d82Slm66018 vdc->instance, vdc->ldc_dring_hdl, 24553af08d82Slm66018 vdc->ldc_handle, status); 24561ae08745Sheppo return (status); 24571ae08745Sheppo } 24581ae08745Sheppo ASSERT(vdc->dring_cookie_count == 1); 24591ae08745Sheppo vdc->initialized |= VDC_DRING_BOUND; 24600a55fbb7Slm66018 } 24611ae08745Sheppo 24621ae08745Sheppo status = ldc_mem_dring_info(vdc->ldc_dring_hdl, &vdc->dring_mem_info); 24631ae08745Sheppo if (status != 0) { 24643af08d82Slm66018 DMSG(vdc, 0, 24653af08d82Slm66018 "[%d] Failed to get info for descriptor ring (%lx)\n", 2466e1ebb9ecSlm66018 vdc->instance, vdc->ldc_dring_hdl); 24671ae08745Sheppo return (status); 24681ae08745Sheppo } 24691ae08745Sheppo 24700a55fbb7Slm66018 if ((vdc->initialized & VDC_DRING_LOCAL) == 0) { 24713af08d82Slm66018 DMSG(vdc, 0, "[%d] local dring\n", vdc->instance); 24720a55fbb7Slm66018 24731ae08745Sheppo /* Allocate the local copy of this dring */ 24740a55fbb7Slm66018 vdc->local_dring = 2475e1ebb9ecSlm66018 kmem_zalloc(vdc->dring_len * sizeof (vdc_local_desc_t), 24761ae08745Sheppo KM_SLEEP); 24771ae08745Sheppo vdc->initialized |= VDC_DRING_LOCAL; 24780a55fbb7Slm66018 } 24791ae08745Sheppo 24801ae08745Sheppo /* 24810a55fbb7Slm66018 * Mark all DRing entries as free and initialize the private 24820a55fbb7Slm66018 * descriptor's memory handles. If any entry is initialized, 24830a55fbb7Slm66018 * we need to free it later so we set the bit in 'initialized' 24840a55fbb7Slm66018 * at the start. 24851ae08745Sheppo */ 24861ae08745Sheppo vdc->initialized |= VDC_DRING_ENTRY; 2487e1ebb9ecSlm66018 for (i = 0; i < vdc->dring_len; i++) { 24881ae08745Sheppo dep = VDC_GET_DRING_ENTRY_PTR(vdc, i); 24891ae08745Sheppo dep->hdr.dstate = VIO_DESC_FREE; 24901ae08745Sheppo 24911ae08745Sheppo status = ldc_mem_alloc_handle(vdc->ldc_handle, 24921ae08745Sheppo &vdc->local_dring[i].desc_mhdl); 24931ae08745Sheppo if (status != 0) { 24943af08d82Slm66018 DMSG(vdc, 0, "![%d] Failed to alloc mem handle for" 24951ae08745Sheppo " descriptor %d", vdc->instance, i); 24961ae08745Sheppo return (status); 24971ae08745Sheppo } 24983af08d82Slm66018 vdc->local_dring[i].is_free = B_TRUE; 24991ae08745Sheppo vdc->local_dring[i].dep = dep; 25001ae08745Sheppo } 25011ae08745Sheppo 25023af08d82Slm66018 /* Initialize the starting index */ 25033af08d82Slm66018 vdc->dring_curr_idx = 0; 25041ae08745Sheppo 25051ae08745Sheppo return (status); 25061ae08745Sheppo } 25071ae08745Sheppo 25080a55fbb7Slm66018 /* 25090a55fbb7Slm66018 * Function: 25100a55fbb7Slm66018 * vdc_destroy_descriptor_ring() 25110a55fbb7Slm66018 * 25120a55fbb7Slm66018 * Description: 25130a55fbb7Slm66018 * 25140a55fbb7Slm66018 * Arguments: 25150a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 25160a55fbb7Slm66018 * 25170a55fbb7Slm66018 * Return Code: 25180a55fbb7Slm66018 * None 25190a55fbb7Slm66018 */ 25201ae08745Sheppo static void 25211ae08745Sheppo vdc_destroy_descriptor_ring(vdc_t *vdc) 25221ae08745Sheppo { 25230a55fbb7Slm66018 vdc_local_desc_t *ldep = NULL; /* Local Dring Entry Pointer */ 25241ae08745Sheppo ldc_mem_handle_t mhdl = NULL; 25253af08d82Slm66018 ldc_mem_info_t minfo; 25261ae08745Sheppo int status = -1; 25271ae08745Sheppo int i; /* loop */ 25281ae08745Sheppo 25291ae08745Sheppo ASSERT(vdc != NULL); 25301ae08745Sheppo ASSERT(mutex_owned(&vdc->lock)); 25311ae08745Sheppo 25323af08d82Slm66018 DMSG(vdc, 0, "[%d] Entered\n", vdc->instance); 25331ae08745Sheppo 25341ae08745Sheppo if (vdc->initialized & VDC_DRING_ENTRY) { 25353af08d82Slm66018 DMSG(vdc, 0, 25363af08d82Slm66018 "[%d] Removing Local DRing entries\n", vdc->instance); 2537e1ebb9ecSlm66018 for (i = 0; i < vdc->dring_len; i++) { 25380a55fbb7Slm66018 ldep = &vdc->local_dring[i]; 25390a55fbb7Slm66018 mhdl = ldep->desc_mhdl; 25401ae08745Sheppo 25410a55fbb7Slm66018 if (mhdl == NULL) 25420a55fbb7Slm66018 continue; 25430a55fbb7Slm66018 25443af08d82Slm66018 if ((status = ldc_mem_info(mhdl, &minfo)) != 0) { 25453af08d82Slm66018 DMSG(vdc, 0, 25463af08d82Slm66018 "ldc_mem_info returned an error: %d\n", 25473af08d82Slm66018 status); 25483af08d82Slm66018 25493af08d82Slm66018 /* 25503af08d82Slm66018 * This must mean that the mem handle 25513af08d82Slm66018 * is not valid. Clear it out so that 25523af08d82Slm66018 * no one tries to use it. 25533af08d82Slm66018 */ 25543af08d82Slm66018 ldep->desc_mhdl = NULL; 25553af08d82Slm66018 continue; 25563af08d82Slm66018 } 25573af08d82Slm66018 25583af08d82Slm66018 if (minfo.status == LDC_BOUND) { 25593af08d82Slm66018 (void) ldc_mem_unbind_handle(mhdl); 25603af08d82Slm66018 } 25613af08d82Slm66018 25621ae08745Sheppo (void) ldc_mem_free_handle(mhdl); 25633af08d82Slm66018 25643af08d82Slm66018 ldep->desc_mhdl = NULL; 25651ae08745Sheppo } 25661ae08745Sheppo vdc->initialized &= ~VDC_DRING_ENTRY; 25671ae08745Sheppo } 25681ae08745Sheppo 25691ae08745Sheppo if (vdc->initialized & VDC_DRING_LOCAL) { 25703af08d82Slm66018 DMSG(vdc, 0, "[%d] Freeing Local DRing\n", vdc->instance); 25711ae08745Sheppo kmem_free(vdc->local_dring, 2572e1ebb9ecSlm66018 vdc->dring_len * sizeof (vdc_local_desc_t)); 25731ae08745Sheppo vdc->initialized &= ~VDC_DRING_LOCAL; 25741ae08745Sheppo } 25751ae08745Sheppo 25761ae08745Sheppo if (vdc->initialized & VDC_DRING_BOUND) { 25773af08d82Slm66018 DMSG(vdc, 0, "[%d] Unbinding DRing\n", vdc->instance); 25781ae08745Sheppo status = ldc_mem_dring_unbind(vdc->ldc_dring_hdl); 25791ae08745Sheppo if (status == 0) { 25801ae08745Sheppo vdc->initialized &= ~VDC_DRING_BOUND; 25811ae08745Sheppo } else { 25823af08d82Slm66018 DMSG(vdc, 0, "[%d] Error %d unbinding DRing %lx", 2583e1ebb9ecSlm66018 vdc->instance, status, vdc->ldc_dring_hdl); 25841ae08745Sheppo } 25853af08d82Slm66018 kmem_free(vdc->dring_cookie, sizeof (ldc_mem_cookie_t)); 25861ae08745Sheppo } 25871ae08745Sheppo 25881ae08745Sheppo if (vdc->initialized & VDC_DRING_INIT) { 25893af08d82Slm66018 DMSG(vdc, 0, "[%d] Destroying DRing\n", vdc->instance); 25901ae08745Sheppo status = ldc_mem_dring_destroy(vdc->ldc_dring_hdl); 25911ae08745Sheppo if (status == 0) { 25921ae08745Sheppo vdc->ldc_dring_hdl = NULL; 25931ae08745Sheppo bzero(&vdc->dring_mem_info, sizeof (ldc_mem_info_t)); 25941ae08745Sheppo vdc->initialized &= ~VDC_DRING_INIT; 25951ae08745Sheppo } else { 25963af08d82Slm66018 DMSG(vdc, 0, "[%d] Error %d destroying DRing (%lx)", 2597e1ebb9ecSlm66018 vdc->instance, status, vdc->ldc_dring_hdl); 25981ae08745Sheppo } 25991ae08745Sheppo } 26001ae08745Sheppo } 26011ae08745Sheppo 26021ae08745Sheppo /* 26033af08d82Slm66018 * Function: 26043af08d82Slm66018 * vdc_map_to_shared_ring() 26051ae08745Sheppo * 26061ae08745Sheppo * Description: 26073af08d82Slm66018 * Copy contents of the local descriptor to the shared 26083af08d82Slm66018 * memory descriptor. 26091ae08745Sheppo * 26103af08d82Slm66018 * Arguments: 26113af08d82Slm66018 * vdcp - soft state pointer for this instance of the device driver. 26123af08d82Slm66018 * idx - descriptor ring index 26133af08d82Slm66018 * 26143af08d82Slm66018 * Return Code: 26153af08d82Slm66018 * None 26161ae08745Sheppo */ 26171ae08745Sheppo static int 26183af08d82Slm66018 vdc_map_to_shared_dring(vdc_t *vdcp, int idx) 26191ae08745Sheppo { 26203af08d82Slm66018 vdc_local_desc_t *ldep; 26213af08d82Slm66018 vd_dring_entry_t *dep; 26223af08d82Slm66018 int rv; 26231ae08745Sheppo 26243af08d82Slm66018 ldep = &(vdcp->local_dring[idx]); 26251ae08745Sheppo 26263af08d82Slm66018 /* for now leave in the old pop_mem_hdl stuff */ 26273af08d82Slm66018 if (ldep->nbytes > 0) { 26283af08d82Slm66018 rv = vdc_populate_mem_hdl(vdcp, ldep); 26293af08d82Slm66018 if (rv) { 26303af08d82Slm66018 DMSG(vdcp, 0, "[%d] Cannot populate mem handle\n", 26313af08d82Slm66018 vdcp->instance); 26323af08d82Slm66018 return (rv); 26333af08d82Slm66018 } 26343af08d82Slm66018 } 26351ae08745Sheppo 26363af08d82Slm66018 /* 26373af08d82Slm66018 * fill in the data details into the DRing 26383af08d82Slm66018 */ 2639d10e4ef2Snarayan dep = ldep->dep; 26401ae08745Sheppo ASSERT(dep != NULL); 26411ae08745Sheppo 26423af08d82Slm66018 dep->payload.req_id = VDC_GET_NEXT_REQ_ID(vdcp); 26433af08d82Slm66018 dep->payload.operation = ldep->operation; 26443af08d82Slm66018 dep->payload.addr = ldep->offset; 26453af08d82Slm66018 dep->payload.nbytes = ldep->nbytes; 2646055d7c80Scarlsonj dep->payload.status = (uint32_t)-1; /* vds will set valid value */ 26473af08d82Slm66018 dep->payload.slice = ldep->slice; 26483af08d82Slm66018 dep->hdr.dstate = VIO_DESC_READY; 26493af08d82Slm66018 dep->hdr.ack = 1; /* request an ACK for every message */ 26501ae08745Sheppo 26513af08d82Slm66018 return (0); 26521ae08745Sheppo } 26531ae08745Sheppo 26541ae08745Sheppo /* 26551ae08745Sheppo * Function: 26563af08d82Slm66018 * vdc_send_request 26573af08d82Slm66018 * 26583af08d82Slm66018 * Description: 26593af08d82Slm66018 * This routine writes the data to be transmitted to vds into the 26603af08d82Slm66018 * descriptor, notifies vds that the ring has been updated and 26613af08d82Slm66018 * then waits for the request to be processed. 26623af08d82Slm66018 * 26633af08d82Slm66018 * Arguments: 26643af08d82Slm66018 * vdcp - the soft state pointer 26653af08d82Slm66018 * operation - operation we want vds to perform (VD_OP_XXX) 26663af08d82Slm66018 * addr - address of data buf to be read/written. 26673af08d82Slm66018 * nbytes - number of bytes to read/write 26683af08d82Slm66018 * slice - the disk slice this request is for 26693af08d82Slm66018 * offset - relative disk offset 26703af08d82Slm66018 * cb_type - type of call - STRATEGY or SYNC 26713af08d82Slm66018 * cb_arg - parameter to be sent to server (depends on VD_OP_XXX type) 26723af08d82Slm66018 * . mode for ioctl(9e) 26733af08d82Slm66018 * . LP64 diskaddr_t (block I/O) 26743af08d82Slm66018 * dir - direction of operation (READ/WRITE/BOTH) 26753af08d82Slm66018 * 26763af08d82Slm66018 * Return Codes: 26773af08d82Slm66018 * 0 26783af08d82Slm66018 * ENXIO 26793af08d82Slm66018 */ 26803af08d82Slm66018 static int 26813af08d82Slm66018 vdc_send_request(vdc_t *vdcp, int operation, caddr_t addr, 26823af08d82Slm66018 size_t nbytes, int slice, diskaddr_t offset, int cb_type, 26833af08d82Slm66018 void *cb_arg, vio_desc_direction_t dir) 26843af08d82Slm66018 { 26853af08d82Slm66018 ASSERT(vdcp != NULL); 268687a7269eSachartre ASSERT(slice == VD_SLICE_NONE || slice < V_NUMPAR); 26873af08d82Slm66018 26883af08d82Slm66018 mutex_enter(&vdcp->lock); 26893af08d82Slm66018 26903af08d82Slm66018 do { 26913c96341aSnarayan while (vdcp->state != VDC_STATE_RUNNING) { 26923af08d82Slm66018 26933c96341aSnarayan /* return error if detaching */ 26943c96341aSnarayan if (vdcp->state == VDC_STATE_DETACH) { 26953c96341aSnarayan mutex_exit(&vdcp->lock); 26963c96341aSnarayan return (ENXIO); 26973c96341aSnarayan } 2698655fd6a9Sachartre 2699655fd6a9Sachartre /* fail request if connection timeout is reached */ 2700655fd6a9Sachartre if (vdcp->ctimeout_reached) { 2701655fd6a9Sachartre mutex_exit(&vdcp->lock); 2702655fd6a9Sachartre return (EIO); 2703655fd6a9Sachartre } 2704655fd6a9Sachartre 27052f5224aeSachartre /* 27062f5224aeSachartre * If we are panicking and the disk is not ready then 27072f5224aeSachartre * we can't send any request because we can't complete 27082f5224aeSachartre * the handshake now. 27092f5224aeSachartre */ 27102f5224aeSachartre if (ddi_in_panic()) { 27112f5224aeSachartre mutex_exit(&vdcp->lock); 27122f5224aeSachartre return (EIO); 27132f5224aeSachartre } 27142f5224aeSachartre 2715655fd6a9Sachartre cv_wait(&vdcp->running_cv, &vdcp->lock); 27163c96341aSnarayan } 27173c96341aSnarayan 27183af08d82Slm66018 } while (vdc_populate_descriptor(vdcp, operation, addr, 27193af08d82Slm66018 nbytes, slice, offset, cb_type, cb_arg, dir)); 27203af08d82Slm66018 27213af08d82Slm66018 mutex_exit(&vdcp->lock); 27223af08d82Slm66018 return (0); 27233af08d82Slm66018 } 27243af08d82Slm66018 27253af08d82Slm66018 27263af08d82Slm66018 /* 27273af08d82Slm66018 * Function: 27281ae08745Sheppo * vdc_populate_descriptor 27291ae08745Sheppo * 27301ae08745Sheppo * Description: 27311ae08745Sheppo * This routine writes the data to be transmitted to vds into the 27321ae08745Sheppo * descriptor, notifies vds that the ring has been updated and 27331ae08745Sheppo * then waits for the request to be processed. 27341ae08745Sheppo * 27351ae08745Sheppo * Arguments: 27363af08d82Slm66018 * vdcp - the soft state pointer 27371ae08745Sheppo * operation - operation we want vds to perform (VD_OP_XXX) 27383af08d82Slm66018 * addr - address of data buf to be read/written. 27393af08d82Slm66018 * nbytes - number of bytes to read/write 27403af08d82Slm66018 * slice - the disk slice this request is for 27413af08d82Slm66018 * offset - relative disk offset 27423af08d82Slm66018 * cb_type - type of call - STRATEGY or SYNC 27433af08d82Slm66018 * cb_arg - parameter to be sent to server (depends on VD_OP_XXX type) 27441ae08745Sheppo * . mode for ioctl(9e) 27451ae08745Sheppo * . LP64 diskaddr_t (block I/O) 27463af08d82Slm66018 * dir - direction of operation (READ/WRITE/BOTH) 27471ae08745Sheppo * 27481ae08745Sheppo * Return Codes: 27491ae08745Sheppo * 0 27501ae08745Sheppo * EAGAIN 275117cadca8Slm66018 * ECONNRESET 27521ae08745Sheppo * ENXIO 27531ae08745Sheppo */ 27541ae08745Sheppo static int 27553af08d82Slm66018 vdc_populate_descriptor(vdc_t *vdcp, int operation, caddr_t addr, 27563af08d82Slm66018 size_t nbytes, int slice, diskaddr_t offset, int cb_type, 27573af08d82Slm66018 void *cb_arg, vio_desc_direction_t dir) 27581ae08745Sheppo { 27593af08d82Slm66018 vdc_local_desc_t *local_dep = NULL; /* Local Dring Pointer */ 27603af08d82Slm66018 int idx; /* Index of DRing entry used */ 27613af08d82Slm66018 int next_idx; 27621ae08745Sheppo vio_dring_msg_t dmsg; 27633af08d82Slm66018 size_t msglen; 27648e6a2a04Slm66018 int rv; 27651ae08745Sheppo 27663af08d82Slm66018 ASSERT(MUTEX_HELD(&vdcp->lock)); 27673af08d82Slm66018 vdcp->threads_pending++; 27683af08d82Slm66018 loop: 27693af08d82Slm66018 DMSG(vdcp, 2, ": dring_curr_idx = %d\n", vdcp->dring_curr_idx); 27701ae08745Sheppo 27713af08d82Slm66018 /* Get next available D-Ring entry */ 27723af08d82Slm66018 idx = vdcp->dring_curr_idx; 27733af08d82Slm66018 local_dep = &(vdcp->local_dring[idx]); 27741ae08745Sheppo 27753af08d82Slm66018 if (!local_dep->is_free) { 27763af08d82Slm66018 DMSG(vdcp, 2, "[%d]: dring full - waiting for space\n", 27773af08d82Slm66018 vdcp->instance); 27783af08d82Slm66018 cv_wait(&vdcp->dring_free_cv, &vdcp->lock); 27793af08d82Slm66018 if (vdcp->state == VDC_STATE_RUNNING || 27803af08d82Slm66018 vdcp->state == VDC_STATE_HANDLE_PENDING) { 27813af08d82Slm66018 goto loop; 27823af08d82Slm66018 } 27833af08d82Slm66018 vdcp->threads_pending--; 27843af08d82Slm66018 return (ECONNRESET); 27851ae08745Sheppo } 27861ae08745Sheppo 27873af08d82Slm66018 next_idx = idx + 1; 27883af08d82Slm66018 if (next_idx >= vdcp->dring_len) 27893af08d82Slm66018 next_idx = 0; 27903af08d82Slm66018 vdcp->dring_curr_idx = next_idx; 27911ae08745Sheppo 27923af08d82Slm66018 ASSERT(local_dep->is_free); 27931ae08745Sheppo 27943af08d82Slm66018 local_dep->operation = operation; 2795d10e4ef2Snarayan local_dep->addr = addr; 27963af08d82Slm66018 local_dep->nbytes = nbytes; 27973af08d82Slm66018 local_dep->slice = slice; 27983af08d82Slm66018 local_dep->offset = offset; 27993af08d82Slm66018 local_dep->cb_type = cb_type; 28003af08d82Slm66018 local_dep->cb_arg = cb_arg; 28013af08d82Slm66018 local_dep->dir = dir; 28023af08d82Slm66018 28033af08d82Slm66018 local_dep->is_free = B_FALSE; 28043af08d82Slm66018 28053af08d82Slm66018 rv = vdc_map_to_shared_dring(vdcp, idx); 28063af08d82Slm66018 if (rv) { 28073af08d82Slm66018 DMSG(vdcp, 0, "[%d]: cannot bind memory - waiting ..\n", 28083af08d82Slm66018 vdcp->instance); 28093af08d82Slm66018 /* free the descriptor */ 28103af08d82Slm66018 local_dep->is_free = B_TRUE; 28113af08d82Slm66018 vdcp->dring_curr_idx = idx; 28123af08d82Slm66018 cv_wait(&vdcp->membind_cv, &vdcp->lock); 28133af08d82Slm66018 if (vdcp->state == VDC_STATE_RUNNING || 28143af08d82Slm66018 vdcp->state == VDC_STATE_HANDLE_PENDING) { 28153af08d82Slm66018 goto loop; 28161ae08745Sheppo } 28173af08d82Slm66018 vdcp->threads_pending--; 28183af08d82Slm66018 return (ECONNRESET); 28191ae08745Sheppo } 28201ae08745Sheppo 28211ae08745Sheppo /* 28221ae08745Sheppo * Send a msg with the DRing details to vds 28231ae08745Sheppo */ 28241ae08745Sheppo VIO_INIT_DRING_DATA_TAG(dmsg); 28253af08d82Slm66018 VDC_INIT_DRING_DATA_MSG_IDS(dmsg, vdcp); 28263af08d82Slm66018 dmsg.dring_ident = vdcp->dring_ident; 28271ae08745Sheppo dmsg.start_idx = idx; 28281ae08745Sheppo dmsg.end_idx = idx; 28293af08d82Slm66018 vdcp->seq_num++; 28301ae08745Sheppo 28313af08d82Slm66018 DTRACE_IO2(send, vio_dring_msg_t *, &dmsg, vdc_t *, vdcp); 2832d10e4ef2Snarayan 28333af08d82Slm66018 DMSG(vdcp, 2, "ident=0x%lx, st=%u, end=%u, seq=%ld\n", 28343af08d82Slm66018 vdcp->dring_ident, dmsg.start_idx, dmsg.end_idx, dmsg.seq_num); 28351ae08745Sheppo 28363af08d82Slm66018 /* 28373af08d82Slm66018 * note we're still holding the lock here to 28383af08d82Slm66018 * make sure the message goes out in order !!!... 28393af08d82Slm66018 */ 28403af08d82Slm66018 msglen = sizeof (dmsg); 28413af08d82Slm66018 rv = vdc_send(vdcp, (caddr_t)&dmsg, &msglen); 28423af08d82Slm66018 switch (rv) { 28433af08d82Slm66018 case ECONNRESET: 28443af08d82Slm66018 /* 28453af08d82Slm66018 * vdc_send initiates the reset on failure. 28463af08d82Slm66018 * Since the transaction has already been put 28473af08d82Slm66018 * on the local dring, it will automatically get 28483af08d82Slm66018 * retried when the channel is reset. Given that, 28493af08d82Slm66018 * it is ok to just return success even though the 28503af08d82Slm66018 * send failed. 28513af08d82Slm66018 */ 28523af08d82Slm66018 rv = 0; 28533af08d82Slm66018 break; 2854d10e4ef2Snarayan 28553af08d82Slm66018 case 0: /* EOK */ 28563af08d82Slm66018 DMSG(vdcp, 1, "sent via LDC: rv=%d\n", rv); 28573af08d82Slm66018 break; 2858d10e4ef2Snarayan 28593af08d82Slm66018 default: 28603af08d82Slm66018 goto cleanup_and_exit; 28613af08d82Slm66018 } 2862e1ebb9ecSlm66018 28633af08d82Slm66018 vdcp->threads_pending--; 28643af08d82Slm66018 return (rv); 28653af08d82Slm66018 28663af08d82Slm66018 cleanup_and_exit: 28673af08d82Slm66018 DMSG(vdcp, 0, "unexpected error, rv=%d\n", rv); 28683af08d82Slm66018 return (ENXIO); 28691ae08745Sheppo } 28701ae08745Sheppo 28711ae08745Sheppo /* 28723af08d82Slm66018 * Function: 28733af08d82Slm66018 * vdc_do_sync_op 28743af08d82Slm66018 * 28753af08d82Slm66018 * Description: 28763af08d82Slm66018 * Wrapper around vdc_populate_descriptor that blocks until the 28773af08d82Slm66018 * response to the message is available. 28783af08d82Slm66018 * 28793af08d82Slm66018 * Arguments: 28803af08d82Slm66018 * vdcp - the soft state pointer 28813af08d82Slm66018 * operation - operation we want vds to perform (VD_OP_XXX) 28823af08d82Slm66018 * addr - address of data buf to be read/written. 28833af08d82Slm66018 * nbytes - number of bytes to read/write 28843af08d82Slm66018 * slice - the disk slice this request is for 28853af08d82Slm66018 * offset - relative disk offset 28863af08d82Slm66018 * cb_type - type of call - STRATEGY or SYNC 28873af08d82Slm66018 * cb_arg - parameter to be sent to server (depends on VD_OP_XXX type) 28883af08d82Slm66018 * . mode for ioctl(9e) 28893af08d82Slm66018 * . LP64 diskaddr_t (block I/O) 28903af08d82Slm66018 * dir - direction of operation (READ/WRITE/BOTH) 28912f5224aeSachartre * rconflict - check for reservation conflict in case of failure 28922f5224aeSachartre * 28932f5224aeSachartre * rconflict should be set to B_TRUE by most callers. Callers invoking the 28942f5224aeSachartre * VD_OP_SCSICMD operation can set rconflict to B_FALSE if they check the 28952f5224aeSachartre * result of a successful operation with vd_scsi_status(). 28963af08d82Slm66018 * 28973af08d82Slm66018 * Return Codes: 28983af08d82Slm66018 * 0 28993af08d82Slm66018 * EAGAIN 29003af08d82Slm66018 * EFAULT 29013af08d82Slm66018 * ENXIO 29023af08d82Slm66018 * EIO 29030a55fbb7Slm66018 */ 29043af08d82Slm66018 static int 29053af08d82Slm66018 vdc_do_sync_op(vdc_t *vdcp, int operation, caddr_t addr, size_t nbytes, 29063af08d82Slm66018 int slice, diskaddr_t offset, int cb_type, void *cb_arg, 29072f5224aeSachartre vio_desc_direction_t dir, boolean_t rconflict) 29083af08d82Slm66018 { 29093af08d82Slm66018 int status; 29102f5224aeSachartre vdc_io_t *vio; 29112f5224aeSachartre boolean_t check_resv_conflict = B_FALSE; 29123af08d82Slm66018 29133af08d82Slm66018 ASSERT(cb_type == CB_SYNC); 29141ae08745Sheppo 29151ae08745Sheppo /* 29163af08d82Slm66018 * Grab the lock, if blocked wait until the server 29173af08d82Slm66018 * response causes us to wake up again. 29183af08d82Slm66018 */ 29193af08d82Slm66018 mutex_enter(&vdcp->lock); 29203af08d82Slm66018 vdcp->sync_op_cnt++; 29213af08d82Slm66018 while (vdcp->sync_op_blocked && vdcp->state != VDC_STATE_DETACH) 29223af08d82Slm66018 cv_wait(&vdcp->sync_blocked_cv, &vdcp->lock); 29233af08d82Slm66018 29243af08d82Slm66018 if (vdcp->state == VDC_STATE_DETACH) { 29253af08d82Slm66018 cv_broadcast(&vdcp->sync_blocked_cv); 29263af08d82Slm66018 vdcp->sync_op_cnt--; 29273af08d82Slm66018 mutex_exit(&vdcp->lock); 29283af08d82Slm66018 return (ENXIO); 29293af08d82Slm66018 } 29303af08d82Slm66018 29313af08d82Slm66018 /* now block anyone other thread entering after us */ 29323af08d82Slm66018 vdcp->sync_op_blocked = B_TRUE; 29333af08d82Slm66018 vdcp->sync_op_pending = B_TRUE; 29343af08d82Slm66018 mutex_exit(&vdcp->lock); 29353af08d82Slm66018 2936655fd6a9Sachartre status = vdc_send_request(vdcp, operation, addr, 29373af08d82Slm66018 nbytes, slice, offset, cb_type, cb_arg, dir); 29383af08d82Slm66018 2939655fd6a9Sachartre mutex_enter(&vdcp->lock); 2940655fd6a9Sachartre 2941655fd6a9Sachartre if (status != 0) { 2942655fd6a9Sachartre vdcp->sync_op_pending = B_FALSE; 2943655fd6a9Sachartre } else { 29443af08d82Slm66018 /* 29453af08d82Slm66018 * block until our transaction completes. 29463af08d82Slm66018 * Also anyone else waiting also gets to go next. 29473af08d82Slm66018 */ 29483af08d82Slm66018 while (vdcp->sync_op_pending && vdcp->state != VDC_STATE_DETACH) 29493af08d82Slm66018 cv_wait(&vdcp->sync_pending_cv, &vdcp->lock); 29503af08d82Slm66018 2951655fd6a9Sachartre DMSG(vdcp, 2, ": operation returned %d\n", 2952655fd6a9Sachartre vdcp->sync_op_status); 29533c96341aSnarayan if (vdcp->state == VDC_STATE_DETACH) { 29543c96341aSnarayan vdcp->sync_op_pending = B_FALSE; 29553af08d82Slm66018 status = ENXIO; 29563c96341aSnarayan } else { 29573af08d82Slm66018 status = vdcp->sync_op_status; 29582f5224aeSachartre if (status != 0 && vdcp->failfast_interval != 0) { 29592f5224aeSachartre /* 29602f5224aeSachartre * Operation has failed and failfast is enabled. 29612f5224aeSachartre * We need to check if the failure is due to a 29622f5224aeSachartre * reservation conflict if this was requested. 29632f5224aeSachartre */ 29642f5224aeSachartre check_resv_conflict = rconflict; 29652f5224aeSachartre } 29662f5224aeSachartre 29673c96341aSnarayan } 2968655fd6a9Sachartre } 29693c96341aSnarayan 29703af08d82Slm66018 vdcp->sync_op_status = 0; 29713af08d82Slm66018 vdcp->sync_op_blocked = B_FALSE; 29723af08d82Slm66018 vdcp->sync_op_cnt--; 29733af08d82Slm66018 29743af08d82Slm66018 /* signal the next waiting thread */ 29753af08d82Slm66018 cv_signal(&vdcp->sync_blocked_cv); 29762f5224aeSachartre 29772f5224aeSachartre /* 29782f5224aeSachartre * We have to check for reservation conflict after unblocking sync 29792f5224aeSachartre * operations because some sync operations will be used to do this 29802f5224aeSachartre * check. 29812f5224aeSachartre */ 29822f5224aeSachartre if (check_resv_conflict) { 29832f5224aeSachartre vio = vdc_failfast_io_queue(vdcp, NULL); 29842f5224aeSachartre while (vio->vio_qtime != 0) 29852f5224aeSachartre cv_wait(&vdcp->failfast_io_cv, &vdcp->lock); 29862f5224aeSachartre kmem_free(vio, sizeof (vdc_io_t)); 29872f5224aeSachartre } 29882f5224aeSachartre 29893af08d82Slm66018 mutex_exit(&vdcp->lock); 29903af08d82Slm66018 29913af08d82Slm66018 return (status); 29923af08d82Slm66018 } 29933af08d82Slm66018 29943af08d82Slm66018 29953af08d82Slm66018 /* 29963af08d82Slm66018 * Function: 29973af08d82Slm66018 * vdc_drain_response() 29983af08d82Slm66018 * 29993af08d82Slm66018 * Description: 30001ae08745Sheppo * When a guest is panicking, the completion of requests needs to be 30011ae08745Sheppo * handled differently because interrupts are disabled and vdc 30021ae08745Sheppo * will not get messages. We have to poll for the messages instead. 30033af08d82Slm66018 * 30043af08d82Slm66018 * Arguments: 30053af08d82Slm66018 * vdc - soft state pointer for this instance of the device driver. 30063af08d82Slm66018 * 30073af08d82Slm66018 * Return Code: 30083af08d82Slm66018 * 0 - Success 30091ae08745Sheppo */ 30103af08d82Slm66018 static int 30113af08d82Slm66018 vdc_drain_response(vdc_t *vdc) 30123af08d82Slm66018 { 30133af08d82Slm66018 int rv, idx, retries; 30143af08d82Slm66018 size_t msglen; 30153af08d82Slm66018 vdc_local_desc_t *ldep = NULL; /* Local Dring Entry Pointer */ 30163af08d82Slm66018 vio_dring_msg_t dmsg; 30173af08d82Slm66018 30183af08d82Slm66018 mutex_enter(&vdc->lock); 30193af08d82Slm66018 30201ae08745Sheppo retries = 0; 30211ae08745Sheppo for (;;) { 30221ae08745Sheppo msglen = sizeof (dmsg); 30233af08d82Slm66018 rv = ldc_read(vdc->ldc_handle, (caddr_t)&dmsg, &msglen); 30248e6a2a04Slm66018 if (rv) { 30258e6a2a04Slm66018 rv = EINVAL; 30261ae08745Sheppo break; 30271ae08745Sheppo } 30281ae08745Sheppo 30291ae08745Sheppo /* 30301ae08745Sheppo * if there are no packets wait and check again 30311ae08745Sheppo */ 30328e6a2a04Slm66018 if ((rv == 0) && (msglen == 0)) { 30331ae08745Sheppo if (retries++ > vdc_dump_retries) { 30348e6a2a04Slm66018 rv = EAGAIN; 30351ae08745Sheppo break; 30361ae08745Sheppo } 30371ae08745Sheppo 3038d10e4ef2Snarayan drv_usecwait(vdc_usec_timeout_dump); 30391ae08745Sheppo continue; 30401ae08745Sheppo } 30411ae08745Sheppo 30421ae08745Sheppo /* 30431ae08745Sheppo * Ignore all messages that are not ACKs/NACKs to 30441ae08745Sheppo * DRing requests. 30451ae08745Sheppo */ 30461ae08745Sheppo if ((dmsg.tag.vio_msgtype != VIO_TYPE_DATA) || 30471ae08745Sheppo (dmsg.tag.vio_subtype_env != VIO_DRING_DATA)) { 30483af08d82Slm66018 DMSG(vdc, 0, "discard pkt: type=%d sub=%d env=%d\n", 30491ae08745Sheppo dmsg.tag.vio_msgtype, 30501ae08745Sheppo dmsg.tag.vio_subtype, 30511ae08745Sheppo dmsg.tag.vio_subtype_env); 30521ae08745Sheppo continue; 30531ae08745Sheppo } 30541ae08745Sheppo 30551ae08745Sheppo /* 30563af08d82Slm66018 * set the appropriate return value for the current request. 30571ae08745Sheppo */ 30581ae08745Sheppo switch (dmsg.tag.vio_subtype) { 30591ae08745Sheppo case VIO_SUBTYPE_ACK: 30608e6a2a04Slm66018 rv = 0; 30611ae08745Sheppo break; 30621ae08745Sheppo case VIO_SUBTYPE_NACK: 30638e6a2a04Slm66018 rv = EAGAIN; 30641ae08745Sheppo break; 30651ae08745Sheppo default: 30661ae08745Sheppo continue; 30671ae08745Sheppo } 30681ae08745Sheppo 30693af08d82Slm66018 idx = dmsg.start_idx; 30703af08d82Slm66018 if (idx >= vdc->dring_len) { 30713af08d82Slm66018 DMSG(vdc, 0, "[%d] Bogus ack data : start %d\n", 3072e1ebb9ecSlm66018 vdc->instance, idx); 30733af08d82Slm66018 continue; 30741ae08745Sheppo } 30753af08d82Slm66018 ldep = &vdc->local_dring[idx]; 30763af08d82Slm66018 if (ldep->dep->hdr.dstate != VIO_DESC_DONE) { 30773af08d82Slm66018 DMSG(vdc, 0, "[%d] Entry @ %d - state !DONE %d\n", 30783af08d82Slm66018 vdc->instance, idx, ldep->dep->hdr.dstate); 30791ae08745Sheppo continue; 30801ae08745Sheppo } 30811ae08745Sheppo 30823af08d82Slm66018 DMSG(vdc, 1, "[%d] Depopulating idx=%d state=%d\n", 30833af08d82Slm66018 vdc->instance, idx, ldep->dep->hdr.dstate); 30843af08d82Slm66018 rv = vdc_depopulate_descriptor(vdc, idx); 30853af08d82Slm66018 if (rv) { 30863af08d82Slm66018 DMSG(vdc, 0, 30873af08d82Slm66018 "[%d] Entry @ %d - depopulate failed ..\n", 30883af08d82Slm66018 vdc->instance, idx); 30891ae08745Sheppo } 30901ae08745Sheppo 30913af08d82Slm66018 /* if this is the last descriptor - break out of loop */ 30923af08d82Slm66018 if ((idx + 1) % vdc->dring_len == vdc->dring_curr_idx) 30933af08d82Slm66018 break; 30943af08d82Slm66018 } 30953af08d82Slm66018 30963af08d82Slm66018 mutex_exit(&vdc->lock); 30973af08d82Slm66018 DMSG(vdc, 0, "End idx=%d\n", idx); 30983af08d82Slm66018 30993af08d82Slm66018 return (rv); 31001ae08745Sheppo } 31011ae08745Sheppo 31021ae08745Sheppo 31030a55fbb7Slm66018 /* 31040a55fbb7Slm66018 * Function: 31050a55fbb7Slm66018 * vdc_depopulate_descriptor() 31060a55fbb7Slm66018 * 31070a55fbb7Slm66018 * Description: 31080a55fbb7Slm66018 * 31090a55fbb7Slm66018 * Arguments: 31100a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 31110a55fbb7Slm66018 * idx - Index of the Descriptor Ring entry being modified 31120a55fbb7Slm66018 * 31130a55fbb7Slm66018 * Return Code: 31140a55fbb7Slm66018 * 0 - Success 31150a55fbb7Slm66018 */ 31161ae08745Sheppo static int 31171ae08745Sheppo vdc_depopulate_descriptor(vdc_t *vdc, uint_t idx) 31181ae08745Sheppo { 31191ae08745Sheppo vd_dring_entry_t *dep = NULL; /* Dring Entry Pointer */ 31201ae08745Sheppo vdc_local_desc_t *ldep = NULL; /* Local Dring Entry Pointer */ 31211ae08745Sheppo int status = ENXIO; 31228e6a2a04Slm66018 int rv = 0; 31231ae08745Sheppo 31241ae08745Sheppo ASSERT(vdc != NULL); 3125e1ebb9ecSlm66018 ASSERT(idx < vdc->dring_len); 31261ae08745Sheppo ldep = &vdc->local_dring[idx]; 31271ae08745Sheppo ASSERT(ldep != NULL); 31283af08d82Slm66018 ASSERT(MUTEX_HELD(&vdc->lock)); 31293af08d82Slm66018 31303af08d82Slm66018 DMSG(vdc, 2, ": idx = %d\n", idx); 31311ae08745Sheppo dep = ldep->dep; 31321ae08745Sheppo ASSERT(dep != NULL); 3133e1ebb9ecSlm66018 ASSERT((dep->hdr.dstate == VIO_DESC_DONE) || 3134e1ebb9ecSlm66018 (dep->payload.status == ECANCELED)); 31351ae08745Sheppo 3136e1ebb9ecSlm66018 VDC_MARK_DRING_ENTRY_FREE(vdc, idx); 31373af08d82Slm66018 31383af08d82Slm66018 ldep->is_free = B_TRUE; 31391ae08745Sheppo status = dep->payload.status; 3140205eeb1aSlm66018 DMSG(vdc, 2, ": is_free = %d : status = %d\n", ldep->is_free, status); 31411ae08745Sheppo 3142eff7243fSlm66018 /* 3143eff7243fSlm66018 * If no buffers were used to transfer information to the server when 3144eff7243fSlm66018 * populating the descriptor then no memory handles need to be unbound 3145eff7243fSlm66018 * and we can return now. 3146eff7243fSlm66018 */ 3147eff7243fSlm66018 if (ldep->nbytes == 0) { 3148eff7243fSlm66018 cv_signal(&vdc->dring_free_cv); 31498e6a2a04Slm66018 return (status); 3150eff7243fSlm66018 } 31518e6a2a04Slm66018 31521ae08745Sheppo /* 31531ae08745Sheppo * If the upper layer passed in a misaligned address we copied the 31541ae08745Sheppo * data into an aligned buffer before sending it to LDC - we now 31551ae08745Sheppo * copy it back to the original buffer. 31561ae08745Sheppo */ 31571ae08745Sheppo if (ldep->align_addr) { 31581ae08745Sheppo ASSERT(ldep->addr != NULL); 31591ae08745Sheppo 31603c96341aSnarayan if (dep->payload.nbytes > 0) 31613c96341aSnarayan bcopy(ldep->align_addr, ldep->addr, 31623c96341aSnarayan dep->payload.nbytes); 31631ae08745Sheppo kmem_free(ldep->align_addr, 31643c96341aSnarayan sizeof (caddr_t) * P2ROUNDUP(ldep->nbytes, 8)); 31651ae08745Sheppo ldep->align_addr = NULL; 31661ae08745Sheppo } 31671ae08745Sheppo 31688e6a2a04Slm66018 rv = ldc_mem_unbind_handle(ldep->desc_mhdl); 31698e6a2a04Slm66018 if (rv != 0) { 31703af08d82Slm66018 DMSG(vdc, 0, "?[%d] unbind mhdl 0x%lx @ idx %d failed (%d)", 31718e6a2a04Slm66018 vdc->instance, ldep->desc_mhdl, idx, rv); 31728e6a2a04Slm66018 /* 31738e6a2a04Slm66018 * The error returned by the vDisk server is more informative 31748e6a2a04Slm66018 * and thus has a higher priority but if it isn't set we ensure 31758e6a2a04Slm66018 * that this function returns an error. 31768e6a2a04Slm66018 */ 31778e6a2a04Slm66018 if (status == 0) 31788e6a2a04Slm66018 status = EINVAL; 31791ae08745Sheppo } 31801ae08745Sheppo 31813af08d82Slm66018 cv_signal(&vdc->membind_cv); 31823af08d82Slm66018 cv_signal(&vdc->dring_free_cv); 31833af08d82Slm66018 31841ae08745Sheppo return (status); 31851ae08745Sheppo } 31861ae08745Sheppo 31870a55fbb7Slm66018 /* 31880a55fbb7Slm66018 * Function: 31890a55fbb7Slm66018 * vdc_populate_mem_hdl() 31900a55fbb7Slm66018 * 31910a55fbb7Slm66018 * Description: 31920a55fbb7Slm66018 * 31930a55fbb7Slm66018 * Arguments: 31940a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 31950a55fbb7Slm66018 * idx - Index of the Descriptor Ring entry being modified 31960a55fbb7Slm66018 * addr - virtual address being mapped in 31970a55fbb7Slm66018 * nybtes - number of bytes in 'addr' 31980a55fbb7Slm66018 * operation - the vDisk operation being performed (VD_OP_xxx) 31990a55fbb7Slm66018 * 32000a55fbb7Slm66018 * Return Code: 32010a55fbb7Slm66018 * 0 - Success 32020a55fbb7Slm66018 */ 32031ae08745Sheppo static int 32043af08d82Slm66018 vdc_populate_mem_hdl(vdc_t *vdcp, vdc_local_desc_t *ldep) 32051ae08745Sheppo { 32061ae08745Sheppo vd_dring_entry_t *dep = NULL; 32071ae08745Sheppo ldc_mem_handle_t mhdl; 32081ae08745Sheppo caddr_t vaddr; 32093af08d82Slm66018 size_t nbytes; 32104bac2208Snarayan uint8_t perm = LDC_MEM_RW; 32114bac2208Snarayan uint8_t maptype; 32121ae08745Sheppo int rv = 0; 32131ae08745Sheppo int i; 32141ae08745Sheppo 32153af08d82Slm66018 ASSERT(vdcp != NULL); 32161ae08745Sheppo 32173af08d82Slm66018 dep = ldep->dep; 32181ae08745Sheppo mhdl = ldep->desc_mhdl; 32191ae08745Sheppo 32203af08d82Slm66018 switch (ldep->dir) { 32213af08d82Slm66018 case VIO_read_dir: 32221ae08745Sheppo perm = LDC_MEM_W; 32231ae08745Sheppo break; 32241ae08745Sheppo 32253af08d82Slm66018 case VIO_write_dir: 32261ae08745Sheppo perm = LDC_MEM_R; 32271ae08745Sheppo break; 32281ae08745Sheppo 32293af08d82Slm66018 case VIO_both_dir: 32301ae08745Sheppo perm = LDC_MEM_RW; 32311ae08745Sheppo break; 32321ae08745Sheppo 32331ae08745Sheppo default: 32341ae08745Sheppo ASSERT(0); /* catch bad programming in vdc */ 32351ae08745Sheppo } 32361ae08745Sheppo 32371ae08745Sheppo /* 32381ae08745Sheppo * LDC expects any addresses passed in to be 8-byte aligned. We need 32391ae08745Sheppo * to copy the contents of any misaligned buffers to a newly allocated 32401ae08745Sheppo * buffer and bind it instead (and copy the the contents back to the 32411ae08745Sheppo * original buffer passed in when depopulating the descriptor) 32421ae08745Sheppo */ 32433af08d82Slm66018 vaddr = ldep->addr; 32443af08d82Slm66018 nbytes = ldep->nbytes; 32453af08d82Slm66018 if (((uint64_t)vaddr & 0x7) != 0) { 3246d10e4ef2Snarayan ASSERT(ldep->align_addr == NULL); 32471ae08745Sheppo ldep->align_addr = 32483af08d82Slm66018 kmem_alloc(sizeof (caddr_t) * 32493af08d82Slm66018 P2ROUNDUP(nbytes, 8), KM_SLEEP); 32503af08d82Slm66018 DMSG(vdcp, 0, "[%d] Misaligned address %p reallocating " 32513af08d82Slm66018 "(buf=%p nb=%ld op=%d)\n", 32523af08d82Slm66018 vdcp->instance, (void *)vaddr, (void *)ldep->align_addr, 32533af08d82Slm66018 nbytes, ldep->operation); 32543af08d82Slm66018 if (perm != LDC_MEM_W) 32553af08d82Slm66018 bcopy(vaddr, ldep->align_addr, nbytes); 32561ae08745Sheppo vaddr = ldep->align_addr; 32571ae08745Sheppo } 32581ae08745Sheppo 32594bac2208Snarayan maptype = LDC_IO_MAP|LDC_SHADOW_MAP|LDC_DIRECT_MAP; 32601ae08745Sheppo rv = ldc_mem_bind_handle(mhdl, vaddr, P2ROUNDUP(nbytes, 8), 326187a7269eSachartre maptype, perm, &dep->payload.cookie[0], &dep->payload.ncookies); 32623af08d82Slm66018 DMSG(vdcp, 2, "[%d] bound mem handle; ncookies=%d\n", 32633af08d82Slm66018 vdcp->instance, dep->payload.ncookies); 32641ae08745Sheppo if (rv != 0) { 32653af08d82Slm66018 DMSG(vdcp, 0, "[%d] Failed to bind LDC memory handle " 32663af08d82Slm66018 "(mhdl=%p, buf=%p, err=%d)\n", 32673af08d82Slm66018 vdcp->instance, (void *)mhdl, (void *)vaddr, rv); 32681ae08745Sheppo if (ldep->align_addr) { 32691ae08745Sheppo kmem_free(ldep->align_addr, 3270d10e4ef2Snarayan sizeof (caddr_t) * P2ROUNDUP(nbytes, 8)); 32711ae08745Sheppo ldep->align_addr = NULL; 32721ae08745Sheppo } 32731ae08745Sheppo return (EAGAIN); 32741ae08745Sheppo } 32751ae08745Sheppo 32761ae08745Sheppo /* 32771ae08745Sheppo * Get the other cookies (if any). 32781ae08745Sheppo */ 32791ae08745Sheppo for (i = 1; i < dep->payload.ncookies; i++) { 32801ae08745Sheppo rv = ldc_mem_nextcookie(mhdl, &dep->payload.cookie[i]); 32811ae08745Sheppo if (rv != 0) { 32821ae08745Sheppo (void) ldc_mem_unbind_handle(mhdl); 32833af08d82Slm66018 DMSG(vdcp, 0, "?[%d] Failed to get next cookie " 3284e1ebb9ecSlm66018 "(mhdl=%lx cnum=%d), err=%d", 32853af08d82Slm66018 vdcp->instance, mhdl, i, rv); 32861ae08745Sheppo if (ldep->align_addr) { 32871ae08745Sheppo kmem_free(ldep->align_addr, 32883c96341aSnarayan sizeof (caddr_t) * ldep->nbytes); 32891ae08745Sheppo ldep->align_addr = NULL; 32901ae08745Sheppo } 32911ae08745Sheppo return (EAGAIN); 32921ae08745Sheppo } 32931ae08745Sheppo } 32941ae08745Sheppo 32951ae08745Sheppo return (rv); 32961ae08745Sheppo } 32971ae08745Sheppo 32981ae08745Sheppo /* 32991ae08745Sheppo * Interrupt handlers for messages from LDC 33001ae08745Sheppo */ 33011ae08745Sheppo 33020a55fbb7Slm66018 /* 33030a55fbb7Slm66018 * Function: 33040a55fbb7Slm66018 * vdc_handle_cb() 33050a55fbb7Slm66018 * 33060a55fbb7Slm66018 * Description: 33070a55fbb7Slm66018 * 33080a55fbb7Slm66018 * Arguments: 33090a55fbb7Slm66018 * event - Type of event (LDC_EVT_xxx) that triggered the callback 33100a55fbb7Slm66018 * arg - soft state pointer for this instance of the device driver. 33110a55fbb7Slm66018 * 33120a55fbb7Slm66018 * Return Code: 33130a55fbb7Slm66018 * 0 - Success 33140a55fbb7Slm66018 */ 33151ae08745Sheppo static uint_t 33161ae08745Sheppo vdc_handle_cb(uint64_t event, caddr_t arg) 33171ae08745Sheppo { 33181ae08745Sheppo ldc_status_t ldc_state; 33191ae08745Sheppo int rv = 0; 33201ae08745Sheppo 33211ae08745Sheppo vdc_t *vdc = (vdc_t *)(void *)arg; 33221ae08745Sheppo 33231ae08745Sheppo ASSERT(vdc != NULL); 33241ae08745Sheppo 33253af08d82Slm66018 DMSG(vdc, 1, "evt=%lx seqID=%ld\n", event, vdc->seq_num); 33261ae08745Sheppo 33271ae08745Sheppo /* 33281ae08745Sheppo * Depending on the type of event that triggered this callback, 33293af08d82Slm66018 * we modify the handshake state or read the data. 33301ae08745Sheppo * 33311ae08745Sheppo * NOTE: not done as a switch() as event could be triggered by 33321ae08745Sheppo * a state change and a read request. Also the ordering of the 33331ae08745Sheppo * check for the event types is deliberate. 33341ae08745Sheppo */ 33351ae08745Sheppo if (event & LDC_EVT_UP) { 33363af08d82Slm66018 DMSG(vdc, 0, "[%d] Received LDC_EVT_UP\n", vdc->instance); 33373af08d82Slm66018 33383af08d82Slm66018 mutex_enter(&vdc->lock); 33391ae08745Sheppo 33401ae08745Sheppo /* get LDC state */ 33411ae08745Sheppo rv = ldc_status(vdc->ldc_handle, &ldc_state); 33421ae08745Sheppo if (rv != 0) { 33433af08d82Slm66018 DMSG(vdc, 0, "[%d] Couldn't get LDC status %d", 33441ae08745Sheppo vdc->instance, rv); 33451ae08745Sheppo return (LDC_SUCCESS); 33461ae08745Sheppo } 33473af08d82Slm66018 if (vdc->ldc_state != LDC_UP && ldc_state == LDC_UP) { 33481ae08745Sheppo /* 33493af08d82Slm66018 * Reset the transaction sequence numbers when 33503af08d82Slm66018 * LDC comes up. We then kick off the handshake 33513af08d82Slm66018 * negotiation with the vDisk server. 33521ae08745Sheppo */ 33530a55fbb7Slm66018 vdc->seq_num = 1; 33541ae08745Sheppo vdc->seq_num_reply = 0; 33551ae08745Sheppo vdc->ldc_state = ldc_state; 33563af08d82Slm66018 cv_signal(&vdc->initwait_cv); 33573af08d82Slm66018 } 33583af08d82Slm66018 33591ae08745Sheppo mutex_exit(&vdc->lock); 33601ae08745Sheppo } 33611ae08745Sheppo 33621ae08745Sheppo if (event & LDC_EVT_READ) { 336317cadca8Slm66018 DMSG(vdc, 1, "[%d] Received LDC_EVT_READ\n", vdc->instance); 33643af08d82Slm66018 mutex_enter(&vdc->read_lock); 33653af08d82Slm66018 cv_signal(&vdc->read_cv); 33663af08d82Slm66018 vdc->read_state = VDC_READ_PENDING; 33673af08d82Slm66018 mutex_exit(&vdc->read_lock); 33681ae08745Sheppo 33691ae08745Sheppo /* that's all we have to do - no need to handle DOWN/RESET */ 33701ae08745Sheppo return (LDC_SUCCESS); 33711ae08745Sheppo } 33721ae08745Sheppo 33733af08d82Slm66018 if (event & (LDC_EVT_RESET|LDC_EVT_DOWN)) { 33740a55fbb7Slm66018 33753af08d82Slm66018 DMSG(vdc, 0, "[%d] Received LDC RESET event\n", vdc->instance); 33763af08d82Slm66018 33770a55fbb7Slm66018 mutex_enter(&vdc->lock); 33783af08d82Slm66018 /* 33793af08d82Slm66018 * Need to wake up any readers so they will 33803af08d82Slm66018 * detect that a reset has occurred. 33813af08d82Slm66018 */ 33823af08d82Slm66018 mutex_enter(&vdc->read_lock); 33833af08d82Slm66018 if ((vdc->read_state == VDC_READ_WAITING) || 33843af08d82Slm66018 (vdc->read_state == VDC_READ_RESET)) 33853af08d82Slm66018 cv_signal(&vdc->read_cv); 33863af08d82Slm66018 vdc->read_state = VDC_READ_RESET; 33873af08d82Slm66018 mutex_exit(&vdc->read_lock); 33880a55fbb7Slm66018 33893af08d82Slm66018 /* wake up any threads waiting for connection to come up */ 33903af08d82Slm66018 if (vdc->state == VDC_STATE_INIT_WAITING) { 33913af08d82Slm66018 vdc->state = VDC_STATE_RESETTING; 33923af08d82Slm66018 cv_signal(&vdc->initwait_cv); 33931ae08745Sheppo } 33941ae08745Sheppo 33950a55fbb7Slm66018 mutex_exit(&vdc->lock); 33961ae08745Sheppo } 33971ae08745Sheppo 33981ae08745Sheppo if (event & ~(LDC_EVT_UP | LDC_EVT_RESET | LDC_EVT_DOWN | LDC_EVT_READ)) 33993af08d82Slm66018 DMSG(vdc, 0, "![%d] Unexpected LDC event (%lx) received", 34001ae08745Sheppo vdc->instance, event); 34011ae08745Sheppo 34021ae08745Sheppo return (LDC_SUCCESS); 34031ae08745Sheppo } 34041ae08745Sheppo 34053af08d82Slm66018 /* 34063af08d82Slm66018 * Function: 34073af08d82Slm66018 * vdc_wait_for_response() 34083af08d82Slm66018 * 34093af08d82Slm66018 * Description: 34103af08d82Slm66018 * Block waiting for a response from the server. If there is 34113af08d82Slm66018 * no data the thread block on the read_cv that is signalled 34123af08d82Slm66018 * by the callback when an EVT_READ occurs. 34133af08d82Slm66018 * 34143af08d82Slm66018 * Arguments: 34153af08d82Slm66018 * vdcp - soft state pointer for this instance of the device driver. 34163af08d82Slm66018 * 34173af08d82Slm66018 * Return Code: 34183af08d82Slm66018 * 0 - Success 34193af08d82Slm66018 */ 34203af08d82Slm66018 static int 34213af08d82Slm66018 vdc_wait_for_response(vdc_t *vdcp, vio_msg_t *msgp) 34223af08d82Slm66018 { 34233af08d82Slm66018 size_t nbytes = sizeof (*msgp); 34243af08d82Slm66018 int status; 34253af08d82Slm66018 34263af08d82Slm66018 ASSERT(vdcp != NULL); 34273af08d82Slm66018 34283af08d82Slm66018 DMSG(vdcp, 1, "[%d] Entered\n", vdcp->instance); 34293af08d82Slm66018 34303af08d82Slm66018 status = vdc_recv(vdcp, msgp, &nbytes); 34313af08d82Slm66018 DMSG(vdcp, 3, "vdc_read() done.. status=0x%x size=0x%x\n", 34323af08d82Slm66018 status, (int)nbytes); 34333af08d82Slm66018 if (status) { 34343af08d82Slm66018 DMSG(vdcp, 0, "?[%d] Error %d reading LDC msg\n", 34353af08d82Slm66018 vdcp->instance, status); 34363af08d82Slm66018 return (status); 34373af08d82Slm66018 } 34383af08d82Slm66018 34393af08d82Slm66018 if (nbytes < sizeof (vio_msg_tag_t)) { 34403af08d82Slm66018 DMSG(vdcp, 0, "?[%d] Expect %lu bytes; recv'd %lu\n", 34413af08d82Slm66018 vdcp->instance, sizeof (vio_msg_tag_t), nbytes); 34423af08d82Slm66018 return (ENOMSG); 34433af08d82Slm66018 } 34443af08d82Slm66018 34453af08d82Slm66018 DMSG(vdcp, 2, "[%d] (%x/%x/%x)\n", vdcp->instance, 34463af08d82Slm66018 msgp->tag.vio_msgtype, 34473af08d82Slm66018 msgp->tag.vio_subtype, 34483af08d82Slm66018 msgp->tag.vio_subtype_env); 34493af08d82Slm66018 34503af08d82Slm66018 /* 34513af08d82Slm66018 * Verify the Session ID of the message 34523af08d82Slm66018 * 34533af08d82Slm66018 * Every message after the Version has been negotiated should 34543af08d82Slm66018 * have the correct session ID set. 34553af08d82Slm66018 */ 34563af08d82Slm66018 if ((msgp->tag.vio_sid != vdcp->session_id) && 34573af08d82Slm66018 (msgp->tag.vio_subtype_env != VIO_VER_INFO)) { 34583af08d82Slm66018 DMSG(vdcp, 0, "[%d] Invalid SID: received 0x%x, " 34593af08d82Slm66018 "expected 0x%lx [seq num %lx @ %d]", 34603af08d82Slm66018 vdcp->instance, msgp->tag.vio_sid, 34613af08d82Slm66018 vdcp->session_id, 34623af08d82Slm66018 ((vio_dring_msg_t *)msgp)->seq_num, 34633af08d82Slm66018 ((vio_dring_msg_t *)msgp)->start_idx); 34643af08d82Slm66018 return (ENOMSG); 34653af08d82Slm66018 } 34663af08d82Slm66018 return (0); 34673af08d82Slm66018 } 34683af08d82Slm66018 34693af08d82Slm66018 34703af08d82Slm66018 /* 34713af08d82Slm66018 * Function: 34723af08d82Slm66018 * vdc_resubmit_backup_dring() 34733af08d82Slm66018 * 34743af08d82Slm66018 * Description: 34753af08d82Slm66018 * Resubmit each descriptor in the backed up dring to 34763af08d82Slm66018 * vDisk server. The Dring was backed up during connection 34773af08d82Slm66018 * reset. 34783af08d82Slm66018 * 34793af08d82Slm66018 * Arguments: 34803af08d82Slm66018 * vdcp - soft state pointer for this instance of the device driver. 34813af08d82Slm66018 * 34823af08d82Slm66018 * Return Code: 34833af08d82Slm66018 * 0 - Success 34843af08d82Slm66018 */ 34853af08d82Slm66018 static int 34863af08d82Slm66018 vdc_resubmit_backup_dring(vdc_t *vdcp) 34873af08d82Slm66018 { 34883af08d82Slm66018 int count; 34893af08d82Slm66018 int b_idx; 34903af08d82Slm66018 int rv; 34913af08d82Slm66018 int dring_size; 34923af08d82Slm66018 int status; 34933af08d82Slm66018 vio_msg_t vio_msg; 34943af08d82Slm66018 vdc_local_desc_t *curr_ldep; 34953af08d82Slm66018 34963af08d82Slm66018 ASSERT(MUTEX_NOT_HELD(&vdcp->lock)); 34973af08d82Slm66018 ASSERT(vdcp->state == VDC_STATE_HANDLE_PENDING); 34983af08d82Slm66018 3499655fd6a9Sachartre if (vdcp->local_dring_backup == NULL) { 3500655fd6a9Sachartre /* the pending requests have already been processed */ 3501655fd6a9Sachartre return (0); 3502655fd6a9Sachartre } 3503655fd6a9Sachartre 35043af08d82Slm66018 DMSG(vdcp, 1, "restoring pending dring entries (len=%d, tail=%d)\n", 35053af08d82Slm66018 vdcp->local_dring_backup_len, vdcp->local_dring_backup_tail); 35063af08d82Slm66018 35073af08d82Slm66018 /* 35083af08d82Slm66018 * Walk the backup copy of the local descriptor ring and 35093af08d82Slm66018 * resubmit all the outstanding transactions. 35103af08d82Slm66018 */ 35113af08d82Slm66018 b_idx = vdcp->local_dring_backup_tail; 35123af08d82Slm66018 for (count = 0; count < vdcp->local_dring_backup_len; count++) { 35133af08d82Slm66018 35143af08d82Slm66018 curr_ldep = &(vdcp->local_dring_backup[b_idx]); 35153af08d82Slm66018 3516eff7243fSlm66018 /* only resubmit outstanding transactions */ 35173af08d82Slm66018 if (!curr_ldep->is_free) { 35183af08d82Slm66018 35193af08d82Slm66018 DMSG(vdcp, 1, "resubmitting entry idx=%x\n", b_idx); 35203af08d82Slm66018 mutex_enter(&vdcp->lock); 35213af08d82Slm66018 rv = vdc_populate_descriptor(vdcp, curr_ldep->operation, 35223af08d82Slm66018 curr_ldep->addr, curr_ldep->nbytes, 35233af08d82Slm66018 curr_ldep->slice, curr_ldep->offset, 35243af08d82Slm66018 curr_ldep->cb_type, curr_ldep->cb_arg, 35253af08d82Slm66018 curr_ldep->dir); 35263af08d82Slm66018 mutex_exit(&vdcp->lock); 35273af08d82Slm66018 if (rv) { 35283af08d82Slm66018 DMSG(vdcp, 1, "[%d] cannot resubmit entry %d\n", 35293af08d82Slm66018 vdcp->instance, b_idx); 35303af08d82Slm66018 return (rv); 35313af08d82Slm66018 } 35323af08d82Slm66018 35333af08d82Slm66018 /* Wait for the response message. */ 35343af08d82Slm66018 DMSG(vdcp, 1, "waiting for response to idx=%x\n", 35353af08d82Slm66018 b_idx); 35363af08d82Slm66018 status = vdc_wait_for_response(vdcp, &vio_msg); 35373af08d82Slm66018 if (status) { 35383af08d82Slm66018 DMSG(vdcp, 1, "[%d] wait_for_response " 35393af08d82Slm66018 "returned err=%d\n", vdcp->instance, 35403af08d82Slm66018 status); 35413af08d82Slm66018 return (status); 35423af08d82Slm66018 } 35433af08d82Slm66018 35443af08d82Slm66018 DMSG(vdcp, 1, "processing msg for idx=%x\n", b_idx); 35453af08d82Slm66018 status = vdc_process_data_msg(vdcp, &vio_msg); 35463af08d82Slm66018 if (status) { 35473af08d82Slm66018 DMSG(vdcp, 1, "[%d] process_data_msg " 35483af08d82Slm66018 "returned err=%d\n", vdcp->instance, 35493af08d82Slm66018 status); 35503af08d82Slm66018 return (status); 35513af08d82Slm66018 } 35523af08d82Slm66018 } 35533af08d82Slm66018 35543af08d82Slm66018 /* get the next element to submit */ 35553af08d82Slm66018 if (++b_idx >= vdcp->local_dring_backup_len) 35563af08d82Slm66018 b_idx = 0; 35573af08d82Slm66018 } 35583af08d82Slm66018 35593af08d82Slm66018 /* all done - now clear up pending dring copy */ 35603af08d82Slm66018 dring_size = vdcp->local_dring_backup_len * 35613af08d82Slm66018 sizeof (vdcp->local_dring_backup[0]); 35623af08d82Slm66018 35633af08d82Slm66018 (void) kmem_free(vdcp->local_dring_backup, dring_size); 35643af08d82Slm66018 35653af08d82Slm66018 vdcp->local_dring_backup = NULL; 35663af08d82Slm66018 35673af08d82Slm66018 return (0); 35683af08d82Slm66018 } 35693af08d82Slm66018 35703af08d82Slm66018 /* 35713af08d82Slm66018 * Function: 3572655fd6a9Sachartre * vdc_cancel_backup_dring 3573655fd6a9Sachartre * 3574655fd6a9Sachartre * Description: 3575655fd6a9Sachartre * Cancel each descriptor in the backed up dring to vDisk server. 3576655fd6a9Sachartre * The Dring was backed up during connection reset. 3577655fd6a9Sachartre * 3578655fd6a9Sachartre * Arguments: 3579655fd6a9Sachartre * vdcp - soft state pointer for this instance of the device driver. 3580655fd6a9Sachartre * 3581655fd6a9Sachartre * Return Code: 3582655fd6a9Sachartre * None 3583655fd6a9Sachartre */ 3584655fd6a9Sachartre void 3585655fd6a9Sachartre vdc_cancel_backup_ring(vdc_t *vdcp) 3586655fd6a9Sachartre { 3587655fd6a9Sachartre vdc_local_desc_t *ldep; 3588655fd6a9Sachartre struct buf *bufp; 3589655fd6a9Sachartre int count; 3590655fd6a9Sachartre int b_idx; 3591655fd6a9Sachartre int dring_size; 3592655fd6a9Sachartre 3593655fd6a9Sachartre ASSERT(MUTEX_HELD(&vdcp->lock)); 3594655fd6a9Sachartre ASSERT(vdcp->state == VDC_STATE_INIT || 3595655fd6a9Sachartre vdcp->state == VDC_STATE_INIT_WAITING || 3596655fd6a9Sachartre vdcp->state == VDC_STATE_NEGOTIATE || 3597655fd6a9Sachartre vdcp->state == VDC_STATE_RESETTING); 3598655fd6a9Sachartre 3599655fd6a9Sachartre if (vdcp->local_dring_backup == NULL) { 3600655fd6a9Sachartre /* the pending requests have already been processed */ 3601655fd6a9Sachartre return; 3602655fd6a9Sachartre } 3603655fd6a9Sachartre 3604655fd6a9Sachartre DMSG(vdcp, 1, "cancelling pending dring entries (len=%d, tail=%d)\n", 3605655fd6a9Sachartre vdcp->local_dring_backup_len, vdcp->local_dring_backup_tail); 3606655fd6a9Sachartre 3607655fd6a9Sachartre /* 3608655fd6a9Sachartre * Walk the backup copy of the local descriptor ring and 3609655fd6a9Sachartre * cancel all the outstanding transactions. 3610655fd6a9Sachartre */ 3611655fd6a9Sachartre b_idx = vdcp->local_dring_backup_tail; 3612655fd6a9Sachartre for (count = 0; count < vdcp->local_dring_backup_len; count++) { 3613655fd6a9Sachartre 3614655fd6a9Sachartre ldep = &(vdcp->local_dring_backup[b_idx]); 3615655fd6a9Sachartre 3616655fd6a9Sachartre /* only cancel outstanding transactions */ 3617655fd6a9Sachartre if (!ldep->is_free) { 3618655fd6a9Sachartre 3619655fd6a9Sachartre DMSG(vdcp, 1, "cancelling entry idx=%x\n", b_idx); 3620655fd6a9Sachartre 3621655fd6a9Sachartre /* 3622655fd6a9Sachartre * All requests have already been cleared from the 3623655fd6a9Sachartre * local descriptor ring and the LDC channel has been 3624655fd6a9Sachartre * reset so we will never get any reply for these 3625655fd6a9Sachartre * requests. Now we just have to notify threads waiting 3626655fd6a9Sachartre * for replies that the request has failed. 3627655fd6a9Sachartre */ 3628655fd6a9Sachartre switch (ldep->cb_type) { 3629655fd6a9Sachartre case CB_SYNC: 3630655fd6a9Sachartre ASSERT(vdcp->sync_op_pending); 3631655fd6a9Sachartre vdcp->sync_op_status = EIO; 3632655fd6a9Sachartre vdcp->sync_op_pending = B_FALSE; 3633655fd6a9Sachartre cv_signal(&vdcp->sync_pending_cv); 3634655fd6a9Sachartre break; 3635655fd6a9Sachartre 3636655fd6a9Sachartre case CB_STRATEGY: 3637655fd6a9Sachartre bufp = ldep->cb_arg; 3638655fd6a9Sachartre ASSERT(bufp != NULL); 3639655fd6a9Sachartre bufp->b_resid = bufp->b_bcount; 3640655fd6a9Sachartre bioerror(bufp, EIO); 3641655fd6a9Sachartre biodone(bufp); 3642655fd6a9Sachartre break; 3643655fd6a9Sachartre 3644655fd6a9Sachartre default: 3645655fd6a9Sachartre ASSERT(0); 3646655fd6a9Sachartre } 3647655fd6a9Sachartre 3648655fd6a9Sachartre } 3649655fd6a9Sachartre 3650655fd6a9Sachartre /* get the next element to cancel */ 3651655fd6a9Sachartre if (++b_idx >= vdcp->local_dring_backup_len) 3652655fd6a9Sachartre b_idx = 0; 3653655fd6a9Sachartre } 3654655fd6a9Sachartre 3655655fd6a9Sachartre /* all done - now clear up pending dring copy */ 3656655fd6a9Sachartre dring_size = vdcp->local_dring_backup_len * 3657655fd6a9Sachartre sizeof (vdcp->local_dring_backup[0]); 3658655fd6a9Sachartre 3659655fd6a9Sachartre (void) kmem_free(vdcp->local_dring_backup, dring_size); 3660655fd6a9Sachartre 3661655fd6a9Sachartre vdcp->local_dring_backup = NULL; 3662655fd6a9Sachartre 3663655fd6a9Sachartre DTRACE_IO2(processed, int, count, vdc_t *, vdcp); 3664655fd6a9Sachartre } 3665655fd6a9Sachartre 3666655fd6a9Sachartre /* 3667655fd6a9Sachartre * Function: 3668655fd6a9Sachartre * vdc_connection_timeout 3669655fd6a9Sachartre * 3670655fd6a9Sachartre * Description: 3671655fd6a9Sachartre * This function is invoked if the timeout set to establish the connection 3672655fd6a9Sachartre * with vds expires. This will happen if we spend too much time in the 3673655fd6a9Sachartre * VDC_STATE_INIT_WAITING or VDC_STATE_NEGOTIATE states. Then we will 3674655fd6a9Sachartre * cancel any pending request and mark them as failed. 3675655fd6a9Sachartre * 3676655fd6a9Sachartre * If the timeout does not expire, it will be cancelled when we reach the 3677655fd6a9Sachartre * VDC_STATE_HANDLE_PENDING or VDC_STATE_RESETTING state. This function can 3678655fd6a9Sachartre * be invoked while we are in the VDC_STATE_HANDLE_PENDING or 3679655fd6a9Sachartre * VDC_STATE_RESETTING state in which case we do nothing because the 3680655fd6a9Sachartre * timeout is being cancelled. 3681655fd6a9Sachartre * 3682655fd6a9Sachartre * Arguments: 3683655fd6a9Sachartre * arg - argument of the timeout function actually a soft state 3684655fd6a9Sachartre * pointer for the instance of the device driver. 3685655fd6a9Sachartre * 3686655fd6a9Sachartre * Return Code: 3687655fd6a9Sachartre * None 3688655fd6a9Sachartre */ 3689655fd6a9Sachartre void 3690655fd6a9Sachartre vdc_connection_timeout(void *arg) 3691655fd6a9Sachartre { 3692655fd6a9Sachartre vdc_t *vdcp = (vdc_t *)arg; 3693655fd6a9Sachartre 3694655fd6a9Sachartre mutex_enter(&vdcp->lock); 3695655fd6a9Sachartre 3696655fd6a9Sachartre if (vdcp->state == VDC_STATE_HANDLE_PENDING || 3697655fd6a9Sachartre vdcp->state == VDC_STATE_DETACH) { 3698655fd6a9Sachartre /* 3699655fd6a9Sachartre * The connection has just been re-established or 3700655fd6a9Sachartre * we are detaching. 3701655fd6a9Sachartre */ 3702655fd6a9Sachartre vdcp->ctimeout_reached = B_FALSE; 3703655fd6a9Sachartre mutex_exit(&vdcp->lock); 3704655fd6a9Sachartre return; 3705655fd6a9Sachartre } 3706655fd6a9Sachartre 3707655fd6a9Sachartre vdcp->ctimeout_reached = B_TRUE; 3708655fd6a9Sachartre 3709655fd6a9Sachartre /* notify requests waiting for sending */ 3710655fd6a9Sachartre cv_broadcast(&vdcp->running_cv); 3711655fd6a9Sachartre 3712655fd6a9Sachartre /* cancel requests waiting for a result */ 3713655fd6a9Sachartre vdc_cancel_backup_ring(vdcp); 3714655fd6a9Sachartre 3715655fd6a9Sachartre mutex_exit(&vdcp->lock); 3716655fd6a9Sachartre 3717655fd6a9Sachartre cmn_err(CE_NOTE, "[%d] connection to service domain timeout", 3718655fd6a9Sachartre vdcp->instance); 3719655fd6a9Sachartre } 3720655fd6a9Sachartre 3721655fd6a9Sachartre /* 3722655fd6a9Sachartre * Function: 37233af08d82Slm66018 * vdc_backup_local_dring() 37243af08d82Slm66018 * 37253af08d82Slm66018 * Description: 37263af08d82Slm66018 * Backup the current dring in the event of a reset. The Dring 37273af08d82Slm66018 * transactions will be resubmitted to the server when the 37283af08d82Slm66018 * connection is restored. 37293af08d82Slm66018 * 37303af08d82Slm66018 * Arguments: 37313af08d82Slm66018 * vdcp - soft state pointer for this instance of the device driver. 37323af08d82Slm66018 * 37333af08d82Slm66018 * Return Code: 37343af08d82Slm66018 * NONE 37353af08d82Slm66018 */ 37363af08d82Slm66018 static void 37373af08d82Slm66018 vdc_backup_local_dring(vdc_t *vdcp) 37383af08d82Slm66018 { 37393af08d82Slm66018 int dring_size; 37403af08d82Slm66018 3741655fd6a9Sachartre ASSERT(MUTEX_HELD(&vdcp->lock)); 37423af08d82Slm66018 ASSERT(vdcp->state == VDC_STATE_RESETTING); 37433af08d82Slm66018 37443af08d82Slm66018 /* 37453af08d82Slm66018 * If the backup dring is stil around, it means 37463af08d82Slm66018 * that the last restore did not complete. However, 37473af08d82Slm66018 * since we never got back into the running state, 37483af08d82Slm66018 * the backup copy we have is still valid. 37493af08d82Slm66018 */ 37503af08d82Slm66018 if (vdcp->local_dring_backup != NULL) { 37513af08d82Slm66018 DMSG(vdcp, 1, "reusing local descriptor ring backup " 37523af08d82Slm66018 "(len=%d, tail=%d)\n", vdcp->local_dring_backup_len, 37533af08d82Slm66018 vdcp->local_dring_backup_tail); 37543af08d82Slm66018 return; 37553af08d82Slm66018 } 37563af08d82Slm66018 3757655fd6a9Sachartre /* 3758655fd6a9Sachartre * The backup dring can be NULL and the local dring may not be 3759655fd6a9Sachartre * initialized. This can happen if we had a reset while establishing 3760655fd6a9Sachartre * a new connection but after the connection has timed out. In that 3761655fd6a9Sachartre * case the backup dring is NULL because the requests have been 3762655fd6a9Sachartre * cancelled and the request occured before the local dring is 3763655fd6a9Sachartre * initialized. 3764655fd6a9Sachartre */ 3765655fd6a9Sachartre if (!(vdcp->initialized & VDC_DRING_LOCAL)) 3766655fd6a9Sachartre return; 3767655fd6a9Sachartre 37683af08d82Slm66018 DMSG(vdcp, 1, "backing up the local descriptor ring (len=%d, " 37693af08d82Slm66018 "tail=%d)\n", vdcp->dring_len, vdcp->dring_curr_idx); 37703af08d82Slm66018 37713af08d82Slm66018 dring_size = vdcp->dring_len * sizeof (vdcp->local_dring[0]); 37723af08d82Slm66018 37733af08d82Slm66018 vdcp->local_dring_backup = kmem_alloc(dring_size, KM_SLEEP); 37743af08d82Slm66018 bcopy(vdcp->local_dring, vdcp->local_dring_backup, dring_size); 37753af08d82Slm66018 37763af08d82Slm66018 vdcp->local_dring_backup_tail = vdcp->dring_curr_idx; 37773af08d82Slm66018 vdcp->local_dring_backup_len = vdcp->dring_len; 37783af08d82Slm66018 } 37793af08d82Slm66018 37801ae08745Sheppo /* -------------------------------------------------------------------------- */ 37811ae08745Sheppo 37821ae08745Sheppo /* 37831ae08745Sheppo * The following functions process the incoming messages from vds 37841ae08745Sheppo */ 37851ae08745Sheppo 37860a55fbb7Slm66018 /* 37870a55fbb7Slm66018 * Function: 37880a55fbb7Slm66018 * vdc_process_msg_thread() 37890a55fbb7Slm66018 * 37900a55fbb7Slm66018 * Description: 37910a55fbb7Slm66018 * 37923af08d82Slm66018 * Main VDC message processing thread. Each vDisk instance 37933af08d82Slm66018 * consists of a copy of this thread. This thread triggers 37943af08d82Slm66018 * all the handshakes and data exchange with the server. It 37953af08d82Slm66018 * also handles all channel resets 37963af08d82Slm66018 * 37970a55fbb7Slm66018 * Arguments: 37980a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 37990a55fbb7Slm66018 * 38000a55fbb7Slm66018 * Return Code: 38010a55fbb7Slm66018 * None 38020a55fbb7Slm66018 */ 38031ae08745Sheppo static void 38043af08d82Slm66018 vdc_process_msg_thread(vdc_t *vdcp) 38051ae08745Sheppo { 38061ae08745Sheppo int status; 3807655fd6a9Sachartre int ctimeout; 3808655fd6a9Sachartre timeout_id_t tmid = 0; 38091ae08745Sheppo 38103af08d82Slm66018 mutex_enter(&vdcp->lock); 38111ae08745Sheppo 38121ae08745Sheppo for (;;) { 38131ae08745Sheppo 38143af08d82Slm66018 #define Q(_s) (vdcp->state == _s) ? #_s : 38153af08d82Slm66018 DMSG(vdcp, 3, "state = %d (%s)\n", vdcp->state, 38163af08d82Slm66018 Q(VDC_STATE_INIT) 38173af08d82Slm66018 Q(VDC_STATE_INIT_WAITING) 38183af08d82Slm66018 Q(VDC_STATE_NEGOTIATE) 38193af08d82Slm66018 Q(VDC_STATE_HANDLE_PENDING) 38203af08d82Slm66018 Q(VDC_STATE_RUNNING) 38213af08d82Slm66018 Q(VDC_STATE_RESETTING) 38223af08d82Slm66018 Q(VDC_STATE_DETACH) 38233af08d82Slm66018 "UNKNOWN"); 38241ae08745Sheppo 38253af08d82Slm66018 switch (vdcp->state) { 38263af08d82Slm66018 case VDC_STATE_INIT: 38273af08d82Slm66018 3828655fd6a9Sachartre /* 3829655fd6a9Sachartre * If requested, start a timeout to check if the 3830655fd6a9Sachartre * connection with vds is established in the 3831655fd6a9Sachartre * specified delay. If the timeout expires, we 3832655fd6a9Sachartre * will cancel any pending request. 3833655fd6a9Sachartre * 3834655fd6a9Sachartre * If some reset have occurred while establishing 3835655fd6a9Sachartre * the connection, we already have a timeout armed 3836655fd6a9Sachartre * and in that case we don't need to arm a new one. 3837655fd6a9Sachartre */ 3838655fd6a9Sachartre ctimeout = (vdc_timeout != 0)? 3839655fd6a9Sachartre vdc_timeout : vdcp->ctimeout; 3840655fd6a9Sachartre 3841655fd6a9Sachartre if (ctimeout != 0 && tmid == 0) { 3842655fd6a9Sachartre tmid = timeout(vdc_connection_timeout, vdcp, 3843655fd6a9Sachartre ctimeout * drv_usectohz(1000000)); 3844655fd6a9Sachartre } 3845655fd6a9Sachartre 38463af08d82Slm66018 /* Check if have re-initializing repeatedly */ 3847655fd6a9Sachartre if (vdcp->hshake_cnt++ > vdc_hshake_retries && 3848655fd6a9Sachartre vdcp->lifecycle != VDC_LC_ONLINE) { 38493c96341aSnarayan cmn_err(CE_NOTE, "[%d] disk access failed.\n", 38503c96341aSnarayan vdcp->instance); 38513af08d82Slm66018 vdcp->state = VDC_STATE_DETACH; 38523af08d82Slm66018 break; 38533af08d82Slm66018 } 38543af08d82Slm66018 38553af08d82Slm66018 /* Bring up connection with vds via LDC */ 38563af08d82Slm66018 status = vdc_start_ldc_connection(vdcp); 3857655fd6a9Sachartre if (status == EINVAL) { 38583af08d82Slm66018 DMSG(vdcp, 0, "[%d] Could not start LDC", 38593af08d82Slm66018 vdcp->instance); 38603af08d82Slm66018 vdcp->state = VDC_STATE_DETACH; 3861655fd6a9Sachartre } else { 38623af08d82Slm66018 vdcp->state = VDC_STATE_INIT_WAITING; 38633af08d82Slm66018 } 38643af08d82Slm66018 break; 38653af08d82Slm66018 38663af08d82Slm66018 case VDC_STATE_INIT_WAITING: 38673af08d82Slm66018 38683af08d82Slm66018 /* 38693af08d82Slm66018 * Let the callback event move us on 38703af08d82Slm66018 * when channel is open to server 38713af08d82Slm66018 */ 38723af08d82Slm66018 while (vdcp->ldc_state != LDC_UP) { 38733af08d82Slm66018 cv_wait(&vdcp->initwait_cv, &vdcp->lock); 38743af08d82Slm66018 if (vdcp->state != VDC_STATE_INIT_WAITING) { 38753af08d82Slm66018 DMSG(vdcp, 0, 38763af08d82Slm66018 "state moved to %d out from under us...\n", 38773af08d82Slm66018 vdcp->state); 38783af08d82Slm66018 38793af08d82Slm66018 break; 38803af08d82Slm66018 } 38813af08d82Slm66018 } 38823af08d82Slm66018 if (vdcp->state == VDC_STATE_INIT_WAITING && 38833af08d82Slm66018 vdcp->ldc_state == LDC_UP) { 38843af08d82Slm66018 vdcp->state = VDC_STATE_NEGOTIATE; 38853af08d82Slm66018 } 38863af08d82Slm66018 break; 38873af08d82Slm66018 38883af08d82Slm66018 case VDC_STATE_NEGOTIATE: 38893af08d82Slm66018 switch (status = vdc_ver_negotiation(vdcp)) { 38903af08d82Slm66018 case 0: 38913af08d82Slm66018 break; 38923af08d82Slm66018 default: 38933af08d82Slm66018 DMSG(vdcp, 0, "ver negotiate failed (%d)..\n", 38943af08d82Slm66018 status); 38953af08d82Slm66018 goto reset; 38963af08d82Slm66018 } 38973af08d82Slm66018 38983af08d82Slm66018 switch (status = vdc_attr_negotiation(vdcp)) { 38993af08d82Slm66018 case 0: 39003af08d82Slm66018 break; 39013af08d82Slm66018 default: 39023af08d82Slm66018 DMSG(vdcp, 0, "attr negotiate failed (%d)..\n", 39033af08d82Slm66018 status); 39043af08d82Slm66018 goto reset; 39053af08d82Slm66018 } 39063af08d82Slm66018 39073af08d82Slm66018 switch (status = vdc_dring_negotiation(vdcp)) { 39083af08d82Slm66018 case 0: 39093af08d82Slm66018 break; 39103af08d82Slm66018 default: 39113af08d82Slm66018 DMSG(vdcp, 0, "dring negotiate failed (%d)..\n", 39123af08d82Slm66018 status); 39133af08d82Slm66018 goto reset; 39143af08d82Slm66018 } 39153af08d82Slm66018 39163af08d82Slm66018 switch (status = vdc_rdx_exchange(vdcp)) { 39173af08d82Slm66018 case 0: 39183af08d82Slm66018 vdcp->state = VDC_STATE_HANDLE_PENDING; 39193af08d82Slm66018 goto done; 39203af08d82Slm66018 default: 39213af08d82Slm66018 DMSG(vdcp, 0, "RDX xchg failed ..(%d)\n", 39223af08d82Slm66018 status); 39233af08d82Slm66018 goto reset; 39243af08d82Slm66018 } 39253af08d82Slm66018 reset: 39263af08d82Slm66018 DMSG(vdcp, 0, "negotiation failed: resetting (%d)\n", 39273af08d82Slm66018 status); 39283af08d82Slm66018 vdcp->state = VDC_STATE_RESETTING; 3929655fd6a9Sachartre vdcp->self_reset = B_TRUE; 39303af08d82Slm66018 done: 39313af08d82Slm66018 DMSG(vdcp, 0, "negotiation complete (state=0x%x)...\n", 39323af08d82Slm66018 vdcp->state); 39333af08d82Slm66018 break; 39343af08d82Slm66018 39353af08d82Slm66018 case VDC_STATE_HANDLE_PENDING: 39363af08d82Slm66018 3937655fd6a9Sachartre if (vdcp->ctimeout_reached) { 3938655fd6a9Sachartre /* 3939655fd6a9Sachartre * The connection timeout had been reached so 3940655fd6a9Sachartre * pending requests have been cancelled. Now 3941655fd6a9Sachartre * that the connection is back we can reset 3942655fd6a9Sachartre * the timeout. 3943655fd6a9Sachartre */ 3944655fd6a9Sachartre ASSERT(vdcp->local_dring_backup == NULL); 3945655fd6a9Sachartre ASSERT(tmid != 0); 3946655fd6a9Sachartre tmid = 0; 3947655fd6a9Sachartre vdcp->ctimeout_reached = B_FALSE; 3948655fd6a9Sachartre vdcp->state = VDC_STATE_RUNNING; 3949655fd6a9Sachartre DMSG(vdcp, 0, "[%d] connection to service " 3950655fd6a9Sachartre "domain is up", vdcp->instance); 3951655fd6a9Sachartre break; 3952655fd6a9Sachartre } 3953655fd6a9Sachartre 39543af08d82Slm66018 mutex_exit(&vdcp->lock); 3955655fd6a9Sachartre if (tmid != 0) { 3956655fd6a9Sachartre (void) untimeout(tmid); 3957655fd6a9Sachartre tmid = 0; 3958655fd6a9Sachartre } 39593af08d82Slm66018 status = vdc_resubmit_backup_dring(vdcp); 39603af08d82Slm66018 mutex_enter(&vdcp->lock); 39613af08d82Slm66018 39623af08d82Slm66018 if (status) 39633af08d82Slm66018 vdcp->state = VDC_STATE_RESETTING; 39643af08d82Slm66018 else 39653af08d82Slm66018 vdcp->state = VDC_STATE_RUNNING; 39663af08d82Slm66018 39673af08d82Slm66018 break; 39683af08d82Slm66018 39693af08d82Slm66018 /* enter running state */ 39703af08d82Slm66018 case VDC_STATE_RUNNING: 39713af08d82Slm66018 /* 39723af08d82Slm66018 * Signal anyone waiting for the connection 39733af08d82Slm66018 * to come on line. 39743af08d82Slm66018 */ 39753af08d82Slm66018 vdcp->hshake_cnt = 0; 39763af08d82Slm66018 cv_broadcast(&vdcp->running_cv); 39772f5224aeSachartre 39782f5224aeSachartre /* failfast has to been checked after reset */ 39792f5224aeSachartre cv_signal(&vdcp->failfast_cv); 39802f5224aeSachartre 39812f5224aeSachartre /* ownership is lost during reset */ 39822f5224aeSachartre if (vdcp->ownership & VDC_OWNERSHIP_WANTED) 39832f5224aeSachartre vdcp->ownership |= VDC_OWNERSHIP_RESET; 39842f5224aeSachartre cv_signal(&vdcp->ownership_cv); 39852f5224aeSachartre 39863af08d82Slm66018 mutex_exit(&vdcp->lock); 39873af08d82Slm66018 39883af08d82Slm66018 for (;;) { 39893af08d82Slm66018 vio_msg_t msg; 39903af08d82Slm66018 status = vdc_wait_for_response(vdcp, &msg); 39913af08d82Slm66018 if (status) break; 39923af08d82Slm66018 39933af08d82Slm66018 DMSG(vdcp, 1, "[%d] new pkt(s) available\n", 39943af08d82Slm66018 vdcp->instance); 39953af08d82Slm66018 status = vdc_process_data_msg(vdcp, &msg); 39961ae08745Sheppo if (status) { 39973af08d82Slm66018 DMSG(vdcp, 1, "[%d] process_data_msg " 39983af08d82Slm66018 "returned err=%d\n", vdcp->instance, 39993af08d82Slm66018 status); 40001ae08745Sheppo break; 40011ae08745Sheppo } 40021ae08745Sheppo 40033af08d82Slm66018 } 4004e1ebb9ecSlm66018 40053af08d82Slm66018 mutex_enter(&vdcp->lock); 40063af08d82Slm66018 40073af08d82Slm66018 vdcp->state = VDC_STATE_RESETTING; 4008690555a1Sachartre vdcp->self_reset = B_TRUE; 40093af08d82Slm66018 break; 40103af08d82Slm66018 40113af08d82Slm66018 case VDC_STATE_RESETTING: 4012655fd6a9Sachartre /* 4013655fd6a9Sachartre * When we reach this state, we either come from the 4014655fd6a9Sachartre * VDC_STATE_RUNNING state and we can have pending 4015655fd6a9Sachartre * request but no timeout is armed; or we come from 4016655fd6a9Sachartre * the VDC_STATE_INIT_WAITING, VDC_NEGOTIATE or 4017655fd6a9Sachartre * VDC_HANDLE_PENDING state and there is no pending 4018655fd6a9Sachartre * request or pending requests have already been copied 4019655fd6a9Sachartre * into the backup dring. So we can safely keep the 4020655fd6a9Sachartre * connection timeout armed while we are in this state. 4021655fd6a9Sachartre */ 4022655fd6a9Sachartre 40233af08d82Slm66018 DMSG(vdcp, 0, "Initiating channel reset " 40243af08d82Slm66018 "(pending = %d)\n", (int)vdcp->threads_pending); 40253af08d82Slm66018 40263af08d82Slm66018 if (vdcp->self_reset) { 40273af08d82Slm66018 DMSG(vdcp, 0, 40283af08d82Slm66018 "[%d] calling stop_ldc_connection.\n", 40293af08d82Slm66018 vdcp->instance); 40303af08d82Slm66018 status = vdc_stop_ldc_connection(vdcp); 40313af08d82Slm66018 vdcp->self_reset = B_FALSE; 40321ae08745Sheppo } 40331ae08745Sheppo 40341ae08745Sheppo /* 40353af08d82Slm66018 * Wait for all threads currently waiting 40363af08d82Slm66018 * for a free dring entry to use. 40371ae08745Sheppo */ 40383af08d82Slm66018 while (vdcp->threads_pending) { 40393af08d82Slm66018 cv_broadcast(&vdcp->membind_cv); 40403af08d82Slm66018 cv_broadcast(&vdcp->dring_free_cv); 40413af08d82Slm66018 mutex_exit(&vdcp->lock); 4042205eeb1aSlm66018 /* give the waiters enough time to wake up */ 4043205eeb1aSlm66018 delay(vdc_hz_min_ldc_delay); 40443af08d82Slm66018 mutex_enter(&vdcp->lock); 40451ae08745Sheppo } 40461ae08745Sheppo 40473af08d82Slm66018 ASSERT(vdcp->threads_pending == 0); 40481ae08745Sheppo 40493af08d82Slm66018 /* Sanity check that no thread is receiving */ 40503af08d82Slm66018 ASSERT(vdcp->read_state != VDC_READ_WAITING); 40510a55fbb7Slm66018 40523af08d82Slm66018 vdcp->read_state = VDC_READ_IDLE; 40533af08d82Slm66018 40543af08d82Slm66018 vdc_backup_local_dring(vdcp); 40553af08d82Slm66018 40563af08d82Slm66018 /* cleanup the old d-ring */ 40573af08d82Slm66018 vdc_destroy_descriptor_ring(vdcp); 40583af08d82Slm66018 40593af08d82Slm66018 /* go and start again */ 40603af08d82Slm66018 vdcp->state = VDC_STATE_INIT; 40613af08d82Slm66018 40620a55fbb7Slm66018 break; 40630a55fbb7Slm66018 40643af08d82Slm66018 case VDC_STATE_DETACH: 40653af08d82Slm66018 DMSG(vdcp, 0, "[%d] Reset thread exit cleanup ..\n", 40663af08d82Slm66018 vdcp->instance); 40673af08d82Slm66018 4068655fd6a9Sachartre /* cancel any pending timeout */ 4069655fd6a9Sachartre mutex_exit(&vdcp->lock); 4070655fd6a9Sachartre if (tmid != 0) { 4071655fd6a9Sachartre (void) untimeout(tmid); 4072655fd6a9Sachartre tmid = 0; 4073655fd6a9Sachartre } 4074655fd6a9Sachartre mutex_enter(&vdcp->lock); 4075655fd6a9Sachartre 40763c96341aSnarayan /* 40773c96341aSnarayan * Signal anyone waiting for connection 40783c96341aSnarayan * to come online 40793c96341aSnarayan */ 40803c96341aSnarayan cv_broadcast(&vdcp->running_cv); 40813c96341aSnarayan 40823af08d82Slm66018 while (vdcp->sync_op_pending) { 40833af08d82Slm66018 cv_signal(&vdcp->sync_pending_cv); 40843af08d82Slm66018 cv_signal(&vdcp->sync_blocked_cv); 40853af08d82Slm66018 mutex_exit(&vdcp->lock); 4086205eeb1aSlm66018 /* give the waiters enough time to wake up */ 4087205eeb1aSlm66018 delay(vdc_hz_min_ldc_delay); 40883af08d82Slm66018 mutex_enter(&vdcp->lock); 40890a55fbb7Slm66018 } 40901ae08745Sheppo 40913af08d82Slm66018 mutex_exit(&vdcp->lock); 40923af08d82Slm66018 40933af08d82Slm66018 DMSG(vdcp, 0, "[%d] Msg processing thread exiting ..\n", 40943af08d82Slm66018 vdcp->instance); 40953af08d82Slm66018 thread_exit(); 40963af08d82Slm66018 break; 40973af08d82Slm66018 } 40983af08d82Slm66018 } 40990a55fbb7Slm66018 } 41000a55fbb7Slm66018 41010a55fbb7Slm66018 41020a55fbb7Slm66018 /* 41030a55fbb7Slm66018 * Function: 41040a55fbb7Slm66018 * vdc_process_data_msg() 41050a55fbb7Slm66018 * 41060a55fbb7Slm66018 * Description: 41070a55fbb7Slm66018 * This function is called by the message processing thread each time 41080a55fbb7Slm66018 * a message with a msgtype of VIO_TYPE_DATA is received. It will either 41090a55fbb7Slm66018 * be an ACK or NACK from vds[1] which vdc handles as follows. 41100a55fbb7Slm66018 * ACK - wake up the waiting thread 41110a55fbb7Slm66018 * NACK - resend any messages necessary 41120a55fbb7Slm66018 * 41130a55fbb7Slm66018 * [1] Although the message format allows it, vds should not send a 41140a55fbb7Slm66018 * VIO_SUBTYPE_INFO message to vdc asking it to read data; if for 41150a55fbb7Slm66018 * some bizarre reason it does, vdc will reset the connection. 41160a55fbb7Slm66018 * 41170a55fbb7Slm66018 * Arguments: 41180a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 41190a55fbb7Slm66018 * msg - the LDC message sent by vds 41200a55fbb7Slm66018 * 41210a55fbb7Slm66018 * Return Code: 41220a55fbb7Slm66018 * 0 - Success. 41230a55fbb7Slm66018 * > 0 - error value returned by LDC 41240a55fbb7Slm66018 */ 41250a55fbb7Slm66018 static int 41263af08d82Slm66018 vdc_process_data_msg(vdc_t *vdcp, vio_msg_t *msg) 41270a55fbb7Slm66018 { 41280a55fbb7Slm66018 int status = 0; 41293af08d82Slm66018 vio_dring_msg_t *dring_msg; 4130d10e4ef2Snarayan vdc_local_desc_t *ldep = NULL; 41313af08d82Slm66018 int start, end; 41323af08d82Slm66018 int idx; 41330a55fbb7Slm66018 41343af08d82Slm66018 dring_msg = (vio_dring_msg_t *)msg; 41350a55fbb7Slm66018 41363af08d82Slm66018 ASSERT(msg->tag.vio_msgtype == VIO_TYPE_DATA); 41373af08d82Slm66018 ASSERT(vdcp != NULL); 41383af08d82Slm66018 41393af08d82Slm66018 mutex_enter(&vdcp->lock); 41400a55fbb7Slm66018 41410a55fbb7Slm66018 /* 41420a55fbb7Slm66018 * Check to see if the message has bogus data 41430a55fbb7Slm66018 */ 4144e1ebb9ecSlm66018 idx = start = dring_msg->start_idx; 41450a55fbb7Slm66018 end = dring_msg->end_idx; 41463af08d82Slm66018 if ((start >= vdcp->dring_len) || 41473af08d82Slm66018 (end >= vdcp->dring_len) || (end < -1)) { 41483af08d82Slm66018 DMSG(vdcp, 0, "[%d] Bogus ACK data : start %d, end %d\n", 41493af08d82Slm66018 vdcp->instance, start, end); 41503af08d82Slm66018 mutex_exit(&vdcp->lock); 4151e1ebb9ecSlm66018 return (EINVAL); 41520a55fbb7Slm66018 } 41530a55fbb7Slm66018 41540a55fbb7Slm66018 /* 41550a55fbb7Slm66018 * Verify that the sequence number is what vdc expects. 41560a55fbb7Slm66018 */ 41573af08d82Slm66018 switch (vdc_verify_seq_num(vdcp, dring_msg)) { 4158e1ebb9ecSlm66018 case VDC_SEQ_NUM_TODO: 4159e1ebb9ecSlm66018 break; /* keep processing this message */ 4160e1ebb9ecSlm66018 case VDC_SEQ_NUM_SKIP: 41613af08d82Slm66018 mutex_exit(&vdcp->lock); 4162e1ebb9ecSlm66018 return (0); 4163e1ebb9ecSlm66018 case VDC_SEQ_NUM_INVALID: 41643af08d82Slm66018 mutex_exit(&vdcp->lock); 41653af08d82Slm66018 DMSG(vdcp, 0, "[%d] invalid seqno\n", vdcp->instance); 41660a55fbb7Slm66018 return (ENXIO); 41670a55fbb7Slm66018 } 41680a55fbb7Slm66018 41693af08d82Slm66018 if (msg->tag.vio_subtype == VIO_SUBTYPE_NACK) { 41703af08d82Slm66018 DMSG(vdcp, 0, "[%d] DATA NACK\n", vdcp->instance); 4171e1ebb9ecSlm66018 VDC_DUMP_DRING_MSG(dring_msg); 41723af08d82Slm66018 mutex_exit(&vdcp->lock); 4173e1ebb9ecSlm66018 return (EIO); 41740a55fbb7Slm66018 41753af08d82Slm66018 } else if (msg->tag.vio_subtype == VIO_SUBTYPE_INFO) { 41763af08d82Slm66018 mutex_exit(&vdcp->lock); 4177e1ebb9ecSlm66018 return (EPROTO); 4178e1ebb9ecSlm66018 } 4179e1ebb9ecSlm66018 41803af08d82Slm66018 DTRACE_IO2(recv, vio_dring_msg_t, dring_msg, vdc_t *, vdcp); 41813af08d82Slm66018 DMSG(vdcp, 1, ": start %d end %d\n", start, end); 41823af08d82Slm66018 ASSERT(start == end); 41833af08d82Slm66018 41843af08d82Slm66018 ldep = &vdcp->local_dring[idx]; 41853af08d82Slm66018 41863af08d82Slm66018 DMSG(vdcp, 1, ": state 0x%x - cb_type 0x%x\n", 41873af08d82Slm66018 ldep->dep->hdr.dstate, ldep->cb_type); 41883af08d82Slm66018 4189e1ebb9ecSlm66018 if (ldep->dep->hdr.dstate == VIO_DESC_DONE) { 41903af08d82Slm66018 struct buf *bufp; 4191e1ebb9ecSlm66018 41923af08d82Slm66018 switch (ldep->cb_type) { 41933af08d82Slm66018 case CB_SYNC: 41943af08d82Slm66018 ASSERT(vdcp->sync_op_pending); 4195d10e4ef2Snarayan 41963af08d82Slm66018 status = vdc_depopulate_descriptor(vdcp, idx); 41973af08d82Slm66018 vdcp->sync_op_status = status; 41983af08d82Slm66018 vdcp->sync_op_pending = B_FALSE; 41993af08d82Slm66018 cv_signal(&vdcp->sync_pending_cv); 42003af08d82Slm66018 break; 42014bac2208Snarayan 42023af08d82Slm66018 case CB_STRATEGY: 42033af08d82Slm66018 bufp = ldep->cb_arg; 42043af08d82Slm66018 ASSERT(bufp != NULL); 42053c96341aSnarayan bufp->b_resid = 42063c96341aSnarayan bufp->b_bcount - ldep->dep->payload.nbytes; 42073af08d82Slm66018 status = ldep->dep->payload.status; /* Future:ntoh */ 42083af08d82Slm66018 if (status != 0) { 42093af08d82Slm66018 DMSG(vdcp, 1, "strategy status=%d\n", status); 42103af08d82Slm66018 bioerror(bufp, status); 4211d10e4ef2Snarayan } 42122f5224aeSachartre 42132f5224aeSachartre (void) vdc_depopulate_descriptor(vdcp, idx); 42143c96341aSnarayan 42153c96341aSnarayan DMSG(vdcp, 1, 42163c96341aSnarayan "strategy complete req=%ld bytes resp=%ld bytes\n", 42173c96341aSnarayan bufp->b_bcount, ldep->dep->payload.nbytes); 42182f5224aeSachartre 42192f5224aeSachartre if (status != 0 && vdcp->failfast_interval != 0) { 42202f5224aeSachartre /* 42212f5224aeSachartre * The I/O has failed and failfast is enabled. 42222f5224aeSachartre * We need the failfast thread to check if the 42232f5224aeSachartre * failure is due to a reservation conflict. 42242f5224aeSachartre */ 42252f5224aeSachartre (void) vdc_failfast_io_queue(vdcp, bufp); 42262f5224aeSachartre } else { 42272f5224aeSachartre biodone(bufp); 42282f5224aeSachartre } 42293af08d82Slm66018 break; 42303af08d82Slm66018 42313af08d82Slm66018 default: 42323af08d82Slm66018 ASSERT(0); 42330a55fbb7Slm66018 } 42343af08d82Slm66018 } 42353af08d82Slm66018 42363af08d82Slm66018 /* let the arrival signal propogate */ 42373af08d82Slm66018 mutex_exit(&vdcp->lock); 42380a55fbb7Slm66018 4239e1ebb9ecSlm66018 /* probe gives the count of how many entries were processed */ 42403af08d82Slm66018 DTRACE_IO2(processed, int, 1, vdc_t *, vdcp); 42410a55fbb7Slm66018 42423af08d82Slm66018 return (0); 42430a55fbb7Slm66018 } 42440a55fbb7Slm66018 42450a55fbb7Slm66018 42460a55fbb7Slm66018 /* 42470a55fbb7Slm66018 * Function: 42480a55fbb7Slm66018 * vdc_handle_ver_msg() 42490a55fbb7Slm66018 * 42500a55fbb7Slm66018 * Description: 42510a55fbb7Slm66018 * 42520a55fbb7Slm66018 * Arguments: 42530a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 42540a55fbb7Slm66018 * ver_msg - LDC message sent by vDisk server 42550a55fbb7Slm66018 * 42560a55fbb7Slm66018 * Return Code: 42570a55fbb7Slm66018 * 0 - Success 42580a55fbb7Slm66018 */ 42590a55fbb7Slm66018 static int 42600a55fbb7Slm66018 vdc_handle_ver_msg(vdc_t *vdc, vio_ver_msg_t *ver_msg) 42610a55fbb7Slm66018 { 42620a55fbb7Slm66018 int status = 0; 42630a55fbb7Slm66018 42640a55fbb7Slm66018 ASSERT(vdc != NULL); 42650a55fbb7Slm66018 ASSERT(mutex_owned(&vdc->lock)); 42660a55fbb7Slm66018 42670a55fbb7Slm66018 if (ver_msg->tag.vio_subtype_env != VIO_VER_INFO) { 42680a55fbb7Slm66018 return (EPROTO); 42690a55fbb7Slm66018 } 42700a55fbb7Slm66018 42710a55fbb7Slm66018 if (ver_msg->dev_class != VDEV_DISK_SERVER) { 42720a55fbb7Slm66018 return (EINVAL); 42730a55fbb7Slm66018 } 42740a55fbb7Slm66018 42750a55fbb7Slm66018 switch (ver_msg->tag.vio_subtype) { 42760a55fbb7Slm66018 case VIO_SUBTYPE_ACK: 42770a55fbb7Slm66018 /* 42780a55fbb7Slm66018 * We check to see if the version returned is indeed supported 42790a55fbb7Slm66018 * (The server may have also adjusted the minor number downwards 42800a55fbb7Slm66018 * and if so 'ver_msg' will contain the actual version agreed) 42810a55fbb7Slm66018 */ 42820a55fbb7Slm66018 if (vdc_is_supported_version(ver_msg)) { 42830a55fbb7Slm66018 vdc->ver.major = ver_msg->ver_major; 42840a55fbb7Slm66018 vdc->ver.minor = ver_msg->ver_minor; 42850a55fbb7Slm66018 ASSERT(vdc->ver.major > 0); 42860a55fbb7Slm66018 } else { 42870a55fbb7Slm66018 status = EPROTO; 42880a55fbb7Slm66018 } 42890a55fbb7Slm66018 break; 42900a55fbb7Slm66018 42910a55fbb7Slm66018 case VIO_SUBTYPE_NACK: 42920a55fbb7Slm66018 /* 42930a55fbb7Slm66018 * call vdc_is_supported_version() which will return the next 42940a55fbb7Slm66018 * supported version (if any) in 'ver_msg' 42950a55fbb7Slm66018 */ 42960a55fbb7Slm66018 (void) vdc_is_supported_version(ver_msg); 42970a55fbb7Slm66018 if (ver_msg->ver_major > 0) { 42980a55fbb7Slm66018 size_t len = sizeof (*ver_msg); 42990a55fbb7Slm66018 43000a55fbb7Slm66018 ASSERT(vdc->ver.major > 0); 43010a55fbb7Slm66018 43020a55fbb7Slm66018 /* reset the necessary fields and resend */ 43030a55fbb7Slm66018 ver_msg->tag.vio_subtype = VIO_SUBTYPE_INFO; 43040a55fbb7Slm66018 ver_msg->dev_class = VDEV_DISK; 43050a55fbb7Slm66018 43060a55fbb7Slm66018 status = vdc_send(vdc, (caddr_t)ver_msg, &len); 43073af08d82Slm66018 DMSG(vdc, 0, "[%d] Resend VER info (LDC status = %d)\n", 43080a55fbb7Slm66018 vdc->instance, status); 43090a55fbb7Slm66018 if (len != sizeof (*ver_msg)) 43100a55fbb7Slm66018 status = EBADMSG; 43110a55fbb7Slm66018 } else { 431287a7269eSachartre DMSG(vdc, 0, "[%d] No common version with vDisk server", 431387a7269eSachartre vdc->instance); 43140a55fbb7Slm66018 status = ENOTSUP; 43150a55fbb7Slm66018 } 43160a55fbb7Slm66018 43170a55fbb7Slm66018 break; 43181ae08745Sheppo case VIO_SUBTYPE_INFO: 43191ae08745Sheppo /* 43201ae08745Sheppo * Handle the case where vds starts handshake 4321eff7243fSlm66018 * (for now only vdc is the instigator) 43221ae08745Sheppo */ 43231ae08745Sheppo status = ENOTSUP; 43241ae08745Sheppo break; 43251ae08745Sheppo 43261ae08745Sheppo default: 43270a55fbb7Slm66018 status = EINVAL; 43281ae08745Sheppo break; 43291ae08745Sheppo } 43301ae08745Sheppo 43310a55fbb7Slm66018 return (status); 43320a55fbb7Slm66018 } 43330a55fbb7Slm66018 43340a55fbb7Slm66018 /* 43350a55fbb7Slm66018 * Function: 43360a55fbb7Slm66018 * vdc_handle_attr_msg() 43370a55fbb7Slm66018 * 43380a55fbb7Slm66018 * Description: 43390a55fbb7Slm66018 * 43400a55fbb7Slm66018 * Arguments: 43410a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 43420a55fbb7Slm66018 * attr_msg - LDC message sent by vDisk server 43430a55fbb7Slm66018 * 43440a55fbb7Slm66018 * Return Code: 43450a55fbb7Slm66018 * 0 - Success 43460a55fbb7Slm66018 */ 43470a55fbb7Slm66018 static int 43480a55fbb7Slm66018 vdc_handle_attr_msg(vdc_t *vdc, vd_attr_msg_t *attr_msg) 43490a55fbb7Slm66018 { 43500a55fbb7Slm66018 int status = 0; 43510a55fbb7Slm66018 43520a55fbb7Slm66018 ASSERT(vdc != NULL); 43530a55fbb7Slm66018 ASSERT(mutex_owned(&vdc->lock)); 43540a55fbb7Slm66018 43550a55fbb7Slm66018 if (attr_msg->tag.vio_subtype_env != VIO_ATTR_INFO) { 43560a55fbb7Slm66018 return (EPROTO); 43570a55fbb7Slm66018 } 43580a55fbb7Slm66018 43590a55fbb7Slm66018 switch (attr_msg->tag.vio_subtype) { 43601ae08745Sheppo case VIO_SUBTYPE_ACK: 43611ae08745Sheppo /* 43621ae08745Sheppo * We now verify the attributes sent by vds. 43631ae08745Sheppo */ 436478fcd0a1Sachartre if (attr_msg->vdisk_size == 0) { 436578fcd0a1Sachartre DMSG(vdc, 0, "[%d] Invalid disk size from vds", 436678fcd0a1Sachartre vdc->instance); 436778fcd0a1Sachartre status = EINVAL; 436878fcd0a1Sachartre break; 436978fcd0a1Sachartre } 437078fcd0a1Sachartre 437178fcd0a1Sachartre if (attr_msg->max_xfer_sz == 0) { 437278fcd0a1Sachartre DMSG(vdc, 0, "[%d] Invalid transfer size from vds", 437378fcd0a1Sachartre vdc->instance); 437478fcd0a1Sachartre status = EINVAL; 437578fcd0a1Sachartre break; 437678fcd0a1Sachartre } 437778fcd0a1Sachartre 43782f5224aeSachartre if (attr_msg->vdisk_size == VD_SIZE_UNKNOWN) { 43792f5224aeSachartre DMSG(vdc, 0, "[%d] Unknown disk size from vds", 43802f5224aeSachartre vdc->instance); 43812f5224aeSachartre attr_msg->vdisk_size = 0; 43822f5224aeSachartre } 43832f5224aeSachartre 438478fcd0a1Sachartre /* 438578fcd0a1Sachartre * If the disk size is already set check that it hasn't changed. 438678fcd0a1Sachartre */ 43872f5224aeSachartre if ((vdc->vdisk_size != 0) && (attr_msg->vdisk_size != 0) && 438878fcd0a1Sachartre (vdc->vdisk_size != attr_msg->vdisk_size)) { 438978fcd0a1Sachartre DMSG(vdc, 0, "[%d] Different disk size from vds " 439078fcd0a1Sachartre "(old=0x%lx - new=0x%lx", vdc->instance, 439178fcd0a1Sachartre vdc->vdisk_size, attr_msg->vdisk_size) 439278fcd0a1Sachartre status = EINVAL; 439378fcd0a1Sachartre break; 439478fcd0a1Sachartre } 439578fcd0a1Sachartre 43961ae08745Sheppo vdc->vdisk_size = attr_msg->vdisk_size; 43971ae08745Sheppo vdc->vdisk_type = attr_msg->vdisk_type; 439817cadca8Slm66018 vdc->operations = attr_msg->operations; 439917cadca8Slm66018 if (vio_ver_is_supported(vdc->ver, 1, 1)) 440017cadca8Slm66018 vdc->vdisk_media = attr_msg->vdisk_media; 440117cadca8Slm66018 else 440217cadca8Slm66018 vdc->vdisk_media = 0; 44031ae08745Sheppo 44043af08d82Slm66018 DMSG(vdc, 0, "[%d] max_xfer_sz: sent %lx acked %lx\n", 4405e1ebb9ecSlm66018 vdc->instance, vdc->max_xfer_sz, attr_msg->max_xfer_sz); 44063af08d82Slm66018 DMSG(vdc, 0, "[%d] vdisk_block_size: sent %lx acked %x\n", 4407e1ebb9ecSlm66018 vdc->instance, vdc->block_size, 4408e1ebb9ecSlm66018 attr_msg->vdisk_block_size); 4409e1ebb9ecSlm66018 44101ae08745Sheppo /* 4411e1ebb9ecSlm66018 * We don't know at compile time what the vDisk server will 441217cadca8Slm66018 * think are good values but we apply a large (arbitrary) 4413e1ebb9ecSlm66018 * upper bound to prevent memory exhaustion in vdc if it was 4414e1ebb9ecSlm66018 * allocating a DRing based of huge values sent by the server. 4415e1ebb9ecSlm66018 * We probably will never exceed this except if the message 4416e1ebb9ecSlm66018 * was garbage. 44171ae08745Sheppo */ 4418e1ebb9ecSlm66018 if ((attr_msg->max_xfer_sz * attr_msg->vdisk_block_size) <= 4419e1ebb9ecSlm66018 (PAGESIZE * DEV_BSIZE)) { 4420e1ebb9ecSlm66018 vdc->max_xfer_sz = attr_msg->max_xfer_sz; 4421e1ebb9ecSlm66018 vdc->block_size = attr_msg->vdisk_block_size; 4422e1ebb9ecSlm66018 } else { 44233af08d82Slm66018 DMSG(vdc, 0, "[%d] vds block transfer size too big;" 4424e1ebb9ecSlm66018 " using max supported by vdc", vdc->instance); 44251ae08745Sheppo } 44261ae08745Sheppo 4427*f0ca1d9aSsb155480 if ((attr_msg->xfer_mode != VIO_DRING_MODE_V1_0) || 44281ae08745Sheppo (attr_msg->vdisk_size > INT64_MAX) || 442917cadca8Slm66018 (attr_msg->operations == 0) || 44301ae08745Sheppo (attr_msg->vdisk_type > VD_DISK_TYPE_DISK)) { 44313af08d82Slm66018 DMSG(vdc, 0, "[%d] Invalid attributes from vds", 4432e1ebb9ecSlm66018 vdc->instance); 44331ae08745Sheppo status = EINVAL; 44341ae08745Sheppo break; 44351ae08745Sheppo } 44361ae08745Sheppo 443778fcd0a1Sachartre /* 443878fcd0a1Sachartre * Now that we have received all attributes we can create a 443978fcd0a1Sachartre * fake geometry for the disk. 444078fcd0a1Sachartre */ 444178fcd0a1Sachartre vdc_create_fake_geometry(vdc); 44421ae08745Sheppo break; 44431ae08745Sheppo 44441ae08745Sheppo case VIO_SUBTYPE_NACK: 44451ae08745Sheppo /* 44461ae08745Sheppo * vds could not handle the attributes we sent so we 44471ae08745Sheppo * stop negotiating. 44481ae08745Sheppo */ 44491ae08745Sheppo status = EPROTO; 44501ae08745Sheppo break; 44511ae08745Sheppo 44521ae08745Sheppo case VIO_SUBTYPE_INFO: 44531ae08745Sheppo /* 44541ae08745Sheppo * Handle the case where vds starts the handshake 44551ae08745Sheppo * (for now; vdc is the only supported instigatior) 44561ae08745Sheppo */ 44571ae08745Sheppo status = ENOTSUP; 44581ae08745Sheppo break; 44591ae08745Sheppo 44601ae08745Sheppo default: 44611ae08745Sheppo status = ENOTSUP; 44621ae08745Sheppo break; 44631ae08745Sheppo } 44641ae08745Sheppo 44650a55fbb7Slm66018 return (status); 44661ae08745Sheppo } 44671ae08745Sheppo 44680a55fbb7Slm66018 /* 44690a55fbb7Slm66018 * Function: 44700a55fbb7Slm66018 * vdc_handle_dring_reg_msg() 44710a55fbb7Slm66018 * 44720a55fbb7Slm66018 * Description: 44730a55fbb7Slm66018 * 44740a55fbb7Slm66018 * Arguments: 44750a55fbb7Slm66018 * vdc - soft state pointer for this instance of the driver. 44760a55fbb7Slm66018 * dring_msg - LDC message sent by vDisk server 44770a55fbb7Slm66018 * 44780a55fbb7Slm66018 * Return Code: 44790a55fbb7Slm66018 * 0 - Success 44800a55fbb7Slm66018 */ 44810a55fbb7Slm66018 static int 44820a55fbb7Slm66018 vdc_handle_dring_reg_msg(vdc_t *vdc, vio_dring_reg_msg_t *dring_msg) 44830a55fbb7Slm66018 { 44840a55fbb7Slm66018 int status = 0; 44851ae08745Sheppo 44860a55fbb7Slm66018 ASSERT(vdc != NULL); 44870a55fbb7Slm66018 ASSERT(mutex_owned(&vdc->lock)); 44880a55fbb7Slm66018 44890a55fbb7Slm66018 if (dring_msg->tag.vio_subtype_env != VIO_DRING_REG) { 44900a55fbb7Slm66018 return (EPROTO); 44910a55fbb7Slm66018 } 44920a55fbb7Slm66018 44930a55fbb7Slm66018 switch (dring_msg->tag.vio_subtype) { 44940a55fbb7Slm66018 case VIO_SUBTYPE_ACK: 44951ae08745Sheppo /* save the received dring_ident */ 44961ae08745Sheppo vdc->dring_ident = dring_msg->dring_ident; 44973af08d82Slm66018 DMSG(vdc, 0, "[%d] Received dring ident=0x%lx\n", 4498e1ebb9ecSlm66018 vdc->instance, vdc->dring_ident); 44991ae08745Sheppo break; 45001ae08745Sheppo 45011ae08745Sheppo case VIO_SUBTYPE_NACK: 45021ae08745Sheppo /* 45031ae08745Sheppo * vds could not handle the DRing info we sent so we 45041ae08745Sheppo * stop negotiating. 45051ae08745Sheppo */ 45063af08d82Slm66018 DMSG(vdc, 0, "[%d] server could not register DRing\n", 45073af08d82Slm66018 vdc->instance); 45081ae08745Sheppo status = EPROTO; 45091ae08745Sheppo break; 45101ae08745Sheppo 45111ae08745Sheppo case VIO_SUBTYPE_INFO: 45121ae08745Sheppo /* 45131ae08745Sheppo * Handle the case where vds starts handshake 45141ae08745Sheppo * (for now only vdc is the instigatior) 45151ae08745Sheppo */ 45161ae08745Sheppo status = ENOTSUP; 45171ae08745Sheppo break; 45181ae08745Sheppo default: 45191ae08745Sheppo status = ENOTSUP; 45201ae08745Sheppo } 45211ae08745Sheppo 45221ae08745Sheppo return (status); 45231ae08745Sheppo } 45241ae08745Sheppo 45251ae08745Sheppo /* 45261ae08745Sheppo * Function: 45271ae08745Sheppo * vdc_verify_seq_num() 45281ae08745Sheppo * 45291ae08745Sheppo * Description: 4530e1ebb9ecSlm66018 * This functions verifies that the sequence number sent back by the vDisk 4531e1ebb9ecSlm66018 * server with the latest message is what is expected (i.e. it is greater 4532e1ebb9ecSlm66018 * than the last seq num sent by the vDisk server and less than or equal 4533e1ebb9ecSlm66018 * to the last seq num generated by vdc). 4534e1ebb9ecSlm66018 * 4535e1ebb9ecSlm66018 * It then checks the request ID to see if any requests need processing 4536e1ebb9ecSlm66018 * in the DRing. 45371ae08745Sheppo * 45381ae08745Sheppo * Arguments: 45391ae08745Sheppo * vdc - soft state pointer for this instance of the driver. 45401ae08745Sheppo * dring_msg - pointer to the LDC message sent by vds 45411ae08745Sheppo * 45421ae08745Sheppo * Return Code: 4543e1ebb9ecSlm66018 * VDC_SEQ_NUM_TODO - Message needs to be processed 4544e1ebb9ecSlm66018 * VDC_SEQ_NUM_SKIP - Message has already been processed 4545e1ebb9ecSlm66018 * VDC_SEQ_NUM_INVALID - The seq numbers are so out of sync, 4546e1ebb9ecSlm66018 * vdc cannot deal with them 45471ae08745Sheppo */ 4548e1ebb9ecSlm66018 static int 4549e1ebb9ecSlm66018 vdc_verify_seq_num(vdc_t *vdc, vio_dring_msg_t *dring_msg) 45501ae08745Sheppo { 45511ae08745Sheppo ASSERT(vdc != NULL); 45521ae08745Sheppo ASSERT(dring_msg != NULL); 4553d10e4ef2Snarayan ASSERT(mutex_owned(&vdc->lock)); 45541ae08745Sheppo 45551ae08745Sheppo /* 45561ae08745Sheppo * Check to see if the messages were responded to in the correct 4557e1ebb9ecSlm66018 * order by vds. 45581ae08745Sheppo */ 4559e1ebb9ecSlm66018 if ((dring_msg->seq_num <= vdc->seq_num_reply) || 4560e1ebb9ecSlm66018 (dring_msg->seq_num > vdc->seq_num)) { 45613af08d82Slm66018 DMSG(vdc, 0, "?[%d] Bogus sequence_number %lu: " 4562e1ebb9ecSlm66018 "%lu > expected <= %lu (last proc req %lu sent %lu)\n", 4563e1ebb9ecSlm66018 vdc->instance, dring_msg->seq_num, 4564e1ebb9ecSlm66018 vdc->seq_num_reply, vdc->seq_num, 4565e1ebb9ecSlm66018 vdc->req_id_proc, vdc->req_id); 4566e1ebb9ecSlm66018 return (VDC_SEQ_NUM_INVALID); 45671ae08745Sheppo } 4568e1ebb9ecSlm66018 vdc->seq_num_reply = dring_msg->seq_num; 45691ae08745Sheppo 4570e1ebb9ecSlm66018 if (vdc->req_id_proc < vdc->req_id) 4571e1ebb9ecSlm66018 return (VDC_SEQ_NUM_TODO); 4572e1ebb9ecSlm66018 else 4573e1ebb9ecSlm66018 return (VDC_SEQ_NUM_SKIP); 45741ae08745Sheppo } 45751ae08745Sheppo 45760a55fbb7Slm66018 45770a55fbb7Slm66018 /* 45780a55fbb7Slm66018 * Function: 45790a55fbb7Slm66018 * vdc_is_supported_version() 45800a55fbb7Slm66018 * 45810a55fbb7Slm66018 * Description: 45820a55fbb7Slm66018 * This routine checks if the major/minor version numbers specified in 45830a55fbb7Slm66018 * 'ver_msg' are supported. If not it finds the next version that is 45840a55fbb7Slm66018 * in the supported version list 'vdc_version[]' and sets the fields in 45850a55fbb7Slm66018 * 'ver_msg' to those values 45860a55fbb7Slm66018 * 45870a55fbb7Slm66018 * Arguments: 45880a55fbb7Slm66018 * ver_msg - LDC message sent by vDisk server 45890a55fbb7Slm66018 * 45900a55fbb7Slm66018 * Return Code: 45910a55fbb7Slm66018 * B_TRUE - Success 45920a55fbb7Slm66018 * B_FALSE - Version not supported 45930a55fbb7Slm66018 */ 45940a55fbb7Slm66018 static boolean_t 45950a55fbb7Slm66018 vdc_is_supported_version(vio_ver_msg_t *ver_msg) 45960a55fbb7Slm66018 { 45970a55fbb7Slm66018 int vdc_num_versions = sizeof (vdc_version) / sizeof (vdc_version[0]); 45980a55fbb7Slm66018 45990a55fbb7Slm66018 for (int i = 0; i < vdc_num_versions; i++) { 46000a55fbb7Slm66018 ASSERT(vdc_version[i].major > 0); 46010a55fbb7Slm66018 ASSERT((i == 0) || 46020a55fbb7Slm66018 (vdc_version[i].major < vdc_version[i-1].major)); 46030a55fbb7Slm66018 46040a55fbb7Slm66018 /* 46050a55fbb7Slm66018 * If the major versions match, adjust the minor version, if 46060a55fbb7Slm66018 * necessary, down to the highest value supported by this 46070a55fbb7Slm66018 * client. The server should support all minor versions lower 46080a55fbb7Slm66018 * than the value it sent 46090a55fbb7Slm66018 */ 46100a55fbb7Slm66018 if (ver_msg->ver_major == vdc_version[i].major) { 46110a55fbb7Slm66018 if (ver_msg->ver_minor > vdc_version[i].minor) { 46123af08d82Slm66018 DMSGX(0, 46133af08d82Slm66018 "Adjusting minor version from %u to %u", 46140a55fbb7Slm66018 ver_msg->ver_minor, vdc_version[i].minor); 46150a55fbb7Slm66018 ver_msg->ver_minor = vdc_version[i].minor; 46160a55fbb7Slm66018 } 46170a55fbb7Slm66018 return (B_TRUE); 46180a55fbb7Slm66018 } 46190a55fbb7Slm66018 46200a55fbb7Slm66018 /* 46210a55fbb7Slm66018 * If the message contains a higher major version number, set 46220a55fbb7Slm66018 * the message's major/minor versions to the current values 46230a55fbb7Slm66018 * and return false, so this message will get resent with 46240a55fbb7Slm66018 * these values, and the server will potentially try again 46250a55fbb7Slm66018 * with the same or a lower version 46260a55fbb7Slm66018 */ 46270a55fbb7Slm66018 if (ver_msg->ver_major > vdc_version[i].major) { 46280a55fbb7Slm66018 ver_msg->ver_major = vdc_version[i].major; 46290a55fbb7Slm66018 ver_msg->ver_minor = vdc_version[i].minor; 46303af08d82Slm66018 DMSGX(0, "Suggesting major/minor (0x%x/0x%x)\n", 46310a55fbb7Slm66018 ver_msg->ver_major, ver_msg->ver_minor); 46320a55fbb7Slm66018 46330a55fbb7Slm66018 return (B_FALSE); 46340a55fbb7Slm66018 } 46350a55fbb7Slm66018 46360a55fbb7Slm66018 /* 46370a55fbb7Slm66018 * Otherwise, the message's major version is less than the 46380a55fbb7Slm66018 * current major version, so continue the loop to the next 46390a55fbb7Slm66018 * (lower) supported version 46400a55fbb7Slm66018 */ 46410a55fbb7Slm66018 } 46420a55fbb7Slm66018 46430a55fbb7Slm66018 /* 46440a55fbb7Slm66018 * No common version was found; "ground" the version pair in the 46450a55fbb7Slm66018 * message to terminate negotiation 46460a55fbb7Slm66018 */ 46470a55fbb7Slm66018 ver_msg->ver_major = 0; 46480a55fbb7Slm66018 ver_msg->ver_minor = 0; 46490a55fbb7Slm66018 46500a55fbb7Slm66018 return (B_FALSE); 46510a55fbb7Slm66018 } 46521ae08745Sheppo /* -------------------------------------------------------------------------- */ 46531ae08745Sheppo 46541ae08745Sheppo /* 46551ae08745Sheppo * DKIO(7) support 46561ae08745Sheppo */ 46571ae08745Sheppo 46581ae08745Sheppo typedef struct vdc_dk_arg { 46591ae08745Sheppo struct dk_callback dkc; 46601ae08745Sheppo int mode; 46611ae08745Sheppo dev_t dev; 46621ae08745Sheppo vdc_t *vdc; 46631ae08745Sheppo } vdc_dk_arg_t; 46641ae08745Sheppo 46651ae08745Sheppo /* 46661ae08745Sheppo * Function: 46671ae08745Sheppo * vdc_dkio_flush_cb() 46681ae08745Sheppo * 46691ae08745Sheppo * Description: 46701ae08745Sheppo * This routine is a callback for DKIOCFLUSHWRITECACHE which can be called 46711ae08745Sheppo * by kernel code. 46721ae08745Sheppo * 46731ae08745Sheppo * Arguments: 46741ae08745Sheppo * arg - a pointer to a vdc_dk_arg_t structure. 46751ae08745Sheppo */ 46761ae08745Sheppo void 46771ae08745Sheppo vdc_dkio_flush_cb(void *arg) 46781ae08745Sheppo { 46791ae08745Sheppo struct vdc_dk_arg *dk_arg = (struct vdc_dk_arg *)arg; 46801ae08745Sheppo struct dk_callback *dkc = NULL; 46811ae08745Sheppo vdc_t *vdc = NULL; 46821ae08745Sheppo int rv; 46831ae08745Sheppo 46841ae08745Sheppo if (dk_arg == NULL) { 46853af08d82Slm66018 cmn_err(CE_NOTE, "?[Unk] DKIOCFLUSHWRITECACHE arg is NULL\n"); 46861ae08745Sheppo return; 46871ae08745Sheppo } 46881ae08745Sheppo dkc = &dk_arg->dkc; 46891ae08745Sheppo vdc = dk_arg->vdc; 46901ae08745Sheppo ASSERT(vdc != NULL); 46911ae08745Sheppo 46923af08d82Slm66018 rv = vdc_do_sync_op(vdc, VD_OP_FLUSH, NULL, 0, 46932f5224aeSachartre VDCPART(dk_arg->dev), 0, CB_SYNC, 0, VIO_both_dir, B_TRUE); 46941ae08745Sheppo if (rv != 0) { 46953af08d82Slm66018 DMSG(vdc, 0, "[%d] DKIOCFLUSHWRITECACHE failed %d : model %x\n", 4696e1ebb9ecSlm66018 vdc->instance, rv, 46971ae08745Sheppo ddi_model_convert_from(dk_arg->mode & FMODELS)); 46981ae08745Sheppo } 46991ae08745Sheppo 47001ae08745Sheppo /* 47011ae08745Sheppo * Trigger the call back to notify the caller the the ioctl call has 47021ae08745Sheppo * been completed. 47031ae08745Sheppo */ 47041ae08745Sheppo if ((dk_arg->mode & FKIOCTL) && 47051ae08745Sheppo (dkc != NULL) && 47061ae08745Sheppo (dkc->dkc_callback != NULL)) { 47071ae08745Sheppo ASSERT(dkc->dkc_cookie != NULL); 47088e6a2a04Slm66018 (*dkc->dkc_callback)(dkc->dkc_cookie, rv); 47091ae08745Sheppo } 47101ae08745Sheppo 47111ae08745Sheppo /* Indicate that one less DKIO write flush is outstanding */ 47121ae08745Sheppo mutex_enter(&vdc->lock); 47131ae08745Sheppo vdc->dkio_flush_pending--; 47141ae08745Sheppo ASSERT(vdc->dkio_flush_pending >= 0); 47151ae08745Sheppo mutex_exit(&vdc->lock); 47168e6a2a04Slm66018 47178e6a2a04Slm66018 /* free the mem that was allocated when the callback was dispatched */ 47188e6a2a04Slm66018 kmem_free(arg, sizeof (vdc_dk_arg_t)); 47191ae08745Sheppo } 47201ae08745Sheppo 47211ae08745Sheppo /* 472287a7269eSachartre * Function: 472387a7269eSachartre * vdc_dkio_get_partition() 472487a7269eSachartre * 472587a7269eSachartre * Description: 472687a7269eSachartre * This function implements the DKIOCGAPART ioctl. 472787a7269eSachartre * 472887a7269eSachartre * Arguments: 472978fcd0a1Sachartre * vdc - soft state pointer 473087a7269eSachartre * arg - a pointer to a dk_map[NDKMAP] or dk_map32[NDKMAP] structure 473187a7269eSachartre * flag - ioctl flags 473287a7269eSachartre */ 473387a7269eSachartre static int 473478fcd0a1Sachartre vdc_dkio_get_partition(vdc_t *vdc, caddr_t arg, int flag) 473587a7269eSachartre { 473678fcd0a1Sachartre struct dk_geom *geom; 473778fcd0a1Sachartre struct vtoc *vtoc; 473887a7269eSachartre union { 473987a7269eSachartre struct dk_map map[NDKMAP]; 474087a7269eSachartre struct dk_map32 map32[NDKMAP]; 474187a7269eSachartre } data; 474287a7269eSachartre int i, rv, size; 474387a7269eSachartre 474478fcd0a1Sachartre mutex_enter(&vdc->lock); 474587a7269eSachartre 474678fcd0a1Sachartre if ((rv = vdc_validate_geometry(vdc)) != 0) { 474778fcd0a1Sachartre mutex_exit(&vdc->lock); 474887a7269eSachartre return (rv); 474978fcd0a1Sachartre } 475087a7269eSachartre 475178fcd0a1Sachartre vtoc = vdc->vtoc; 475278fcd0a1Sachartre geom = vdc->geom; 475387a7269eSachartre 475487a7269eSachartre if (ddi_model_convert_from(flag & FMODELS) == DDI_MODEL_ILP32) { 475587a7269eSachartre 475678fcd0a1Sachartre for (i = 0; i < vtoc->v_nparts; i++) { 475778fcd0a1Sachartre data.map32[i].dkl_cylno = vtoc->v_part[i].p_start / 475878fcd0a1Sachartre (geom->dkg_nhead * geom->dkg_nsect); 475978fcd0a1Sachartre data.map32[i].dkl_nblk = vtoc->v_part[i].p_size; 476087a7269eSachartre } 476187a7269eSachartre size = NDKMAP * sizeof (struct dk_map32); 476287a7269eSachartre 476387a7269eSachartre } else { 476487a7269eSachartre 476578fcd0a1Sachartre for (i = 0; i < vtoc->v_nparts; i++) { 476678fcd0a1Sachartre data.map[i].dkl_cylno = vtoc->v_part[i].p_start / 476778fcd0a1Sachartre (geom->dkg_nhead * geom->dkg_nsect); 476878fcd0a1Sachartre data.map[i].dkl_nblk = vtoc->v_part[i].p_size; 476987a7269eSachartre } 477087a7269eSachartre size = NDKMAP * sizeof (struct dk_map); 477187a7269eSachartre 477287a7269eSachartre } 477387a7269eSachartre 477478fcd0a1Sachartre mutex_exit(&vdc->lock); 477578fcd0a1Sachartre 477687a7269eSachartre if (ddi_copyout(&data, arg, size, flag) != 0) 477787a7269eSachartre return (EFAULT); 477887a7269eSachartre 477987a7269eSachartre return (0); 478087a7269eSachartre } 478187a7269eSachartre 478287a7269eSachartre /* 478387a7269eSachartre * Function: 478487a7269eSachartre * vdc_dioctl_rwcmd() 478587a7269eSachartre * 478687a7269eSachartre * Description: 478787a7269eSachartre * This function implements the DIOCTL_RWCMD ioctl. This ioctl is used 478887a7269eSachartre * for DKC_DIRECT disks to read or write at an absolute disk offset. 478987a7269eSachartre * 479087a7269eSachartre * Arguments: 479187a7269eSachartre * dev - device 479287a7269eSachartre * arg - a pointer to a dadkio_rwcmd or dadkio_rwcmd32 structure 479387a7269eSachartre * flag - ioctl flags 479487a7269eSachartre */ 479587a7269eSachartre static int 479687a7269eSachartre vdc_dioctl_rwcmd(dev_t dev, caddr_t arg, int flag) 479787a7269eSachartre { 479887a7269eSachartre struct dadkio_rwcmd32 rwcmd32; 479987a7269eSachartre struct dadkio_rwcmd rwcmd; 480087a7269eSachartre struct iovec aiov; 480187a7269eSachartre struct uio auio; 480287a7269eSachartre int rw, status; 480387a7269eSachartre struct buf *buf; 480487a7269eSachartre 480587a7269eSachartre if (ddi_model_convert_from(flag & FMODELS) == DDI_MODEL_ILP32) { 480687a7269eSachartre if (ddi_copyin((caddr_t)arg, (caddr_t)&rwcmd32, 480787a7269eSachartre sizeof (struct dadkio_rwcmd32), flag)) { 480887a7269eSachartre return (EFAULT); 480987a7269eSachartre } 481087a7269eSachartre rwcmd.cmd = rwcmd32.cmd; 481187a7269eSachartre rwcmd.flags = rwcmd32.flags; 481287a7269eSachartre rwcmd.blkaddr = (daddr_t)rwcmd32.blkaddr; 481387a7269eSachartre rwcmd.buflen = rwcmd32.buflen; 481487a7269eSachartre rwcmd.bufaddr = (caddr_t)(uintptr_t)rwcmd32.bufaddr; 481587a7269eSachartre } else { 481687a7269eSachartre if (ddi_copyin((caddr_t)arg, (caddr_t)&rwcmd, 481787a7269eSachartre sizeof (struct dadkio_rwcmd), flag)) { 481887a7269eSachartre return (EFAULT); 481987a7269eSachartre } 482087a7269eSachartre } 482187a7269eSachartre 482287a7269eSachartre switch (rwcmd.cmd) { 482387a7269eSachartre case DADKIO_RWCMD_READ: 482487a7269eSachartre rw = B_READ; 482587a7269eSachartre break; 482687a7269eSachartre case DADKIO_RWCMD_WRITE: 482787a7269eSachartre rw = B_WRITE; 482887a7269eSachartre break; 482987a7269eSachartre default: 483087a7269eSachartre return (EINVAL); 483187a7269eSachartre } 483287a7269eSachartre 483387a7269eSachartre bzero((caddr_t)&aiov, sizeof (struct iovec)); 483487a7269eSachartre aiov.iov_base = rwcmd.bufaddr; 483587a7269eSachartre aiov.iov_len = rwcmd.buflen; 483687a7269eSachartre 483787a7269eSachartre bzero((caddr_t)&auio, sizeof (struct uio)); 483887a7269eSachartre auio.uio_iov = &aiov; 483987a7269eSachartre auio.uio_iovcnt = 1; 484087a7269eSachartre auio.uio_loffset = rwcmd.blkaddr * DEV_BSIZE; 484187a7269eSachartre auio.uio_resid = rwcmd.buflen; 484287a7269eSachartre auio.uio_segflg = flag & FKIOCTL ? UIO_SYSSPACE : UIO_USERSPACE; 484387a7269eSachartre 484487a7269eSachartre buf = kmem_alloc(sizeof (buf_t), KM_SLEEP); 484587a7269eSachartre bioinit(buf); 484687a7269eSachartre /* 484787a7269eSachartre * We use the private field of buf to specify that this is an 484887a7269eSachartre * I/O using an absolute offset. 484987a7269eSachartre */ 485087a7269eSachartre buf->b_private = (void *)VD_SLICE_NONE; 485187a7269eSachartre 485287a7269eSachartre status = physio(vdc_strategy, buf, dev, rw, vdc_min, &auio); 485387a7269eSachartre 485487a7269eSachartre biofini(buf); 485587a7269eSachartre kmem_free(buf, sizeof (buf_t)); 485687a7269eSachartre 485787a7269eSachartre return (status); 485887a7269eSachartre } 485987a7269eSachartre 486087a7269eSachartre /* 48612f5224aeSachartre * Allocate a buffer for a VD_OP_SCSICMD operation. The size of the allocated 48622f5224aeSachartre * buffer is returned in alloc_len. 48632f5224aeSachartre */ 48642f5224aeSachartre static vd_scsi_t * 48652f5224aeSachartre vdc_scsi_alloc(int cdb_len, int sense_len, int datain_len, int dataout_len, 48662f5224aeSachartre int *alloc_len) 48672f5224aeSachartre { 48682f5224aeSachartre vd_scsi_t *vd_scsi; 48692f5224aeSachartre int vd_scsi_len = VD_SCSI_SIZE; 48702f5224aeSachartre 48712f5224aeSachartre vd_scsi_len += P2ROUNDUP(cdb_len, sizeof (uint64_t)); 48722f5224aeSachartre vd_scsi_len += P2ROUNDUP(sense_len, sizeof (uint64_t)); 48732f5224aeSachartre vd_scsi_len += P2ROUNDUP(datain_len, sizeof (uint64_t)); 48742f5224aeSachartre vd_scsi_len += P2ROUNDUP(dataout_len, sizeof (uint64_t)); 48752f5224aeSachartre 48762f5224aeSachartre ASSERT(vd_scsi_len % sizeof (uint64_t) == 0); 48772f5224aeSachartre 48782f5224aeSachartre vd_scsi = kmem_zalloc(vd_scsi_len, KM_SLEEP); 48792f5224aeSachartre 48802f5224aeSachartre vd_scsi->cdb_len = cdb_len; 48812f5224aeSachartre vd_scsi->sense_len = sense_len; 48822f5224aeSachartre vd_scsi->datain_len = datain_len; 48832f5224aeSachartre vd_scsi->dataout_len = dataout_len; 48842f5224aeSachartre 48852f5224aeSachartre *alloc_len = vd_scsi_len; 48862f5224aeSachartre 48872f5224aeSachartre return (vd_scsi); 48882f5224aeSachartre } 48892f5224aeSachartre 48902f5224aeSachartre /* 48912f5224aeSachartre * Convert the status of a SCSI command to a Solaris return code. 48922f5224aeSachartre * 48932f5224aeSachartre * Arguments: 48942f5224aeSachartre * vd_scsi - The SCSI operation buffer. 48952f5224aeSachartre * log_error - indicate if an error message should be logged. 48962f5224aeSachartre * 48972f5224aeSachartre * Note that our SCSI error messages are rather primitive for the moment 48982f5224aeSachartre * and could be improved by decoding some data like the SCSI command and 48992f5224aeSachartre * the sense key. 49002f5224aeSachartre * 49012f5224aeSachartre * Return value: 49022f5224aeSachartre * 0 - Status is good. 49032f5224aeSachartre * EACCES - Status reports a reservation conflict. 49042f5224aeSachartre * ENOTSUP - Status reports a check condition and sense key 49052f5224aeSachartre * reports an illegal request. 49062f5224aeSachartre * EIO - Any other status. 49072f5224aeSachartre */ 49082f5224aeSachartre static int 49092f5224aeSachartre vdc_scsi_status(vdc_t *vdc, vd_scsi_t *vd_scsi, boolean_t log_error) 49102f5224aeSachartre { 49112f5224aeSachartre int rv; 49122f5224aeSachartre char path_str[MAXPATHLEN]; 49132f5224aeSachartre char panic_str[VDC_RESV_CONFLICT_FMT_LEN + MAXPATHLEN]; 49142f5224aeSachartre union scsi_cdb *cdb; 49152f5224aeSachartre struct scsi_extended_sense *sense; 49162f5224aeSachartre 49172f5224aeSachartre if (vd_scsi->cmd_status == STATUS_GOOD) 49182f5224aeSachartre /* no error */ 49192f5224aeSachartre return (0); 49202f5224aeSachartre 49212f5224aeSachartre /* when the tunable vdc_scsi_log_error is true we log all errors */ 49222f5224aeSachartre if (vdc_scsi_log_error) 49232f5224aeSachartre log_error = B_TRUE; 49242f5224aeSachartre 49252f5224aeSachartre if (log_error) { 49262f5224aeSachartre cmn_err(CE_WARN, "%s (vdc%d):\tError for Command: 0x%x)\n", 49272f5224aeSachartre ddi_pathname(vdc->dip, path_str), vdc->instance, 49282f5224aeSachartre GETCMD(VD_SCSI_DATA_CDB(vd_scsi))); 49292f5224aeSachartre } 49302f5224aeSachartre 49312f5224aeSachartre /* default returned value */ 49322f5224aeSachartre rv = EIO; 49332f5224aeSachartre 49342f5224aeSachartre switch (vd_scsi->cmd_status) { 49352f5224aeSachartre 49362f5224aeSachartre case STATUS_CHECK: 49372f5224aeSachartre case STATUS_TERMINATED: 49382f5224aeSachartre if (log_error) 49392f5224aeSachartre cmn_err(CE_CONT, "\tCheck Condition Error\n"); 49402f5224aeSachartre 49412f5224aeSachartre /* check sense buffer */ 49422f5224aeSachartre if (vd_scsi->sense_len == 0 || 49432f5224aeSachartre vd_scsi->sense_status != STATUS_GOOD) { 49442f5224aeSachartre if (log_error) 49452f5224aeSachartre cmn_err(CE_CONT, "\tNo Sense Data Available\n"); 49462f5224aeSachartre break; 49472f5224aeSachartre } 49482f5224aeSachartre 49492f5224aeSachartre sense = VD_SCSI_DATA_SENSE(vd_scsi); 49502f5224aeSachartre 49512f5224aeSachartre if (log_error) { 49522f5224aeSachartre cmn_err(CE_CONT, "\tSense Key: 0x%x\n" 49532f5224aeSachartre "\tASC: 0x%x, ASCQ: 0x%x\n", 49542f5224aeSachartre scsi_sense_key((uint8_t *)sense), 49552f5224aeSachartre scsi_sense_asc((uint8_t *)sense), 49562f5224aeSachartre scsi_sense_ascq((uint8_t *)sense)); 49572f5224aeSachartre } 49582f5224aeSachartre 49592f5224aeSachartre if (scsi_sense_key((uint8_t *)sense) == KEY_ILLEGAL_REQUEST) 49602f5224aeSachartre rv = ENOTSUP; 49612f5224aeSachartre break; 49622f5224aeSachartre 49632f5224aeSachartre case STATUS_BUSY: 49642f5224aeSachartre if (log_error) 49652f5224aeSachartre cmn_err(CE_NOTE, "\tDevice Busy\n"); 49662f5224aeSachartre break; 49672f5224aeSachartre 49682f5224aeSachartre case STATUS_RESERVATION_CONFLICT: 49692f5224aeSachartre /* 49702f5224aeSachartre * If the command was PERSISTENT_RESERVATION_[IN|OUT] then 49712f5224aeSachartre * reservation conflict could be due to various reasons like 49722f5224aeSachartre * incorrect keys, not registered or not reserved etc. So, 49732f5224aeSachartre * we should not panic in that case. 49742f5224aeSachartre */ 49752f5224aeSachartre cdb = VD_SCSI_DATA_CDB(vd_scsi); 49762f5224aeSachartre if (vdc->failfast_interval != 0 && 49772f5224aeSachartre cdb->scc_cmd != SCMD_PERSISTENT_RESERVE_IN && 49782f5224aeSachartre cdb->scc_cmd != SCMD_PERSISTENT_RESERVE_OUT) { 49792f5224aeSachartre /* failfast is enabled so we have to panic */ 49802f5224aeSachartre (void) snprintf(panic_str, sizeof (panic_str), 49812f5224aeSachartre VDC_RESV_CONFLICT_FMT_STR "%s", 49822f5224aeSachartre ddi_pathname(vdc->dip, path_str)); 49832f5224aeSachartre panic(panic_str); 49842f5224aeSachartre } 49852f5224aeSachartre if (log_error) 49862f5224aeSachartre cmn_err(CE_NOTE, "\tReservation Conflict\n"); 49872f5224aeSachartre rv = EACCES; 49882f5224aeSachartre break; 49892f5224aeSachartre 49902f5224aeSachartre case STATUS_QFULL: 49912f5224aeSachartre if (log_error) 49922f5224aeSachartre cmn_err(CE_NOTE, "\tQueue Full\n"); 49932f5224aeSachartre break; 49942f5224aeSachartre 49952f5224aeSachartre case STATUS_MET: 49962f5224aeSachartre case STATUS_INTERMEDIATE: 49972f5224aeSachartre case STATUS_SCSI2: 49982f5224aeSachartre case STATUS_INTERMEDIATE_MET: 49992f5224aeSachartre case STATUS_ACA_ACTIVE: 50002f5224aeSachartre if (log_error) 50012f5224aeSachartre cmn_err(CE_CONT, 50022f5224aeSachartre "\tUnexpected SCSI status received: 0x%x\n", 50032f5224aeSachartre vd_scsi->cmd_status); 50042f5224aeSachartre break; 50052f5224aeSachartre 50062f5224aeSachartre default: 50072f5224aeSachartre if (log_error) 50082f5224aeSachartre cmn_err(CE_CONT, 50092f5224aeSachartre "\tInvalid SCSI status received: 0x%x\n", 50102f5224aeSachartre vd_scsi->cmd_status); 50112f5224aeSachartre break; 50122f5224aeSachartre } 50132f5224aeSachartre 50142f5224aeSachartre return (rv); 50152f5224aeSachartre } 50162f5224aeSachartre 50172f5224aeSachartre /* 50182f5224aeSachartre * Implemented the USCSICMD uscsi(7I) ioctl. This ioctl is converted to 50192f5224aeSachartre * a VD_OP_SCSICMD operation which is sent to the vdisk server. If a SCSI 50202f5224aeSachartre * reset is requested (i.e. a flag USCSI_RESET* is set) then the ioctl is 50212f5224aeSachartre * converted to a VD_OP_RESET operation. 50222f5224aeSachartre */ 50232f5224aeSachartre static int 50242f5224aeSachartre vdc_uscsi_cmd(vdc_t *vdc, caddr_t arg, int mode) 50252f5224aeSachartre { 50262f5224aeSachartre struct uscsi_cmd uscsi; 50272f5224aeSachartre struct uscsi_cmd32 uscsi32; 50282f5224aeSachartre vd_scsi_t *vd_scsi; 50292f5224aeSachartre int vd_scsi_len; 50302f5224aeSachartre union scsi_cdb *cdb; 50312f5224aeSachartre struct scsi_extended_sense *sense; 50322f5224aeSachartre char *datain, *dataout; 50332f5224aeSachartre size_t cdb_len, datain_len, dataout_len, sense_len; 50342f5224aeSachartre int rv; 50352f5224aeSachartre 50362f5224aeSachartre if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 50372f5224aeSachartre if (ddi_copyin(arg, &uscsi32, sizeof (struct uscsi_cmd32), 50382f5224aeSachartre mode) != 0) 50392f5224aeSachartre return (EFAULT); 50402f5224aeSachartre uscsi_cmd32touscsi_cmd((&uscsi32), (&uscsi)); 50412f5224aeSachartre } else { 50422f5224aeSachartre if (ddi_copyin(arg, &uscsi, sizeof (struct uscsi_cmd), 50432f5224aeSachartre mode) != 0) 50442f5224aeSachartre return (EFAULT); 50452f5224aeSachartre } 50462f5224aeSachartre 50472f5224aeSachartre /* a uscsi reset is converted to a VD_OP_RESET operation */ 50482f5224aeSachartre if (uscsi.uscsi_flags & (USCSI_RESET | USCSI_RESET_LUN | 50492f5224aeSachartre USCSI_RESET_ALL)) { 50502f5224aeSachartre rv = vdc_do_sync_op(vdc, VD_OP_RESET, NULL, 0, 0, 0, CB_SYNC, 50512f5224aeSachartre (void *)(uint64_t)mode, VIO_both_dir, B_TRUE); 50522f5224aeSachartre return (rv); 50532f5224aeSachartre } 50542f5224aeSachartre 50552f5224aeSachartre /* cdb buffer length */ 50562f5224aeSachartre cdb_len = uscsi.uscsi_cdblen; 50572f5224aeSachartre 50582f5224aeSachartre /* data in and out buffers length */ 50592f5224aeSachartre if (uscsi.uscsi_flags & USCSI_READ) { 50602f5224aeSachartre datain_len = uscsi.uscsi_buflen; 50612f5224aeSachartre dataout_len = 0; 50622f5224aeSachartre } else { 50632f5224aeSachartre datain_len = 0; 50642f5224aeSachartre dataout_len = uscsi.uscsi_buflen; 50652f5224aeSachartre } 50662f5224aeSachartre 50672f5224aeSachartre /* sense buffer length */ 50682f5224aeSachartre if (uscsi.uscsi_flags & USCSI_RQENABLE) 50692f5224aeSachartre sense_len = uscsi.uscsi_rqlen; 50702f5224aeSachartre else 50712f5224aeSachartre sense_len = 0; 50722f5224aeSachartre 50732f5224aeSachartre /* allocate buffer for the VD_SCSICMD_OP operation */ 50742f5224aeSachartre vd_scsi = vdc_scsi_alloc(cdb_len, sense_len, datain_len, dataout_len, 50752f5224aeSachartre &vd_scsi_len); 50762f5224aeSachartre 50772f5224aeSachartre /* 50782f5224aeSachartre * The documentation of USCSI_ISOLATE and USCSI_DIAGNOSE is very vague, 50792f5224aeSachartre * but basically they prevent a SCSI command from being retried in case 50802f5224aeSachartre * of an error. 50812f5224aeSachartre */ 50822f5224aeSachartre if ((uscsi.uscsi_flags & USCSI_ISOLATE) || 50832f5224aeSachartre (uscsi.uscsi_flags & USCSI_DIAGNOSE)) 50842f5224aeSachartre vd_scsi->options |= VD_SCSI_OPT_NORETRY; 50852f5224aeSachartre 50862f5224aeSachartre /* set task attribute */ 50872f5224aeSachartre if (uscsi.uscsi_flags & USCSI_NOTAG) { 50882f5224aeSachartre vd_scsi->task_attribute = 0; 50892f5224aeSachartre } else { 50902f5224aeSachartre if (uscsi.uscsi_flags & USCSI_HEAD) 50912f5224aeSachartre vd_scsi->task_attribute = VD_SCSI_TASK_ACA; 50922f5224aeSachartre else if (uscsi.uscsi_flags & USCSI_HTAG) 50932f5224aeSachartre vd_scsi->task_attribute = VD_SCSI_TASK_HQUEUE; 50942f5224aeSachartre else if (uscsi.uscsi_flags & USCSI_OTAG) 50952f5224aeSachartre vd_scsi->task_attribute = VD_SCSI_TASK_ORDERED; 50962f5224aeSachartre else 50972f5224aeSachartre vd_scsi->task_attribute = 0; 50982f5224aeSachartre } 50992f5224aeSachartre 51002f5224aeSachartre /* set timeout */ 51012f5224aeSachartre vd_scsi->timeout = uscsi.uscsi_timeout; 51022f5224aeSachartre 51032f5224aeSachartre /* copy-in cdb data */ 51042f5224aeSachartre cdb = VD_SCSI_DATA_CDB(vd_scsi); 51052f5224aeSachartre if (ddi_copyin(uscsi.uscsi_cdb, cdb, cdb_len, mode) != 0) { 51062f5224aeSachartre rv = EFAULT; 51072f5224aeSachartre goto done; 51082f5224aeSachartre } 51092f5224aeSachartre 51102f5224aeSachartre /* keep a pointer to the sense buffer */ 51112f5224aeSachartre sense = VD_SCSI_DATA_SENSE(vd_scsi); 51122f5224aeSachartre 51132f5224aeSachartre /* keep a pointer to the data-in buffer */ 51142f5224aeSachartre datain = (char *)VD_SCSI_DATA_IN(vd_scsi); 51152f5224aeSachartre 51162f5224aeSachartre /* copy-in request data to the data-out buffer */ 51172f5224aeSachartre dataout = (char *)VD_SCSI_DATA_OUT(vd_scsi); 51182f5224aeSachartre if (!(uscsi.uscsi_flags & USCSI_READ)) { 51192f5224aeSachartre if (ddi_copyin(uscsi.uscsi_bufaddr, dataout, dataout_len, 51202f5224aeSachartre mode)) { 51212f5224aeSachartre rv = EFAULT; 51222f5224aeSachartre goto done; 51232f5224aeSachartre } 51242f5224aeSachartre } 51252f5224aeSachartre 51262f5224aeSachartre /* submit the request */ 51272f5224aeSachartre rv = vdc_do_sync_op(vdc, VD_OP_SCSICMD, (caddr_t)vd_scsi, vd_scsi_len, 51282f5224aeSachartre 0, 0, CB_SYNC, (void *)(uint64_t)mode, VIO_both_dir, B_FALSE); 51292f5224aeSachartre 51302f5224aeSachartre if (rv != 0) 51312f5224aeSachartre goto done; 51322f5224aeSachartre 51332f5224aeSachartre /* update scsi status */ 51342f5224aeSachartre uscsi.uscsi_status = vd_scsi->cmd_status; 51352f5224aeSachartre 51362f5224aeSachartre /* update sense data */ 51372f5224aeSachartre if ((uscsi.uscsi_flags & USCSI_RQENABLE) && 51382f5224aeSachartre (uscsi.uscsi_status == STATUS_CHECK || 51392f5224aeSachartre uscsi.uscsi_status == STATUS_TERMINATED)) { 51402f5224aeSachartre 51412f5224aeSachartre uscsi.uscsi_rqstatus = vd_scsi->sense_status; 51422f5224aeSachartre 51432f5224aeSachartre if (uscsi.uscsi_rqstatus == STATUS_GOOD) { 51442f5224aeSachartre uscsi.uscsi_rqresid = uscsi.uscsi_rqlen - 51452f5224aeSachartre vd_scsi->sense_len; 51462f5224aeSachartre if (ddi_copyout(sense, uscsi.uscsi_rqbuf, 51472f5224aeSachartre vd_scsi->sense_len, mode) != 0) { 51482f5224aeSachartre rv = EFAULT; 51492f5224aeSachartre goto done; 51502f5224aeSachartre } 51512f5224aeSachartre } 51522f5224aeSachartre } 51532f5224aeSachartre 51542f5224aeSachartre /* update request data */ 51552f5224aeSachartre if (uscsi.uscsi_status == STATUS_GOOD) { 51562f5224aeSachartre if (uscsi.uscsi_flags & USCSI_READ) { 51572f5224aeSachartre uscsi.uscsi_resid = uscsi.uscsi_buflen - 51582f5224aeSachartre vd_scsi->datain_len; 51592f5224aeSachartre if (ddi_copyout(datain, uscsi.uscsi_bufaddr, 51602f5224aeSachartre vd_scsi->datain_len, mode) != 0) { 51612f5224aeSachartre rv = EFAULT; 51622f5224aeSachartre goto done; 51632f5224aeSachartre } 51642f5224aeSachartre } else { 51652f5224aeSachartre uscsi.uscsi_resid = uscsi.uscsi_buflen - 51662f5224aeSachartre vd_scsi->dataout_len; 51672f5224aeSachartre } 51682f5224aeSachartre } 51692f5224aeSachartre 51702f5224aeSachartre /* copy-out result */ 51712f5224aeSachartre if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 51722f5224aeSachartre uscsi_cmdtouscsi_cmd32((&uscsi), (&uscsi32)); 51732f5224aeSachartre if (ddi_copyout(&uscsi32, arg, sizeof (struct uscsi_cmd32), 51742f5224aeSachartre mode) != 0) { 51752f5224aeSachartre rv = EFAULT; 51762f5224aeSachartre goto done; 51772f5224aeSachartre } 51782f5224aeSachartre } else { 51792f5224aeSachartre if (ddi_copyout(&uscsi, arg, sizeof (struct uscsi_cmd), 51802f5224aeSachartre mode) != 0) { 51812f5224aeSachartre rv = EFAULT; 51822f5224aeSachartre goto done; 51832f5224aeSachartre } 51842f5224aeSachartre } 51852f5224aeSachartre 51862f5224aeSachartre /* get the return code from the SCSI command status */ 51872f5224aeSachartre rv = vdc_scsi_status(vdc, vd_scsi, 51882f5224aeSachartre !(uscsi.uscsi_flags & USCSI_SILENT)); 51892f5224aeSachartre 51902f5224aeSachartre done: 51912f5224aeSachartre kmem_free(vd_scsi, vd_scsi_len); 51922f5224aeSachartre return (rv); 51932f5224aeSachartre } 51942f5224aeSachartre 51952f5224aeSachartre /* 51962f5224aeSachartre * Create a VD_OP_SCSICMD buffer for a SCSI PERSISTENT IN command. 51972f5224aeSachartre * 51982f5224aeSachartre * Arguments: 51992f5224aeSachartre * cmd - SCSI PERSISTENT IN command 52002f5224aeSachartre * len - length of the SCSI input buffer 52012f5224aeSachartre * vd_scsi_len - return the length of the allocated buffer 52022f5224aeSachartre * 52032f5224aeSachartre * Returned Value: 52042f5224aeSachartre * a pointer to the allocated VD_OP_SCSICMD buffer. 52052f5224aeSachartre */ 52062f5224aeSachartre static vd_scsi_t * 52072f5224aeSachartre vdc_scsi_alloc_persistent_in(uchar_t cmd, int len, int *vd_scsi_len) 52082f5224aeSachartre { 52092f5224aeSachartre int cdb_len, sense_len, datain_len, dataout_len; 52102f5224aeSachartre vd_scsi_t *vd_scsi; 52112f5224aeSachartre union scsi_cdb *cdb; 52122f5224aeSachartre 52132f5224aeSachartre cdb_len = CDB_GROUP1; 52142f5224aeSachartre sense_len = sizeof (struct scsi_extended_sense); 52152f5224aeSachartre datain_len = len; 52162f5224aeSachartre dataout_len = 0; 52172f5224aeSachartre 52182f5224aeSachartre vd_scsi = vdc_scsi_alloc(cdb_len, sense_len, datain_len, dataout_len, 52192f5224aeSachartre vd_scsi_len); 52202f5224aeSachartre 52212f5224aeSachartre cdb = VD_SCSI_DATA_CDB(vd_scsi); 52222f5224aeSachartre 52232f5224aeSachartre /* set cdb */ 52242f5224aeSachartre cdb->scc_cmd = SCMD_PERSISTENT_RESERVE_IN; 52252f5224aeSachartre cdb->cdb_opaque[1] = cmd; 52262f5224aeSachartre FORMG1COUNT(cdb, datain_len); 52272f5224aeSachartre 52282f5224aeSachartre vd_scsi->timeout = vdc_scsi_timeout; 52292f5224aeSachartre 52302f5224aeSachartre return (vd_scsi); 52312f5224aeSachartre } 52322f5224aeSachartre 52332f5224aeSachartre /* 52342f5224aeSachartre * Create a VD_OP_SCSICMD buffer for a SCSI PERSISTENT OUT command. 52352f5224aeSachartre * 52362f5224aeSachartre * Arguments: 52372f5224aeSachartre * cmd - SCSI PERSISTENT OUT command 52382f5224aeSachartre * len - length of the SCSI output buffer 52392f5224aeSachartre * vd_scsi_len - return the length of the allocated buffer 52402f5224aeSachartre * 52412f5224aeSachartre * Returned Code: 52422f5224aeSachartre * a pointer to the allocated VD_OP_SCSICMD buffer. 52432f5224aeSachartre */ 52442f5224aeSachartre static vd_scsi_t * 52452f5224aeSachartre vdc_scsi_alloc_persistent_out(uchar_t cmd, int len, int *vd_scsi_len) 52462f5224aeSachartre { 52472f5224aeSachartre int cdb_len, sense_len, datain_len, dataout_len; 52482f5224aeSachartre vd_scsi_t *vd_scsi; 52492f5224aeSachartre union scsi_cdb *cdb; 52502f5224aeSachartre 52512f5224aeSachartre cdb_len = CDB_GROUP1; 52522f5224aeSachartre sense_len = sizeof (struct scsi_extended_sense); 52532f5224aeSachartre datain_len = 0; 52542f5224aeSachartre dataout_len = len; 52552f5224aeSachartre 52562f5224aeSachartre vd_scsi = vdc_scsi_alloc(cdb_len, sense_len, datain_len, dataout_len, 52572f5224aeSachartre vd_scsi_len); 52582f5224aeSachartre 52592f5224aeSachartre cdb = VD_SCSI_DATA_CDB(vd_scsi); 52602f5224aeSachartre 52612f5224aeSachartre /* set cdb */ 52622f5224aeSachartre cdb->scc_cmd = SCMD_PERSISTENT_RESERVE_OUT; 52632f5224aeSachartre cdb->cdb_opaque[1] = cmd; 52642f5224aeSachartre FORMG1COUNT(cdb, dataout_len); 52652f5224aeSachartre 52662f5224aeSachartre vd_scsi->timeout = vdc_scsi_timeout; 52672f5224aeSachartre 52682f5224aeSachartre return (vd_scsi); 52692f5224aeSachartre } 52702f5224aeSachartre 52712f5224aeSachartre /* 52722f5224aeSachartre * Implement the MHIOCGRP_INKEYS mhd(7i) ioctl. The ioctl is converted 52732f5224aeSachartre * to a SCSI PERSISTENT IN READ KEYS command which is sent to the vdisk 52742f5224aeSachartre * server with a VD_OP_SCSICMD operation. 52752f5224aeSachartre */ 52762f5224aeSachartre static int 52772f5224aeSachartre vdc_mhd_inkeys(vdc_t *vdc, caddr_t arg, int mode) 52782f5224aeSachartre { 52792f5224aeSachartre vd_scsi_t *vd_scsi; 52802f5224aeSachartre mhioc_inkeys_t inkeys; 52812f5224aeSachartre mhioc_key_list_t klist; 52822f5224aeSachartre struct mhioc_inkeys32 inkeys32; 52832f5224aeSachartre struct mhioc_key_list32 klist32; 52842f5224aeSachartre sd_prin_readkeys_t *scsi_keys; 52852f5224aeSachartre void *user_keys; 52862f5224aeSachartre int vd_scsi_len; 52872f5224aeSachartre int listsize, listlen, rv; 52882f5224aeSachartre 52892f5224aeSachartre /* copyin arguments */ 52902f5224aeSachartre if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 52912f5224aeSachartre rv = ddi_copyin(arg, &inkeys32, sizeof (inkeys32), mode); 52922f5224aeSachartre if (rv != 0) 52932f5224aeSachartre return (EFAULT); 52942f5224aeSachartre 52952f5224aeSachartre rv = ddi_copyin((caddr_t)(uintptr_t)inkeys32.li, &klist32, 52962f5224aeSachartre sizeof (klist32), mode); 52972f5224aeSachartre if (rv != 0) 52982f5224aeSachartre return (EFAULT); 52992f5224aeSachartre 53002f5224aeSachartre listsize = klist32.listsize; 53012f5224aeSachartre } else { 53022f5224aeSachartre rv = ddi_copyin(arg, &inkeys, sizeof (inkeys), mode); 53032f5224aeSachartre if (rv != 0) 53042f5224aeSachartre return (EFAULT); 53052f5224aeSachartre 53062f5224aeSachartre rv = ddi_copyin(inkeys.li, &klist, sizeof (klist), mode); 53072f5224aeSachartre if (rv != 0) 53082f5224aeSachartre return (EFAULT); 53092f5224aeSachartre 53102f5224aeSachartre listsize = klist.listsize; 53112f5224aeSachartre } 53122f5224aeSachartre 53132f5224aeSachartre /* build SCSI VD_OP request */ 53142f5224aeSachartre vd_scsi = vdc_scsi_alloc_persistent_in(SD_READ_KEYS, 53152f5224aeSachartre sizeof (sd_prin_readkeys_t) - sizeof (caddr_t) + 53162f5224aeSachartre (sizeof (mhioc_resv_key_t) * listsize), &vd_scsi_len); 53172f5224aeSachartre 53182f5224aeSachartre scsi_keys = (sd_prin_readkeys_t *)VD_SCSI_DATA_IN(vd_scsi); 53192f5224aeSachartre 53202f5224aeSachartre /* submit the request */ 53212f5224aeSachartre rv = vdc_do_sync_op(vdc, VD_OP_SCSICMD, (caddr_t)vd_scsi, vd_scsi_len, 53222f5224aeSachartre 0, 0, CB_SYNC, (void *)(uint64_t)mode, VIO_both_dir, B_FALSE); 53232f5224aeSachartre 53242f5224aeSachartre if (rv != 0) 53252f5224aeSachartre goto done; 53262f5224aeSachartre 53272f5224aeSachartre listlen = scsi_keys->len / MHIOC_RESV_KEY_SIZE; 53282f5224aeSachartre 53292f5224aeSachartre if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 53302f5224aeSachartre inkeys32.generation = scsi_keys->generation; 53312f5224aeSachartre rv = ddi_copyout(&inkeys32, arg, sizeof (inkeys32), mode); 53322f5224aeSachartre if (rv != 0) { 53332f5224aeSachartre rv = EFAULT; 53342f5224aeSachartre goto done; 53352f5224aeSachartre } 53362f5224aeSachartre 53372f5224aeSachartre klist32.listlen = listlen; 53382f5224aeSachartre rv = ddi_copyout(&klist32, (caddr_t)(uintptr_t)inkeys32.li, 53392f5224aeSachartre sizeof (klist32), mode); 53402f5224aeSachartre if (rv != 0) { 53412f5224aeSachartre rv = EFAULT; 53422f5224aeSachartre goto done; 53432f5224aeSachartre } 53442f5224aeSachartre 53452f5224aeSachartre user_keys = (caddr_t)(uintptr_t)klist32.list; 53462f5224aeSachartre } else { 53472f5224aeSachartre inkeys.generation = scsi_keys->generation; 53482f5224aeSachartre rv = ddi_copyout(&inkeys, arg, sizeof (inkeys), mode); 53492f5224aeSachartre if (rv != 0) { 53502f5224aeSachartre rv = EFAULT; 53512f5224aeSachartre goto done; 53522f5224aeSachartre } 53532f5224aeSachartre 53542f5224aeSachartre klist.listlen = listlen; 53552f5224aeSachartre rv = ddi_copyout(&klist, inkeys.li, sizeof (klist), mode); 53562f5224aeSachartre if (rv != 0) { 53572f5224aeSachartre rv = EFAULT; 53582f5224aeSachartre goto done; 53592f5224aeSachartre } 53602f5224aeSachartre 53612f5224aeSachartre user_keys = klist.list; 53622f5224aeSachartre } 53632f5224aeSachartre 53642f5224aeSachartre /* copy out keys */ 53652f5224aeSachartre if (listlen > 0 && listsize > 0) { 53662f5224aeSachartre if (listsize < listlen) 53672f5224aeSachartre listlen = listsize; 53682f5224aeSachartre rv = ddi_copyout(&scsi_keys->keylist, user_keys, 53692f5224aeSachartre listlen * MHIOC_RESV_KEY_SIZE, mode); 53702f5224aeSachartre if (rv != 0) 53712f5224aeSachartre rv = EFAULT; 53722f5224aeSachartre } 53732f5224aeSachartre 53742f5224aeSachartre if (rv == 0) 53752f5224aeSachartre rv = vdc_scsi_status(vdc, vd_scsi, B_FALSE); 53762f5224aeSachartre 53772f5224aeSachartre done: 53782f5224aeSachartre kmem_free(vd_scsi, vd_scsi_len); 53792f5224aeSachartre 53802f5224aeSachartre return (rv); 53812f5224aeSachartre } 53822f5224aeSachartre 53832f5224aeSachartre /* 53842f5224aeSachartre * Implement the MHIOCGRP_INRESV mhd(7i) ioctl. The ioctl is converted 53852f5224aeSachartre * to a SCSI PERSISTENT IN READ RESERVATION command which is sent to 53862f5224aeSachartre * the vdisk server with a VD_OP_SCSICMD operation. 53872f5224aeSachartre */ 53882f5224aeSachartre static int 53892f5224aeSachartre vdc_mhd_inresv(vdc_t *vdc, caddr_t arg, int mode) 53902f5224aeSachartre { 53912f5224aeSachartre vd_scsi_t *vd_scsi; 53922f5224aeSachartre mhioc_inresvs_t inresv; 53932f5224aeSachartre mhioc_resv_desc_list_t rlist; 53942f5224aeSachartre struct mhioc_inresvs32 inresv32; 53952f5224aeSachartre struct mhioc_resv_desc_list32 rlist32; 53962f5224aeSachartre mhioc_resv_desc_t mhd_resv; 53972f5224aeSachartre sd_prin_readresv_t *scsi_resv; 53982f5224aeSachartre sd_readresv_desc_t *resv; 53992f5224aeSachartre mhioc_resv_desc_t *user_resv; 54002f5224aeSachartre int vd_scsi_len; 54012f5224aeSachartre int listsize, listlen, i, rv; 54022f5224aeSachartre 54032f5224aeSachartre /* copyin arguments */ 54042f5224aeSachartre if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 54052f5224aeSachartre rv = ddi_copyin(arg, &inresv32, sizeof (inresv32), mode); 54062f5224aeSachartre if (rv != 0) 54072f5224aeSachartre return (EFAULT); 54082f5224aeSachartre 54092f5224aeSachartre rv = ddi_copyin((caddr_t)(uintptr_t)inresv32.li, &rlist32, 54102f5224aeSachartre sizeof (rlist32), mode); 54112f5224aeSachartre if (rv != 0) 54122f5224aeSachartre return (EFAULT); 54132f5224aeSachartre 54142f5224aeSachartre listsize = rlist32.listsize; 54152f5224aeSachartre } else { 54162f5224aeSachartre rv = ddi_copyin(arg, &inresv, sizeof (inresv), mode); 54172f5224aeSachartre if (rv != 0) 54182f5224aeSachartre return (EFAULT); 54192f5224aeSachartre 54202f5224aeSachartre rv = ddi_copyin(inresv.li, &rlist, sizeof (rlist), mode); 54212f5224aeSachartre if (rv != 0) 54222f5224aeSachartre return (EFAULT); 54232f5224aeSachartre 54242f5224aeSachartre listsize = rlist.listsize; 54252f5224aeSachartre } 54262f5224aeSachartre 54272f5224aeSachartre /* build SCSI VD_OP request */ 54282f5224aeSachartre vd_scsi = vdc_scsi_alloc_persistent_in(SD_READ_RESV, 54292f5224aeSachartre sizeof (sd_prin_readresv_t) - sizeof (caddr_t) + 54302f5224aeSachartre (SCSI3_RESV_DESC_LEN * listsize), &vd_scsi_len); 54312f5224aeSachartre 54322f5224aeSachartre scsi_resv = (sd_prin_readresv_t *)VD_SCSI_DATA_IN(vd_scsi); 54332f5224aeSachartre 54342f5224aeSachartre /* submit the request */ 54352f5224aeSachartre rv = vdc_do_sync_op(vdc, VD_OP_SCSICMD, (caddr_t)vd_scsi, vd_scsi_len, 54362f5224aeSachartre 0, 0, CB_SYNC, (void *)(uint64_t)mode, VIO_both_dir, B_FALSE); 54372f5224aeSachartre 54382f5224aeSachartre if (rv != 0) 54392f5224aeSachartre goto done; 54402f5224aeSachartre 54412f5224aeSachartre listlen = scsi_resv->len / SCSI3_RESV_DESC_LEN; 54422f5224aeSachartre 54432f5224aeSachartre if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 54442f5224aeSachartre inresv32.generation = scsi_resv->generation; 54452f5224aeSachartre rv = ddi_copyout(&inresv32, arg, sizeof (inresv32), mode); 54462f5224aeSachartre if (rv != 0) { 54472f5224aeSachartre rv = EFAULT; 54482f5224aeSachartre goto done; 54492f5224aeSachartre } 54502f5224aeSachartre 54512f5224aeSachartre rlist32.listlen = listlen; 54522f5224aeSachartre rv = ddi_copyout(&rlist32, (caddr_t)(uintptr_t)inresv32.li, 54532f5224aeSachartre sizeof (rlist32), mode); 54542f5224aeSachartre if (rv != 0) { 54552f5224aeSachartre rv = EFAULT; 54562f5224aeSachartre goto done; 54572f5224aeSachartre } 54582f5224aeSachartre 54592f5224aeSachartre user_resv = (mhioc_resv_desc_t *)(uintptr_t)rlist32.list; 54602f5224aeSachartre } else { 54612f5224aeSachartre inresv.generation = scsi_resv->generation; 54622f5224aeSachartre rv = ddi_copyout(&inresv, arg, sizeof (inresv), mode); 54632f5224aeSachartre if (rv != 0) { 54642f5224aeSachartre rv = EFAULT; 54652f5224aeSachartre goto done; 54662f5224aeSachartre } 54672f5224aeSachartre 54682f5224aeSachartre rlist.listlen = listlen; 54692f5224aeSachartre rv = ddi_copyout(&rlist, inresv.li, sizeof (rlist), mode); 54702f5224aeSachartre if (rv != 0) { 54712f5224aeSachartre rv = EFAULT; 54722f5224aeSachartre goto done; 54732f5224aeSachartre } 54742f5224aeSachartre 54752f5224aeSachartre user_resv = rlist.list; 54762f5224aeSachartre } 54772f5224aeSachartre 54782f5224aeSachartre /* copy out reservations */ 54792f5224aeSachartre if (listsize > 0 && listlen > 0) { 54802f5224aeSachartre if (listsize < listlen) 54812f5224aeSachartre listlen = listsize; 54822f5224aeSachartre resv = (sd_readresv_desc_t *)&scsi_resv->readresv_desc; 54832f5224aeSachartre 54842f5224aeSachartre for (i = 0; i < listlen; i++) { 54852f5224aeSachartre mhd_resv.type = resv->type; 54862f5224aeSachartre mhd_resv.scope = resv->scope; 54872f5224aeSachartre mhd_resv.scope_specific_addr = 54882f5224aeSachartre BE_32(resv->scope_specific_addr); 54892f5224aeSachartre bcopy(&resv->resvkey, &mhd_resv.key, 54902f5224aeSachartre MHIOC_RESV_KEY_SIZE); 54912f5224aeSachartre 54922f5224aeSachartre rv = ddi_copyout(&mhd_resv, user_resv, 54932f5224aeSachartre sizeof (mhd_resv), mode); 54942f5224aeSachartre if (rv != 0) { 54952f5224aeSachartre rv = EFAULT; 54962f5224aeSachartre goto done; 54972f5224aeSachartre } 54982f5224aeSachartre resv++; 54992f5224aeSachartre user_resv++; 55002f5224aeSachartre } 55012f5224aeSachartre } 55022f5224aeSachartre 55032f5224aeSachartre if (rv == 0) 55042f5224aeSachartre rv = vdc_scsi_status(vdc, vd_scsi, B_FALSE); 55052f5224aeSachartre 55062f5224aeSachartre done: 55072f5224aeSachartre kmem_free(vd_scsi, vd_scsi_len); 55082f5224aeSachartre return (rv); 55092f5224aeSachartre } 55102f5224aeSachartre 55112f5224aeSachartre /* 55122f5224aeSachartre * Implement the MHIOCGRP_REGISTER mhd(7i) ioctl. The ioctl is converted 55132f5224aeSachartre * to a SCSI PERSISTENT OUT REGISTER command which is sent to the vdisk 55142f5224aeSachartre * server with a VD_OP_SCSICMD operation. 55152f5224aeSachartre */ 55162f5224aeSachartre static int 55172f5224aeSachartre vdc_mhd_register(vdc_t *vdc, caddr_t arg, int mode) 55182f5224aeSachartre { 55192f5224aeSachartre vd_scsi_t *vd_scsi; 55202f5224aeSachartre sd_prout_t *scsi_prout; 55212f5224aeSachartre mhioc_register_t mhd_reg; 55222f5224aeSachartre int vd_scsi_len, rv; 55232f5224aeSachartre 55242f5224aeSachartre /* copyin arguments */ 55252f5224aeSachartre rv = ddi_copyin(arg, &mhd_reg, sizeof (mhd_reg), mode); 55262f5224aeSachartre if (rv != 0) 55272f5224aeSachartre return (EFAULT); 55282f5224aeSachartre 55292f5224aeSachartre /* build SCSI VD_OP request */ 55302f5224aeSachartre vd_scsi = vdc_scsi_alloc_persistent_out(SD_SCSI3_REGISTER, 55312f5224aeSachartre sizeof (sd_prout_t), &vd_scsi_len); 55322f5224aeSachartre 55332f5224aeSachartre /* set parameters */ 55342f5224aeSachartre scsi_prout = (sd_prout_t *)VD_SCSI_DATA_OUT(vd_scsi); 55352f5224aeSachartre bcopy(mhd_reg.oldkey.key, scsi_prout->res_key, MHIOC_RESV_KEY_SIZE); 55362f5224aeSachartre bcopy(mhd_reg.newkey.key, scsi_prout->service_key, MHIOC_RESV_KEY_SIZE); 55372f5224aeSachartre scsi_prout->aptpl = (uchar_t)mhd_reg.aptpl; 55382f5224aeSachartre 55392f5224aeSachartre /* submit the request */ 55402f5224aeSachartre rv = vdc_do_sync_op(vdc, VD_OP_SCSICMD, (caddr_t)vd_scsi, vd_scsi_len, 55412f5224aeSachartre 0, 0, CB_SYNC, (void *)(uint64_t)mode, VIO_both_dir, B_FALSE); 55422f5224aeSachartre 55432f5224aeSachartre if (rv == 0) 55442f5224aeSachartre rv = vdc_scsi_status(vdc, vd_scsi, B_FALSE); 55452f5224aeSachartre 55462f5224aeSachartre kmem_free(vd_scsi, vd_scsi_len); 55472f5224aeSachartre return (rv); 55482f5224aeSachartre } 55492f5224aeSachartre 55502f5224aeSachartre /* 55512f5224aeSachartre * Implement the MHIOCGRP_RESERVE mhd(7i) ioctl. The ioctl is converted 55522f5224aeSachartre * to a SCSI PERSISTENT OUT RESERVE command which is sent to the vdisk 55532f5224aeSachartre * server with a VD_OP_SCSICMD operation. 55542f5224aeSachartre */ 55552f5224aeSachartre static int 55562f5224aeSachartre vdc_mhd_reserve(vdc_t *vdc, caddr_t arg, int mode) 55572f5224aeSachartre { 55582f5224aeSachartre union scsi_cdb *cdb; 55592f5224aeSachartre vd_scsi_t *vd_scsi; 55602f5224aeSachartre sd_prout_t *scsi_prout; 55612f5224aeSachartre mhioc_resv_desc_t mhd_resv; 55622f5224aeSachartre int vd_scsi_len, rv; 55632f5224aeSachartre 55642f5224aeSachartre /* copyin arguments */ 55652f5224aeSachartre rv = ddi_copyin(arg, &mhd_resv, sizeof (mhd_resv), mode); 55662f5224aeSachartre if (rv != 0) 55672f5224aeSachartre return (EFAULT); 55682f5224aeSachartre 55692f5224aeSachartre /* build SCSI VD_OP request */ 55702f5224aeSachartre vd_scsi = vdc_scsi_alloc_persistent_out(SD_SCSI3_RESERVE, 55712f5224aeSachartre sizeof (sd_prout_t), &vd_scsi_len); 55722f5224aeSachartre 55732f5224aeSachartre /* set parameters */ 55742f5224aeSachartre cdb = VD_SCSI_DATA_CDB(vd_scsi); 55752f5224aeSachartre scsi_prout = (sd_prout_t *)VD_SCSI_DATA_OUT(vd_scsi); 55762f5224aeSachartre bcopy(mhd_resv.key.key, scsi_prout->res_key, MHIOC_RESV_KEY_SIZE); 55772f5224aeSachartre scsi_prout->scope_address = mhd_resv.scope_specific_addr; 55782f5224aeSachartre cdb->cdb_opaque[2] = mhd_resv.type; 55792f5224aeSachartre 55802f5224aeSachartre /* submit the request */ 55812f5224aeSachartre rv = vdc_do_sync_op(vdc, VD_OP_SCSICMD, (caddr_t)vd_scsi, vd_scsi_len, 55822f5224aeSachartre 0, 0, CB_SYNC, (void *)(uint64_t)mode, VIO_both_dir, B_FALSE); 55832f5224aeSachartre 55842f5224aeSachartre if (rv == 0) 55852f5224aeSachartre rv = vdc_scsi_status(vdc, vd_scsi, B_FALSE); 55862f5224aeSachartre 55872f5224aeSachartre kmem_free(vd_scsi, vd_scsi_len); 55882f5224aeSachartre return (rv); 55892f5224aeSachartre } 55902f5224aeSachartre 55912f5224aeSachartre /* 55922f5224aeSachartre * Implement the MHIOCGRP_PREEMPTANDABORT mhd(7i) ioctl. The ioctl is 55932f5224aeSachartre * converted to a SCSI PERSISTENT OUT PREEMPT AND ABORT command which 55942f5224aeSachartre * is sent to the vdisk server with a VD_OP_SCSICMD operation. 55952f5224aeSachartre */ 55962f5224aeSachartre static int 55972f5224aeSachartre vdc_mhd_preemptabort(vdc_t *vdc, caddr_t arg, int mode) 55982f5224aeSachartre { 55992f5224aeSachartre union scsi_cdb *cdb; 56002f5224aeSachartre vd_scsi_t *vd_scsi; 56012f5224aeSachartre sd_prout_t *scsi_prout; 56022f5224aeSachartre mhioc_preemptandabort_t mhd_preempt; 56032f5224aeSachartre int vd_scsi_len, rv; 56042f5224aeSachartre 56052f5224aeSachartre /* copyin arguments */ 56062f5224aeSachartre rv = ddi_copyin(arg, &mhd_preempt, sizeof (mhd_preempt), mode); 56072f5224aeSachartre if (rv != 0) 56082f5224aeSachartre return (EFAULT); 56092f5224aeSachartre 56102f5224aeSachartre /* build SCSI VD_OP request */ 56112f5224aeSachartre vd_scsi = vdc_scsi_alloc_persistent_out(SD_SCSI3_PREEMPTANDABORT, 56122f5224aeSachartre sizeof (sd_prout_t), &vd_scsi_len); 56132f5224aeSachartre 56142f5224aeSachartre /* set parameters */ 56152f5224aeSachartre vd_scsi->task_attribute = VD_SCSI_TASK_ACA; 56162f5224aeSachartre cdb = VD_SCSI_DATA_CDB(vd_scsi); 56172f5224aeSachartre scsi_prout = (sd_prout_t *)VD_SCSI_DATA_OUT(vd_scsi); 56182f5224aeSachartre bcopy(mhd_preempt.resvdesc.key.key, scsi_prout->res_key, 56192f5224aeSachartre MHIOC_RESV_KEY_SIZE); 56202f5224aeSachartre bcopy(mhd_preempt.victim_key.key, scsi_prout->service_key, 56212f5224aeSachartre MHIOC_RESV_KEY_SIZE); 56222f5224aeSachartre scsi_prout->scope_address = mhd_preempt.resvdesc.scope_specific_addr; 56232f5224aeSachartre cdb->cdb_opaque[2] = mhd_preempt.resvdesc.type; 56242f5224aeSachartre 56252f5224aeSachartre /* submit the request */ 56262f5224aeSachartre rv = vdc_do_sync_op(vdc, VD_OP_SCSICMD, (caddr_t)vd_scsi, vd_scsi_len, 56272f5224aeSachartre 0, 0, CB_SYNC, (void *)(uint64_t)mode, VIO_both_dir, B_FALSE); 56282f5224aeSachartre 56292f5224aeSachartre if (rv == 0) 56302f5224aeSachartre rv = vdc_scsi_status(vdc, vd_scsi, B_FALSE); 56312f5224aeSachartre 56322f5224aeSachartre kmem_free(vd_scsi, vd_scsi_len); 56332f5224aeSachartre return (rv); 56342f5224aeSachartre } 56352f5224aeSachartre 56362f5224aeSachartre /* 56372f5224aeSachartre * Implement the MHIOCGRP_REGISTERANDIGNOREKEY mhd(7i) ioctl. The ioctl 56382f5224aeSachartre * is converted to a SCSI PERSISTENT OUT REGISTER AND IGNORE EXISTING KEY 56392f5224aeSachartre * command which is sent to the vdisk server with a VD_OP_SCSICMD operation. 56402f5224aeSachartre */ 56412f5224aeSachartre static int 56422f5224aeSachartre vdc_mhd_registerignore(vdc_t *vdc, caddr_t arg, int mode) 56432f5224aeSachartre { 56442f5224aeSachartre vd_scsi_t *vd_scsi; 56452f5224aeSachartre sd_prout_t *scsi_prout; 56462f5224aeSachartre mhioc_registerandignorekey_t mhd_regi; 56472f5224aeSachartre int vd_scsi_len, rv; 56482f5224aeSachartre 56492f5224aeSachartre /* copyin arguments */ 56502f5224aeSachartre rv = ddi_copyin(arg, &mhd_regi, sizeof (mhd_regi), mode); 56512f5224aeSachartre if (rv != 0) 56522f5224aeSachartre return (EFAULT); 56532f5224aeSachartre 56542f5224aeSachartre /* build SCSI VD_OP request */ 56552f5224aeSachartre vd_scsi = vdc_scsi_alloc_persistent_out(SD_SCSI3_REGISTERANDIGNOREKEY, 56562f5224aeSachartre sizeof (sd_prout_t), &vd_scsi_len); 56572f5224aeSachartre 56582f5224aeSachartre /* set parameters */ 56592f5224aeSachartre scsi_prout = (sd_prout_t *)VD_SCSI_DATA_OUT(vd_scsi); 56602f5224aeSachartre bcopy(mhd_regi.newkey.key, scsi_prout->service_key, 56612f5224aeSachartre MHIOC_RESV_KEY_SIZE); 56622f5224aeSachartre scsi_prout->aptpl = (uchar_t)mhd_regi.aptpl; 56632f5224aeSachartre 56642f5224aeSachartre /* submit the request */ 56652f5224aeSachartre rv = vdc_do_sync_op(vdc, VD_OP_SCSICMD, (caddr_t)vd_scsi, vd_scsi_len, 56662f5224aeSachartre 0, 0, CB_SYNC, (void *)(uint64_t)mode, VIO_both_dir, B_FALSE); 56672f5224aeSachartre 56682f5224aeSachartre if (rv == 0) 56692f5224aeSachartre rv = vdc_scsi_status(vdc, vd_scsi, B_FALSE); 56702f5224aeSachartre 56712f5224aeSachartre kmem_free(vd_scsi, vd_scsi_len); 56722f5224aeSachartre return (rv); 56732f5224aeSachartre } 56742f5224aeSachartre 56752f5224aeSachartre /* 56762f5224aeSachartre * This function is used by the failfast mechanism to send a SCSI command 56772f5224aeSachartre * to check for reservation conflict. 56782f5224aeSachartre */ 56792f5224aeSachartre static int 56802f5224aeSachartre vdc_failfast_scsi_cmd(vdc_t *vdc, uchar_t scmd) 56812f5224aeSachartre { 56822f5224aeSachartre int cdb_len, sense_len, vd_scsi_len; 56832f5224aeSachartre vd_scsi_t *vd_scsi; 56842f5224aeSachartre union scsi_cdb *cdb; 56852f5224aeSachartre int rv; 56862f5224aeSachartre 56872f5224aeSachartre ASSERT(scmd == SCMD_TEST_UNIT_READY || scmd == SCMD_WRITE_G1); 56882f5224aeSachartre 56892f5224aeSachartre if (scmd == SCMD_WRITE_G1) 56902f5224aeSachartre cdb_len = CDB_GROUP1; 56912f5224aeSachartre else 56922f5224aeSachartre cdb_len = CDB_GROUP0; 56932f5224aeSachartre 56942f5224aeSachartre sense_len = sizeof (struct scsi_extended_sense); 56952f5224aeSachartre 56962f5224aeSachartre vd_scsi = vdc_scsi_alloc(cdb_len, sense_len, 0, 0, &vd_scsi_len); 56972f5224aeSachartre 56982f5224aeSachartre /* set cdb */ 56992f5224aeSachartre cdb = VD_SCSI_DATA_CDB(vd_scsi); 57002f5224aeSachartre cdb->scc_cmd = scmd; 57012f5224aeSachartre 57022f5224aeSachartre vd_scsi->timeout = vdc_scsi_timeout; 57032f5224aeSachartre 57042f5224aeSachartre /* 57052f5224aeSachartre * Submit the request. The last argument has to be B_FALSE so that 57062f5224aeSachartre * vdc_do_sync_op does not loop checking for reservation conflict if 57072f5224aeSachartre * the operation returns an error. 57082f5224aeSachartre */ 57092f5224aeSachartre rv = vdc_do_sync_op(vdc, VD_OP_SCSICMD, (caddr_t)vd_scsi, vd_scsi_len, 57102f5224aeSachartre 0, 0, CB_SYNC, (void *)(uint64_t)FKIOCTL, VIO_both_dir, B_FALSE); 57112f5224aeSachartre 57122f5224aeSachartre if (rv == 0) 57132f5224aeSachartre (void) vdc_scsi_status(vdc, vd_scsi, B_FALSE); 57142f5224aeSachartre 57152f5224aeSachartre kmem_free(vd_scsi, vd_scsi_len); 57162f5224aeSachartre return (rv); 57172f5224aeSachartre } 57182f5224aeSachartre 57192f5224aeSachartre /* 57202f5224aeSachartre * This function is used by the failfast mechanism to check for reservation 57212f5224aeSachartre * conflict. It sends some SCSI commands which will fail with a reservation 57222f5224aeSachartre * conflict error if the system does not have access to the disk and this 57232f5224aeSachartre * will panic the system. 57242f5224aeSachartre * 57252f5224aeSachartre * Returned Code: 57262f5224aeSachartre * 0 - disk is accessible without reservation conflict error 57272f5224aeSachartre * != 0 - unable to check if disk is accessible 57282f5224aeSachartre */ 57292f5224aeSachartre int 57302f5224aeSachartre vdc_failfast_check_resv(vdc_t *vdc) 57312f5224aeSachartre { 57322f5224aeSachartre int failure = 0; 57332f5224aeSachartre 57342f5224aeSachartre /* 57352f5224aeSachartre * Send a TEST UNIT READY command. The command will panic 57362f5224aeSachartre * the system if it fails with a reservation conflict. 57372f5224aeSachartre */ 57382f5224aeSachartre if (vdc_failfast_scsi_cmd(vdc, SCMD_TEST_UNIT_READY) != 0) 57392f5224aeSachartre failure++; 57402f5224aeSachartre 57412f5224aeSachartre /* 57422f5224aeSachartre * With SPC-3 compliant devices TEST UNIT READY will succeed on 57432f5224aeSachartre * a reserved device, so we also do a WRITE(10) of zero byte in 57442f5224aeSachartre * order to provoke a Reservation Conflict status on those newer 57452f5224aeSachartre * devices. 57462f5224aeSachartre */ 57472f5224aeSachartre if (vdc_failfast_scsi_cmd(vdc, SCMD_WRITE_G1) != 0) 57482f5224aeSachartre failure++; 57492f5224aeSachartre 57502f5224aeSachartre return (failure); 57512f5224aeSachartre } 57522f5224aeSachartre 57532f5224aeSachartre /* 57542f5224aeSachartre * Add a pending I/O to the failfast I/O queue. An I/O is added to this 57552f5224aeSachartre * queue when it has failed and failfast is enabled. Then we have to check 57562f5224aeSachartre * if it has failed because of a reservation conflict in which case we have 57572f5224aeSachartre * to panic the system. 57582f5224aeSachartre * 57592f5224aeSachartre * Async I/O should be queued with their block I/O data transfer structure 57602f5224aeSachartre * (buf). Sync I/O should be queued with buf = NULL. 57612f5224aeSachartre */ 57622f5224aeSachartre static vdc_io_t * 57632f5224aeSachartre vdc_failfast_io_queue(vdc_t *vdc, struct buf *buf) 57642f5224aeSachartre { 57652f5224aeSachartre vdc_io_t *vio; 57662f5224aeSachartre 57672f5224aeSachartre ASSERT(MUTEX_HELD(&vdc->lock)); 57682f5224aeSachartre 57692f5224aeSachartre vio = kmem_alloc(sizeof (vdc_io_t), KM_SLEEP); 57702f5224aeSachartre vio->vio_next = vdc->failfast_io_queue; 57712f5224aeSachartre vio->vio_buf = buf; 57722f5224aeSachartre vio->vio_qtime = ddi_get_lbolt(); 57732f5224aeSachartre 57742f5224aeSachartre vdc->failfast_io_queue = vio; 57752f5224aeSachartre 57762f5224aeSachartre /* notify the failfast thread that a new I/O is queued */ 57772f5224aeSachartre cv_signal(&vdc->failfast_cv); 57782f5224aeSachartre 57792f5224aeSachartre return (vio); 57802f5224aeSachartre } 57812f5224aeSachartre 57822f5224aeSachartre /* 57832f5224aeSachartre * Remove and complete I/O in the failfast I/O queue which have been 57842f5224aeSachartre * added after the indicated deadline. A deadline of 0 means that all 57852f5224aeSachartre * I/O have to be unqueued and marked as completed. 57862f5224aeSachartre */ 57872f5224aeSachartre static void 57882f5224aeSachartre vdc_failfast_io_unqueue(vdc_t *vdc, clock_t deadline) 57892f5224aeSachartre { 57902f5224aeSachartre vdc_io_t *vio, *vio_tmp; 57912f5224aeSachartre 57922f5224aeSachartre ASSERT(MUTEX_HELD(&vdc->lock)); 57932f5224aeSachartre 57942f5224aeSachartre vio_tmp = NULL; 57952f5224aeSachartre vio = vdc->failfast_io_queue; 57962f5224aeSachartre 57972f5224aeSachartre if (deadline != 0) { 57982f5224aeSachartre /* 57992f5224aeSachartre * Skip any io queued after the deadline. The failfast 58002f5224aeSachartre * I/O queue is ordered starting with the last I/O added 58012f5224aeSachartre * to the queue. 58022f5224aeSachartre */ 58032f5224aeSachartre while (vio != NULL && vio->vio_qtime > deadline) { 58042f5224aeSachartre vio_tmp = vio; 58052f5224aeSachartre vio = vio->vio_next; 58062f5224aeSachartre } 58072f5224aeSachartre } 58082f5224aeSachartre 58092f5224aeSachartre if (vio == NULL) 58102f5224aeSachartre /* nothing to unqueue */ 58112f5224aeSachartre return; 58122f5224aeSachartre 58132f5224aeSachartre /* update the queue */ 58142f5224aeSachartre if (vio_tmp == NULL) 58152f5224aeSachartre vdc->failfast_io_queue = NULL; 58162f5224aeSachartre else 58172f5224aeSachartre vio_tmp->vio_next = NULL; 58182f5224aeSachartre 58192f5224aeSachartre /* 58202f5224aeSachartre * Complete unqueued I/O. Async I/O have a block I/O data transfer 58212f5224aeSachartre * structure (buf) and they are completed by calling biodone(). Sync 58222f5224aeSachartre * I/O do not have a buf and they are completed by setting the 58232f5224aeSachartre * vio_qtime to zero and signaling failfast_io_cv. In that case, the 58242f5224aeSachartre * thread waiting for the I/O to complete is responsible for freeing 58252f5224aeSachartre * the vio structure. 58262f5224aeSachartre */ 58272f5224aeSachartre while (vio != NULL) { 58282f5224aeSachartre vio_tmp = vio->vio_next; 58292f5224aeSachartre if (vio->vio_buf != NULL) { 58302f5224aeSachartre biodone(vio->vio_buf); 58312f5224aeSachartre kmem_free(vio, sizeof (vdc_io_t)); 58322f5224aeSachartre } else { 58332f5224aeSachartre vio->vio_qtime = 0; 58342f5224aeSachartre } 58352f5224aeSachartre vio = vio_tmp; 58362f5224aeSachartre } 58372f5224aeSachartre 58382f5224aeSachartre cv_broadcast(&vdc->failfast_io_cv); 58392f5224aeSachartre } 58402f5224aeSachartre 58412f5224aeSachartre /* 58422f5224aeSachartre * Failfast Thread. 58432f5224aeSachartre * 58442f5224aeSachartre * While failfast is enabled, the failfast thread sends a TEST UNIT READY 58452f5224aeSachartre * and a zero size WRITE(10) SCSI commands on a regular basis to check that 58462f5224aeSachartre * we still have access to the disk. If a command fails with a RESERVATION 58472f5224aeSachartre * CONFLICT error then the system will immediatly panic. 58482f5224aeSachartre * 58492f5224aeSachartre * The failfast thread is also woken up when an I/O has failed. It then check 58502f5224aeSachartre * the access to the disk to ensure that the I/O failure was not due to a 58512f5224aeSachartre * reservation conflict. 58522f5224aeSachartre * 58532f5224aeSachartre * There is one failfast thread for each virtual disk for which failfast is 58542f5224aeSachartre * enabled. We could have only one thread sending requests for all disks but 58552f5224aeSachartre * this would need vdc to send asynchronous requests and to have callbacks to 58562f5224aeSachartre * process replies. 58572f5224aeSachartre */ 58582f5224aeSachartre static void 58592f5224aeSachartre vdc_failfast_thread(void *arg) 58602f5224aeSachartre { 58612f5224aeSachartre int status; 58622f5224aeSachartre vdc_t *vdc = (vdc_t *)arg; 58632f5224aeSachartre clock_t timeout, starttime; 58642f5224aeSachartre 58652f5224aeSachartre mutex_enter(&vdc->lock); 58662f5224aeSachartre 58672f5224aeSachartre while (vdc->failfast_interval != 0) { 58682f5224aeSachartre 58692f5224aeSachartre starttime = ddi_get_lbolt(); 58702f5224aeSachartre 58712f5224aeSachartre mutex_exit(&vdc->lock); 58722f5224aeSachartre 58732f5224aeSachartre /* check for reservation conflict */ 58742f5224aeSachartre status = vdc_failfast_check_resv(vdc); 58752f5224aeSachartre 58762f5224aeSachartre mutex_enter(&vdc->lock); 58772f5224aeSachartre /* 58782f5224aeSachartre * We have dropped the lock to send the SCSI command so we have 58792f5224aeSachartre * to check that failfast is still enabled. 58802f5224aeSachartre */ 58812f5224aeSachartre if (vdc->failfast_interval == 0) 58822f5224aeSachartre break; 58832f5224aeSachartre 58842f5224aeSachartre /* 58852f5224aeSachartre * If we have successfully check the disk access and there was 58862f5224aeSachartre * no reservation conflict then we can complete any I/O queued 58872f5224aeSachartre * before the last check. 58882f5224aeSachartre */ 58892f5224aeSachartre if (status == 0) 58902f5224aeSachartre vdc_failfast_io_unqueue(vdc, starttime); 58912f5224aeSachartre 58922f5224aeSachartre /* proceed again if some I/O are still in the queue */ 58932f5224aeSachartre if (vdc->failfast_io_queue != NULL) 58942f5224aeSachartre continue; 58952f5224aeSachartre 58962f5224aeSachartre timeout = ddi_get_lbolt() + 58972f5224aeSachartre drv_usectohz(vdc->failfast_interval); 58982f5224aeSachartre (void) cv_timedwait(&vdc->failfast_cv, &vdc->lock, timeout); 58992f5224aeSachartre } 59002f5224aeSachartre 59012f5224aeSachartre /* 59022f5224aeSachartre * Failfast is being stop so we can complete any queued I/O. 59032f5224aeSachartre */ 59042f5224aeSachartre vdc_failfast_io_unqueue(vdc, 0); 59052f5224aeSachartre vdc->failfast_thread = NULL; 59062f5224aeSachartre mutex_exit(&vdc->lock); 59072f5224aeSachartre thread_exit(); 59082f5224aeSachartre } 59092f5224aeSachartre 59102f5224aeSachartre /* 59112f5224aeSachartre * Implement the MHIOCENFAILFAST mhd(7i) ioctl. 59122f5224aeSachartre */ 59132f5224aeSachartre static int 59142f5224aeSachartre vdc_failfast(vdc_t *vdc, caddr_t arg, int mode) 59152f5224aeSachartre { 59162f5224aeSachartre unsigned int mh_time; 59172f5224aeSachartre 59182f5224aeSachartre if (ddi_copyin((void *)arg, &mh_time, sizeof (int), mode)) 59192f5224aeSachartre return (EFAULT); 59202f5224aeSachartre 59212f5224aeSachartre mutex_enter(&vdc->lock); 59222f5224aeSachartre if (mh_time != 0 && vdc->failfast_thread == NULL) { 59232f5224aeSachartre vdc->failfast_thread = thread_create(NULL, 0, 59242f5224aeSachartre vdc_failfast_thread, vdc, 0, &p0, TS_RUN, 59252f5224aeSachartre v.v_maxsyspri - 2); 59262f5224aeSachartre } 59272f5224aeSachartre 59282f5224aeSachartre vdc->failfast_interval = mh_time * 1000; 59292f5224aeSachartre cv_signal(&vdc->failfast_cv); 59302f5224aeSachartre mutex_exit(&vdc->lock); 59312f5224aeSachartre 59322f5224aeSachartre return (0); 59332f5224aeSachartre } 59342f5224aeSachartre 59352f5224aeSachartre /* 59362f5224aeSachartre * Implement the MHIOCTKOWN and MHIOCRELEASE mhd(7i) ioctls. These ioctls are 59372f5224aeSachartre * converted to VD_OP_SET_ACCESS operations. 59382f5224aeSachartre */ 59392f5224aeSachartre static int 59402f5224aeSachartre vdc_access_set(vdc_t *vdc, uint64_t flags, int mode) 59412f5224aeSachartre { 59422f5224aeSachartre int rv; 59432f5224aeSachartre 59442f5224aeSachartre /* submit owership command request */ 59452f5224aeSachartre rv = vdc_do_sync_op(vdc, VD_OP_SET_ACCESS, (caddr_t)&flags, 59462f5224aeSachartre sizeof (uint64_t), 0, 0, CB_SYNC, (void *)(uint64_t)mode, 59472f5224aeSachartre VIO_both_dir, B_TRUE); 59482f5224aeSachartre 59492f5224aeSachartre return (rv); 59502f5224aeSachartre } 59512f5224aeSachartre 59522f5224aeSachartre /* 59532f5224aeSachartre * Implement the MHIOCSTATUS mhd(7i) ioctl. This ioctl is converted to a 59542f5224aeSachartre * VD_OP_GET_ACCESS operation. 59552f5224aeSachartre */ 59562f5224aeSachartre static int 59572f5224aeSachartre vdc_access_get(vdc_t *vdc, uint64_t *status, int mode) 59582f5224aeSachartre { 59592f5224aeSachartre int rv; 59602f5224aeSachartre 59612f5224aeSachartre /* submit owership command request */ 59622f5224aeSachartre rv = vdc_do_sync_op(vdc, VD_OP_GET_ACCESS, (caddr_t)status, 59632f5224aeSachartre sizeof (uint64_t), 0, 0, CB_SYNC, (void *)(uint64_t)mode, 59642f5224aeSachartre VIO_both_dir, B_TRUE); 59652f5224aeSachartre 59662f5224aeSachartre return (rv); 59672f5224aeSachartre } 59682f5224aeSachartre 59692f5224aeSachartre /* 59702f5224aeSachartre * Disk Ownership Thread. 59712f5224aeSachartre * 59722f5224aeSachartre * When we have taken the ownership of a disk, this thread waits to be 59732f5224aeSachartre * notified when the LDC channel is reset so that it can recover the 59742f5224aeSachartre * ownership. 59752f5224aeSachartre * 59762f5224aeSachartre * Note that the thread handling the LDC reset (vdc_process_msg_thread()) 59772f5224aeSachartre * can not be used to do the ownership recovery because it has to be 59782f5224aeSachartre * running to handle the reply message to the ownership operation. 59792f5224aeSachartre */ 59802f5224aeSachartre static void 59812f5224aeSachartre vdc_ownership_thread(void *arg) 59822f5224aeSachartre { 59832f5224aeSachartre vdc_t *vdc = (vdc_t *)arg; 59842f5224aeSachartre clock_t timeout; 59852f5224aeSachartre uint64_t status; 59862f5224aeSachartre 59872f5224aeSachartre mutex_enter(&vdc->ownership_lock); 59882f5224aeSachartre mutex_enter(&vdc->lock); 59892f5224aeSachartre 59902f5224aeSachartre while (vdc->ownership & VDC_OWNERSHIP_WANTED) { 59912f5224aeSachartre 59922f5224aeSachartre if ((vdc->ownership & VDC_OWNERSHIP_RESET) || 59932f5224aeSachartre !(vdc->ownership & VDC_OWNERSHIP_GRANTED)) { 59942f5224aeSachartre /* 59952f5224aeSachartre * There was a reset so the ownership has been lost, 59962f5224aeSachartre * try to recover. We do this without using the preempt 59972f5224aeSachartre * option so that we don't steal the ownership from 59982f5224aeSachartre * someone who has preempted us. 59992f5224aeSachartre */ 60002f5224aeSachartre DMSG(vdc, 0, "[%d] Ownership lost, recovering", 60012f5224aeSachartre vdc->instance); 60022f5224aeSachartre 60032f5224aeSachartre vdc->ownership &= ~(VDC_OWNERSHIP_RESET | 60042f5224aeSachartre VDC_OWNERSHIP_GRANTED); 60052f5224aeSachartre 60062f5224aeSachartre mutex_exit(&vdc->lock); 60072f5224aeSachartre 60082f5224aeSachartre status = vdc_access_set(vdc, VD_ACCESS_SET_EXCLUSIVE | 60092f5224aeSachartre VD_ACCESS_SET_PRESERVE, FKIOCTL); 60102f5224aeSachartre 60112f5224aeSachartre mutex_enter(&vdc->lock); 60122f5224aeSachartre 60132f5224aeSachartre if (status == 0) { 60142f5224aeSachartre DMSG(vdc, 0, "[%d] Ownership recovered", 60152f5224aeSachartre vdc->instance); 60162f5224aeSachartre vdc->ownership |= VDC_OWNERSHIP_GRANTED; 60172f5224aeSachartre } else { 60182f5224aeSachartre DMSG(vdc, 0, "[%d] Fail to recover ownership", 60192f5224aeSachartre vdc->instance); 60202f5224aeSachartre } 60212f5224aeSachartre 60222f5224aeSachartre } 60232f5224aeSachartre 60242f5224aeSachartre /* 60252f5224aeSachartre * If we have the ownership then we just wait for an event 60262f5224aeSachartre * to happen (LDC reset), otherwise we will retry to recover 60272f5224aeSachartre * after a delay. 60282f5224aeSachartre */ 60292f5224aeSachartre if (vdc->ownership & VDC_OWNERSHIP_GRANTED) 60302f5224aeSachartre timeout = 0; 60312f5224aeSachartre else 60322f5224aeSachartre timeout = ddi_get_lbolt() + 60332f5224aeSachartre drv_usectohz(vdc_ownership_delay); 60342f5224aeSachartre 60352f5224aeSachartre /* Release the ownership_lock and wait on the vdc lock */ 60362f5224aeSachartre mutex_exit(&vdc->ownership_lock); 60372f5224aeSachartre 60382f5224aeSachartre if (timeout == 0) 60392f5224aeSachartre (void) cv_wait(&vdc->ownership_cv, &vdc->lock); 60402f5224aeSachartre else 60412f5224aeSachartre (void) cv_timedwait(&vdc->ownership_cv, 60422f5224aeSachartre &vdc->lock, timeout); 60432f5224aeSachartre 60442f5224aeSachartre mutex_exit(&vdc->lock); 60452f5224aeSachartre 60462f5224aeSachartre mutex_enter(&vdc->ownership_lock); 60472f5224aeSachartre mutex_enter(&vdc->lock); 60482f5224aeSachartre } 60492f5224aeSachartre 60502f5224aeSachartre vdc->ownership_thread = NULL; 60512f5224aeSachartre mutex_exit(&vdc->lock); 60522f5224aeSachartre mutex_exit(&vdc->ownership_lock); 60532f5224aeSachartre 60542f5224aeSachartre thread_exit(); 60552f5224aeSachartre } 60562f5224aeSachartre 60572f5224aeSachartre static void 60582f5224aeSachartre vdc_ownership_update(vdc_t *vdc, int ownership_flags) 60592f5224aeSachartre { 60602f5224aeSachartre ASSERT(MUTEX_HELD(&vdc->ownership_lock)); 60612f5224aeSachartre 60622f5224aeSachartre mutex_enter(&vdc->lock); 60632f5224aeSachartre vdc->ownership = ownership_flags; 60642f5224aeSachartre if ((vdc->ownership & VDC_OWNERSHIP_WANTED) && 60652f5224aeSachartre vdc->ownership_thread == NULL) { 60662f5224aeSachartre /* start ownership thread */ 60672f5224aeSachartre vdc->ownership_thread = thread_create(NULL, 0, 60682f5224aeSachartre vdc_ownership_thread, vdc, 0, &p0, TS_RUN, 60692f5224aeSachartre v.v_maxsyspri - 2); 60702f5224aeSachartre } else { 60712f5224aeSachartre /* notify the ownership thread */ 60722f5224aeSachartre cv_signal(&vdc->ownership_cv); 60732f5224aeSachartre } 60742f5224aeSachartre mutex_exit(&vdc->lock); 60752f5224aeSachartre } 60762f5224aeSachartre 60772f5224aeSachartre /* 60782f5224aeSachartre * Get the size and the block size of a virtual disk from the vdisk server. 60792f5224aeSachartre * We need to use this operation when the vdisk_size attribute was not 60802f5224aeSachartre * available during the handshake with the vdisk server. 60812f5224aeSachartre */ 60822f5224aeSachartre static int 60832f5224aeSachartre vdc_check_capacity(vdc_t *vdc) 60842f5224aeSachartre { 60852f5224aeSachartre int rv = 0; 60862f5224aeSachartre size_t alloc_len; 60872f5224aeSachartre vd_capacity_t *vd_cap; 60882f5224aeSachartre 60892f5224aeSachartre if (vdc->vdisk_size != 0) 60902f5224aeSachartre return (0); 60912f5224aeSachartre 60922f5224aeSachartre alloc_len = P2ROUNDUP(sizeof (vd_capacity_t), sizeof (uint64_t)); 60932f5224aeSachartre 60942f5224aeSachartre vd_cap = kmem_zalloc(alloc_len, KM_SLEEP); 60952f5224aeSachartre 60962f5224aeSachartre rv = vdc_do_sync_op(vdc, VD_OP_GET_CAPACITY, (caddr_t)vd_cap, alloc_len, 60972f5224aeSachartre 0, 0, CB_SYNC, (void *)(uint64_t)FKIOCTL, VIO_both_dir, B_TRUE); 60982f5224aeSachartre 60992f5224aeSachartre if (rv == 0) { 61002f5224aeSachartre if (vd_cap->vdisk_block_size != vdc->block_size || 61012f5224aeSachartre vd_cap->vdisk_size == VD_SIZE_UNKNOWN || 61022f5224aeSachartre vd_cap->vdisk_size == 0) 61032f5224aeSachartre rv = EINVAL; 61042f5224aeSachartre else 61052f5224aeSachartre vdc->vdisk_size = vd_cap->vdisk_size; 61062f5224aeSachartre } 61072f5224aeSachartre 61082f5224aeSachartre kmem_free(vd_cap, alloc_len); 61092f5224aeSachartre return (rv); 61102f5224aeSachartre } 61112f5224aeSachartre 61122f5224aeSachartre /* 61131ae08745Sheppo * This structure is used in the DKIO(7I) array below. 61141ae08745Sheppo */ 61151ae08745Sheppo typedef struct vdc_dk_ioctl { 61161ae08745Sheppo uint8_t op; /* VD_OP_XXX value */ 61171ae08745Sheppo int cmd; /* Solaris ioctl operation number */ 61181ae08745Sheppo size_t nbytes; /* size of structure to be copied */ 61190a55fbb7Slm66018 61200a55fbb7Slm66018 /* function to convert between vDisk and Solaris structure formats */ 6121d10e4ef2Snarayan int (*convert)(vdc_t *vdc, void *vd_buf, void *ioctl_arg, 6122d10e4ef2Snarayan int mode, int dir); 61231ae08745Sheppo } vdc_dk_ioctl_t; 61241ae08745Sheppo 61251ae08745Sheppo /* 61261ae08745Sheppo * Subset of DKIO(7I) operations currently supported 61271ae08745Sheppo */ 61281ae08745Sheppo static vdc_dk_ioctl_t dk_ioctl[] = { 6129eff7243fSlm66018 {VD_OP_FLUSH, DKIOCFLUSHWRITECACHE, 0, 61300a55fbb7Slm66018 vdc_null_copy_func}, 61310a55fbb7Slm66018 {VD_OP_GET_WCE, DKIOCGETWCE, sizeof (int), 61324bac2208Snarayan vdc_get_wce_convert}, 61330a55fbb7Slm66018 {VD_OP_SET_WCE, DKIOCSETWCE, sizeof (int), 61344bac2208Snarayan vdc_set_wce_convert}, 61350a55fbb7Slm66018 {VD_OP_GET_VTOC, DKIOCGVTOC, sizeof (vd_vtoc_t), 61360a55fbb7Slm66018 vdc_get_vtoc_convert}, 61370a55fbb7Slm66018 {VD_OP_SET_VTOC, DKIOCSVTOC, sizeof (vd_vtoc_t), 61380a55fbb7Slm66018 vdc_set_vtoc_convert}, 61390a55fbb7Slm66018 {VD_OP_GET_DISKGEOM, DKIOCGGEOM, sizeof (vd_geom_t), 61400a55fbb7Slm66018 vdc_get_geom_convert}, 61410a55fbb7Slm66018 {VD_OP_GET_DISKGEOM, DKIOCG_PHYGEOM, sizeof (vd_geom_t), 61420a55fbb7Slm66018 vdc_get_geom_convert}, 61430a55fbb7Slm66018 {VD_OP_GET_DISKGEOM, DKIOCG_VIRTGEOM, sizeof (vd_geom_t), 61440a55fbb7Slm66018 vdc_get_geom_convert}, 61450a55fbb7Slm66018 {VD_OP_SET_DISKGEOM, DKIOCSGEOM, sizeof (vd_geom_t), 61460a55fbb7Slm66018 vdc_set_geom_convert}, 61474bac2208Snarayan {VD_OP_GET_EFI, DKIOCGETEFI, 0, 61484bac2208Snarayan vdc_get_efi_convert}, 61494bac2208Snarayan {VD_OP_SET_EFI, DKIOCSETEFI, 0, 61504bac2208Snarayan vdc_set_efi_convert}, 61510a55fbb7Slm66018 615287a7269eSachartre /* DIOCTL_RWCMD is converted to a read or a write */ 615387a7269eSachartre {0, DIOCTL_RWCMD, sizeof (struct dadkio_rwcmd), NULL}, 615487a7269eSachartre 61552f5224aeSachartre /* mhd(7I) non-shared multihost disks ioctls */ 61562f5224aeSachartre {0, MHIOCTKOWN, 0, vdc_null_copy_func}, 61572f5224aeSachartre {0, MHIOCRELEASE, 0, vdc_null_copy_func}, 61582f5224aeSachartre {0, MHIOCSTATUS, 0, vdc_null_copy_func}, 61592f5224aeSachartre {0, MHIOCQRESERVE, 0, vdc_null_copy_func}, 61602f5224aeSachartre 61612f5224aeSachartre /* mhd(7I) shared multihost disks ioctls */ 61622f5224aeSachartre {0, MHIOCGRP_INKEYS, 0, vdc_null_copy_func}, 61632f5224aeSachartre {0, MHIOCGRP_INRESV, 0, vdc_null_copy_func}, 61642f5224aeSachartre {0, MHIOCGRP_REGISTER, 0, vdc_null_copy_func}, 61652f5224aeSachartre {0, MHIOCGRP_RESERVE, 0, vdc_null_copy_func}, 61662f5224aeSachartre {0, MHIOCGRP_PREEMPTANDABORT, 0, vdc_null_copy_func}, 61672f5224aeSachartre {0, MHIOCGRP_REGISTERANDIGNOREKEY, 0, vdc_null_copy_func}, 61682f5224aeSachartre 61692f5224aeSachartre /* mhd(7I) failfast ioctl */ 61702f5224aeSachartre {0, MHIOCENFAILFAST, 0, vdc_null_copy_func}, 61712f5224aeSachartre 61720a55fbb7Slm66018 /* 61730a55fbb7Slm66018 * These particular ioctls are not sent to the server - vdc fakes up 61740a55fbb7Slm66018 * the necessary info. 61750a55fbb7Slm66018 */ 61760a55fbb7Slm66018 {0, DKIOCINFO, sizeof (struct dk_cinfo), vdc_null_copy_func}, 61770a55fbb7Slm66018 {0, DKIOCGMEDIAINFO, sizeof (struct dk_minfo), vdc_null_copy_func}, 61780a55fbb7Slm66018 {0, USCSICMD, sizeof (struct uscsi_cmd), vdc_null_copy_func}, 617987a7269eSachartre {0, DKIOCGAPART, 0, vdc_null_copy_func }, 61800a55fbb7Slm66018 {0, DKIOCREMOVABLE, 0, vdc_null_copy_func}, 61810a55fbb7Slm66018 {0, CDROMREADOFFSET, 0, vdc_null_copy_func} 61821ae08745Sheppo }; 61831ae08745Sheppo 61841ae08745Sheppo /* 6185edcc0754Sachartre * This function handles ioctl requests from the vd_efi_alloc_and_read() 6186edcc0754Sachartre * function and forward them to the vdisk. 61872f5224aeSachartre */ 61882f5224aeSachartre static int 6189edcc0754Sachartre vd_process_efi_ioctl(void *vdisk, int cmd, uintptr_t arg) 61902f5224aeSachartre { 6191edcc0754Sachartre vdc_t *vdc = (vdc_t *)vdisk; 6192edcc0754Sachartre dev_t dev; 61932f5224aeSachartre int rval; 6194edcc0754Sachartre 6195edcc0754Sachartre dev = makedevice(ddi_driver_major(vdc->dip), 6196edcc0754Sachartre VD_MAKE_DEV(vdc->instance, 0)); 6197edcc0754Sachartre 6198edcc0754Sachartre return (vd_process_ioctl(dev, cmd, (caddr_t)arg, FKIOCTL, &rval)); 61992f5224aeSachartre } 62002f5224aeSachartre 62012f5224aeSachartre /* 62021ae08745Sheppo * Function: 62031ae08745Sheppo * vd_process_ioctl() 62041ae08745Sheppo * 62051ae08745Sheppo * Description: 62060a55fbb7Slm66018 * This routine processes disk specific ioctl calls 62071ae08745Sheppo * 62081ae08745Sheppo * Arguments: 62091ae08745Sheppo * dev - the device number 62101ae08745Sheppo * cmd - the operation [dkio(7I)] to be processed 62111ae08745Sheppo * arg - pointer to user provided structure 62121ae08745Sheppo * (contains data to be set or reference parameter for get) 62131ae08745Sheppo * mode - bit flag, indicating open settings, 32/64 bit type, etc 62142f5224aeSachartre * rvalp - pointer to return value for calling process. 62151ae08745Sheppo * 62161ae08745Sheppo * Return Code: 62171ae08745Sheppo * 0 62181ae08745Sheppo * EFAULT 62191ae08745Sheppo * ENXIO 62201ae08745Sheppo * EIO 62211ae08745Sheppo * ENOTSUP 62221ae08745Sheppo */ 62231ae08745Sheppo static int 62242f5224aeSachartre vd_process_ioctl(dev_t dev, int cmd, caddr_t arg, int mode, int *rvalp) 62251ae08745Sheppo { 62260d0c8d4bSnarayan int instance = VDCUNIT(dev); 62271ae08745Sheppo vdc_t *vdc = NULL; 62281ae08745Sheppo int rv = -1; 62291ae08745Sheppo int idx = 0; /* index into dk_ioctl[] */ 62301ae08745Sheppo size_t len = 0; /* #bytes to send to vds */ 62311ae08745Sheppo size_t alloc_len = 0; /* #bytes to allocate mem for */ 62321ae08745Sheppo caddr_t mem_p = NULL; 62331ae08745Sheppo size_t nioctls = (sizeof (dk_ioctl)) / (sizeof (dk_ioctl[0])); 62343af08d82Slm66018 vdc_dk_ioctl_t *iop; 62351ae08745Sheppo 62361ae08745Sheppo vdc = ddi_get_soft_state(vdc_state, instance); 62371ae08745Sheppo if (vdc == NULL) { 62381ae08745Sheppo cmn_err(CE_NOTE, "![%d] Could not get soft state structure", 62391ae08745Sheppo instance); 62401ae08745Sheppo return (ENXIO); 62411ae08745Sheppo } 62421ae08745Sheppo 62433af08d82Slm66018 DMSG(vdc, 0, "[%d] Processing ioctl(%x) for dev %lx : model %x\n", 62443af08d82Slm66018 instance, cmd, dev, ddi_model_convert_from(mode & FMODELS)); 62451ae08745Sheppo 62462f5224aeSachartre if (rvalp != NULL) { 62472f5224aeSachartre /* the return value of the ioctl is 0 by default */ 62482f5224aeSachartre *rvalp = 0; 62492f5224aeSachartre } 62502f5224aeSachartre 62511ae08745Sheppo /* 62521ae08745Sheppo * Validate the ioctl operation to be performed. 62531ae08745Sheppo * 62541ae08745Sheppo * If we have looped through the array without finding a match then we 62551ae08745Sheppo * don't support this ioctl. 62561ae08745Sheppo */ 62571ae08745Sheppo for (idx = 0; idx < nioctls; idx++) { 62581ae08745Sheppo if (cmd == dk_ioctl[idx].cmd) 62591ae08745Sheppo break; 62601ae08745Sheppo } 62611ae08745Sheppo 62621ae08745Sheppo if (idx >= nioctls) { 62633af08d82Slm66018 DMSG(vdc, 0, "[%d] Unsupported ioctl (0x%x)\n", 6264e1ebb9ecSlm66018 vdc->instance, cmd); 62651ae08745Sheppo return (ENOTSUP); 62661ae08745Sheppo } 62671ae08745Sheppo 62683af08d82Slm66018 iop = &(dk_ioctl[idx]); 62693af08d82Slm66018 62704bac2208Snarayan if (cmd == DKIOCGETEFI || cmd == DKIOCSETEFI) { 62714bac2208Snarayan /* size is not fixed for EFI ioctls, it depends on ioctl arg */ 62724bac2208Snarayan dk_efi_t dk_efi; 62734bac2208Snarayan 62744bac2208Snarayan rv = ddi_copyin(arg, &dk_efi, sizeof (dk_efi_t), mode); 62754bac2208Snarayan if (rv != 0) 62764bac2208Snarayan return (EFAULT); 62774bac2208Snarayan 62784bac2208Snarayan len = sizeof (vd_efi_t) - 1 + dk_efi.dki_length; 62794bac2208Snarayan } else { 62803af08d82Slm66018 len = iop->nbytes; 62814bac2208Snarayan } 62821ae08745Sheppo 62832f5224aeSachartre /* check if the ioctl is applicable */ 62841ae08745Sheppo switch (cmd) { 62851ae08745Sheppo case CDROMREADOFFSET: 62861ae08745Sheppo case DKIOCREMOVABLE: 62871ae08745Sheppo return (ENOTTY); 62881ae08745Sheppo 62892f5224aeSachartre case USCSICMD: 62902f5224aeSachartre case MHIOCTKOWN: 62912f5224aeSachartre case MHIOCSTATUS: 62922f5224aeSachartre case MHIOCQRESERVE: 62932f5224aeSachartre case MHIOCRELEASE: 62942f5224aeSachartre case MHIOCGRP_INKEYS: 62952f5224aeSachartre case MHIOCGRP_INRESV: 62962f5224aeSachartre case MHIOCGRP_REGISTER: 62972f5224aeSachartre case MHIOCGRP_RESERVE: 62982f5224aeSachartre case MHIOCGRP_PREEMPTANDABORT: 62992f5224aeSachartre case MHIOCGRP_REGISTERANDIGNOREKEY: 63002f5224aeSachartre case MHIOCENFAILFAST: 63012f5224aeSachartre if (vdc->cinfo == NULL) 63022f5224aeSachartre return (ENXIO); 63032f5224aeSachartre if (vdc->cinfo->dki_ctype != DKC_SCSI_CCS) 63042f5224aeSachartre return (ENOTTY); 63052f5224aeSachartre break; 63062f5224aeSachartre 63072f5224aeSachartre case DIOCTL_RWCMD: 63082f5224aeSachartre if (vdc->cinfo == NULL) 63092f5224aeSachartre return (ENXIO); 63102f5224aeSachartre if (vdc->cinfo->dki_ctype != DKC_DIRECT) 63112f5224aeSachartre return (ENOTTY); 63122f5224aeSachartre break; 63132f5224aeSachartre 63142f5224aeSachartre case DKIOCINFO: 63152f5224aeSachartre if (vdc->cinfo == NULL) 63162f5224aeSachartre return (ENXIO); 63172f5224aeSachartre break; 63182f5224aeSachartre 63192f5224aeSachartre case DKIOCGMEDIAINFO: 63202f5224aeSachartre if (vdc->minfo == NULL) 63212f5224aeSachartre return (ENXIO); 63222f5224aeSachartre if (vdc_check_capacity(vdc) != 0) 63232f5224aeSachartre /* disk capacity is not available */ 63242f5224aeSachartre return (EIO); 63252f5224aeSachartre break; 63262f5224aeSachartre } 63272f5224aeSachartre 63282f5224aeSachartre /* 63292f5224aeSachartre * Deal with ioctls which require a processing different than 63302f5224aeSachartre * converting ioctl arguments and sending a corresponding 63312f5224aeSachartre * VD operation. 63322f5224aeSachartre */ 63332f5224aeSachartre switch (cmd) { 63342f5224aeSachartre 63352f5224aeSachartre case USCSICMD: 63362f5224aeSachartre { 63372f5224aeSachartre return (vdc_uscsi_cmd(vdc, arg, mode)); 63382f5224aeSachartre } 63392f5224aeSachartre 63402f5224aeSachartre case MHIOCTKOWN: 63412f5224aeSachartre { 63422f5224aeSachartre mutex_enter(&vdc->ownership_lock); 63432f5224aeSachartre /* 63442f5224aeSachartre * We have to set VDC_OWNERSHIP_WANTED now so that the ownership 63452f5224aeSachartre * can be flagged with VDC_OWNERSHIP_RESET if the LDC is reset 63462f5224aeSachartre * while we are processing the ioctl. 63472f5224aeSachartre */ 63482f5224aeSachartre vdc_ownership_update(vdc, VDC_OWNERSHIP_WANTED); 63492f5224aeSachartre 63502f5224aeSachartre rv = vdc_access_set(vdc, VD_ACCESS_SET_EXCLUSIVE | 63512f5224aeSachartre VD_ACCESS_SET_PREEMPT | VD_ACCESS_SET_PRESERVE, mode); 63522f5224aeSachartre if (rv == 0) { 63532f5224aeSachartre vdc_ownership_update(vdc, VDC_OWNERSHIP_WANTED | 63542f5224aeSachartre VDC_OWNERSHIP_GRANTED); 63552f5224aeSachartre } else { 63562f5224aeSachartre vdc_ownership_update(vdc, VDC_OWNERSHIP_NONE); 63572f5224aeSachartre } 63582f5224aeSachartre mutex_exit(&vdc->ownership_lock); 63592f5224aeSachartre return (rv); 63602f5224aeSachartre } 63612f5224aeSachartre 63622f5224aeSachartre case MHIOCRELEASE: 63632f5224aeSachartre { 63642f5224aeSachartre mutex_enter(&vdc->ownership_lock); 63652f5224aeSachartre rv = vdc_access_set(vdc, VD_ACCESS_SET_CLEAR, mode); 63662f5224aeSachartre if (rv == 0) { 63672f5224aeSachartre vdc_ownership_update(vdc, VDC_OWNERSHIP_NONE); 63682f5224aeSachartre } 63692f5224aeSachartre mutex_exit(&vdc->ownership_lock); 63702f5224aeSachartre return (rv); 63712f5224aeSachartre } 63722f5224aeSachartre 63732f5224aeSachartre case MHIOCSTATUS: 63742f5224aeSachartre { 63752f5224aeSachartre uint64_t status; 63762f5224aeSachartre 63772f5224aeSachartre rv = vdc_access_get(vdc, &status, mode); 63782f5224aeSachartre if (rv == 0 && rvalp != NULL) 63792f5224aeSachartre *rvalp = (status & VD_ACCESS_ALLOWED)? 0 : 1; 63802f5224aeSachartre return (rv); 63812f5224aeSachartre } 63822f5224aeSachartre 63832f5224aeSachartre case MHIOCQRESERVE: 63842f5224aeSachartre { 63852f5224aeSachartre rv = vdc_access_set(vdc, VD_ACCESS_SET_EXCLUSIVE, mode); 63862f5224aeSachartre return (rv); 63872f5224aeSachartre } 63882f5224aeSachartre 63892f5224aeSachartre case MHIOCGRP_INKEYS: 63902f5224aeSachartre { 63912f5224aeSachartre return (vdc_mhd_inkeys(vdc, arg, mode)); 63922f5224aeSachartre } 63932f5224aeSachartre 63942f5224aeSachartre case MHIOCGRP_INRESV: 63952f5224aeSachartre { 63962f5224aeSachartre return (vdc_mhd_inresv(vdc, arg, mode)); 63972f5224aeSachartre } 63982f5224aeSachartre 63992f5224aeSachartre case MHIOCGRP_REGISTER: 64002f5224aeSachartre { 64012f5224aeSachartre return (vdc_mhd_register(vdc, arg, mode)); 64022f5224aeSachartre } 64032f5224aeSachartre 64042f5224aeSachartre case MHIOCGRP_RESERVE: 64052f5224aeSachartre { 64062f5224aeSachartre return (vdc_mhd_reserve(vdc, arg, mode)); 64072f5224aeSachartre } 64082f5224aeSachartre 64092f5224aeSachartre case MHIOCGRP_PREEMPTANDABORT: 64102f5224aeSachartre { 64112f5224aeSachartre return (vdc_mhd_preemptabort(vdc, arg, mode)); 64122f5224aeSachartre } 64132f5224aeSachartre 64142f5224aeSachartre case MHIOCGRP_REGISTERANDIGNOREKEY: 64152f5224aeSachartre { 64162f5224aeSachartre return (vdc_mhd_registerignore(vdc, arg, mode)); 64172f5224aeSachartre } 64182f5224aeSachartre 64192f5224aeSachartre case MHIOCENFAILFAST: 64202f5224aeSachartre { 64212f5224aeSachartre rv = vdc_failfast(vdc, arg, mode); 64222f5224aeSachartre return (rv); 64232f5224aeSachartre } 64242f5224aeSachartre 642587a7269eSachartre case DIOCTL_RWCMD: 642687a7269eSachartre { 642787a7269eSachartre return (vdc_dioctl_rwcmd(dev, arg, mode)); 642887a7269eSachartre } 642987a7269eSachartre 643087a7269eSachartre case DKIOCGAPART: 643187a7269eSachartre { 643278fcd0a1Sachartre return (vdc_dkio_get_partition(vdc, arg, mode)); 643387a7269eSachartre } 643487a7269eSachartre 64351ae08745Sheppo case DKIOCINFO: 64361ae08745Sheppo { 64371ae08745Sheppo struct dk_cinfo cinfo; 64381ae08745Sheppo 64391ae08745Sheppo bcopy(vdc->cinfo, &cinfo, sizeof (struct dk_cinfo)); 64400d0c8d4bSnarayan cinfo.dki_partition = VDCPART(dev); 64411ae08745Sheppo 64421ae08745Sheppo rv = ddi_copyout(&cinfo, (void *)arg, 64431ae08745Sheppo sizeof (struct dk_cinfo), mode); 64441ae08745Sheppo if (rv != 0) 64451ae08745Sheppo return (EFAULT); 64461ae08745Sheppo 64471ae08745Sheppo return (0); 64481ae08745Sheppo } 64491ae08745Sheppo 64501ae08745Sheppo case DKIOCGMEDIAINFO: 64518e6a2a04Slm66018 { 64522f5224aeSachartre ASSERT(vdc->vdisk_size != 0); 64532f5224aeSachartre if (vdc->minfo->dki_capacity == 0) 64542f5224aeSachartre vdc->minfo->dki_capacity = vdc->vdisk_size; 64551ae08745Sheppo rv = ddi_copyout(vdc->minfo, (void *)arg, 64561ae08745Sheppo sizeof (struct dk_minfo), mode); 64571ae08745Sheppo if (rv != 0) 64581ae08745Sheppo return (EFAULT); 64591ae08745Sheppo 64601ae08745Sheppo return (0); 64611ae08745Sheppo } 64621ae08745Sheppo 64638e6a2a04Slm66018 case DKIOCFLUSHWRITECACHE: 64648e6a2a04Slm66018 { 646517cadca8Slm66018 struct dk_callback *dkc = 646617cadca8Slm66018 (struct dk_callback *)(uintptr_t)arg; 64678e6a2a04Slm66018 vdc_dk_arg_t *dkarg = NULL; 64688e6a2a04Slm66018 64693af08d82Slm66018 DMSG(vdc, 1, "[%d] Flush W$: mode %x\n", 64703af08d82Slm66018 instance, mode); 64718e6a2a04Slm66018 64728e6a2a04Slm66018 /* 64738e6a2a04Slm66018 * If arg is NULL, then there is no callback function 64748e6a2a04Slm66018 * registered and the call operates synchronously; we 64758e6a2a04Slm66018 * break and continue with the rest of the function and 64768e6a2a04Slm66018 * wait for vds to return (i.e. after the request to 64778e6a2a04Slm66018 * vds returns successfully, all writes completed prior 64788e6a2a04Slm66018 * to the ioctl will have been flushed from the disk 64798e6a2a04Slm66018 * write cache to persistent media. 64808e6a2a04Slm66018 * 64818e6a2a04Slm66018 * If a callback function is registered, we dispatch 64828e6a2a04Slm66018 * the request on a task queue and return immediately. 64838e6a2a04Slm66018 * The callback will deal with informing the calling 64848e6a2a04Slm66018 * thread that the flush request is completed. 64858e6a2a04Slm66018 */ 64868e6a2a04Slm66018 if (dkc == NULL) 64878e6a2a04Slm66018 break; 64888e6a2a04Slm66018 6489eff7243fSlm66018 /* 6490eff7243fSlm66018 * the asynchronous callback is only supported if 6491eff7243fSlm66018 * invoked from within the kernel 6492eff7243fSlm66018 */ 6493eff7243fSlm66018 if ((mode & FKIOCTL) == 0) 6494eff7243fSlm66018 return (ENOTSUP); 6495eff7243fSlm66018 64968e6a2a04Slm66018 dkarg = kmem_zalloc(sizeof (vdc_dk_arg_t), KM_SLEEP); 64978e6a2a04Slm66018 64988e6a2a04Slm66018 dkarg->mode = mode; 64998e6a2a04Slm66018 dkarg->dev = dev; 65008e6a2a04Slm66018 bcopy(dkc, &dkarg->dkc, sizeof (*dkc)); 65018e6a2a04Slm66018 65028e6a2a04Slm66018 mutex_enter(&vdc->lock); 65038e6a2a04Slm66018 vdc->dkio_flush_pending++; 65048e6a2a04Slm66018 dkarg->vdc = vdc; 65058e6a2a04Slm66018 mutex_exit(&vdc->lock); 65068e6a2a04Slm66018 65078e6a2a04Slm66018 /* put the request on a task queue */ 65088e6a2a04Slm66018 rv = taskq_dispatch(system_taskq, vdc_dkio_flush_cb, 65098e6a2a04Slm66018 (void *)dkarg, DDI_SLEEP); 65103af08d82Slm66018 if (rv == NULL) { 65113af08d82Slm66018 /* clean up if dispatch fails */ 65123af08d82Slm66018 mutex_enter(&vdc->lock); 65133af08d82Slm66018 vdc->dkio_flush_pending--; 651478fcd0a1Sachartre mutex_exit(&vdc->lock); 65153af08d82Slm66018 kmem_free(dkarg, sizeof (vdc_dk_arg_t)); 65163af08d82Slm66018 } 65178e6a2a04Slm66018 65188e6a2a04Slm66018 return (rv == NULL ? ENOMEM : 0); 65198e6a2a04Slm66018 } 65208e6a2a04Slm66018 } 65218e6a2a04Slm66018 65221ae08745Sheppo /* catch programming error in vdc - should be a VD_OP_XXX ioctl */ 65233af08d82Slm66018 ASSERT(iop->op != 0); 65241ae08745Sheppo 652517cadca8Slm66018 /* check if the vDisk server handles the operation for this vDisk */ 652617cadca8Slm66018 if (VD_OP_SUPPORTED(vdc->operations, iop->op) == B_FALSE) { 652717cadca8Slm66018 DMSG(vdc, 0, "[%d] Unsupported VD_OP operation (0x%x)\n", 652817cadca8Slm66018 vdc->instance, iop->op); 652917cadca8Slm66018 return (ENOTSUP); 653017cadca8Slm66018 } 653117cadca8Slm66018 65321ae08745Sheppo /* LDC requires that the memory being mapped is 8-byte aligned */ 65331ae08745Sheppo alloc_len = P2ROUNDUP(len, sizeof (uint64_t)); 65343af08d82Slm66018 DMSG(vdc, 1, "[%d] struct size %ld alloc %ld\n", 65353af08d82Slm66018 instance, len, alloc_len); 65361ae08745Sheppo 6537eff7243fSlm66018 if (alloc_len > 0) 65381ae08745Sheppo mem_p = kmem_zalloc(alloc_len, KM_SLEEP); 65391ae08745Sheppo 65400a55fbb7Slm66018 /* 6541eff7243fSlm66018 * Call the conversion function for this ioctl which, if necessary, 65420a55fbb7Slm66018 * converts from the Solaris format to the format ARC'ed 65430a55fbb7Slm66018 * as part of the vDisk protocol (FWARC 2006/195) 65440a55fbb7Slm66018 */ 65453af08d82Slm66018 ASSERT(iop->convert != NULL); 65463af08d82Slm66018 rv = (iop->convert)(vdc, arg, mem_p, mode, VD_COPYIN); 65471ae08745Sheppo if (rv != 0) { 65483af08d82Slm66018 DMSG(vdc, 0, "[%d] convert func returned %d for ioctl 0x%x\n", 6549e1ebb9ecSlm66018 instance, rv, cmd); 65501ae08745Sheppo if (mem_p != NULL) 65511ae08745Sheppo kmem_free(mem_p, alloc_len); 65520a55fbb7Slm66018 return (rv); 65531ae08745Sheppo } 65541ae08745Sheppo 65551ae08745Sheppo /* 65561ae08745Sheppo * send request to vds to service the ioctl. 65571ae08745Sheppo */ 65583af08d82Slm66018 rv = vdc_do_sync_op(vdc, iop->op, mem_p, alloc_len, 65590d0c8d4bSnarayan VDCPART(dev), 0, CB_SYNC, (void *)(uint64_t)mode, 65602f5224aeSachartre VIO_both_dir, B_TRUE); 656178fcd0a1Sachartre 65621ae08745Sheppo if (rv != 0) { 65631ae08745Sheppo /* 65641ae08745Sheppo * This is not necessarily an error. The ioctl could 65651ae08745Sheppo * be returning a value such as ENOTTY to indicate 65661ae08745Sheppo * that the ioctl is not applicable. 65671ae08745Sheppo */ 65683af08d82Slm66018 DMSG(vdc, 0, "[%d] vds returned %d for ioctl 0x%x\n", 6569e1ebb9ecSlm66018 instance, rv, cmd); 65701ae08745Sheppo if (mem_p != NULL) 65711ae08745Sheppo kmem_free(mem_p, alloc_len); 6572d10e4ef2Snarayan 65731ae08745Sheppo return (rv); 65741ae08745Sheppo } 65751ae08745Sheppo 65761ae08745Sheppo /* 65770a55fbb7Slm66018 * Call the conversion function (if it exists) for this ioctl 65780a55fbb7Slm66018 * which converts from the format ARC'ed as part of the vDisk 65790a55fbb7Slm66018 * protocol (FWARC 2006/195) back to a format understood by 65800a55fbb7Slm66018 * the rest of Solaris. 65811ae08745Sheppo */ 65823af08d82Slm66018 rv = (iop->convert)(vdc, mem_p, arg, mode, VD_COPYOUT); 65830a55fbb7Slm66018 if (rv != 0) { 65843af08d82Slm66018 DMSG(vdc, 0, "[%d] convert func returned %d for ioctl 0x%x\n", 6585e1ebb9ecSlm66018 instance, rv, cmd); 65861ae08745Sheppo if (mem_p != NULL) 65871ae08745Sheppo kmem_free(mem_p, alloc_len); 65880a55fbb7Slm66018 return (rv); 65891ae08745Sheppo } 65901ae08745Sheppo 65911ae08745Sheppo if (mem_p != NULL) 65921ae08745Sheppo kmem_free(mem_p, alloc_len); 65931ae08745Sheppo 65941ae08745Sheppo return (rv); 65951ae08745Sheppo } 65961ae08745Sheppo 65971ae08745Sheppo /* 65981ae08745Sheppo * Function: 65990a55fbb7Slm66018 * 66000a55fbb7Slm66018 * Description: 66010a55fbb7Slm66018 * This is an empty conversion function used by ioctl calls which 66020a55fbb7Slm66018 * do not need to convert the data being passed in/out to userland 66030a55fbb7Slm66018 */ 66040a55fbb7Slm66018 static int 6605d10e4ef2Snarayan vdc_null_copy_func(vdc_t *vdc, void *from, void *to, int mode, int dir) 66060a55fbb7Slm66018 { 6607d10e4ef2Snarayan _NOTE(ARGUNUSED(vdc)) 66080a55fbb7Slm66018 _NOTE(ARGUNUSED(from)) 66090a55fbb7Slm66018 _NOTE(ARGUNUSED(to)) 66100a55fbb7Slm66018 _NOTE(ARGUNUSED(mode)) 66110a55fbb7Slm66018 _NOTE(ARGUNUSED(dir)) 66120a55fbb7Slm66018 66130a55fbb7Slm66018 return (0); 66140a55fbb7Slm66018 } 66150a55fbb7Slm66018 66164bac2208Snarayan static int 66174bac2208Snarayan vdc_get_wce_convert(vdc_t *vdc, void *from, void *to, 66184bac2208Snarayan int mode, int dir) 66194bac2208Snarayan { 66204bac2208Snarayan _NOTE(ARGUNUSED(vdc)) 66214bac2208Snarayan 66224bac2208Snarayan if (dir == VD_COPYIN) 66234bac2208Snarayan return (0); /* nothing to do */ 66244bac2208Snarayan 66254bac2208Snarayan if (ddi_copyout(from, to, sizeof (int), mode) != 0) 66264bac2208Snarayan return (EFAULT); 66274bac2208Snarayan 66284bac2208Snarayan return (0); 66294bac2208Snarayan } 66304bac2208Snarayan 66314bac2208Snarayan static int 66324bac2208Snarayan vdc_set_wce_convert(vdc_t *vdc, void *from, void *to, 66334bac2208Snarayan int mode, int dir) 66344bac2208Snarayan { 66354bac2208Snarayan _NOTE(ARGUNUSED(vdc)) 66364bac2208Snarayan 66374bac2208Snarayan if (dir == VD_COPYOUT) 66384bac2208Snarayan return (0); /* nothing to do */ 66394bac2208Snarayan 66404bac2208Snarayan if (ddi_copyin(from, to, sizeof (int), mode) != 0) 66414bac2208Snarayan return (EFAULT); 66424bac2208Snarayan 66434bac2208Snarayan return (0); 66444bac2208Snarayan } 66454bac2208Snarayan 66460a55fbb7Slm66018 /* 66470a55fbb7Slm66018 * Function: 66480a55fbb7Slm66018 * vdc_get_vtoc_convert() 66490a55fbb7Slm66018 * 66500a55fbb7Slm66018 * Description: 6651d10e4ef2Snarayan * This routine performs the necessary convertions from the DKIOCGVTOC 6652d10e4ef2Snarayan * Solaris structure to the format defined in FWARC 2006/195. 6653d10e4ef2Snarayan * 6654d10e4ef2Snarayan * In the struct vtoc definition, the timestamp field is marked as not 6655d10e4ef2Snarayan * supported so it is not part of vDisk protocol (FWARC 2006/195). 6656d10e4ef2Snarayan * However SVM uses that field to check it can write into the VTOC, 6657d10e4ef2Snarayan * so we fake up the info of that field. 66580a55fbb7Slm66018 * 66590a55fbb7Slm66018 * Arguments: 6660d10e4ef2Snarayan * vdc - the vDisk client 66610a55fbb7Slm66018 * from - the buffer containing the data to be copied from 66620a55fbb7Slm66018 * to - the buffer to be copied to 66630a55fbb7Slm66018 * mode - flags passed to ioctl() call 66640a55fbb7Slm66018 * dir - the "direction" of the copy - VD_COPYIN or VD_COPYOUT 66650a55fbb7Slm66018 * 66660a55fbb7Slm66018 * Return Code: 66670a55fbb7Slm66018 * 0 - Success 66680a55fbb7Slm66018 * ENXIO - incorrect buffer passed in. 6669d10e4ef2Snarayan * EFAULT - ddi_copyout routine encountered an error. 66700a55fbb7Slm66018 */ 66710a55fbb7Slm66018 static int 6672d10e4ef2Snarayan vdc_get_vtoc_convert(vdc_t *vdc, void *from, void *to, int mode, int dir) 66730a55fbb7Slm66018 { 6674d10e4ef2Snarayan int i; 66750a55fbb7Slm66018 void *tmp_mem = NULL; 66760a55fbb7Slm66018 void *tmp_memp; 66770a55fbb7Slm66018 struct vtoc vt; 66780a55fbb7Slm66018 struct vtoc32 vt32; 66790a55fbb7Slm66018 int copy_len = 0; 66800a55fbb7Slm66018 int rv = 0; 66810a55fbb7Slm66018 66820a55fbb7Slm66018 if (dir != VD_COPYOUT) 66830a55fbb7Slm66018 return (0); /* nothing to do */ 66840a55fbb7Slm66018 66850a55fbb7Slm66018 if ((from == NULL) || (to == NULL)) 66860a55fbb7Slm66018 return (ENXIO); 66870a55fbb7Slm66018 66880a55fbb7Slm66018 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) 66890a55fbb7Slm66018 copy_len = sizeof (struct vtoc32); 66900a55fbb7Slm66018 else 66910a55fbb7Slm66018 copy_len = sizeof (struct vtoc); 66920a55fbb7Slm66018 66930a55fbb7Slm66018 tmp_mem = kmem_alloc(copy_len, KM_SLEEP); 66940a55fbb7Slm66018 66950a55fbb7Slm66018 VD_VTOC2VTOC((vd_vtoc_t *)from, &vt); 6696d10e4ef2Snarayan 6697d10e4ef2Snarayan /* fake the VTOC timestamp field */ 6698d10e4ef2Snarayan for (i = 0; i < V_NUMPAR; i++) { 6699d10e4ef2Snarayan vt.timestamp[i] = vdc->vtoc->timestamp[i]; 6700d10e4ef2Snarayan } 6701d10e4ef2Snarayan 67020a55fbb7Slm66018 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 670317cadca8Slm66018 /* LINTED E_ASSIGN_NARROW_CONV */ 67040a55fbb7Slm66018 vtoctovtoc32(vt, vt32); 67050a55fbb7Slm66018 tmp_memp = &vt32; 67060a55fbb7Slm66018 } else { 67070a55fbb7Slm66018 tmp_memp = &vt; 67080a55fbb7Slm66018 } 67090a55fbb7Slm66018 rv = ddi_copyout(tmp_memp, to, copy_len, mode); 67100a55fbb7Slm66018 if (rv != 0) 67110a55fbb7Slm66018 rv = EFAULT; 67120a55fbb7Slm66018 67130a55fbb7Slm66018 kmem_free(tmp_mem, copy_len); 67140a55fbb7Slm66018 return (rv); 67150a55fbb7Slm66018 } 67160a55fbb7Slm66018 67170a55fbb7Slm66018 /* 67180a55fbb7Slm66018 * Function: 67190a55fbb7Slm66018 * vdc_set_vtoc_convert() 67200a55fbb7Slm66018 * 67210a55fbb7Slm66018 * Description: 6722d10e4ef2Snarayan * This routine performs the necessary convertions from the DKIOCSVTOC 6723d10e4ef2Snarayan * Solaris structure to the format defined in FWARC 2006/195. 67240a55fbb7Slm66018 * 67250a55fbb7Slm66018 * Arguments: 6726d10e4ef2Snarayan * vdc - the vDisk client 67270a55fbb7Slm66018 * from - Buffer with data 67280a55fbb7Slm66018 * to - Buffer where data is to be copied to 67290a55fbb7Slm66018 * mode - flags passed to ioctl 67300a55fbb7Slm66018 * dir - direction of copy (in or out) 67310a55fbb7Slm66018 * 67320a55fbb7Slm66018 * Return Code: 67330a55fbb7Slm66018 * 0 - Success 67340a55fbb7Slm66018 * ENXIO - Invalid buffer passed in 67350a55fbb7Slm66018 * EFAULT - ddi_copyin of data failed 67360a55fbb7Slm66018 */ 67370a55fbb7Slm66018 static int 6738d10e4ef2Snarayan vdc_set_vtoc_convert(vdc_t *vdc, void *from, void *to, int mode, int dir) 67390a55fbb7Slm66018 { 674078fcd0a1Sachartre _NOTE(ARGUNUSED(vdc)) 674178fcd0a1Sachartre 67422f5224aeSachartre void *tmp_mem = NULL, *uvtoc; 67430a55fbb7Slm66018 struct vtoc vt; 67440a55fbb7Slm66018 struct vtoc *vtp = &vt; 67450a55fbb7Slm66018 vd_vtoc_t vtvd; 67460a55fbb7Slm66018 int copy_len = 0; 67472f5224aeSachartre int i, rv = 0; 67480a55fbb7Slm66018 67490a55fbb7Slm66018 if ((from == NULL) || (to == NULL)) 67500a55fbb7Slm66018 return (ENXIO); 67510a55fbb7Slm66018 67522f5224aeSachartre if (dir == VD_COPYIN) 67532f5224aeSachartre uvtoc = from; 67542f5224aeSachartre else 67552f5224aeSachartre uvtoc = to; 67562f5224aeSachartre 67570a55fbb7Slm66018 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) 67580a55fbb7Slm66018 copy_len = sizeof (struct vtoc32); 67590a55fbb7Slm66018 else 67600a55fbb7Slm66018 copy_len = sizeof (struct vtoc); 67610a55fbb7Slm66018 67620a55fbb7Slm66018 tmp_mem = kmem_alloc(copy_len, KM_SLEEP); 67630a55fbb7Slm66018 67642f5224aeSachartre rv = ddi_copyin(uvtoc, tmp_mem, copy_len, mode); 67650a55fbb7Slm66018 if (rv != 0) { 67660a55fbb7Slm66018 kmem_free(tmp_mem, copy_len); 67670a55fbb7Slm66018 return (EFAULT); 67680a55fbb7Slm66018 } 67690a55fbb7Slm66018 67700a55fbb7Slm66018 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 67710a55fbb7Slm66018 vtoc32tovtoc((*(struct vtoc32 *)tmp_mem), vt); 67720a55fbb7Slm66018 } else { 67730a55fbb7Slm66018 vtp = tmp_mem; 67740a55fbb7Slm66018 } 67750a55fbb7Slm66018 67762f5224aeSachartre if (dir == VD_COPYOUT) { 67772f5224aeSachartre /* 67782f5224aeSachartre * The disk label may have changed. Revalidate the disk 67792f5224aeSachartre * geometry. This will also update the device nodes and 67802f5224aeSachartre * properties. 67812f5224aeSachartre */ 67822f5224aeSachartre vdc_validate(vdc); 67832f5224aeSachartre 67842f5224aeSachartre /* 67852f5224aeSachartre * We also need to keep track of the timestamp fields. 67862f5224aeSachartre */ 67872f5224aeSachartre for (i = 0; i < V_NUMPAR; i++) { 67882f5224aeSachartre vdc->vtoc->timestamp[i] = vtp->timestamp[i]; 67892f5224aeSachartre } 67902f5224aeSachartre 67912f5224aeSachartre return (0); 67922f5224aeSachartre } 67932f5224aeSachartre 67940a55fbb7Slm66018 VTOC2VD_VTOC(vtp, &vtvd); 67950a55fbb7Slm66018 bcopy(&vtvd, to, sizeof (vd_vtoc_t)); 67960a55fbb7Slm66018 kmem_free(tmp_mem, copy_len); 67970a55fbb7Slm66018 67980a55fbb7Slm66018 return (0); 67990a55fbb7Slm66018 } 68000a55fbb7Slm66018 68010a55fbb7Slm66018 /* 68020a55fbb7Slm66018 * Function: 68030a55fbb7Slm66018 * vdc_get_geom_convert() 68040a55fbb7Slm66018 * 68050a55fbb7Slm66018 * Description: 6806d10e4ef2Snarayan * This routine performs the necessary convertions from the DKIOCGGEOM, 6807d10e4ef2Snarayan * DKIOCG_PHYSGEOM and DKIOG_VIRTGEOM Solaris structures to the format 6808d10e4ef2Snarayan * defined in FWARC 2006/195 68090a55fbb7Slm66018 * 68100a55fbb7Slm66018 * Arguments: 6811d10e4ef2Snarayan * vdc - the vDisk client 68120a55fbb7Slm66018 * from - Buffer with data 68130a55fbb7Slm66018 * to - Buffer where data is to be copied to 68140a55fbb7Slm66018 * mode - flags passed to ioctl 68150a55fbb7Slm66018 * dir - direction of copy (in or out) 68160a55fbb7Slm66018 * 68170a55fbb7Slm66018 * Return Code: 68180a55fbb7Slm66018 * 0 - Success 68190a55fbb7Slm66018 * ENXIO - Invalid buffer passed in 6820d10e4ef2Snarayan * EFAULT - ddi_copyout of data failed 68210a55fbb7Slm66018 */ 68220a55fbb7Slm66018 static int 6823d10e4ef2Snarayan vdc_get_geom_convert(vdc_t *vdc, void *from, void *to, int mode, int dir) 68240a55fbb7Slm66018 { 6825d10e4ef2Snarayan _NOTE(ARGUNUSED(vdc)) 6826d10e4ef2Snarayan 68270a55fbb7Slm66018 struct dk_geom geom; 68280a55fbb7Slm66018 int copy_len = sizeof (struct dk_geom); 68290a55fbb7Slm66018 int rv = 0; 68300a55fbb7Slm66018 68310a55fbb7Slm66018 if (dir != VD_COPYOUT) 68320a55fbb7Slm66018 return (0); /* nothing to do */ 68330a55fbb7Slm66018 68340a55fbb7Slm66018 if ((from == NULL) || (to == NULL)) 68350a55fbb7Slm66018 return (ENXIO); 68360a55fbb7Slm66018 68370a55fbb7Slm66018 VD_GEOM2DK_GEOM((vd_geom_t *)from, &geom); 68380a55fbb7Slm66018 rv = ddi_copyout(&geom, to, copy_len, mode); 68390a55fbb7Slm66018 if (rv != 0) 68400a55fbb7Slm66018 rv = EFAULT; 68410a55fbb7Slm66018 68420a55fbb7Slm66018 return (rv); 68430a55fbb7Slm66018 } 68440a55fbb7Slm66018 68450a55fbb7Slm66018 /* 68460a55fbb7Slm66018 * Function: 68470a55fbb7Slm66018 * vdc_set_geom_convert() 68480a55fbb7Slm66018 * 68490a55fbb7Slm66018 * Description: 6850d10e4ef2Snarayan * This routine performs the necessary convertions from the DKIOCSGEOM 6851d10e4ef2Snarayan * Solaris structure to the format defined in FWARC 2006/195. 68520a55fbb7Slm66018 * 68530a55fbb7Slm66018 * Arguments: 6854d10e4ef2Snarayan * vdc - the vDisk client 68550a55fbb7Slm66018 * from - Buffer with data 68560a55fbb7Slm66018 * to - Buffer where data is to be copied to 68570a55fbb7Slm66018 * mode - flags passed to ioctl 68580a55fbb7Slm66018 * dir - direction of copy (in or out) 68590a55fbb7Slm66018 * 68600a55fbb7Slm66018 * Return Code: 68610a55fbb7Slm66018 * 0 - Success 68620a55fbb7Slm66018 * ENXIO - Invalid buffer passed in 68630a55fbb7Slm66018 * EFAULT - ddi_copyin of data failed 68640a55fbb7Slm66018 */ 68650a55fbb7Slm66018 static int 6866d10e4ef2Snarayan vdc_set_geom_convert(vdc_t *vdc, void *from, void *to, int mode, int dir) 68670a55fbb7Slm66018 { 6868d10e4ef2Snarayan _NOTE(ARGUNUSED(vdc)) 6869d10e4ef2Snarayan 68700a55fbb7Slm66018 vd_geom_t vdgeom; 68710a55fbb7Slm66018 void *tmp_mem = NULL; 68720a55fbb7Slm66018 int copy_len = sizeof (struct dk_geom); 68730a55fbb7Slm66018 int rv = 0; 68740a55fbb7Slm66018 68750a55fbb7Slm66018 if (dir != VD_COPYIN) 68760a55fbb7Slm66018 return (0); /* nothing to do */ 68770a55fbb7Slm66018 68780a55fbb7Slm66018 if ((from == NULL) || (to == NULL)) 68790a55fbb7Slm66018 return (ENXIO); 68800a55fbb7Slm66018 68810a55fbb7Slm66018 tmp_mem = kmem_alloc(copy_len, KM_SLEEP); 68820a55fbb7Slm66018 68830a55fbb7Slm66018 rv = ddi_copyin(from, tmp_mem, copy_len, mode); 68840a55fbb7Slm66018 if (rv != 0) { 68850a55fbb7Slm66018 kmem_free(tmp_mem, copy_len); 68860a55fbb7Slm66018 return (EFAULT); 68870a55fbb7Slm66018 } 68880a55fbb7Slm66018 DK_GEOM2VD_GEOM((struct dk_geom *)tmp_mem, &vdgeom); 68890a55fbb7Slm66018 bcopy(&vdgeom, to, sizeof (vdgeom)); 68900a55fbb7Slm66018 kmem_free(tmp_mem, copy_len); 68910a55fbb7Slm66018 68920a55fbb7Slm66018 return (0); 68930a55fbb7Slm66018 } 68940a55fbb7Slm66018 68954bac2208Snarayan static int 68964bac2208Snarayan vdc_get_efi_convert(vdc_t *vdc, void *from, void *to, int mode, int dir) 68974bac2208Snarayan { 68984bac2208Snarayan _NOTE(ARGUNUSED(vdc)) 68994bac2208Snarayan 69004bac2208Snarayan vd_efi_t *vd_efi; 69014bac2208Snarayan dk_efi_t dk_efi; 69024bac2208Snarayan int rv = 0; 69034bac2208Snarayan void *uaddr; 69044bac2208Snarayan 69054bac2208Snarayan if ((from == NULL) || (to == NULL)) 69064bac2208Snarayan return (ENXIO); 69074bac2208Snarayan 69084bac2208Snarayan if (dir == VD_COPYIN) { 69094bac2208Snarayan 69104bac2208Snarayan vd_efi = (vd_efi_t *)to; 69114bac2208Snarayan 69124bac2208Snarayan rv = ddi_copyin(from, &dk_efi, sizeof (dk_efi_t), mode); 69134bac2208Snarayan if (rv != 0) 69144bac2208Snarayan return (EFAULT); 69154bac2208Snarayan 69164bac2208Snarayan vd_efi->lba = dk_efi.dki_lba; 69174bac2208Snarayan vd_efi->length = dk_efi.dki_length; 69184bac2208Snarayan bzero(vd_efi->data, vd_efi->length); 69194bac2208Snarayan 69204bac2208Snarayan } else { 69214bac2208Snarayan 69224bac2208Snarayan rv = ddi_copyin(to, &dk_efi, sizeof (dk_efi_t), mode); 69234bac2208Snarayan if (rv != 0) 69244bac2208Snarayan return (EFAULT); 69254bac2208Snarayan 69264bac2208Snarayan uaddr = dk_efi.dki_data; 69274bac2208Snarayan 69284bac2208Snarayan dk_efi.dki_data = kmem_alloc(dk_efi.dki_length, KM_SLEEP); 69294bac2208Snarayan 69304bac2208Snarayan VD_EFI2DK_EFI((vd_efi_t *)from, &dk_efi); 69314bac2208Snarayan 69324bac2208Snarayan rv = ddi_copyout(dk_efi.dki_data, uaddr, dk_efi.dki_length, 69334bac2208Snarayan mode); 69344bac2208Snarayan if (rv != 0) 69354bac2208Snarayan return (EFAULT); 69364bac2208Snarayan 69374bac2208Snarayan kmem_free(dk_efi.dki_data, dk_efi.dki_length); 69384bac2208Snarayan } 69394bac2208Snarayan 69404bac2208Snarayan return (0); 69414bac2208Snarayan } 69424bac2208Snarayan 69434bac2208Snarayan static int 69444bac2208Snarayan vdc_set_efi_convert(vdc_t *vdc, void *from, void *to, int mode, int dir) 69454bac2208Snarayan { 69464bac2208Snarayan _NOTE(ARGUNUSED(vdc)) 69474bac2208Snarayan 69484bac2208Snarayan dk_efi_t dk_efi; 69494bac2208Snarayan void *uaddr; 69504bac2208Snarayan 69512f5224aeSachartre if (dir == VD_COPYOUT) { 69522f5224aeSachartre /* 69532f5224aeSachartre * The disk label may have changed. Revalidate the disk 69542f5224aeSachartre * geometry. This will also update the device nodes and 69552f5224aeSachartre * properties. 69562f5224aeSachartre */ 69572f5224aeSachartre vdc_validate(vdc); 69582f5224aeSachartre return (0); 69592f5224aeSachartre } 69604bac2208Snarayan 69614bac2208Snarayan if ((from == NULL) || (to == NULL)) 69624bac2208Snarayan return (ENXIO); 69634bac2208Snarayan 69644bac2208Snarayan if (ddi_copyin(from, &dk_efi, sizeof (dk_efi_t), mode) != 0) 69654bac2208Snarayan return (EFAULT); 69664bac2208Snarayan 69674bac2208Snarayan uaddr = dk_efi.dki_data; 69684bac2208Snarayan 69694bac2208Snarayan dk_efi.dki_data = kmem_alloc(dk_efi.dki_length, KM_SLEEP); 69704bac2208Snarayan 69714bac2208Snarayan if (ddi_copyin(uaddr, dk_efi.dki_data, dk_efi.dki_length, mode) != 0) 69724bac2208Snarayan return (EFAULT); 69734bac2208Snarayan 69744bac2208Snarayan DK_EFI2VD_EFI(&dk_efi, (vd_efi_t *)to); 69754bac2208Snarayan 69764bac2208Snarayan kmem_free(dk_efi.dki_data, dk_efi.dki_length); 69774bac2208Snarayan 69784bac2208Snarayan return (0); 69794bac2208Snarayan } 69804bac2208Snarayan 698117cadca8Slm66018 698217cadca8Slm66018 /* -------------------------------------------------------------------------- */ 698317cadca8Slm66018 69840a55fbb7Slm66018 /* 69850a55fbb7Slm66018 * Function: 69861ae08745Sheppo * vdc_create_fake_geometry() 69871ae08745Sheppo * 69881ae08745Sheppo * Description: 698917cadca8Slm66018 * This routine fakes up the disk info needed for some DKIO ioctls such 699017cadca8Slm66018 * as DKIOCINFO and DKIOCGMEDIAINFO [just like lofi(7D) and ramdisk(7D) do] 69911ae08745Sheppo * 699217cadca8Slm66018 * Note: This function must not be called until the vDisk attributes have 699317cadca8Slm66018 * been exchanged as part of the handshake with the vDisk server. 69941ae08745Sheppo * 69951ae08745Sheppo * Arguments: 69961ae08745Sheppo * vdc - soft state pointer for this instance of the device driver. 69971ae08745Sheppo * 69981ae08745Sheppo * Return Code: 699978fcd0a1Sachartre * none. 70001ae08745Sheppo */ 700178fcd0a1Sachartre static void 70021ae08745Sheppo vdc_create_fake_geometry(vdc_t *vdc) 70031ae08745Sheppo { 70041ae08745Sheppo ASSERT(vdc != NULL); 700578fcd0a1Sachartre ASSERT(vdc->max_xfer_sz != 0); 70060d0c8d4bSnarayan 70070d0c8d4bSnarayan /* 70081ae08745Sheppo * DKIOCINFO support 70091ae08745Sheppo */ 701078fcd0a1Sachartre if (vdc->cinfo == NULL) 70111ae08745Sheppo vdc->cinfo = kmem_zalloc(sizeof (struct dk_cinfo), KM_SLEEP); 70121ae08745Sheppo 70131ae08745Sheppo (void) strcpy(vdc->cinfo->dki_cname, VDC_DRIVER_NAME); 70141ae08745Sheppo (void) strcpy(vdc->cinfo->dki_dname, VDC_DRIVER_NAME); 70158e6a2a04Slm66018 /* max_xfer_sz is #blocks so we don't need to divide by DEV_BSIZE */ 70168e6a2a04Slm66018 vdc->cinfo->dki_maxtransfer = vdc->max_xfer_sz; 70172f5224aeSachartre 701887a7269eSachartre /* 70192f5224aeSachartre * We set the controller type to DKC_SCSI_CCS only if the VD_OP_SCSICMD 70202f5224aeSachartre * operation is supported, otherwise the controller type is DKC_DIRECT. 70212f5224aeSachartre * Version 1.0 does not support the VD_OP_SCSICMD operation, so the 70222f5224aeSachartre * controller type is always DKC_DIRECT in that case. 70232f5224aeSachartre * 702417cadca8Slm66018 * If the virtual disk is backed by a physical CD/DVD device or 702517cadca8Slm66018 * an ISO image, modify the controller type to indicate this 702687a7269eSachartre */ 702717cadca8Slm66018 switch (vdc->vdisk_media) { 702817cadca8Slm66018 case VD_MEDIA_CD: 702917cadca8Slm66018 case VD_MEDIA_DVD: 703017cadca8Slm66018 vdc->cinfo->dki_ctype = DKC_CDROM; 703117cadca8Slm66018 break; 703217cadca8Slm66018 case VD_MEDIA_FIXED: 70332f5224aeSachartre if (VD_OP_SUPPORTED(vdc->operations, VD_OP_SCSICMD)) 70342f5224aeSachartre vdc->cinfo->dki_ctype = DKC_SCSI_CCS; 70352f5224aeSachartre else 703687a7269eSachartre vdc->cinfo->dki_ctype = DKC_DIRECT; 703717cadca8Slm66018 break; 703817cadca8Slm66018 default: 703917cadca8Slm66018 /* in the case of v1.0 we default to a fixed disk */ 704017cadca8Slm66018 vdc->cinfo->dki_ctype = DKC_DIRECT; 704117cadca8Slm66018 break; 704217cadca8Slm66018 } 70431ae08745Sheppo vdc->cinfo->dki_flags = DKI_FMTVOL; 70441ae08745Sheppo vdc->cinfo->dki_cnum = 0; 70451ae08745Sheppo vdc->cinfo->dki_addr = 0; 70461ae08745Sheppo vdc->cinfo->dki_space = 0; 70471ae08745Sheppo vdc->cinfo->dki_prio = 0; 70481ae08745Sheppo vdc->cinfo->dki_vec = 0; 70491ae08745Sheppo vdc->cinfo->dki_unit = vdc->instance; 70501ae08745Sheppo vdc->cinfo->dki_slave = 0; 70511ae08745Sheppo /* 70521ae08745Sheppo * The partition number will be created on the fly depending on the 70531ae08745Sheppo * actual slice (i.e. minor node) that is used to request the data. 70541ae08745Sheppo */ 70551ae08745Sheppo vdc->cinfo->dki_partition = 0; 70561ae08745Sheppo 70571ae08745Sheppo /* 70581ae08745Sheppo * DKIOCGMEDIAINFO support 70591ae08745Sheppo */ 70600a55fbb7Slm66018 if (vdc->minfo == NULL) 70611ae08745Sheppo vdc->minfo = kmem_zalloc(sizeof (struct dk_minfo), KM_SLEEP); 706217cadca8Slm66018 706317cadca8Slm66018 if (vio_ver_is_supported(vdc->ver, 1, 1)) { 706417cadca8Slm66018 vdc->minfo->dki_media_type = 706517cadca8Slm66018 VD_MEDIATYPE2DK_MEDIATYPE(vdc->vdisk_media); 706617cadca8Slm66018 } else { 70671ae08745Sheppo vdc->minfo->dki_media_type = DK_FIXED_DISK; 706817cadca8Slm66018 } 706917cadca8Slm66018 70704bac2208Snarayan vdc->minfo->dki_capacity = vdc->vdisk_size; 707117cadca8Slm66018 vdc->minfo->dki_lbsize = vdc->block_size; 707278fcd0a1Sachartre } 70731ae08745Sheppo 707478fcd0a1Sachartre static ushort_t 707578fcd0a1Sachartre vdc_lbl2cksum(struct dk_label *label) 707678fcd0a1Sachartre { 707778fcd0a1Sachartre int count; 707878fcd0a1Sachartre ushort_t sum, *sp; 707978fcd0a1Sachartre 708078fcd0a1Sachartre count = (sizeof (struct dk_label)) / (sizeof (short)) - 1; 708178fcd0a1Sachartre sp = (ushort_t *)label; 708278fcd0a1Sachartre sum = 0; 708378fcd0a1Sachartre while (count--) { 708478fcd0a1Sachartre sum ^= *sp++; 708578fcd0a1Sachartre } 708678fcd0a1Sachartre 708778fcd0a1Sachartre return (sum); 70880a55fbb7Slm66018 } 70890a55fbb7Slm66018 70900a55fbb7Slm66018 /* 70910a55fbb7Slm66018 * Function: 709278fcd0a1Sachartre * vdc_validate_geometry 70930a55fbb7Slm66018 * 70940a55fbb7Slm66018 * Description: 709578fcd0a1Sachartre * This routine discovers the label and geometry of the disk. It stores 709678fcd0a1Sachartre * the disk label and related information in the vdc structure. If it 709778fcd0a1Sachartre * fails to validate the geometry or to discover the disk label then 709878fcd0a1Sachartre * the label is marked as unknown (VD_DISK_LABEL_UNK). 70990a55fbb7Slm66018 * 71000a55fbb7Slm66018 * Arguments: 71010a55fbb7Slm66018 * vdc - soft state pointer for this instance of the device driver. 71020a55fbb7Slm66018 * 71030a55fbb7Slm66018 * Return Code: 710478fcd0a1Sachartre * 0 - success. 710578fcd0a1Sachartre * EINVAL - unknown disk label. 710678fcd0a1Sachartre * ENOTSUP - geometry not applicable (EFI label). 710778fcd0a1Sachartre * EIO - error accessing the disk. 71080a55fbb7Slm66018 */ 71090a55fbb7Slm66018 static int 711078fcd0a1Sachartre vdc_validate_geometry(vdc_t *vdc) 71110a55fbb7Slm66018 { 7112d10e4ef2Snarayan buf_t *buf; /* BREAD requests need to be in a buf_t structure */ 71130a55fbb7Slm66018 dev_t dev; 71142f5224aeSachartre int rv, rval; 711578fcd0a1Sachartre struct dk_label label; 711678fcd0a1Sachartre struct dk_geom geom; 711778fcd0a1Sachartre struct vtoc vtoc; 7118edcc0754Sachartre efi_gpt_t *gpt; 7119edcc0754Sachartre efi_gpe_t *gpe; 7120edcc0754Sachartre vd_efi_dev_t edev; 71210a55fbb7Slm66018 71220a55fbb7Slm66018 ASSERT(vdc != NULL); 712378fcd0a1Sachartre ASSERT(vdc->vtoc != NULL && vdc->geom != NULL); 712478fcd0a1Sachartre ASSERT(MUTEX_HELD(&vdc->lock)); 71250a55fbb7Slm66018 712678fcd0a1Sachartre mutex_exit(&vdc->lock); 71270a55fbb7Slm66018 71280a55fbb7Slm66018 dev = makedevice(ddi_driver_major(vdc->dip), 71290a55fbb7Slm66018 VD_MAKE_DEV(vdc->instance, 0)); 71304bac2208Snarayan 71312f5224aeSachartre rv = vd_process_ioctl(dev, DKIOCGGEOM, (caddr_t)&geom, FKIOCTL, &rval); 713278fcd0a1Sachartre if (rv == 0) 71332f5224aeSachartre rv = vd_process_ioctl(dev, DKIOCGVTOC, (caddr_t)&vtoc, 71342f5224aeSachartre FKIOCTL, &rval); 71350d0c8d4bSnarayan 71364bac2208Snarayan if (rv == ENOTSUP) { 71374bac2208Snarayan /* 71384bac2208Snarayan * If the device does not support VTOC then we try 71394bac2208Snarayan * to read an EFI label. 7140edcc0754Sachartre * 7141edcc0754Sachartre * We need to know the block size and the disk size to 7142edcc0754Sachartre * be able to read an EFI label. 71434bac2208Snarayan */ 7144edcc0754Sachartre if (vdc->vdisk_size == 0) { 7145edcc0754Sachartre if ((rv = vdc_check_capacity(vdc)) != 0) { 7146edcc0754Sachartre mutex_enter(&vdc->lock); 7147edcc0754Sachartre vdc_store_label_unk(vdc); 7148edcc0754Sachartre return (rv); 7149edcc0754Sachartre } 7150edcc0754Sachartre } 71514bac2208Snarayan 7152edcc0754Sachartre VD_EFI_DEV_SET(edev, vdc, vd_process_efi_ioctl); 7153edcc0754Sachartre 7154edcc0754Sachartre rv = vd_efi_alloc_and_read(&edev, &gpt, &gpe); 71554bac2208Snarayan 71564bac2208Snarayan if (rv) { 71573af08d82Slm66018 DMSG(vdc, 0, "[%d] Failed to get EFI (err=%d)", 71584bac2208Snarayan vdc->instance, rv); 715978fcd0a1Sachartre mutex_enter(&vdc->lock); 716078fcd0a1Sachartre vdc_store_label_unk(vdc); 716178fcd0a1Sachartre return (EIO); 716278fcd0a1Sachartre } 716378fcd0a1Sachartre 716478fcd0a1Sachartre mutex_enter(&vdc->lock); 7165edcc0754Sachartre vdc_store_label_efi(vdc, gpt, gpe); 7166edcc0754Sachartre vd_efi_free(&edev, gpt, gpe); 716778fcd0a1Sachartre return (ENOTSUP); 716878fcd0a1Sachartre } 716978fcd0a1Sachartre 717078fcd0a1Sachartre if (rv != 0) { 717178fcd0a1Sachartre DMSG(vdc, 0, "[%d] Failed to get VTOC (err=%d)", 717278fcd0a1Sachartre vdc->instance, rv); 717378fcd0a1Sachartre mutex_enter(&vdc->lock); 717478fcd0a1Sachartre vdc_store_label_unk(vdc); 717578fcd0a1Sachartre if (rv != EINVAL) 717678fcd0a1Sachartre rv = EIO; 71774bac2208Snarayan return (rv); 71784bac2208Snarayan } 71794bac2208Snarayan 718078fcd0a1Sachartre /* check that geometry and vtoc are valid */ 718178fcd0a1Sachartre if (geom.dkg_nhead == 0 || geom.dkg_nsect == 0 || 718278fcd0a1Sachartre vtoc.v_sanity != VTOC_SANE) { 718378fcd0a1Sachartre mutex_enter(&vdc->lock); 718478fcd0a1Sachartre vdc_store_label_unk(vdc); 718578fcd0a1Sachartre return (EINVAL); 718678fcd0a1Sachartre } 71874bac2208Snarayan 718878fcd0a1Sachartre /* 718978fcd0a1Sachartre * We have a disk and a valid VTOC. However this does not mean 719078fcd0a1Sachartre * that the disk currently have a VTOC label. The returned VTOC may 719178fcd0a1Sachartre * be a default VTOC to be used for configuring the disk (this is 719278fcd0a1Sachartre * what is done for disk image). So we read the label from the 719378fcd0a1Sachartre * beginning of the disk to ensure we really have a VTOC label. 719478fcd0a1Sachartre * 719578fcd0a1Sachartre * FUTURE: This could be the default way for reading the VTOC 719678fcd0a1Sachartre * from the disk as opposed to sending the VD_OP_GET_VTOC 719778fcd0a1Sachartre * to the server. This will be the default if vdc is implemented 719878fcd0a1Sachartre * ontop of cmlb. 719978fcd0a1Sachartre */ 720078fcd0a1Sachartre 720178fcd0a1Sachartre /* 720278fcd0a1Sachartre * Single slice disk does not support read using an absolute disk 720378fcd0a1Sachartre * offset so we just rely on the DKIOCGVTOC ioctl in that case. 720478fcd0a1Sachartre */ 720578fcd0a1Sachartre if (vdc->vdisk_type == VD_DISK_TYPE_SLICE) { 720678fcd0a1Sachartre mutex_enter(&vdc->lock); 720778fcd0a1Sachartre if (vtoc.v_nparts != 1) { 720878fcd0a1Sachartre vdc_store_label_unk(vdc); 720978fcd0a1Sachartre return (EINVAL); 721078fcd0a1Sachartre } 721178fcd0a1Sachartre vdc_store_label_vtoc(vdc, &geom, &vtoc); 72124bac2208Snarayan return (0); 72134bac2208Snarayan } 72144bac2208Snarayan 721578fcd0a1Sachartre if (vtoc.v_nparts != V_NUMPAR) { 721678fcd0a1Sachartre mutex_enter(&vdc->lock); 721778fcd0a1Sachartre vdc_store_label_unk(vdc); 721878fcd0a1Sachartre return (EINVAL); 72190a55fbb7Slm66018 } 7220d10e4ef2Snarayan 7221d10e4ef2Snarayan /* 7222d10e4ef2Snarayan * Read disk label from start of disk 7223d10e4ef2Snarayan */ 7224d10e4ef2Snarayan buf = kmem_alloc(sizeof (buf_t), KM_SLEEP); 7225d10e4ef2Snarayan bioinit(buf); 722678fcd0a1Sachartre buf->b_un.b_addr = (caddr_t)&label; 7227d10e4ef2Snarayan buf->b_bcount = DK_LABEL_SIZE; 7228d10e4ef2Snarayan buf->b_flags = B_BUSY | B_READ; 722917cadca8Slm66018 buf->b_dev = cmpdev(dev); 723078fcd0a1Sachartre rv = vdc_send_request(vdc, VD_OP_BREAD, (caddr_t)&label, 723178fcd0a1Sachartre DK_LABEL_SIZE, VD_SLICE_NONE, 0, CB_STRATEGY, buf, VIO_read_dir); 72323af08d82Slm66018 if (rv) { 72333af08d82Slm66018 DMSG(vdc, 1, "[%d] Failed to read disk block 0\n", 72343af08d82Slm66018 vdc->instance); 723578fcd0a1Sachartre } else { 7236d10e4ef2Snarayan rv = biowait(buf); 7237d10e4ef2Snarayan biofini(buf); 723878fcd0a1Sachartre } 7239d10e4ef2Snarayan kmem_free(buf, sizeof (buf_t)); 72400a55fbb7Slm66018 724178fcd0a1Sachartre if (rv != 0 || label.dkl_magic != DKL_MAGIC || 724278fcd0a1Sachartre label.dkl_cksum != vdc_lbl2cksum(&label)) { 724378fcd0a1Sachartre DMSG(vdc, 1, "[%d] Got VTOC with invalid label\n", 724478fcd0a1Sachartre vdc->instance); 724578fcd0a1Sachartre mutex_enter(&vdc->lock); 724678fcd0a1Sachartre vdc_store_label_unk(vdc); 724778fcd0a1Sachartre return (EINVAL); 724878fcd0a1Sachartre } 724978fcd0a1Sachartre 725078fcd0a1Sachartre mutex_enter(&vdc->lock); 725178fcd0a1Sachartre vdc_store_label_vtoc(vdc, &geom, &vtoc); 725278fcd0a1Sachartre return (0); 725378fcd0a1Sachartre } 725478fcd0a1Sachartre 725578fcd0a1Sachartre /* 725678fcd0a1Sachartre * Function: 725778fcd0a1Sachartre * vdc_validate 725878fcd0a1Sachartre * 725978fcd0a1Sachartre * Description: 726078fcd0a1Sachartre * This routine discovers the label of the disk and create the 726178fcd0a1Sachartre * appropriate device nodes if the label has changed. 726278fcd0a1Sachartre * 726378fcd0a1Sachartre * Arguments: 726478fcd0a1Sachartre * vdc - soft state pointer for this instance of the device driver. 726578fcd0a1Sachartre * 726678fcd0a1Sachartre * Return Code: 726778fcd0a1Sachartre * none. 726878fcd0a1Sachartre */ 726978fcd0a1Sachartre static void 727078fcd0a1Sachartre vdc_validate(vdc_t *vdc) 727178fcd0a1Sachartre { 727278fcd0a1Sachartre vd_disk_label_t old_label; 7273edcc0754Sachartre vd_slice_t old_slice[V_NUMPAR]; 727478fcd0a1Sachartre int rv; 727578fcd0a1Sachartre 727678fcd0a1Sachartre ASSERT(!MUTEX_HELD(&vdc->lock)); 727778fcd0a1Sachartre 727878fcd0a1Sachartre mutex_enter(&vdc->lock); 727978fcd0a1Sachartre 728078fcd0a1Sachartre /* save the current label and vtoc */ 728178fcd0a1Sachartre old_label = vdc->vdisk_label; 7282edcc0754Sachartre bcopy(vdc->slice, &old_slice, sizeof (vd_slice_t) * V_NUMPAR); 728378fcd0a1Sachartre 728478fcd0a1Sachartre /* check the geometry */ 728578fcd0a1Sachartre (void) vdc_validate_geometry(vdc); 728678fcd0a1Sachartre 728778fcd0a1Sachartre /* if the disk label has changed, update device nodes */ 728878fcd0a1Sachartre if (vdc->vdisk_label != old_label) { 728978fcd0a1Sachartre 729078fcd0a1Sachartre if (vdc->vdisk_label == VD_DISK_LABEL_EFI) 729178fcd0a1Sachartre rv = vdc_create_device_nodes_efi(vdc); 729278fcd0a1Sachartre else 729378fcd0a1Sachartre rv = vdc_create_device_nodes_vtoc(vdc); 729478fcd0a1Sachartre 729578fcd0a1Sachartre if (rv != 0) { 729678fcd0a1Sachartre DMSG(vdc, 0, "![%d] Failed to update device nodes", 729778fcd0a1Sachartre vdc->instance); 729878fcd0a1Sachartre } 729978fcd0a1Sachartre } 730078fcd0a1Sachartre 730178fcd0a1Sachartre /* if the vtoc has changed, update device nodes properties */ 7302edcc0754Sachartre if (bcmp(vdc->slice, &old_slice, sizeof (vd_slice_t) * V_NUMPAR) != 0) { 730378fcd0a1Sachartre 730478fcd0a1Sachartre if (vdc_create_device_nodes_props(vdc) != 0) { 730578fcd0a1Sachartre DMSG(vdc, 0, "![%d] Failed to update device nodes" 730678fcd0a1Sachartre " properties", vdc->instance); 730778fcd0a1Sachartre } 730878fcd0a1Sachartre } 730978fcd0a1Sachartre 731078fcd0a1Sachartre mutex_exit(&vdc->lock); 731178fcd0a1Sachartre } 731278fcd0a1Sachartre 731378fcd0a1Sachartre static void 731478fcd0a1Sachartre vdc_validate_task(void *arg) 731578fcd0a1Sachartre { 731678fcd0a1Sachartre vdc_t *vdc = (vdc_t *)arg; 731778fcd0a1Sachartre 731878fcd0a1Sachartre vdc_validate(vdc); 731978fcd0a1Sachartre 732078fcd0a1Sachartre mutex_enter(&vdc->lock); 732178fcd0a1Sachartre ASSERT(vdc->validate_pending > 0); 732278fcd0a1Sachartre vdc->validate_pending--; 732378fcd0a1Sachartre mutex_exit(&vdc->lock); 73241ae08745Sheppo } 73254bac2208Snarayan 73264bac2208Snarayan /* 73274bac2208Snarayan * Function: 73284bac2208Snarayan * vdc_setup_devid() 73294bac2208Snarayan * 73304bac2208Snarayan * Description: 73314bac2208Snarayan * This routine discovers the devid of a vDisk. It requests the devid of 73324bac2208Snarayan * the underlying device from the vDisk server, builds an encapsulated 73334bac2208Snarayan * devid based on the retrieved devid and registers that new devid to 73344bac2208Snarayan * the vDisk. 73354bac2208Snarayan * 73364bac2208Snarayan * Arguments: 73374bac2208Snarayan * vdc - soft state pointer for this instance of the device driver. 73384bac2208Snarayan * 73394bac2208Snarayan * Return Code: 73404bac2208Snarayan * 0 - A devid was succesfully registered for the vDisk 73414bac2208Snarayan */ 73424bac2208Snarayan static int 73434bac2208Snarayan vdc_setup_devid(vdc_t *vdc) 73444bac2208Snarayan { 73454bac2208Snarayan int rv; 73464bac2208Snarayan vd_devid_t *vd_devid; 73474bac2208Snarayan size_t bufsize, bufid_len; 73484bac2208Snarayan 73494bac2208Snarayan /* 73504bac2208Snarayan * At first sight, we don't know the size of the devid that the 73514bac2208Snarayan * server will return but this size will be encoded into the 73524bac2208Snarayan * reply. So we do a first request using a default size then we 73534bac2208Snarayan * check if this size was large enough. If not then we do a second 73544bac2208Snarayan * request with the correct size returned by the server. Note that 73554bac2208Snarayan * ldc requires size to be 8-byte aligned. 73564bac2208Snarayan */ 73574bac2208Snarayan bufsize = P2ROUNDUP(VD_DEVID_SIZE(VD_DEVID_DEFAULT_LEN), 73584bac2208Snarayan sizeof (uint64_t)); 73594bac2208Snarayan vd_devid = kmem_zalloc(bufsize, KM_SLEEP); 73604bac2208Snarayan bufid_len = bufsize - sizeof (vd_efi_t) - 1; 73614bac2208Snarayan 73623af08d82Slm66018 rv = vdc_do_sync_op(vdc, VD_OP_GET_DEVID, (caddr_t)vd_devid, 73632f5224aeSachartre bufsize, 0, 0, CB_SYNC, 0, VIO_both_dir, B_TRUE); 73643af08d82Slm66018 73653af08d82Slm66018 DMSG(vdc, 2, "sync_op returned %d\n", rv); 73663af08d82Slm66018 73674bac2208Snarayan if (rv) { 73684bac2208Snarayan kmem_free(vd_devid, bufsize); 73694bac2208Snarayan return (rv); 73704bac2208Snarayan } 73714bac2208Snarayan 73724bac2208Snarayan if (vd_devid->length > bufid_len) { 73734bac2208Snarayan /* 73744bac2208Snarayan * The returned devid is larger than the buffer used. Try again 73754bac2208Snarayan * with a buffer with the right size. 73764bac2208Snarayan */ 73774bac2208Snarayan kmem_free(vd_devid, bufsize); 73784bac2208Snarayan bufsize = P2ROUNDUP(VD_DEVID_SIZE(vd_devid->length), 73794bac2208Snarayan sizeof (uint64_t)); 73804bac2208Snarayan vd_devid = kmem_zalloc(bufsize, KM_SLEEP); 73814bac2208Snarayan bufid_len = bufsize - sizeof (vd_efi_t) - 1; 73824bac2208Snarayan 73833af08d82Slm66018 rv = vdc_do_sync_op(vdc, VD_OP_GET_DEVID, 73843af08d82Slm66018 (caddr_t)vd_devid, bufsize, 0, 0, CB_SYNC, 0, 73852f5224aeSachartre VIO_both_dir, B_TRUE); 73863af08d82Slm66018 73874bac2208Snarayan if (rv) { 73884bac2208Snarayan kmem_free(vd_devid, bufsize); 73894bac2208Snarayan return (rv); 73904bac2208Snarayan } 73914bac2208Snarayan } 73924bac2208Snarayan 73934bac2208Snarayan /* 73944bac2208Snarayan * The virtual disk should have the same device id as the one associated 73954bac2208Snarayan * with the physical disk it is mapped on, otherwise sharing a disk 73964bac2208Snarayan * between a LDom and a non-LDom may not work (for example for a shared 73974bac2208Snarayan * SVM disk set). 73984bac2208Snarayan * 73994bac2208Snarayan * The DDI framework does not allow creating a device id with any 74004bac2208Snarayan * type so we first create a device id of type DEVID_ENCAP and then 74014bac2208Snarayan * we restore the orignal type of the physical device. 74024bac2208Snarayan */ 74034bac2208Snarayan 74043af08d82Slm66018 DMSG(vdc, 2, ": devid length = %d\n", vd_devid->length); 74053af08d82Slm66018 74064bac2208Snarayan /* build an encapsulated devid based on the returned devid */ 74074bac2208Snarayan if (ddi_devid_init(vdc->dip, DEVID_ENCAP, vd_devid->length, 74084bac2208Snarayan vd_devid->id, &vdc->devid) != DDI_SUCCESS) { 74093af08d82Slm66018 DMSG(vdc, 1, "[%d] Fail to created devid\n", vdc->instance); 74104bac2208Snarayan kmem_free(vd_devid, bufsize); 74114bac2208Snarayan return (1); 74124bac2208Snarayan } 74134bac2208Snarayan 74144bac2208Snarayan DEVID_FORMTYPE((impl_devid_t *)vdc->devid, vd_devid->type); 74154bac2208Snarayan 74164bac2208Snarayan ASSERT(ddi_devid_valid(vdc->devid) == DDI_SUCCESS); 74174bac2208Snarayan 74184bac2208Snarayan kmem_free(vd_devid, bufsize); 74194bac2208Snarayan 74204bac2208Snarayan if (ddi_devid_register(vdc->dip, vdc->devid) != DDI_SUCCESS) { 74213af08d82Slm66018 DMSG(vdc, 1, "[%d] Fail to register devid\n", vdc->instance); 74224bac2208Snarayan return (1); 74234bac2208Snarayan } 74244bac2208Snarayan 74254bac2208Snarayan return (0); 74264bac2208Snarayan } 74274bac2208Snarayan 74284bac2208Snarayan static void 7429edcc0754Sachartre vdc_store_label_efi(vdc_t *vdc, efi_gpt_t *gpt, efi_gpe_t *gpe) 74304bac2208Snarayan { 7431edcc0754Sachartre int i, nparts; 74324bac2208Snarayan 743378fcd0a1Sachartre ASSERT(MUTEX_HELD(&vdc->lock)); 743478fcd0a1Sachartre 743578fcd0a1Sachartre vdc->vdisk_label = VD_DISK_LABEL_EFI; 7436edcc0754Sachartre bzero(vdc->vtoc, sizeof (struct vtoc)); 743778fcd0a1Sachartre bzero(vdc->geom, sizeof (struct dk_geom)); 7438edcc0754Sachartre bzero(vdc->slice, sizeof (vd_slice_t) * V_NUMPAR); 7439edcc0754Sachartre 7440edcc0754Sachartre nparts = gpt->efi_gpt_NumberOfPartitionEntries; 7441edcc0754Sachartre 7442edcc0754Sachartre for (i = 0; i < nparts && i < VD_EFI_WD_SLICE; i++) { 7443edcc0754Sachartre 7444edcc0754Sachartre if (gpe[i].efi_gpe_StartingLBA == 0 || 7445edcc0754Sachartre gpe[i].efi_gpe_EndingLBA == 0) { 7446edcc0754Sachartre continue; 74474bac2208Snarayan } 7448edcc0754Sachartre 7449edcc0754Sachartre vdc->slice[i].start = gpe[i].efi_gpe_StartingLBA; 7450edcc0754Sachartre vdc->slice[i].nblocks = gpe[i].efi_gpe_EndingLBA - 7451edcc0754Sachartre gpe[i].efi_gpe_StartingLBA + 1; 7452edcc0754Sachartre } 7453edcc0754Sachartre 7454edcc0754Sachartre ASSERT(vdc->vdisk_size != 0); 7455edcc0754Sachartre vdc->slice[VD_EFI_WD_SLICE].start = 0; 7456edcc0754Sachartre vdc->slice[VD_EFI_WD_SLICE].nblocks = vdc->vdisk_size; 7457edcc0754Sachartre 74584bac2208Snarayan } 745978fcd0a1Sachartre 746078fcd0a1Sachartre static void 746178fcd0a1Sachartre vdc_store_label_vtoc(vdc_t *vdc, struct dk_geom *geom, struct vtoc *vtoc) 746278fcd0a1Sachartre { 7463edcc0754Sachartre int i; 7464edcc0754Sachartre 746578fcd0a1Sachartre ASSERT(MUTEX_HELD(&vdc->lock)); 7466edcc0754Sachartre ASSERT(vdc->block_size == vtoc->v_sectorsz); 746778fcd0a1Sachartre 746878fcd0a1Sachartre vdc->vdisk_label = VD_DISK_LABEL_VTOC; 746978fcd0a1Sachartre bcopy(vtoc, vdc->vtoc, sizeof (struct vtoc)); 747078fcd0a1Sachartre bcopy(geom, vdc->geom, sizeof (struct dk_geom)); 7471edcc0754Sachartre bzero(vdc->slice, sizeof (vd_slice_t) * V_NUMPAR); 7472edcc0754Sachartre 7473edcc0754Sachartre for (i = 0; i < vtoc->v_nparts; i++) { 7474edcc0754Sachartre vdc->slice[i].start = vtoc->v_part[i].p_start; 7475edcc0754Sachartre vdc->slice[i].nblocks = vtoc->v_part[i].p_size; 7476edcc0754Sachartre } 747778fcd0a1Sachartre } 747878fcd0a1Sachartre 747978fcd0a1Sachartre static void 748078fcd0a1Sachartre vdc_store_label_unk(vdc_t *vdc) 748178fcd0a1Sachartre { 748278fcd0a1Sachartre ASSERT(MUTEX_HELD(&vdc->lock)); 748378fcd0a1Sachartre 748478fcd0a1Sachartre vdc->vdisk_label = VD_DISK_LABEL_UNK; 748578fcd0a1Sachartre bzero(vdc->vtoc, sizeof (struct vtoc)); 748678fcd0a1Sachartre bzero(vdc->geom, sizeof (struct dk_geom)); 7487edcc0754Sachartre bzero(vdc->slice, sizeof (vd_slice_t) * V_NUMPAR); 748878fcd0a1Sachartre } 7489