11709Smlf /* 21709Smlf * CDDL HEADER START 31709Smlf * 41709Smlf * The contents of this file are subject to the terms of the 5*3525Sshidokht * Common Development and Distribution License (the "License"). 6*3525Sshidokht * You may not use this file except in compliance with the License. 71709Smlf * 81709Smlf * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91709Smlf * or http://www.opensolaris.org/os/licensing. 101709Smlf * See the License for the specific language governing permissions 111709Smlf * and limitations under the License. 121709Smlf * 131709Smlf * When distributing Covered Code, include this CDDL HEADER in each 141709Smlf * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151709Smlf * If applicable, add the following below this CDDL HEADER, with the 161709Smlf * fields enclosed by brackets "[]" replaced with your own identifying 171709Smlf * information: Portions Copyright [yyyy] [name of copyright owner] 181709Smlf * 191709Smlf * CDDL HEADER END 201709Smlf */ 211709Smlf /* 22*3525Sshidokht * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 231709Smlf * Use is subject to license terms. 241709Smlf */ 251709Smlf 261709Smlf #pragma ident "%Z%%M% %I% %E% SMI" 271709Smlf 281709Smlf #include <sys/scsi/scsi.h> 291709Smlf #include <sys/dktp/cm.h> 301709Smlf #include <sys/dktp/quetypes.h> 311709Smlf #include <sys/dktp/queue.h> 321709Smlf #include <sys/dktp/fctypes.h> 331709Smlf #include <sys/dktp/flowctrl.h> 341709Smlf #include <sys/dktp/cmdev.h> 351709Smlf #include <sys/dkio.h> 361709Smlf #include <sys/dktp/tgdk.h> 371709Smlf #include <sys/dktp/dadk.h> 381709Smlf #include <sys/dktp/bbh.h> 391709Smlf #include <sys/dktp/altsctr.h> 401709Smlf #include <sys/dktp/cmdk.h> 411709Smlf 421709Smlf #include <sys/stat.h> 431709Smlf #include <sys/vtoc.h> 441709Smlf #include <sys/file.h> 451709Smlf #include <sys/dktp/dadkio.h> 461709Smlf #include <sys/aio_req.h> 471709Smlf 481709Smlf #include <sys/cmlb.h> 491709Smlf 501709Smlf /* 511709Smlf * Local Static Data 521709Smlf */ 531709Smlf #ifdef CMDK_DEBUG 541709Smlf #define DENT 0x0001 551709Smlf #define DIO 0x0002 561709Smlf 571709Smlf static int cmdk_debug = DIO; 581709Smlf #endif 591709Smlf 601709Smlf #ifndef TRUE 611709Smlf #define TRUE 1 621709Smlf #endif 631709Smlf 641709Smlf #ifndef FALSE 651709Smlf #define FALSE 0 661709Smlf #endif 671709Smlf 681709Smlf /* 691709Smlf * NDKMAP is the base number for accessing the fdisk partitions. 701709Smlf * c?d?p0 --> cmdk@?,?:q 711709Smlf */ 721709Smlf #define PARTITION0_INDEX (NDKMAP + 0) 731709Smlf 741709Smlf #define DKTP_DATA (dkp->dk_tgobjp)->tg_data 751709Smlf #define DKTP_EXT (dkp->dk_tgobjp)->tg_ext 761709Smlf 771709Smlf static void *cmdk_state; 781709Smlf 791709Smlf /* 801709Smlf * the cmdk_attach_mutex protects cmdk_max_instance in multi-threaded 811709Smlf * attach situations 821709Smlf */ 831709Smlf static kmutex_t cmdk_attach_mutex; 841709Smlf static int cmdk_max_instance = 0; 851709Smlf 861709Smlf /* 871709Smlf * Panic dumpsys state 881709Smlf * There is only a single flag that is not mutex locked since 891709Smlf * the system is prevented from thread switching and cmdk_dump 901709Smlf * will only be called in a single threaded operation. 911709Smlf */ 921709Smlf static int cmdk_indump; 931709Smlf 941709Smlf /* 951709Smlf * Local Function Prototypes 961709Smlf */ 971709Smlf static int cmdk_create_obj(dev_info_t *dip, struct cmdk *dkp); 981709Smlf static void cmdk_destroy_obj(dev_info_t *dip, struct cmdk *dkp); 991709Smlf static void cmdkmin(struct buf *bp); 1001709Smlf static int cmdkrw(dev_t dev, struct uio *uio, int flag); 1011709Smlf static int cmdkarw(dev_t dev, struct aio_req *aio, int flag); 1021709Smlf 1031709Smlf /* 1041709Smlf * Bad Block Handling Functions Prototypes 1051709Smlf */ 1061709Smlf static void cmdk_bbh_reopen(struct cmdk *dkp); 1071709Smlf static opaque_t cmdk_bbh_gethandle(opaque_t bbh_data, struct buf *bp); 1081709Smlf static bbh_cookie_t cmdk_bbh_htoc(opaque_t bbh_data, opaque_t handle); 1091709Smlf static void cmdk_bbh_freehandle(opaque_t bbh_data, opaque_t handle); 1101709Smlf static void cmdk_bbh_close(struct cmdk *dkp); 1111709Smlf static void cmdk_bbh_setalts_idx(struct cmdk *dkp); 1121709Smlf static int cmdk_bbh_bsearch(struct alts_ent *buf, int cnt, daddr32_t key); 1131709Smlf 1141709Smlf static struct bbh_objops cmdk_bbh_ops = { 1151709Smlf nulldev, 1161709Smlf nulldev, 1171709Smlf cmdk_bbh_gethandle, 1181709Smlf cmdk_bbh_htoc, 1191709Smlf cmdk_bbh_freehandle, 1201709Smlf 0, 0 1211709Smlf }; 1221709Smlf 1231709Smlf static int cmdkopen(dev_t *dev_p, int flag, int otyp, cred_t *credp); 1241709Smlf static int cmdkclose(dev_t dev, int flag, int otyp, cred_t *credp); 1251709Smlf static int cmdkstrategy(struct buf *bp); 1261709Smlf static int cmdkdump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk); 1271709Smlf static int cmdkioctl(dev_t, int, intptr_t, int, cred_t *, int *); 1281709Smlf static int cmdkread(dev_t dev, struct uio *uio, cred_t *credp); 1291709Smlf static int cmdkwrite(dev_t dev, struct uio *uio, cred_t *credp); 1301709Smlf static int cmdk_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, 1311709Smlf int mod_flags, char *name, caddr_t valuep, int *lengthp); 1321709Smlf static int cmdkaread(dev_t dev, struct aio_req *aio, cred_t *credp); 1331709Smlf static int cmdkawrite(dev_t dev, struct aio_req *aio, cred_t *credp); 1341709Smlf 1351709Smlf /* 1361709Smlf * Device driver ops vector 1371709Smlf */ 1381709Smlf 1391709Smlf static struct cb_ops cmdk_cb_ops = { 1401709Smlf cmdkopen, /* open */ 1411709Smlf cmdkclose, /* close */ 1421709Smlf cmdkstrategy, /* strategy */ 1431709Smlf nodev, /* print */ 1441709Smlf cmdkdump, /* dump */ 1451709Smlf cmdkread, /* read */ 1461709Smlf cmdkwrite, /* write */ 1471709Smlf cmdkioctl, /* ioctl */ 1481709Smlf nodev, /* devmap */ 1491709Smlf nodev, /* mmap */ 1501709Smlf nodev, /* segmap */ 1511709Smlf nochpoll, /* poll */ 1521709Smlf cmdk_prop_op, /* cb_prop_op */ 1531709Smlf 0, /* streamtab */ 1541709Smlf D_64BIT | D_MP | D_NEW, /* Driver comaptibility flag */ 1551709Smlf CB_REV, /* cb_rev */ 1561709Smlf cmdkaread, /* async read */ 1571709Smlf cmdkawrite /* async write */ 1581709Smlf }; 1591709Smlf 1601709Smlf static int cmdkinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 1611709Smlf void **result); 1621709Smlf static int cmdkprobe(dev_info_t *dip); 1631709Smlf static int cmdkattach(dev_info_t *dip, ddi_attach_cmd_t cmd); 1641709Smlf static int cmdkdetach(dev_info_t *dip, ddi_detach_cmd_t cmd); 1651709Smlf 1661709Smlf struct dev_ops cmdk_ops = { 1671709Smlf DEVO_REV, /* devo_rev, */ 1681709Smlf 0, /* refcnt */ 1691709Smlf cmdkinfo, /* info */ 1701709Smlf nulldev, /* identify */ 1711709Smlf cmdkprobe, /* probe */ 1721709Smlf cmdkattach, /* attach */ 1731709Smlf cmdkdetach, /* detach */ 1741709Smlf nodev, /* reset */ 1751709Smlf &cmdk_cb_ops, /* driver operations */ 1761709Smlf (struct bus_ops *)0 /* bus operations */ 1771709Smlf }; 1781709Smlf 1791709Smlf /* 1801709Smlf * This is the loadable module wrapper. 1811709Smlf */ 1821709Smlf #include <sys/modctl.h> 1831709Smlf 1841709Smlf extern struct mod_ops mod_driverops; 1851709Smlf 1861709Smlf static struct modldrv modldrv = { 1871709Smlf &mod_driverops, /* Type of module. This one is a driver */ 1881709Smlf "Common Direct Access Disk %I%", 1891709Smlf &cmdk_ops, /* driver ops */ 1901709Smlf }; 1911709Smlf 1921709Smlf static struct modlinkage modlinkage = { 1931709Smlf MODREV_1, (void *)&modldrv, NULL 1941709Smlf }; 1951709Smlf 1961709Smlf /* Function prototypes for cmlb callbacks */ 1971709Smlf 1981709Smlf static int cmdk_lb_rdwr(dev_info_t *dip, uchar_t cmd, void *bufaddr, 199*3525Sshidokht diskaddr_t start, size_t length, void *tg_cookie); 200*3525Sshidokht 201*3525Sshidokht static int cmdk_lb_getinfo(dev_info_t *dip, int cmd, void *arg, 202*3525Sshidokht void *tg_cookie); 2031709Smlf 2041709Smlf static void cmdk_devid_setup(struct cmdk *dkp); 2051709Smlf static int cmdk_devid_modser(struct cmdk *dkp); 2061709Smlf static int cmdk_get_modser(struct cmdk *dkp, int ioccmd, char *buf, int len); 2071709Smlf static int cmdk_devid_fabricate(struct cmdk *dkp); 2081709Smlf static int cmdk_devid_read(struct cmdk *dkp); 2091709Smlf 2101709Smlf static cmlb_tg_ops_t cmdk_lb_ops = { 211*3525Sshidokht TG_DK_OPS_VERSION_1, 2121709Smlf cmdk_lb_rdwr, 213*3525Sshidokht cmdk_lb_getinfo 2141709Smlf }; 2151709Smlf 2161709Smlf int 2171709Smlf _init(void) 2181709Smlf { 2191709Smlf int rval; 2201709Smlf 2211709Smlf if (rval = ddi_soft_state_init(&cmdk_state, sizeof (struct cmdk), 7)) 2221709Smlf return (rval); 2231709Smlf 2241709Smlf mutex_init(&cmdk_attach_mutex, NULL, MUTEX_DRIVER, NULL); 2251709Smlf if ((rval = mod_install(&modlinkage)) != 0) { 2261709Smlf mutex_destroy(&cmdk_attach_mutex); 2271709Smlf ddi_soft_state_fini(&cmdk_state); 2281709Smlf } 2291709Smlf return (rval); 2301709Smlf } 2311709Smlf 2321709Smlf int 2331709Smlf _fini(void) 2341709Smlf { 2351709Smlf return (EBUSY); 2361709Smlf 2371709Smlf /* 2381709Smlf * This has been commented out until cmdk is a true 2391709Smlf * unloadable module. Right now x86's are panicking on 2401709Smlf * a diskless reconfig boot. 2411709Smlf */ 2421709Smlf 2431709Smlf #if 0 /* bugid 1186679 */ 2441709Smlf int rval; 2451709Smlf 2461709Smlf rval = mod_remove(&modlinkage); 2471709Smlf if (rval != 0) 2481709Smlf return (rval); 2491709Smlf 2501709Smlf mutex_destroy(&cmdk_attach_mutex); 2511709Smlf ddi_soft_state_fini(&cmdk_state); 2521709Smlf 2531709Smlf return (0); 2541709Smlf #endif 2551709Smlf } 2561709Smlf 2571709Smlf int 2581709Smlf _info(struct modinfo *modinfop) 2591709Smlf { 2601709Smlf return (mod_info(&modlinkage, modinfop)); 2611709Smlf } 2621709Smlf 2631709Smlf /* 2641709Smlf * Autoconfiguration Routines 2651709Smlf */ 2661709Smlf static int 2671709Smlf cmdkprobe(dev_info_t *dip) 2681709Smlf { 2691709Smlf int instance; 2701709Smlf int status; 2711709Smlf struct cmdk *dkp; 2721709Smlf 2731709Smlf instance = ddi_get_instance(dip); 2741709Smlf 2751709Smlf if (ddi_get_soft_state(cmdk_state, instance)) 2761709Smlf return (DDI_PROBE_PARTIAL); 2771709Smlf 2781709Smlf if ((ddi_soft_state_zalloc(cmdk_state, instance) != DDI_SUCCESS) || 2791709Smlf ((dkp = ddi_get_soft_state(cmdk_state, instance)) == NULL)) 2801709Smlf return (DDI_PROBE_PARTIAL); 2811709Smlf 2821709Smlf mutex_init(&dkp->dk_mutex, NULL, MUTEX_DRIVER, NULL); 2831709Smlf rw_init(&dkp->dk_bbh_mutex, NULL, RW_DRIVER, NULL); 2841709Smlf dkp->dk_dip = dip; 2851709Smlf mutex_enter(&dkp->dk_mutex); 2861709Smlf 2871709Smlf dkp->dk_dev = makedevice(ddi_driver_major(dip), 2881709Smlf ddi_get_instance(dip) << CMDK_UNITSHF); 2891709Smlf 2901709Smlf /* linkage to dadk and strategy */ 2911709Smlf if (cmdk_create_obj(dip, dkp) != DDI_SUCCESS) { 2921709Smlf mutex_exit(&dkp->dk_mutex); 2931709Smlf mutex_destroy(&dkp->dk_mutex); 2941709Smlf rw_destroy(&dkp->dk_bbh_mutex); 2951709Smlf ddi_soft_state_free(cmdk_state, instance); 2961709Smlf return (DDI_PROBE_PARTIAL); 2971709Smlf } 2981709Smlf 2991709Smlf status = dadk_probe(DKTP_DATA, KM_NOSLEEP); 3001709Smlf if (status != DDI_PROBE_SUCCESS) { 3011709Smlf cmdk_destroy_obj(dip, dkp); /* dadk/strategy linkage */ 3021709Smlf mutex_exit(&dkp->dk_mutex); 3031709Smlf mutex_destroy(&dkp->dk_mutex); 3041709Smlf rw_destroy(&dkp->dk_bbh_mutex); 3051709Smlf ddi_soft_state_free(cmdk_state, instance); 3061709Smlf return (status); 3071709Smlf } 3081709Smlf 3091709Smlf mutex_exit(&dkp->dk_mutex); 3101709Smlf #ifdef CMDK_DEBUG 3111709Smlf if (cmdk_debug & DENT) 3121709Smlf PRF("cmdkprobe: instance= %d name= `%s`\n", 3131709Smlf instance, ddi_get_name_addr(dip)); 3141709Smlf #endif 3151709Smlf return (status); 3161709Smlf } 3171709Smlf 3181709Smlf static int 3191709Smlf cmdkattach(dev_info_t *dip, ddi_attach_cmd_t cmd) 3201709Smlf { 3211709Smlf int instance; 3221709Smlf struct cmdk *dkp; 3231709Smlf char *node_type; 3241709Smlf 3251709Smlf if (cmd != DDI_ATTACH) 3261709Smlf return (DDI_FAILURE); 3271709Smlf 3281709Smlf instance = ddi_get_instance(dip); 3291709Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 3301709Smlf return (DDI_FAILURE); 3311709Smlf 3321709Smlf mutex_enter(&dkp->dk_mutex); 3331709Smlf 3341709Smlf /* dadk_attach is an empty function that only returns SUCCESS */ 3351709Smlf (void) dadk_attach(DKTP_DATA); 3361709Smlf 3371709Smlf node_type = (DKTP_EXT->tg_nodetype); 3381709Smlf 3391709Smlf /* 3401709Smlf * this open allows cmlb to read the device 3411709Smlf * and determine the label types 3421709Smlf * so that cmlb can create minor nodes for device 3431709Smlf */ 3441709Smlf 3451709Smlf /* open the target disk */ 3461709Smlf if (dadk_open(DKTP_DATA, 0) != DDI_SUCCESS) 3471709Smlf goto fail2; 3481709Smlf 3491709Smlf /* mark as having opened target */ 3501709Smlf dkp->dk_flag |= CMDK_TGDK_OPEN; 3511709Smlf 3521709Smlf cmlb_alloc_handle((cmlb_handle_t *)&dkp->dk_cmlbhandle); 3531709Smlf 3541709Smlf if (cmlb_attach(dip, 3551709Smlf &cmdk_lb_ops, 3561709Smlf DTYPE_DIRECT, /* device_type */ 3571709Smlf 0, /* removable */ 358*3525Sshidokht 0, /* hot pluggable XXX */ 3591709Smlf node_type, 3601709Smlf CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT, /* alter_behaviour */ 361*3525Sshidokht dkp->dk_cmlbhandle, 362*3525Sshidokht 0) != 0) 3631709Smlf goto fail1; 3641709Smlf 3651709Smlf /* Calling validate will create minor nodes according to disk label */ 366*3525Sshidokht (void) cmlb_validate(dkp->dk_cmlbhandle, 0, 0); 3671709Smlf 3681709Smlf /* set bbh (Bad Block Handling) */ 3691709Smlf cmdk_bbh_reopen(dkp); 3701709Smlf 3711709Smlf /* setup devid string */ 3721709Smlf cmdk_devid_setup(dkp); 3731709Smlf 3741709Smlf mutex_enter(&cmdk_attach_mutex); 3751709Smlf if (instance > cmdk_max_instance) 3761709Smlf cmdk_max_instance = instance; 3771709Smlf mutex_exit(&cmdk_attach_mutex); 3781709Smlf 3791709Smlf mutex_exit(&dkp->dk_mutex); 3801709Smlf 3811709Smlf /* 3821709Smlf * Add a zero-length attribute to tell the world we support 3831709Smlf * kernel ioctls (for layered drivers) 3841709Smlf */ 3851709Smlf (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, 3861709Smlf DDI_KERNEL_IOCTL, NULL, 0); 3871709Smlf ddi_report_dev(dip); 3881709Smlf 3891709Smlf return (DDI_SUCCESS); 3901709Smlf 3911709Smlf fail1: 3921709Smlf cmlb_free_handle(&dkp->dk_cmlbhandle); 3931709Smlf (void) dadk_close(DKTP_DATA); 3941709Smlf fail2: 3951709Smlf cmdk_destroy_obj(dip, dkp); 3961709Smlf rw_destroy(&dkp->dk_bbh_mutex); 3971709Smlf mutex_exit(&dkp->dk_mutex); 3981709Smlf mutex_destroy(&dkp->dk_mutex); 3991709Smlf ddi_soft_state_free(cmdk_state, instance); 4001709Smlf return (DDI_FAILURE); 4011709Smlf } 4021709Smlf 4031709Smlf 4041709Smlf static int 4051709Smlf cmdkdetach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4061709Smlf { 4071709Smlf struct cmdk *dkp; 4081709Smlf int instance; 4091709Smlf int max_instance; 4101709Smlf 4111709Smlf if (cmd != DDI_DETACH) { 4121709Smlf #ifdef CMDK_DEBUG 4131709Smlf if (cmdk_debug & DIO) { 4141709Smlf PRF("cmdkdetach: cmd = %d unknown\n", cmd); 4151709Smlf } 4161709Smlf #endif 4171709Smlf return (DDI_FAILURE); 4181709Smlf } 4191709Smlf 4201709Smlf mutex_enter(&cmdk_attach_mutex); 4211709Smlf max_instance = cmdk_max_instance; 4221709Smlf mutex_exit(&cmdk_attach_mutex); 4231709Smlf 4241709Smlf /* check if any instance of driver is open */ 4251709Smlf for (instance = 0; instance < max_instance; instance++) { 4261709Smlf dkp = ddi_get_soft_state(cmdk_state, instance); 4271709Smlf if (!dkp) 4281709Smlf continue; 4291709Smlf if (dkp->dk_flag & CMDK_OPEN) 4301709Smlf return (DDI_FAILURE); 4311709Smlf } 4321709Smlf 4331709Smlf instance = ddi_get_instance(dip); 4341709Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 4351709Smlf return (DDI_SUCCESS); 4361709Smlf 4371709Smlf mutex_enter(&dkp->dk_mutex); 4381709Smlf 4391709Smlf /* 4401709Smlf * The cmdk_part_info call at the end of cmdkattach may have 4411709Smlf * caused cmdk_reopen to do a TGDK_OPEN, make sure we close on 4421709Smlf * detach for case when cmdkopen/cmdkclose never occurs. 4431709Smlf */ 4441709Smlf if (dkp->dk_flag & CMDK_TGDK_OPEN) { 4451709Smlf dkp->dk_flag &= ~CMDK_TGDK_OPEN; 4461709Smlf (void) dadk_close(DKTP_DATA); 4471709Smlf } 4481709Smlf 449*3525Sshidokht cmlb_detach(dkp->dk_cmlbhandle, 0); 4501709Smlf cmlb_free_handle(&dkp->dk_cmlbhandle); 4511709Smlf ddi_prop_remove_all(dip); 4521709Smlf 4531709Smlf cmdk_destroy_obj(dip, dkp); /* dadk/strategy linkage */ 4541709Smlf mutex_exit(&dkp->dk_mutex); 4551709Smlf mutex_destroy(&dkp->dk_mutex); 4561709Smlf rw_destroy(&dkp->dk_bbh_mutex); 4571709Smlf ddi_soft_state_free(cmdk_state, instance); 4581709Smlf 4591709Smlf return (DDI_SUCCESS); 4601709Smlf } 4611709Smlf 4621709Smlf static int 4631709Smlf cmdkinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 4641709Smlf { 4651709Smlf dev_t dev = (dev_t)arg; 4661709Smlf int instance; 4671709Smlf struct cmdk *dkp; 4681709Smlf 4691709Smlf #ifdef lint 4701709Smlf dip = dip; /* no one ever uses this */ 4711709Smlf #endif 4721709Smlf #ifdef CMDK_DEBUG 4731709Smlf if (cmdk_debug & DENT) 4741709Smlf PRF("cmdkinfo: call\n"); 4751709Smlf #endif 4761709Smlf instance = CMDKUNIT(dev); 4771709Smlf 4781709Smlf switch (infocmd) { 4791709Smlf case DDI_INFO_DEVT2DEVINFO: 4801709Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 4811709Smlf return (DDI_FAILURE); 4821709Smlf *result = (void *) dkp->dk_dip; 4831709Smlf break; 4841709Smlf case DDI_INFO_DEVT2INSTANCE: 4851709Smlf *result = (void *)(intptr_t)instance; 4861709Smlf break; 4871709Smlf default: 4881709Smlf return (DDI_FAILURE); 4891709Smlf } 4901709Smlf return (DDI_SUCCESS); 4911709Smlf } 4921709Smlf 4931709Smlf static int 4941709Smlf cmdk_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags, 4951709Smlf char *name, caddr_t valuep, int *lengthp) 4961709Smlf { 4971709Smlf struct cmdk *dkp; 4981709Smlf diskaddr_t p_lblksrt; 4991709Smlf diskaddr_t p_lblkcnt; 5001709Smlf 5011709Smlf #ifdef CMDK_DEBUG 5021709Smlf if (cmdk_debug & DENT) 5031709Smlf PRF("cmdk_prop_op: call\n"); 5041709Smlf #endif 5051709Smlf 5061709Smlf dkp = ddi_get_soft_state(cmdk_state, ddi_get_instance(dip)); 5071709Smlf 5081709Smlf /* 5091709Smlf * Our dynamic properties are all device specific and size oriented. 5101709Smlf * Requests issued under conditions where size is valid are passed 5111709Smlf * to ddi_prop_op_nblocks with the size information, otherwise the 5121709Smlf * request is passed to ddi_prop_op. Size depends on valid label. 5131709Smlf */ 5141709Smlf if ((dev != DDI_DEV_T_ANY) && (dkp != NULL)) { 5151709Smlf if (!cmlb_partinfo( 5161709Smlf dkp->dk_cmlbhandle, 5171709Smlf CMDKPART(dev), 5181709Smlf &p_lblkcnt, 5191709Smlf &p_lblksrt, 5201709Smlf NULL, 521*3525Sshidokht NULL, 522*3525Sshidokht 0)) 5231709Smlf return (ddi_prop_op_nblocks(dev, dip, 5241709Smlf prop_op, mod_flags, 5251709Smlf name, valuep, lengthp, 5261709Smlf (uint64_t)p_lblkcnt)); 5271709Smlf } 5281709Smlf 5291709Smlf return (ddi_prop_op(dev, dip, 5301709Smlf prop_op, mod_flags, 5311709Smlf name, valuep, lengthp)); 5321709Smlf } 5331709Smlf 5341709Smlf /* 5351709Smlf * dump routine 5361709Smlf */ 5371709Smlf static int 5381709Smlf cmdkdump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk) 5391709Smlf { 5401709Smlf int instance; 5411709Smlf struct cmdk *dkp; 5421709Smlf diskaddr_t p_lblksrt; 5431709Smlf diskaddr_t p_lblkcnt; 5441709Smlf struct buf local; 5451709Smlf struct buf *bp; 5461709Smlf 5471709Smlf #ifdef CMDK_DEBUG 5481709Smlf if (cmdk_debug & DENT) 5491709Smlf PRF("cmdkdump: call\n"); 5501709Smlf #endif 5511709Smlf instance = CMDKUNIT(dev); 5521709Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance)) || (blkno < 0)) 5531709Smlf return (ENXIO); 5541709Smlf 5551709Smlf if (cmlb_partinfo( 5561709Smlf dkp->dk_cmlbhandle, 5571709Smlf CMDKPART(dev), 5581709Smlf &p_lblkcnt, 5591709Smlf &p_lblksrt, 5601709Smlf NULL, 561*3525Sshidokht NULL, 562*3525Sshidokht 0)) { 5631709Smlf return (ENXIO); 5641709Smlf } 5651709Smlf 5661709Smlf if ((blkno+nblk) > p_lblkcnt) 5671709Smlf return (EINVAL); 5681709Smlf 5691709Smlf cmdk_indump = 1; /* Tell disk targets we are panic dumpping */ 5701709Smlf 5711709Smlf bp = &local; 5721709Smlf bzero(bp, sizeof (*bp)); 5731709Smlf bp->b_flags = B_BUSY; 5741709Smlf bp->b_un.b_addr = addr; 5751709Smlf bp->b_bcount = nblk << SCTRSHFT; 5761709Smlf SET_BP_SEC(bp, ((ulong_t)(p_lblksrt + blkno))); 5771709Smlf 5781709Smlf (void) dadk_dump(DKTP_DATA, bp); 5791709Smlf return (bp->b_error); 5801709Smlf } 5811709Smlf 5821709Smlf /* 5831709Smlf * Copy in the dadkio_rwcmd according to the user's data model. If needed, 5841709Smlf * convert it for our internal use. 5851709Smlf */ 5861709Smlf static int 5871709Smlf rwcmd_copyin(struct dadkio_rwcmd *rwcmdp, caddr_t inaddr, int flag) 5881709Smlf { 5891709Smlf switch (ddi_model_convert_from(flag)) { 5901709Smlf case DDI_MODEL_ILP32: { 5911709Smlf struct dadkio_rwcmd32 cmd32; 5921709Smlf 5931709Smlf if (ddi_copyin(inaddr, &cmd32, 5941709Smlf sizeof (struct dadkio_rwcmd32), flag)) { 5951709Smlf return (EFAULT); 5961709Smlf } 5971709Smlf 5981709Smlf rwcmdp->cmd = cmd32.cmd; 5991709Smlf rwcmdp->flags = cmd32.flags; 6001709Smlf rwcmdp->blkaddr = (daddr_t)cmd32.blkaddr; 6011709Smlf rwcmdp->buflen = cmd32.buflen; 6021709Smlf rwcmdp->bufaddr = (caddr_t)(intptr_t)cmd32.bufaddr; 6031709Smlf /* 6041709Smlf * Note: we do not convert the 'status' field, 6051709Smlf * as it should not contain valid data at this 6061709Smlf * point. 6071709Smlf */ 6081709Smlf bzero(&rwcmdp->status, sizeof (rwcmdp->status)); 6091709Smlf break; 6101709Smlf } 6111709Smlf case DDI_MODEL_NONE: { 6121709Smlf if (ddi_copyin(inaddr, rwcmdp, 6131709Smlf sizeof (struct dadkio_rwcmd), flag)) { 6141709Smlf return (EFAULT); 6151709Smlf } 6161709Smlf } 6171709Smlf } 6181709Smlf return (0); 6191709Smlf } 6201709Smlf 6211709Smlf /* 6221709Smlf * If necessary, convert the internal rwcmdp and status to the appropriate 6231709Smlf * data model and copy it out to the user. 6241709Smlf */ 6251709Smlf static int 6261709Smlf rwcmd_copyout(struct dadkio_rwcmd *rwcmdp, caddr_t outaddr, int flag) 6271709Smlf { 6281709Smlf switch (ddi_model_convert_from(flag)) { 6291709Smlf case DDI_MODEL_ILP32: { 6301709Smlf struct dadkio_rwcmd32 cmd32; 6311709Smlf 6321709Smlf cmd32.cmd = rwcmdp->cmd; 6331709Smlf cmd32.flags = rwcmdp->flags; 6341709Smlf cmd32.blkaddr = rwcmdp->blkaddr; 6351709Smlf cmd32.buflen = rwcmdp->buflen; 6361709Smlf ASSERT64(((uintptr_t)rwcmdp->bufaddr >> 32) == 0); 6371709Smlf cmd32.bufaddr = (caddr32_t)(uintptr_t)rwcmdp->bufaddr; 6381709Smlf 6391709Smlf cmd32.status.status = rwcmdp->status.status; 6401709Smlf cmd32.status.resid = rwcmdp->status.resid; 6411709Smlf cmd32.status.failed_blk_is_valid = 6421709Smlf rwcmdp->status.failed_blk_is_valid; 6431709Smlf cmd32.status.failed_blk = rwcmdp->status.failed_blk; 6441709Smlf cmd32.status.fru_code_is_valid = 6451709Smlf rwcmdp->status.fru_code_is_valid; 6461709Smlf cmd32.status.fru_code = rwcmdp->status.fru_code; 6471709Smlf 6481709Smlf bcopy(rwcmdp->status.add_error_info, 6491709Smlf cmd32.status.add_error_info, DADKIO_ERROR_INFO_LEN); 6501709Smlf 6511709Smlf if (ddi_copyout(&cmd32, outaddr, 6521709Smlf sizeof (struct dadkio_rwcmd32), flag)) 6531709Smlf return (EFAULT); 6541709Smlf break; 6551709Smlf } 6561709Smlf case DDI_MODEL_NONE: { 6571709Smlf if (ddi_copyout(rwcmdp, outaddr, 6581709Smlf sizeof (struct dadkio_rwcmd), flag)) 6591709Smlf return (EFAULT); 6601709Smlf } 6611709Smlf } 6621709Smlf return (0); 6631709Smlf } 6641709Smlf 6651709Smlf /* 6661709Smlf * ioctl routine 6671709Smlf */ 6681709Smlf static int 6691709Smlf cmdkioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp, int *rvalp) 6701709Smlf { 6711709Smlf int instance; 6721709Smlf struct scsi_device *devp; 6731709Smlf struct cmdk *dkp; 6741709Smlf char data[NBPSCTR]; 6751709Smlf 6761709Smlf instance = CMDKUNIT(dev); 6771709Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 6781709Smlf return (ENXIO); 6791709Smlf 6801709Smlf bzero(data, sizeof (data)); 6811709Smlf 6821709Smlf switch (cmd) { 6831709Smlf 6841709Smlf case DKIOCGMEDIAINFO: { 6851709Smlf struct dk_minfo media_info; 6861709Smlf struct tgdk_geom phyg; 6871709Smlf 6881709Smlf /* dadk_getphygeom always returns success */ 6891709Smlf (void) dadk_getphygeom(DKTP_DATA, &phyg); 6901709Smlf 6911709Smlf media_info.dki_lbsize = phyg.g_secsiz; 6921709Smlf media_info.dki_capacity = phyg.g_cap; 6931709Smlf media_info.dki_media_type = DK_FIXED_DISK; 6941709Smlf 6951709Smlf if (ddi_copyout(&media_info, (void *)arg, 6961709Smlf sizeof (struct dk_minfo), flag)) { 6971709Smlf return (EFAULT); 6981709Smlf } else { 6991709Smlf return (0); 7001709Smlf } 7011709Smlf } 7021709Smlf 7031709Smlf case DKIOCINFO: { 7041709Smlf struct dk_cinfo *info = (struct dk_cinfo *)data; 7051709Smlf 7061709Smlf /* controller information */ 7071709Smlf info->dki_ctype = (DKTP_EXT->tg_ctype); 7081709Smlf info->dki_cnum = ddi_get_instance(ddi_get_parent(dkp->dk_dip)); 7091709Smlf (void) strcpy(info->dki_cname, 7101709Smlf ddi_get_name(ddi_get_parent(dkp->dk_dip))); 7111709Smlf 7121709Smlf /* Unit Information */ 7131709Smlf info->dki_unit = ddi_get_instance(dkp->dk_dip); 7141709Smlf devp = ddi_get_driver_private(dkp->dk_dip); 7151709Smlf info->dki_slave = (CMDEV_TARG(devp)<<3) | CMDEV_LUN(devp); 7161709Smlf (void) strcpy(info->dki_dname, ddi_driver_name(dkp->dk_dip)); 7171709Smlf info->dki_flags = DKI_FMTVOL; 7181709Smlf info->dki_partition = CMDKPART(dev); 7191709Smlf 7201709Smlf info->dki_maxtransfer = maxphys / DEV_BSIZE; 7211709Smlf info->dki_addr = 1; 7221709Smlf info->dki_space = 0; 7231709Smlf info->dki_prio = 0; 7241709Smlf info->dki_vec = 0; 7251709Smlf 7261709Smlf if (ddi_copyout(data, (void *)arg, sizeof (*info), flag)) 7271709Smlf return (EFAULT); 7281709Smlf else 7291709Smlf return (0); 7301709Smlf } 7311709Smlf 7321709Smlf case DKIOCSTATE: { 7331709Smlf int state; 7341709Smlf int rval; 7351709Smlf diskaddr_t p_lblksrt; 7361709Smlf diskaddr_t p_lblkcnt; 7371709Smlf 7381709Smlf if (ddi_copyin((void *)arg, &state, sizeof (int), flag)) 7391709Smlf return (EFAULT); 7401709Smlf 7411709Smlf /* dadk_check_media blocks until state changes */ 7421709Smlf if (rval = dadk_check_media(DKTP_DATA, &state)) 7431709Smlf return (rval); 7441709Smlf 7451709Smlf if (state == DKIO_INSERTED) { 7461709Smlf 747*3525Sshidokht if (cmlb_validate(dkp->dk_cmlbhandle, 0, 0) != 0) 7481709Smlf return (ENXIO); 7491709Smlf 7501709Smlf if (cmlb_partinfo(dkp->dk_cmlbhandle, CMDKPART(dev), 751*3525Sshidokht &p_lblkcnt, &p_lblksrt, NULL, NULL, 0)) 7521709Smlf return (ENXIO); 7531709Smlf 7541709Smlf if (p_lblkcnt <= 0) 7551709Smlf return (ENXIO); 7561709Smlf } 7571709Smlf 7581709Smlf if (ddi_copyout(&state, (caddr_t)arg, sizeof (int), flag)) 7591709Smlf return (EFAULT); 7601709Smlf 7611709Smlf return (0); 7621709Smlf } 7631709Smlf 7641709Smlf /* 7651709Smlf * is media removable? 7661709Smlf */ 7671709Smlf case DKIOCREMOVABLE: { 7681709Smlf int i; 7691709Smlf 7701709Smlf i = (DKTP_EXT->tg_rmb) ? 1 : 0; 7711709Smlf 7721709Smlf if (ddi_copyout(&i, (caddr_t)arg, sizeof (int), flag)) 7731709Smlf return (EFAULT); 7741709Smlf 7751709Smlf return (0); 7761709Smlf } 7771709Smlf 7781709Smlf case DKIOCADDBAD: 7791709Smlf /* 7801709Smlf * This is not an update mechanism to add bad blocks 7811709Smlf * to the bad block structures stored on disk. 7821709Smlf * 7831709Smlf * addbadsec(1M) will update the bad block data on disk 7841709Smlf * and use this ioctl to force the driver to re-initialize 7851709Smlf * the list of bad blocks in the driver. 7861709Smlf */ 7871709Smlf 7881709Smlf /* start BBH */ 7891709Smlf cmdk_bbh_reopen(dkp); 7901709Smlf return (0); 7911709Smlf 7921709Smlf case DKIOCG_PHYGEOM: 7931709Smlf case DKIOCG_VIRTGEOM: 7941709Smlf case DKIOCGGEOM: 7951709Smlf case DKIOCSGEOM: 7961709Smlf case DKIOCGAPART: 7971709Smlf case DKIOCSAPART: 7981709Smlf case DKIOCGVTOC: 7991709Smlf case DKIOCSVTOC: 8001709Smlf case DKIOCPARTINFO: 8011709Smlf case DKIOCGMBOOT: 8021709Smlf case DKIOCSMBOOT: 8031709Smlf case DKIOCGETEFI: 8041709Smlf case DKIOCSETEFI: 8051709Smlf case DKIOCPARTITION: 8061709Smlf { 8071709Smlf int rc; 8081709Smlf 809*3525Sshidokht rc = cmlb_ioctl(dkp->dk_cmlbhandle, dev, cmd, arg, flag, 810*3525Sshidokht credp, rvalp, 0); 8111709Smlf if (cmd == DKIOCSVTOC) 8121709Smlf cmdk_devid_setup(dkp); 8131709Smlf return (rc); 8141709Smlf } 8151709Smlf 8161709Smlf case DIOCTL_RWCMD: { 8171709Smlf struct dadkio_rwcmd *rwcmdp; 8181709Smlf int status; 8191709Smlf 8201709Smlf rwcmdp = kmem_alloc(sizeof (struct dadkio_rwcmd), KM_SLEEP); 8211709Smlf 8221709Smlf status = rwcmd_copyin(rwcmdp, (caddr_t)arg, flag); 8231709Smlf 8241709Smlf if (status == 0) { 8251709Smlf bzero(&(rwcmdp->status), sizeof (struct dadkio_status)); 8261709Smlf status = dadk_ioctl(DKTP_DATA, 8271709Smlf dev, 8281709Smlf cmd, 8291709Smlf (uintptr_t)rwcmdp, 8301709Smlf flag, 8311709Smlf credp, 8321709Smlf rvalp); 8331709Smlf } 8341709Smlf if (status == 0) 8351709Smlf status = rwcmd_copyout(rwcmdp, (caddr_t)arg, flag); 8361709Smlf 8371709Smlf kmem_free(rwcmdp, sizeof (struct dadkio_rwcmd)); 8381709Smlf return (status); 8391709Smlf } 8401709Smlf 8411709Smlf default: 8421709Smlf return (dadk_ioctl(DKTP_DATA, 8431709Smlf dev, 8441709Smlf cmd, 8451709Smlf arg, 8461709Smlf flag, 8471709Smlf credp, 8481709Smlf rvalp)); 8491709Smlf } 8501709Smlf } 8511709Smlf 8521709Smlf /*ARGSUSED1*/ 8531709Smlf static int 8541709Smlf cmdkclose(dev_t dev, int flag, int otyp, cred_t *credp) 8551709Smlf { 8561709Smlf int part; 8571709Smlf ulong_t partbit; 8581709Smlf int instance; 8591709Smlf struct cmdk *dkp; 8601709Smlf int lastclose = 1; 8611709Smlf int i; 8621709Smlf 8631709Smlf instance = CMDKUNIT(dev); 8641709Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance)) || 8651709Smlf (otyp >= OTYPCNT)) 8661709Smlf return (ENXIO); 8671709Smlf 8681709Smlf mutex_enter(&dkp->dk_mutex); 8691709Smlf 8701709Smlf /* check if device has been opened */ 8711709Smlf if (!(dkp->dk_flag & CMDK_OPEN)) { 8721709Smlf mutex_exit(&dkp->dk_mutex); 8731709Smlf return (ENXIO); 8741709Smlf } 8751709Smlf 8761709Smlf part = CMDKPART(dev); 8771709Smlf partbit = 1 << part; 8781709Smlf 8791709Smlf /* account for close */ 8801709Smlf if (otyp == OTYP_LYR) { 8811709Smlf if (dkp->dk_open_lyr[part]) 8821709Smlf dkp->dk_open_lyr[part]--; 8831709Smlf } else 8841709Smlf dkp->dk_open_reg[otyp] &= ~partbit; 8851709Smlf dkp->dk_open_exl &= ~partbit; 8861709Smlf 8871709Smlf for (i = 0; i < CMDK_MAXPART; i++) 8881709Smlf if (dkp->dk_open_lyr[i] != 0) { 8891709Smlf lastclose = 0; 8901709Smlf break; 8911709Smlf } 8921709Smlf 8931709Smlf if (lastclose) 8941709Smlf for (i = 0; i < OTYPCNT; i++) 8951709Smlf if (dkp->dk_open_reg[i] != 0) { 8961709Smlf lastclose = 0; 8971709Smlf break; 8981709Smlf } 8991709Smlf 9001709Smlf mutex_exit(&dkp->dk_mutex); 9011709Smlf 9021709Smlf if (lastclose) 903*3525Sshidokht cmlb_invalidate(dkp->dk_cmlbhandle, 0); 9041709Smlf 9051709Smlf return (DDI_SUCCESS); 9061709Smlf } 9071709Smlf 9081709Smlf /*ARGSUSED3*/ 9091709Smlf static int 9101709Smlf cmdkopen(dev_t *dev_p, int flag, int otyp, cred_t *credp) 9111709Smlf { 9121709Smlf dev_t dev = *dev_p; 9131709Smlf int part; 9141709Smlf ulong_t partbit; 9151709Smlf int instance; 9161709Smlf struct cmdk *dkp; 9171709Smlf diskaddr_t p_lblksrt; 9181709Smlf diskaddr_t p_lblkcnt; 9191709Smlf int i; 9201709Smlf int nodelay; 9211709Smlf 9221709Smlf instance = CMDKUNIT(dev); 9231709Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 9241709Smlf return (ENXIO); 9251709Smlf 9261709Smlf if (otyp >= OTYPCNT) 9271709Smlf return (EINVAL); 9281709Smlf 9291709Smlf part = CMDKPART(dev); 9301709Smlf partbit = 1 << part; 9311709Smlf nodelay = (flag & (FNDELAY | FNONBLOCK)); 9321709Smlf 9331709Smlf mutex_enter(&dkp->dk_mutex); 9341709Smlf 935*3525Sshidokht if (cmlb_validate(dkp->dk_cmlbhandle, 0, 0) != 0) { 9361709Smlf 9371709Smlf /* fail if not doing non block open */ 9381709Smlf if (!nodelay) { 9391709Smlf mutex_exit(&dkp->dk_mutex); 9401709Smlf return (ENXIO); 9411709Smlf } 9421709Smlf } else if (cmlb_partinfo(dkp->dk_cmlbhandle, part, &p_lblkcnt, 943*3525Sshidokht &p_lblksrt, NULL, NULL, 0) == 0) { 9441709Smlf 9451709Smlf if (p_lblkcnt <= 0 && (!nodelay || otyp != OTYP_CHR)) { 9461709Smlf mutex_exit(&dkp->dk_mutex); 9471709Smlf return (ENXIO); 9481709Smlf } 9491709Smlf } else { 9501709Smlf /* fail if not doing non block open */ 9511709Smlf if (!nodelay) { 9521709Smlf mutex_exit(&dkp->dk_mutex); 9531709Smlf return (ENXIO); 9541709Smlf } 9551709Smlf } 9561709Smlf 9571709Smlf if ((DKTP_EXT->tg_rdonly) && (flag & FWRITE)) { 9581709Smlf mutex_exit(&dkp->dk_mutex); 9591709Smlf return (EROFS); 9601709Smlf } 9611709Smlf 9621709Smlf /* check for part already opend exclusively */ 9631709Smlf if (dkp->dk_open_exl & partbit) 9641709Smlf goto excl_open_fail; 9651709Smlf 9661709Smlf /* check if we can establish exclusive open */ 9671709Smlf if (flag & FEXCL) { 9681709Smlf if (dkp->dk_open_lyr[part]) 9691709Smlf goto excl_open_fail; 9701709Smlf for (i = 0; i < OTYPCNT; i++) { 9711709Smlf if (dkp->dk_open_reg[i] & partbit) 9721709Smlf goto excl_open_fail; 9731709Smlf } 9741709Smlf } 9751709Smlf 9761709Smlf /* open will succeed, account for open */ 9771709Smlf dkp->dk_flag |= CMDK_OPEN; 9781709Smlf if (otyp == OTYP_LYR) 9791709Smlf dkp->dk_open_lyr[part]++; 9801709Smlf else 9811709Smlf dkp->dk_open_reg[otyp] |= partbit; 9821709Smlf if (flag & FEXCL) 9831709Smlf dkp->dk_open_exl |= partbit; 9841709Smlf 9851709Smlf mutex_exit(&dkp->dk_mutex); 9861709Smlf return (DDI_SUCCESS); 9871709Smlf 9881709Smlf excl_open_fail: 9891709Smlf mutex_exit(&dkp->dk_mutex); 9901709Smlf return (EBUSY); 9911709Smlf } 9921709Smlf 9931709Smlf /* 9941709Smlf * read routine 9951709Smlf */ 9961709Smlf /*ARGSUSED2*/ 9971709Smlf static int 9981709Smlf cmdkread(dev_t dev, struct uio *uio, cred_t *credp) 9991709Smlf { 10001709Smlf return (cmdkrw(dev, uio, B_READ)); 10011709Smlf } 10021709Smlf 10031709Smlf /* 10041709Smlf * async read routine 10051709Smlf */ 10061709Smlf /*ARGSUSED2*/ 10071709Smlf static int 10081709Smlf cmdkaread(dev_t dev, struct aio_req *aio, cred_t *credp) 10091709Smlf { 10101709Smlf return (cmdkarw(dev, aio, B_READ)); 10111709Smlf } 10121709Smlf 10131709Smlf /* 10141709Smlf * write routine 10151709Smlf */ 10161709Smlf /*ARGSUSED2*/ 10171709Smlf static int 10181709Smlf cmdkwrite(dev_t dev, struct uio *uio, cred_t *credp) 10191709Smlf { 10201709Smlf return (cmdkrw(dev, uio, B_WRITE)); 10211709Smlf } 10221709Smlf 10231709Smlf /* 10241709Smlf * async write routine 10251709Smlf */ 10261709Smlf /*ARGSUSED2*/ 10271709Smlf static int 10281709Smlf cmdkawrite(dev_t dev, struct aio_req *aio, cred_t *credp) 10291709Smlf { 10301709Smlf return (cmdkarw(dev, aio, B_WRITE)); 10311709Smlf } 10321709Smlf 10331709Smlf static void 10341709Smlf cmdkmin(struct buf *bp) 10351709Smlf { 10361709Smlf if (bp->b_bcount > DK_MAXRECSIZE) 10371709Smlf bp->b_bcount = DK_MAXRECSIZE; 10381709Smlf } 10391709Smlf 10401709Smlf static int 10411709Smlf cmdkrw(dev_t dev, struct uio *uio, int flag) 10421709Smlf { 10431709Smlf return (physio(cmdkstrategy, (struct buf *)0, dev, flag, cmdkmin, uio)); 10441709Smlf } 10451709Smlf 10461709Smlf static int 10471709Smlf cmdkarw(dev_t dev, struct aio_req *aio, int flag) 10481709Smlf { 10491709Smlf return (aphysio(cmdkstrategy, anocancel, dev, flag, cmdkmin, aio)); 10501709Smlf } 10511709Smlf 10521709Smlf /* 10531709Smlf * strategy routine 10541709Smlf */ 10551709Smlf static int 10561709Smlf cmdkstrategy(struct buf *bp) 10571709Smlf { 10581709Smlf int instance; 10591709Smlf struct cmdk *dkp; 10601709Smlf long d_cnt; 10611709Smlf diskaddr_t p_lblksrt; 10621709Smlf diskaddr_t p_lblkcnt; 10631709Smlf 10641709Smlf instance = CMDKUNIT(bp->b_edev); 10651709Smlf if (cmdk_indump || !(dkp = ddi_get_soft_state(cmdk_state, instance)) || 10661709Smlf (dkblock(bp) < 0)) { 10671709Smlf bp->b_resid = bp->b_bcount; 10681709Smlf SETBPERR(bp, ENXIO); 10691709Smlf biodone(bp); 10701709Smlf return (0); 10711709Smlf } 10721709Smlf 10731709Smlf bp->b_flags &= ~(B_DONE|B_ERROR); 10741709Smlf bp->b_resid = 0; 10751709Smlf bp->av_back = NULL; 10761709Smlf 10771709Smlf /* 10781709Smlf * only re-read the vtoc if necessary (force == FALSE) 10791709Smlf */ 1080*3525Sshidokht if (cmlb_partinfo(dkp->dk_cmlbhandle, CMDKPART(bp->b_edev), 1081*3525Sshidokht &p_lblkcnt, &p_lblksrt, NULL, NULL, 0)) { 10821709Smlf SETBPERR(bp, ENXIO); 10831709Smlf } 10841709Smlf 10851709Smlf if ((bp->b_bcount & (NBPSCTR-1)) || (dkblock(bp) > p_lblkcnt)) 10861709Smlf SETBPERR(bp, ENXIO); 10871709Smlf 10881709Smlf if ((bp->b_flags & B_ERROR) || (dkblock(bp) == p_lblkcnt)) { 10891709Smlf bp->b_resid = bp->b_bcount; 10901709Smlf biodone(bp); 10911709Smlf return (0); 10921709Smlf } 10931709Smlf 10941709Smlf d_cnt = bp->b_bcount >> SCTRSHFT; 10951709Smlf if ((dkblock(bp) + d_cnt) > p_lblkcnt) { 10961709Smlf bp->b_resid = ((dkblock(bp) + d_cnt) - p_lblkcnt) << SCTRSHFT; 10971709Smlf bp->b_bcount -= bp->b_resid; 10981709Smlf } 10991709Smlf 11001709Smlf SET_BP_SEC(bp, ((ulong_t)(p_lblksrt + dkblock(bp)))); 11011709Smlf if (dadk_strategy(DKTP_DATA, bp) != DDI_SUCCESS) { 11021709Smlf bp->b_resid += bp->b_bcount; 11031709Smlf biodone(bp); 11041709Smlf } 11051709Smlf return (0); 11061709Smlf } 11071709Smlf 11081709Smlf static int 11091709Smlf cmdk_create_obj(dev_info_t *dip, struct cmdk *dkp) 11101709Smlf { 11111709Smlf struct scsi_device *devp; 11121709Smlf opaque_t queobjp = NULL; 11131709Smlf opaque_t flcobjp = NULL; 11141709Smlf char que_keyvalp[64]; 11151709Smlf int que_keylen; 11161709Smlf char flc_keyvalp[64]; 11171709Smlf int flc_keylen; 11181709Smlf 11191709Smlf ASSERT(mutex_owned(&dkp->dk_mutex)); 11201709Smlf 11211709Smlf /* Create linkage to queueing routines based on property */ 11221709Smlf que_keylen = sizeof (que_keyvalp); 11231709Smlf if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF, 11241709Smlf DDI_PROP_CANSLEEP, "queue", que_keyvalp, &que_keylen) != 11251709Smlf DDI_PROP_SUCCESS) { 11261709Smlf cmn_err(CE_WARN, "cmdk_create_obj: queue property undefined"); 11271709Smlf return (DDI_FAILURE); 11281709Smlf } 11291709Smlf que_keyvalp[que_keylen] = (char)0; 11301709Smlf 11311709Smlf if (strcmp(que_keyvalp, "qfifo") == 0) { 11321709Smlf queobjp = (opaque_t)qfifo_create(); 11331709Smlf } else if (strcmp(que_keyvalp, "qsort") == 0) { 11341709Smlf queobjp = (opaque_t)qsort_create(); 11351709Smlf } else { 11361709Smlf return (DDI_FAILURE); 11371709Smlf } 11381709Smlf 11391709Smlf /* Create linkage to dequeueing routines based on property */ 11401709Smlf flc_keylen = sizeof (flc_keyvalp); 11411709Smlf if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF, 11421709Smlf DDI_PROP_CANSLEEP, "flow_control", flc_keyvalp, &flc_keylen) != 11431709Smlf DDI_PROP_SUCCESS) { 11441709Smlf cmn_err(CE_WARN, 11451709Smlf "cmdk_create_obj: flow-control property undefined"); 11461709Smlf return (DDI_FAILURE); 11471709Smlf } 11481709Smlf 11491709Smlf flc_keyvalp[flc_keylen] = (char)0; 11501709Smlf 11511709Smlf if (strcmp(flc_keyvalp, "dsngl") == 0) { 11521709Smlf flcobjp = (opaque_t)dsngl_create(); 11531709Smlf } else if (strcmp(flc_keyvalp, "dmult") == 0) { 11541709Smlf flcobjp = (opaque_t)dmult_create(); 11551709Smlf } else { 11561709Smlf return (DDI_FAILURE); 11571709Smlf } 11581709Smlf 11591709Smlf /* populate bbh_obj object stored in dkp */ 11601709Smlf dkp->dk_bbh_obj.bbh_data = dkp; 11611709Smlf dkp->dk_bbh_obj.bbh_ops = &cmdk_bbh_ops; 11621709Smlf 11631709Smlf /* create linkage to dadk */ 11641709Smlf dkp->dk_tgobjp = (opaque_t)dadk_create(); 11651709Smlf 11661709Smlf devp = ddi_get_driver_private(dip); 11671709Smlf (void) dadk_init(DKTP_DATA, devp, flcobjp, queobjp, &dkp->dk_bbh_obj, 11681709Smlf NULL); 11691709Smlf 11701709Smlf return (DDI_SUCCESS); 11711709Smlf } 11721709Smlf 11731709Smlf static void 11741709Smlf cmdk_destroy_obj(dev_info_t *dip, struct cmdk *dkp) 11751709Smlf { 11761709Smlf char que_keyvalp[64]; 11771709Smlf int que_keylen; 11781709Smlf char flc_keyvalp[64]; 11791709Smlf int flc_keylen; 11801709Smlf 11811709Smlf ASSERT(mutex_owned(&dkp->dk_mutex)); 11821709Smlf 11831709Smlf (void) dadk_free((dkp->dk_tgobjp)); 11841709Smlf dkp->dk_tgobjp = NULL; 11851709Smlf 11861709Smlf que_keylen = sizeof (que_keyvalp); 11871709Smlf if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF, 11881709Smlf DDI_PROP_CANSLEEP, "queue", que_keyvalp, &que_keylen) != 11891709Smlf DDI_PROP_SUCCESS) { 11901709Smlf cmn_err(CE_WARN, "cmdk_destroy_obj: queue property undefined"); 11911709Smlf return; 11921709Smlf } 11931709Smlf que_keyvalp[que_keylen] = (char)0; 11941709Smlf 11951709Smlf flc_keylen = sizeof (flc_keyvalp); 11961709Smlf if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF, 11971709Smlf DDI_PROP_CANSLEEP, "flow_control", flc_keyvalp, &flc_keylen) != 11981709Smlf DDI_PROP_SUCCESS) { 11991709Smlf cmn_err(CE_WARN, 12001709Smlf "cmdk_destroy_obj: flow-control property undefined"); 12011709Smlf return; 12021709Smlf } 12031709Smlf flc_keyvalp[flc_keylen] = (char)0; 12041709Smlf } 1205*3525Sshidokht /*ARGSUSED5*/ 12061709Smlf static int 1207*3525Sshidokht cmdk_lb_rdwr(dev_info_t *dip, uchar_t cmd, void *bufaddr, 1208*3525Sshidokht diskaddr_t start, size_t count, void *tg_cookie) 12091709Smlf { 12101709Smlf struct cmdk *dkp; 12111709Smlf opaque_t handle; 12121709Smlf int rc = 0; 12131709Smlf char *bufa; 12141709Smlf 12151709Smlf dkp = ddi_get_soft_state(cmdk_state, ddi_get_instance(dip)); 12161709Smlf if (dkp == NULL) 12171709Smlf return (ENXIO); 12181709Smlf 12191709Smlf if (cmd != TG_READ && cmd != TG_WRITE) 12201709Smlf return (EINVAL); 12211709Smlf 12221709Smlf /* count must be multiple of 512 */ 12231709Smlf count = (count + NBPSCTR - 1) & -NBPSCTR; 12241709Smlf handle = dadk_iob_alloc(DKTP_DATA, start, count, KM_SLEEP); 12251709Smlf if (!handle) 12261709Smlf return (ENOMEM); 12271709Smlf 12281709Smlf if (cmd == TG_READ) { 12291709Smlf bufa = dadk_iob_xfer(DKTP_DATA, handle, B_READ); 12301709Smlf if (!bufa) 12311709Smlf rc = EIO; 12321709Smlf else 12331709Smlf bcopy(bufa, bufaddr, count); 12341709Smlf } else { 12351709Smlf bufa = dadk_iob_htoc(DKTP_DATA, handle); 12361709Smlf bcopy(bufaddr, bufa, count); 12371709Smlf bufa = dadk_iob_xfer(DKTP_DATA, handle, B_WRITE); 12381709Smlf if (!bufa) 12391709Smlf rc = EIO; 12401709Smlf } 12411709Smlf (void) dadk_iob_free(DKTP_DATA, handle); 12421709Smlf 12431709Smlf return (rc); 12441709Smlf } 12451709Smlf 1246*3525Sshidokht /*ARGSUSED3*/ 12471709Smlf static int 1248*3525Sshidokht cmdk_lb_getinfo(dev_info_t *dip, int cmd, void *arg, void *tg_cookie) 12491709Smlf { 1250*3525Sshidokht 12511709Smlf struct cmdk *dkp; 12521709Smlf struct tgdk_geom phyg; 12531709Smlf 12541709Smlf 12551709Smlf dkp = ddi_get_soft_state(cmdk_state, ddi_get_instance(dip)); 12561709Smlf if (dkp == NULL) 12571709Smlf return (ENXIO); 12581709Smlf 1259*3525Sshidokht switch (cmd) { 1260*3525Sshidokht case TG_GETPHYGEOM: { 1261*3525Sshidokht cmlb_geom_t *phygeomp = (cmlb_geom_t *)arg; 1262*3525Sshidokht 1263*3525Sshidokht /* dadk_getphygeom always returns success */ 1264*3525Sshidokht (void) dadk_getphygeom(DKTP_DATA, &phyg); 1265*3525Sshidokht 1266*3525Sshidokht phygeomp->g_capacity = phyg.g_cap; 1267*3525Sshidokht phygeomp->g_nsect = phyg.g_sec; 1268*3525Sshidokht phygeomp->g_nhead = phyg.g_head; 1269*3525Sshidokht phygeomp->g_acyl = phyg.g_acyl; 1270*3525Sshidokht phygeomp->g_ncyl = phyg.g_cyl; 1271*3525Sshidokht phygeomp->g_secsize = phyg.g_secsiz; 1272*3525Sshidokht phygeomp->g_intrlv = 1; 1273*3525Sshidokht phygeomp->g_rpm = 3600; 12741709Smlf 1275*3525Sshidokht return (0); 1276*3525Sshidokht } 1277*3525Sshidokht 1278*3525Sshidokht case TG_GETVIRTGEOM: { 1279*3525Sshidokht cmlb_geom_t *virtgeomp = (cmlb_geom_t *)arg; 1280*3525Sshidokht diskaddr_t capacity; 1281*3525Sshidokht 1282*3525Sshidokht (void) dadk_getgeom(DKTP_DATA, &phyg); 1283*3525Sshidokht capacity = phyg.g_cap; 1284*3525Sshidokht 1285*3525Sshidokht /* 1286*3525Sshidokht * If the controller returned us something that doesn't 1287*3525Sshidokht * really fit into an Int 13/function 8 geometry 1288*3525Sshidokht * result, just fail the ioctl. See PSARC 1998/313. 1289*3525Sshidokht */ 1290*3525Sshidokht if (capacity < 0 || capacity >= 63 * 254 * 1024) 1291*3525Sshidokht return (EINVAL); 12921709Smlf 1293*3525Sshidokht virtgeomp->g_capacity = capacity; 1294*3525Sshidokht virtgeomp->g_nsect = 63; 1295*3525Sshidokht virtgeomp->g_nhead = 254; 1296*3525Sshidokht virtgeomp->g_ncyl = capacity / (63 * 254); 1297*3525Sshidokht virtgeomp->g_acyl = 0; 1298*3525Sshidokht virtgeomp->g_secsize = 512; 1299*3525Sshidokht virtgeomp->g_intrlv = 1; 1300*3525Sshidokht virtgeomp->g_rpm = 3600; 1301*3525Sshidokht 1302*3525Sshidokht return (0); 1303*3525Sshidokht } 1304*3525Sshidokht 1305*3525Sshidokht case TG_GETCAPACITY: 1306*3525Sshidokht case TG_GETBLOCKSIZE: 1307*3525Sshidokht { 13081709Smlf 1309*3525Sshidokht /* dadk_getphygeom always returns success */ 1310*3525Sshidokht (void) dadk_getphygeom(DKTP_DATA, &phyg); 1311*3525Sshidokht if (cmd == TG_GETCAPACITY) 1312*3525Sshidokht *(diskaddr_t *)arg = phyg.g_cap; 1313*3525Sshidokht else 1314*3525Sshidokht *(uint32_t *)arg = (uint32_t)phyg.g_secsiz; 1315*3525Sshidokht 1316*3525Sshidokht return (0); 1317*3525Sshidokht } 1318*3525Sshidokht 1319*3525Sshidokht case TG_GETATTR: { 1320*3525Sshidokht tg_attribute_t *tgattribute = (tg_attribute_t *)arg; 1321*3525Sshidokht if ((DKTP_EXT->tg_rdonly)) 1322*3525Sshidokht tgattribute->media_is_writable = FALSE; 1323*3525Sshidokht else 1324*3525Sshidokht tgattribute->media_is_writable = TRUE; 1325*3525Sshidokht 1326*3525Sshidokht return (0); 1327*3525Sshidokht } 1328*3525Sshidokht 1329*3525Sshidokht default: 1330*3525Sshidokht return (ENOTTY); 1331*3525Sshidokht } 13321709Smlf } 13331709Smlf 13341709Smlf 13351709Smlf 13361709Smlf 13371709Smlf 13381709Smlf /* 13391709Smlf * Create and register the devid. 13401709Smlf * There are 4 different ways we can get a device id: 13411709Smlf * 1. Already have one - nothing to do 13421709Smlf * 2. Build one from the drive's model and serial numbers 13431709Smlf * 3. Read one from the disk (first sector of last track) 13441709Smlf * 4. Fabricate one and write it on the disk. 13451709Smlf * If any of these succeeds, register the deviceid 13461709Smlf */ 13471709Smlf static void 13481709Smlf cmdk_devid_setup(struct cmdk *dkp) 13491709Smlf { 13501709Smlf int rc; 13511709Smlf 13521709Smlf /* Try options until one succeeds, or all have failed */ 13531709Smlf 13541709Smlf /* 1. All done if already registered */ 13551709Smlf if (dkp->dk_devid != NULL) 13561709Smlf return; 13571709Smlf 13581709Smlf /* 2. Build a devid from the model and serial number */ 13591709Smlf rc = cmdk_devid_modser(dkp); 13601709Smlf if (rc != DDI_SUCCESS) { 13611709Smlf /* 3. Read devid from the disk, if present */ 13621709Smlf rc = cmdk_devid_read(dkp); 13631709Smlf 13641709Smlf /* 4. otherwise make one up and write it on the disk */ 13651709Smlf if (rc != DDI_SUCCESS) 13661709Smlf rc = cmdk_devid_fabricate(dkp); 13671709Smlf } 13681709Smlf 13691709Smlf /* If we managed to get a devid any of the above ways, register it */ 13701709Smlf if (rc == DDI_SUCCESS) 13711709Smlf (void) ddi_devid_register(dkp->dk_dip, dkp->dk_devid); 13721709Smlf 13731709Smlf } 13741709Smlf 13751709Smlf /* 13761709Smlf * Build a devid from the model and serial number 13771709Smlf * Return DDI_SUCCESS or DDI_FAILURE. 13781709Smlf */ 13791709Smlf static int 13801709Smlf cmdk_devid_modser(struct cmdk *dkp) 13811709Smlf { 13821709Smlf int rc = DDI_FAILURE; 13831709Smlf char *hwid; 13841709Smlf int modlen; 13851709Smlf int serlen; 13861709Smlf 13871709Smlf /* 13881709Smlf * device ID is a concatenation of model number, '=', serial number. 13891709Smlf */ 13901709Smlf hwid = kmem_alloc(CMDK_HWIDLEN, KM_SLEEP); 13911709Smlf modlen = cmdk_get_modser(dkp, DIOCTL_GETMODEL, hwid, CMDK_HWIDLEN); 13921709Smlf if (modlen == 0) { 13931709Smlf rc = DDI_FAILURE; 13941709Smlf goto err; 13951709Smlf } 13961709Smlf hwid[modlen++] = '='; 13971709Smlf serlen = cmdk_get_modser(dkp, DIOCTL_GETSERIAL, 13981709Smlf hwid + modlen, CMDK_HWIDLEN - modlen); 13991709Smlf if (serlen == 0) { 14001709Smlf rc = DDI_FAILURE; 14011709Smlf goto err; 14021709Smlf } 14031709Smlf hwid[modlen + serlen] = 0; 14041709Smlf 14051709Smlf /* Initialize the device ID, trailing NULL not included */ 14061709Smlf rc = ddi_devid_init(dkp->dk_dip, DEVID_ATA_SERIAL, modlen + serlen, 14071709Smlf hwid, (ddi_devid_t *)&dkp->dk_devid); 14081709Smlf if (rc != DDI_SUCCESS) { 14091709Smlf rc = DDI_FAILURE; 14101709Smlf goto err; 14111709Smlf } 14121709Smlf 14131709Smlf rc = DDI_SUCCESS; 14141709Smlf 14151709Smlf err: 14161709Smlf kmem_free(hwid, CMDK_HWIDLEN); 14171709Smlf return (rc); 14181709Smlf } 14191709Smlf 14201709Smlf static int 14211709Smlf cmdk_get_modser(struct cmdk *dkp, int ioccmd, char *buf, int len) 14221709Smlf { 14231709Smlf dadk_ioc_string_t strarg; 14241709Smlf int rval; 14251709Smlf char *s; 14261709Smlf char ch; 14271709Smlf boolean_t ret; 14281709Smlf int i; 14291709Smlf int tb; 14301709Smlf 14311709Smlf strarg.is_buf = buf; 14321709Smlf strarg.is_size = len; 14331709Smlf if (dadk_ioctl(DKTP_DATA, 14341709Smlf dkp->dk_dev, 14351709Smlf ioccmd, 14361709Smlf (uintptr_t)&strarg, 14371709Smlf FNATIVE | FKIOCTL, 14381709Smlf NULL, 14391709Smlf &rval) != 0) 14401709Smlf return (0); 14411709Smlf 14421709Smlf /* 14431709Smlf * valid model/serial string must contain a non-zero non-space 14441709Smlf * trim trailing spaces/NULL 14451709Smlf */ 14461709Smlf ret = B_FALSE; 14471709Smlf s = buf; 14481709Smlf for (i = 0; i < strarg.is_size; i++) { 14491709Smlf ch = *s++; 14501709Smlf if (ch != ' ' && ch != '\0') 14511709Smlf tb = i + 1; 14521709Smlf if (ch != ' ' && ch != '\0' && ch != '0') 14531709Smlf ret = B_TRUE; 14541709Smlf } 14551709Smlf 14561709Smlf if (ret == B_FALSE) 14571709Smlf return (0); 14581709Smlf 14591709Smlf return (tb); 14601709Smlf } 14611709Smlf 14621709Smlf /* 14631709Smlf * Read a devid from on the first block of the last track of 14641709Smlf * the last cylinder. Make sure what we read is a valid devid. 14651709Smlf * Return DDI_SUCCESS or DDI_FAILURE. 14661709Smlf */ 14671709Smlf static int 14681709Smlf cmdk_devid_read(struct cmdk *dkp) 14691709Smlf { 14701709Smlf diskaddr_t blk; 14711709Smlf struct dk_devid *dkdevidp; 14721709Smlf uint_t *ip; 14731709Smlf int chksum; 14741709Smlf int i, sz; 14751709Smlf tgdk_iob_handle handle; 14761709Smlf int rc = DDI_FAILURE; 14771709Smlf 1478*3525Sshidokht if (cmlb_get_devid_block(dkp->dk_cmlbhandle, &blk, 0)) 14791709Smlf goto err; 14801709Smlf 14811709Smlf /* read the devid */ 14821709Smlf handle = dadk_iob_alloc(DKTP_DATA, blk, NBPSCTR, KM_SLEEP); 14831709Smlf if (handle == NULL) 14841709Smlf goto err; 14851709Smlf 14861709Smlf dkdevidp = (struct dk_devid *)dadk_iob_xfer(DKTP_DATA, handle, B_READ); 14871709Smlf if (dkdevidp == NULL) 14881709Smlf goto err; 14891709Smlf 14901709Smlf /* Validate the revision */ 14911709Smlf if ((dkdevidp->dkd_rev_hi != DK_DEVID_REV_MSB) || 14921709Smlf (dkdevidp->dkd_rev_lo != DK_DEVID_REV_LSB)) 14931709Smlf goto err; 14941709Smlf 14951709Smlf /* Calculate the checksum */ 14961709Smlf chksum = 0; 14971709Smlf ip = (uint_t *)dkdevidp; 14981709Smlf for (i = 0; i < ((NBPSCTR - sizeof (int))/sizeof (int)); i++) 14991709Smlf chksum ^= ip[i]; 15001709Smlf if (DKD_GETCHKSUM(dkdevidp) != chksum) 15011709Smlf goto err; 15021709Smlf 15031709Smlf /* Validate the device id */ 15041709Smlf if (ddi_devid_valid((ddi_devid_t)dkdevidp->dkd_devid) != DDI_SUCCESS) 15051709Smlf goto err; 15061709Smlf 15071709Smlf /* keep a copy of the device id */ 15081709Smlf sz = ddi_devid_sizeof((ddi_devid_t)dkdevidp->dkd_devid); 15091709Smlf dkp->dk_devid = kmem_alloc(sz, KM_SLEEP); 15101709Smlf bcopy(dkdevidp->dkd_devid, dkp->dk_devid, sz); 15111709Smlf 15121709Smlf rc = DDI_SUCCESS; 15131709Smlf 15141709Smlf err: 15151709Smlf if (handle != NULL) 15161709Smlf (void) dadk_iob_free(DKTP_DATA, handle); 15171709Smlf return (rc); 15181709Smlf } 15191709Smlf 15201709Smlf /* 15211709Smlf * Create a devid and write it on the first block of the last track of 15221709Smlf * the last cylinder. 15231709Smlf * Return DDI_SUCCESS or DDI_FAILURE. 15241709Smlf */ 15251709Smlf static int 15261709Smlf cmdk_devid_fabricate(struct cmdk *dkp) 15271709Smlf { 15281709Smlf ddi_devid_t devid = NULL; /* devid made by ddi_devid_init */ 15291709Smlf struct dk_devid *dkdevidp; /* devid struct stored on disk */ 15301709Smlf diskaddr_t blk; 15311709Smlf tgdk_iob_handle handle = NULL; 15321709Smlf uint_t *ip, chksum; 15331709Smlf int i; 15341709Smlf int rc; 15351709Smlf 15361709Smlf rc = ddi_devid_init(dkp->dk_dip, DEVID_FAB, 0, NULL, &devid); 15371709Smlf if (rc != DDI_SUCCESS) 15381709Smlf goto err; 15391709Smlf 1540*3525Sshidokht if (cmlb_get_devid_block(dkp->dk_cmlbhandle, &blk, 0)) { 15411709Smlf /* no device id block address */ 15421709Smlf return (DDI_FAILURE); 15431709Smlf } 15441709Smlf 15451709Smlf handle = dadk_iob_alloc(DKTP_DATA, blk, NBPSCTR, KM_SLEEP); 15461709Smlf if (!handle) 15471709Smlf goto err; 15481709Smlf 15491709Smlf /* Locate the buffer */ 15501709Smlf dkdevidp = (struct dk_devid *)dadk_iob_htoc(DKTP_DATA, handle); 15511709Smlf 15521709Smlf /* Fill in the revision */ 15531709Smlf bzero(dkdevidp, NBPSCTR); 15541709Smlf dkdevidp->dkd_rev_hi = DK_DEVID_REV_MSB; 15551709Smlf dkdevidp->dkd_rev_lo = DK_DEVID_REV_LSB; 15561709Smlf 15571709Smlf /* Copy in the device id */ 15581709Smlf i = ddi_devid_sizeof(devid); 15591709Smlf if (i > DK_DEVID_SIZE) 15601709Smlf goto err; 15611709Smlf bcopy(devid, dkdevidp->dkd_devid, i); 15621709Smlf 15631709Smlf /* Calculate the chksum */ 15641709Smlf chksum = 0; 15651709Smlf ip = (uint_t *)dkdevidp; 15661709Smlf for (i = 0; i < ((NBPSCTR - sizeof (int))/sizeof (int)); i++) 15671709Smlf chksum ^= ip[i]; 15681709Smlf 15691709Smlf /* Fill in the checksum */ 15701709Smlf DKD_FORMCHKSUM(chksum, dkdevidp); 15711709Smlf 15721709Smlf /* write the devid */ 15731709Smlf (void) dadk_iob_xfer(DKTP_DATA, handle, B_WRITE); 15741709Smlf 15751709Smlf dkp->dk_devid = devid; 15761709Smlf 15771709Smlf rc = DDI_SUCCESS; 15781709Smlf 15791709Smlf err: 15801709Smlf if (handle != NULL) 15811709Smlf (void) dadk_iob_free(DKTP_DATA, handle); 15821709Smlf 15831709Smlf if (rc != DDI_SUCCESS && devid != NULL) 15841709Smlf ddi_devid_free(devid); 15851709Smlf 15861709Smlf return (rc); 15871709Smlf } 15881709Smlf 15891709Smlf static void 15901709Smlf cmdk_bbh_free_alts(struct cmdk *dkp) 15911709Smlf { 15921709Smlf if (dkp->dk_alts_hdl) { 15931709Smlf (void) dadk_iob_free(DKTP_DATA, dkp->dk_alts_hdl); 15941709Smlf kmem_free(dkp->dk_slc_cnt, 15951709Smlf NDKMAP * (sizeof (uint32_t) + sizeof (struct alts_ent *))); 15961709Smlf dkp->dk_alts_hdl = NULL; 15971709Smlf } 15981709Smlf } 15991709Smlf 16001709Smlf static void 16011709Smlf cmdk_bbh_reopen(struct cmdk *dkp) 16021709Smlf { 16031709Smlf tgdk_iob_handle handle = NULL; 16041709Smlf diskaddr_t slcb, slcn, slce; 16051709Smlf struct alts_parttbl *ap; 16061709Smlf struct alts_ent *enttblp; 16071709Smlf uint32_t altused; 16081709Smlf uint32_t altbase; 16091709Smlf uint32_t altlast; 16101709Smlf int alts; 16111709Smlf uint16_t vtoctag; 16121709Smlf int i, j; 16131709Smlf 16141709Smlf /* find slice with V_ALTSCTR tag */ 16151709Smlf for (alts = 0; alts < NDKMAP; alts++) { 16161709Smlf if (cmlb_partinfo( 16171709Smlf dkp->dk_cmlbhandle, 16181709Smlf alts, 16191709Smlf &slcn, 16201709Smlf &slcb, 16211709Smlf NULL, 1622*3525Sshidokht &vtoctag, 1623*3525Sshidokht 0)) { 16241709Smlf goto empty; /* no partition table exists */ 16251709Smlf } 16261709Smlf 16271709Smlf if (vtoctag == V_ALTSCTR && slcn > 1) 16281709Smlf break; 16291709Smlf } 16301709Smlf if (alts >= NDKMAP) { 16311709Smlf goto empty; /* no V_ALTSCTR slice defined */ 16321709Smlf } 16331709Smlf 16341709Smlf /* read in ALTS label block */ 16351709Smlf handle = dadk_iob_alloc(DKTP_DATA, slcb, NBPSCTR, KM_SLEEP); 16361709Smlf if (!handle) { 16371709Smlf goto empty; 16381709Smlf } 16391709Smlf 16401709Smlf ap = (struct alts_parttbl *)dadk_iob_xfer(DKTP_DATA, handle, B_READ); 16411709Smlf if (!ap || (ap->alts_sanity != ALTS_SANITY)) { 16421709Smlf goto empty; 16431709Smlf } 16441709Smlf 16451709Smlf altused = ap->alts_ent_used; /* number of BB entries */ 16461709Smlf altbase = ap->alts_ent_base; /* blk offset from begin slice */ 16471709Smlf altlast = ap->alts_ent_end; /* blk offset to last block */ 16481709Smlf /* ((altused * sizeof (struct alts_ent) + NBPSCTR - 1) & ~NBPSCTR) */ 16491709Smlf 16501709Smlf if (altused == 0 || 16511709Smlf altbase < 1 || 16521709Smlf altbase > altlast || 16531709Smlf altlast >= slcn) { 16541709Smlf goto empty; 16551709Smlf } 16561709Smlf (void) dadk_iob_free(DKTP_DATA, handle); 16571709Smlf 16581709Smlf /* read in ALTS remapping table */ 16591709Smlf handle = dadk_iob_alloc(DKTP_DATA, 16601709Smlf slcb + altbase, 16611709Smlf (altlast - altbase + 1) << SCTRSHFT, KM_SLEEP); 16621709Smlf if (!handle) { 16631709Smlf goto empty; 16641709Smlf } 16651709Smlf 16661709Smlf enttblp = (struct alts_ent *)dadk_iob_xfer(DKTP_DATA, handle, B_READ); 16671709Smlf if (!enttblp) { 16681709Smlf goto empty; 16691709Smlf } 16701709Smlf 16711709Smlf rw_enter(&dkp->dk_bbh_mutex, RW_WRITER); 16721709Smlf 16731709Smlf /* allocate space for dk_slc_cnt and dk_slc_ent tables */ 16741709Smlf if (dkp->dk_slc_cnt == NULL) { 16751709Smlf dkp->dk_slc_cnt = kmem_alloc(NDKMAP * 16761709Smlf (sizeof (long) + sizeof (struct alts_ent *)), KM_SLEEP); 16771709Smlf } 16781709Smlf dkp->dk_slc_ent = (struct alts_ent **)(dkp->dk_slc_cnt + NDKMAP); 16791709Smlf 16801709Smlf /* free previous BB table (if any) */ 16811709Smlf if (dkp->dk_alts_hdl) { 16821709Smlf (void) dadk_iob_free(DKTP_DATA, dkp->dk_alts_hdl); 16831709Smlf dkp->dk_alts_hdl = NULL; 16841709Smlf dkp->dk_altused = 0; 16851709Smlf } 16861709Smlf 16871709Smlf /* save linkage to new BB table */ 16881709Smlf dkp->dk_alts_hdl = handle; 16891709Smlf dkp->dk_altused = altused; 16901709Smlf 16911709Smlf /* 16921709Smlf * build indexes to BB table by slice 16931709Smlf * effectively we have 16941709Smlf * struct alts_ent *enttblp[altused]; 16951709Smlf * 16961709Smlf * uint32_t dk_slc_cnt[NDKMAP]; 16971709Smlf * struct alts_ent *dk_slc_ent[NDKMAP]; 16981709Smlf */ 16991709Smlf for (i = 0; i < NDKMAP; i++) { 17001709Smlf if (cmlb_partinfo( 17011709Smlf dkp->dk_cmlbhandle, 17021709Smlf i, 17031709Smlf &slcn, 17041709Smlf &slcb, 17051709Smlf NULL, 1706*3525Sshidokht NULL, 1707*3525Sshidokht 0)) { 17081709Smlf goto empty1; 17091709Smlf } 17101709Smlf 17111709Smlf dkp->dk_slc_cnt[i] = 0; 17121709Smlf if (slcn == 0) 17131709Smlf continue; /* slice is not allocated */ 17141709Smlf 17151709Smlf /* last block in slice */ 17161709Smlf slce = slcb + slcn - 1; 17171709Smlf 17181709Smlf /* find first remap entry in after beginnning of slice */ 17191709Smlf for (j = 0; j < altused; j++) { 17201709Smlf if (enttblp[j].bad_start + enttblp[j].bad_end >= slcb) 17211709Smlf break; 17221709Smlf } 17231709Smlf dkp->dk_slc_ent[i] = enttblp + j; 17241709Smlf 17251709Smlf /* count remap entrys until end of slice */ 17261709Smlf for (; j < altused && enttblp[j].bad_start <= slce; j++) { 17271709Smlf dkp->dk_slc_cnt[i] += 1; 17281709Smlf } 17291709Smlf } 17301709Smlf 17311709Smlf rw_exit(&dkp->dk_bbh_mutex); 17321709Smlf return; 17331709Smlf 17341709Smlf empty: 17351709Smlf rw_enter(&dkp->dk_bbh_mutex, RW_WRITER); 17361709Smlf empty1: 17371709Smlf if (handle && handle != dkp->dk_alts_hdl) 17381709Smlf (void) dadk_iob_free(DKTP_DATA, handle); 17391709Smlf 17401709Smlf if (dkp->dk_alts_hdl) { 17411709Smlf (void) dadk_iob_free(DKTP_DATA, dkp->dk_alts_hdl); 17421709Smlf dkp->dk_alts_hdl = NULL; 17431709Smlf } 17441709Smlf 17451709Smlf rw_exit(&dkp->dk_bbh_mutex); 17461709Smlf } 17471709Smlf 17481709Smlf /*ARGSUSED*/ 17491709Smlf static bbh_cookie_t 17501709Smlf cmdk_bbh_htoc(opaque_t bbh_data, opaque_t handle) 17511709Smlf { 17521709Smlf struct bbh_handle *hp; 17531709Smlf bbh_cookie_t ckp; 17541709Smlf 17551709Smlf hp = (struct bbh_handle *)handle; 17561709Smlf ckp = hp->h_cktab + hp->h_idx; 17571709Smlf hp->h_idx++; 17581709Smlf return (ckp); 17591709Smlf } 17601709Smlf 17611709Smlf /*ARGSUSED*/ 17621709Smlf static void 17631709Smlf cmdk_bbh_freehandle(opaque_t bbh_data, opaque_t handle) 17641709Smlf { 17651709Smlf struct bbh_handle *hp; 17661709Smlf 17671709Smlf hp = (struct bbh_handle *)handle; 17681709Smlf kmem_free(handle, (sizeof (struct bbh_handle) + 17691709Smlf (hp->h_totck * (sizeof (struct bbh_cookie))))); 17701709Smlf } 17711709Smlf 17721709Smlf 17731709Smlf /* 17741709Smlf * cmdk_bbh_gethandle remaps the bad sectors to alternates. 17751709Smlf * There are 7 different cases when the comparison is made 17761709Smlf * between the bad sector cluster and the disk section. 17771709Smlf * 17781709Smlf * bad sector cluster gggggggggggbbbbbbbggggggggggg 17791709Smlf * case 1: ddddd 17801709Smlf * case 2: -d----- 17811709Smlf * case 3: ddddd 17821709Smlf * case 4: dddddddddddd 17831709Smlf * case 5: ddddddd----- 17841709Smlf * case 6: ---ddddddd 17851709Smlf * case 7: ddddddd 17861709Smlf * 17871709Smlf * where: g = good sector, b = bad sector 17881709Smlf * d = sector in disk section 17891709Smlf * - = disk section may be extended to cover those disk area 17901709Smlf */ 17911709Smlf 17921709Smlf static opaque_t 17931709Smlf cmdk_bbh_gethandle(opaque_t bbh_data, struct buf *bp) 17941709Smlf { 17951709Smlf struct cmdk *dkp = (struct cmdk *)bbh_data; 17961709Smlf struct bbh_handle *hp; 17971709Smlf struct bbh_cookie *ckp; 17981709Smlf struct alts_ent *altp; 17991709Smlf uint32_t alts_used; 18001709Smlf uint32_t part = CMDKPART(bp->b_edev); 18011709Smlf daddr32_t lastsec; 18021709Smlf long d_count; 18031709Smlf int i; 18041709Smlf int idx; 18051709Smlf int cnt; 18061709Smlf 18071709Smlf if (part >= V_NUMPAR) 18081709Smlf return (NULL); 18091709Smlf 18101709Smlf /* 18111709Smlf * This if statement is atomic and it will succeed 18121709Smlf * if there are no bad blocks (almost always) 18131709Smlf * 18141709Smlf * so this if is performed outside of the rw_enter for speed 18151709Smlf * and then repeated inside the rw_enter for safety 18161709Smlf */ 18171709Smlf if (!dkp->dk_alts_hdl) { 18181709Smlf return (NULL); 18191709Smlf } 18201709Smlf 18211709Smlf rw_enter(&dkp->dk_bbh_mutex, RW_READER); 18221709Smlf 18231709Smlf if (dkp->dk_alts_hdl == NULL) { 18241709Smlf rw_exit(&dkp->dk_bbh_mutex); 18251709Smlf return (NULL); 18261709Smlf } 18271709Smlf 18281709Smlf alts_used = dkp->dk_slc_cnt[part]; 18291709Smlf if (alts_used == 0) { 18301709Smlf rw_exit(&dkp->dk_bbh_mutex); 18311709Smlf return (NULL); 18321709Smlf } 18331709Smlf altp = dkp->dk_slc_ent[part]; 18341709Smlf 18351709Smlf /* 18361709Smlf * binary search for the largest bad sector index in the alternate 18371709Smlf * entry table which overlaps or larger than the starting d_sec 18381709Smlf */ 18391709Smlf i = cmdk_bbh_bsearch(altp, alts_used, GET_BP_SEC(bp)); 18401709Smlf /* if starting sector is > the largest bad sector, return */ 18411709Smlf if (i == -1) { 18421709Smlf rw_exit(&dkp->dk_bbh_mutex); 18431709Smlf return (NULL); 18441709Smlf } 18451709Smlf /* i is the starting index. Set altp to the starting entry addr */ 18461709Smlf altp += i; 18471709Smlf 18481709Smlf d_count = bp->b_bcount >> SCTRSHFT; 18491709Smlf lastsec = GET_BP_SEC(bp) + d_count - 1; 18501709Smlf 18511709Smlf /* calculate the number of bad sectors */ 18521709Smlf for (idx = i, cnt = 0; idx < alts_used; idx++, altp++, cnt++) { 18531709Smlf if (lastsec < altp->bad_start) 18541709Smlf break; 18551709Smlf } 18561709Smlf 18571709Smlf if (!cnt) { 18581709Smlf rw_exit(&dkp->dk_bbh_mutex); 18591709Smlf return (NULL); 18601709Smlf } 18611709Smlf 18621709Smlf /* calculate the maximum number of reserved cookies */ 18631709Smlf cnt <<= 1; 18641709Smlf cnt++; 18651709Smlf 18661709Smlf /* allocate the handle */ 18671709Smlf hp = (struct bbh_handle *)kmem_zalloc((sizeof (*hp) + 18681709Smlf (cnt * sizeof (*ckp))), KM_SLEEP); 18691709Smlf 18701709Smlf hp->h_idx = 0; 18711709Smlf hp->h_totck = cnt; 18721709Smlf ckp = hp->h_cktab = (struct bbh_cookie *)(hp + 1); 18731709Smlf ckp[0].ck_sector = GET_BP_SEC(bp); 18741709Smlf ckp[0].ck_seclen = d_count; 18751709Smlf 18761709Smlf altp = dkp->dk_slc_ent[part]; 18771709Smlf altp += i; 18781709Smlf for (idx = 0; i < alts_used; i++, altp++) { 18791709Smlf /* CASE 1: */ 18801709Smlf if (lastsec < altp->bad_start) 18811709Smlf break; 18821709Smlf 18831709Smlf /* CASE 3: */ 18841709Smlf if (ckp[idx].ck_sector > altp->bad_end) 18851709Smlf continue; 18861709Smlf 18871709Smlf /* CASE 2 and 7: */ 18881709Smlf if ((ckp[idx].ck_sector >= altp->bad_start) && 18891709Smlf (lastsec <= altp->bad_end)) { 18901709Smlf ckp[idx].ck_sector = altp->good_start + 18911709Smlf ckp[idx].ck_sector - altp->bad_start; 18921709Smlf break; 18931709Smlf } 18941709Smlf 18951709Smlf /* at least one bad sector in our section. break it. */ 18961709Smlf /* CASE 5: */ 18971709Smlf if ((lastsec >= altp->bad_start) && 18981709Smlf (lastsec <= altp->bad_end)) { 18991709Smlf ckp[idx+1].ck_seclen = lastsec - altp->bad_start + 1; 19001709Smlf ckp[idx].ck_seclen -= ckp[idx+1].ck_seclen; 19011709Smlf ckp[idx+1].ck_sector = altp->good_start; 19021709Smlf break; 19031709Smlf } 19041709Smlf /* CASE 6: */ 19051709Smlf if ((ckp[idx].ck_sector <= altp->bad_end) && 19061709Smlf (ckp[idx].ck_sector >= altp->bad_start)) { 19071709Smlf ckp[idx+1].ck_seclen = ckp[idx].ck_seclen; 19081709Smlf ckp[idx].ck_seclen = altp->bad_end - 19091709Smlf ckp[idx].ck_sector + 1; 19101709Smlf ckp[idx+1].ck_seclen -= ckp[idx].ck_seclen; 19111709Smlf ckp[idx].ck_sector = altp->good_start + 19121709Smlf ckp[idx].ck_sector - altp->bad_start; 19131709Smlf idx++; 19141709Smlf ckp[idx].ck_sector = altp->bad_end + 1; 19151709Smlf continue; /* check rest of section */ 19161709Smlf } 19171709Smlf 19181709Smlf /* CASE 4: */ 19191709Smlf ckp[idx].ck_seclen = altp->bad_start - ckp[idx].ck_sector; 19201709Smlf ckp[idx+1].ck_sector = altp->good_start; 19211709Smlf ckp[idx+1].ck_seclen = altp->bad_end - altp->bad_start + 1; 19221709Smlf idx += 2; 19231709Smlf ckp[idx].ck_sector = altp->bad_end + 1; 19241709Smlf ckp[idx].ck_seclen = lastsec - altp->bad_end; 19251709Smlf } 19261709Smlf 19271709Smlf rw_exit(&dkp->dk_bbh_mutex); 19281709Smlf return ((opaque_t)hp); 19291709Smlf } 19301709Smlf 19311709Smlf static int 19321709Smlf cmdk_bbh_bsearch(struct alts_ent *buf, int cnt, daddr32_t key) 19331709Smlf { 19341709Smlf int i; 19351709Smlf int ind; 19361709Smlf int interval; 19371709Smlf int mystatus = -1; 19381709Smlf 19391709Smlf if (!cnt) 19401709Smlf return (mystatus); 19411709Smlf 19421709Smlf ind = 1; /* compiler complains about possible uninitialized var */ 19431709Smlf for (i = 1; i <= cnt; i <<= 1) 19441709Smlf ind = i; 19451709Smlf 19461709Smlf for (interval = ind; interval; ) { 19471709Smlf if ((key >= buf[ind-1].bad_start) && 19481709Smlf (key <= buf[ind-1].bad_end)) { 19491709Smlf return (ind-1); 19501709Smlf } else { 19511709Smlf interval >>= 1; 19521709Smlf if (key < buf[ind-1].bad_start) { 19531709Smlf /* record the largest bad sector index */ 19541709Smlf mystatus = ind-1; 19551709Smlf if (!interval) 19561709Smlf break; 19571709Smlf ind = ind - interval; 19581709Smlf } else { 19591709Smlf /* 19601709Smlf * if key is larger than the last element 19611709Smlf * then break 19621709Smlf */ 19631709Smlf if ((ind == cnt) || !interval) 19641709Smlf break; 19651709Smlf if ((ind+interval) <= cnt) 19661709Smlf ind += interval; 19671709Smlf } 19681709Smlf } 19691709Smlf } 19701709Smlf return (mystatus); 19711709Smlf } 1972