11709Smlf /* 21709Smlf * CDDL HEADER START 31709Smlf * 41709Smlf * The contents of this file are subject to the terms of the 53525Sshidokht * Common Development and Distribution License (the "License"). 63525Sshidokht * 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 /* 223525Sshidokht * 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 166*5295Srandyf static void cmdk_setup_pm(dev_info_t *dip, struct cmdk *dkp); 167*5295Srandyf static int cmdkresume(dev_info_t *dip); 168*5295Srandyf static int cmdksuspend(dev_info_t *dip); 169*5295Srandyf static int cmdkpower(dev_info_t *dip, int component, int level); 170*5295Srandyf 1711709Smlf struct dev_ops cmdk_ops = { 1721709Smlf DEVO_REV, /* devo_rev, */ 1731709Smlf 0, /* refcnt */ 1741709Smlf cmdkinfo, /* info */ 1751709Smlf nulldev, /* identify */ 1761709Smlf cmdkprobe, /* probe */ 1771709Smlf cmdkattach, /* attach */ 1781709Smlf cmdkdetach, /* detach */ 1791709Smlf nodev, /* reset */ 1801709Smlf &cmdk_cb_ops, /* driver operations */ 181*5295Srandyf (struct bus_ops *)0, /* bus operations */ 182*5295Srandyf cmdkpower /* power */ 1831709Smlf }; 1841709Smlf 1851709Smlf /* 1861709Smlf * This is the loadable module wrapper. 1871709Smlf */ 1881709Smlf #include <sys/modctl.h> 1891709Smlf 1901709Smlf extern struct mod_ops mod_driverops; 1911709Smlf 1921709Smlf static struct modldrv modldrv = { 1931709Smlf &mod_driverops, /* Type of module. This one is a driver */ 1941709Smlf "Common Direct Access Disk %I%", 1951709Smlf &cmdk_ops, /* driver ops */ 1961709Smlf }; 1971709Smlf 1981709Smlf static struct modlinkage modlinkage = { 1991709Smlf MODREV_1, (void *)&modldrv, NULL 2001709Smlf }; 2011709Smlf 2021709Smlf /* Function prototypes for cmlb callbacks */ 2031709Smlf 2041709Smlf static int cmdk_lb_rdwr(dev_info_t *dip, uchar_t cmd, void *bufaddr, 2053525Sshidokht diskaddr_t start, size_t length, void *tg_cookie); 2063525Sshidokht 2073525Sshidokht static int cmdk_lb_getinfo(dev_info_t *dip, int cmd, void *arg, 2083525Sshidokht void *tg_cookie); 2091709Smlf 2101709Smlf static void cmdk_devid_setup(struct cmdk *dkp); 2111709Smlf static int cmdk_devid_modser(struct cmdk *dkp); 2121709Smlf static int cmdk_get_modser(struct cmdk *dkp, int ioccmd, char *buf, int len); 2131709Smlf static int cmdk_devid_fabricate(struct cmdk *dkp); 2141709Smlf static int cmdk_devid_read(struct cmdk *dkp); 2151709Smlf 2161709Smlf static cmlb_tg_ops_t cmdk_lb_ops = { 2173525Sshidokht TG_DK_OPS_VERSION_1, 2181709Smlf cmdk_lb_rdwr, 2193525Sshidokht cmdk_lb_getinfo 2201709Smlf }; 2211709Smlf 2221709Smlf int 2231709Smlf _init(void) 2241709Smlf { 2251709Smlf int rval; 2261709Smlf 2271709Smlf if (rval = ddi_soft_state_init(&cmdk_state, sizeof (struct cmdk), 7)) 2281709Smlf return (rval); 2291709Smlf 2301709Smlf mutex_init(&cmdk_attach_mutex, NULL, MUTEX_DRIVER, NULL); 2311709Smlf if ((rval = mod_install(&modlinkage)) != 0) { 2321709Smlf mutex_destroy(&cmdk_attach_mutex); 2331709Smlf ddi_soft_state_fini(&cmdk_state); 2341709Smlf } 2351709Smlf return (rval); 2361709Smlf } 2371709Smlf 2381709Smlf int 2391709Smlf _fini(void) 2401709Smlf { 2411709Smlf return (EBUSY); 2421709Smlf 2431709Smlf /* 2441709Smlf * This has been commented out until cmdk is a true 2451709Smlf * unloadable module. Right now x86's are panicking on 2461709Smlf * a diskless reconfig boot. 2471709Smlf */ 2481709Smlf 2491709Smlf #if 0 /* bugid 1186679 */ 2501709Smlf int rval; 2511709Smlf 2521709Smlf rval = mod_remove(&modlinkage); 2531709Smlf if (rval != 0) 2541709Smlf return (rval); 2551709Smlf 2561709Smlf mutex_destroy(&cmdk_attach_mutex); 2571709Smlf ddi_soft_state_fini(&cmdk_state); 2581709Smlf 2591709Smlf return (0); 2601709Smlf #endif 2611709Smlf } 2621709Smlf 2631709Smlf int 2641709Smlf _info(struct modinfo *modinfop) 2651709Smlf { 2661709Smlf return (mod_info(&modlinkage, modinfop)); 2671709Smlf } 2681709Smlf 2691709Smlf /* 2701709Smlf * Autoconfiguration Routines 2711709Smlf */ 2721709Smlf static int 2731709Smlf cmdkprobe(dev_info_t *dip) 2741709Smlf { 2751709Smlf int instance; 2761709Smlf int status; 2771709Smlf struct cmdk *dkp; 2781709Smlf 2791709Smlf instance = ddi_get_instance(dip); 2801709Smlf 2811709Smlf if (ddi_get_soft_state(cmdk_state, instance)) 2821709Smlf return (DDI_PROBE_PARTIAL); 2831709Smlf 2841709Smlf if ((ddi_soft_state_zalloc(cmdk_state, instance) != DDI_SUCCESS) || 2851709Smlf ((dkp = ddi_get_soft_state(cmdk_state, instance)) == NULL)) 2861709Smlf return (DDI_PROBE_PARTIAL); 2871709Smlf 2881709Smlf mutex_init(&dkp->dk_mutex, NULL, MUTEX_DRIVER, NULL); 2891709Smlf rw_init(&dkp->dk_bbh_mutex, NULL, RW_DRIVER, NULL); 2901709Smlf dkp->dk_dip = dip; 2911709Smlf mutex_enter(&dkp->dk_mutex); 2921709Smlf 2931709Smlf dkp->dk_dev = makedevice(ddi_driver_major(dip), 2941709Smlf ddi_get_instance(dip) << CMDK_UNITSHF); 2951709Smlf 2961709Smlf /* linkage to dadk and strategy */ 2971709Smlf if (cmdk_create_obj(dip, dkp) != DDI_SUCCESS) { 2981709Smlf mutex_exit(&dkp->dk_mutex); 2991709Smlf mutex_destroy(&dkp->dk_mutex); 3001709Smlf rw_destroy(&dkp->dk_bbh_mutex); 3011709Smlf ddi_soft_state_free(cmdk_state, instance); 3021709Smlf return (DDI_PROBE_PARTIAL); 3031709Smlf } 3041709Smlf 3051709Smlf status = dadk_probe(DKTP_DATA, KM_NOSLEEP); 3061709Smlf if (status != DDI_PROBE_SUCCESS) { 3071709Smlf cmdk_destroy_obj(dip, dkp); /* dadk/strategy linkage */ 3081709Smlf mutex_exit(&dkp->dk_mutex); 3091709Smlf mutex_destroy(&dkp->dk_mutex); 3101709Smlf rw_destroy(&dkp->dk_bbh_mutex); 3111709Smlf ddi_soft_state_free(cmdk_state, instance); 3121709Smlf return (status); 3131709Smlf } 3141709Smlf 3151709Smlf mutex_exit(&dkp->dk_mutex); 3161709Smlf #ifdef CMDK_DEBUG 3171709Smlf if (cmdk_debug & DENT) 3181709Smlf PRF("cmdkprobe: instance= %d name= `%s`\n", 3191709Smlf instance, ddi_get_name_addr(dip)); 3201709Smlf #endif 3211709Smlf return (status); 3221709Smlf } 3231709Smlf 3241709Smlf static int 3251709Smlf cmdkattach(dev_info_t *dip, ddi_attach_cmd_t cmd) 3261709Smlf { 3271709Smlf int instance; 3281709Smlf struct cmdk *dkp; 3291709Smlf char *node_type; 3301709Smlf 331*5295Srandyf switch (cmd) { 332*5295Srandyf case DDI_ATTACH: 333*5295Srandyf break; 334*5295Srandyf case DDI_RESUME: 335*5295Srandyf return (cmdkresume(dip)); 336*5295Srandyf default: 3371709Smlf return (DDI_FAILURE); 338*5295Srandyf } 3391709Smlf 3401709Smlf instance = ddi_get_instance(dip); 3411709Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 3421709Smlf return (DDI_FAILURE); 3431709Smlf 344*5295Srandyf dkp->dk_pm_level = CMDK_SPINDLE_UNINIT; 345*5295Srandyf mutex_init(&dkp->dk_mutex, NULL, MUTEX_DRIVER, NULL); 346*5295Srandyf 3471709Smlf mutex_enter(&dkp->dk_mutex); 3481709Smlf 3491709Smlf /* dadk_attach is an empty function that only returns SUCCESS */ 3501709Smlf (void) dadk_attach(DKTP_DATA); 3511709Smlf 3521709Smlf node_type = (DKTP_EXT->tg_nodetype); 3531709Smlf 3541709Smlf /* 3551709Smlf * this open allows cmlb to read the device 3561709Smlf * and determine the label types 3571709Smlf * so that cmlb can create minor nodes for device 3581709Smlf */ 3591709Smlf 3601709Smlf /* open the target disk */ 3611709Smlf if (dadk_open(DKTP_DATA, 0) != DDI_SUCCESS) 3621709Smlf goto fail2; 3631709Smlf 3641709Smlf /* mark as having opened target */ 3651709Smlf dkp->dk_flag |= CMDK_TGDK_OPEN; 3661709Smlf 3671709Smlf cmlb_alloc_handle((cmlb_handle_t *)&dkp->dk_cmlbhandle); 3681709Smlf 3691709Smlf if (cmlb_attach(dip, 3701709Smlf &cmdk_lb_ops, 3711709Smlf DTYPE_DIRECT, /* device_type */ 3721709Smlf 0, /* removable */ 3733525Sshidokht 0, /* hot pluggable XXX */ 3741709Smlf node_type, 3751709Smlf CMLB_CREATE_ALTSLICE_VTOC_16_DTYPE_DIRECT, /* alter_behaviour */ 3763525Sshidokht dkp->dk_cmlbhandle, 3773525Sshidokht 0) != 0) 3781709Smlf goto fail1; 3791709Smlf 3801709Smlf /* Calling validate will create minor nodes according to disk label */ 3813525Sshidokht (void) cmlb_validate(dkp->dk_cmlbhandle, 0, 0); 3821709Smlf 3831709Smlf /* set bbh (Bad Block Handling) */ 3841709Smlf cmdk_bbh_reopen(dkp); 3851709Smlf 3861709Smlf /* setup devid string */ 3871709Smlf cmdk_devid_setup(dkp); 3881709Smlf 3891709Smlf mutex_enter(&cmdk_attach_mutex); 3901709Smlf if (instance > cmdk_max_instance) 3911709Smlf cmdk_max_instance = instance; 3921709Smlf mutex_exit(&cmdk_attach_mutex); 3931709Smlf 3941709Smlf mutex_exit(&dkp->dk_mutex); 3951709Smlf 3961709Smlf /* 3971709Smlf * Add a zero-length attribute to tell the world we support 3981709Smlf * kernel ioctls (for layered drivers) 3991709Smlf */ 4001709Smlf (void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, 4011709Smlf DDI_KERNEL_IOCTL, NULL, 0); 4021709Smlf ddi_report_dev(dip); 4031709Smlf 404*5295Srandyf /* 405*5295Srandyf * Initialize power management 406*5295Srandyf */ 407*5295Srandyf mutex_init(&dkp->dk_pm_mutex, NULL, MUTEX_DRIVER, NULL); 408*5295Srandyf cv_init(&dkp->dk_suspend_cv, NULL, CV_DRIVER, NULL); 409*5295Srandyf cmdk_setup_pm(dip, dkp); 410*5295Srandyf 4111709Smlf return (DDI_SUCCESS); 4121709Smlf 4131709Smlf fail1: 4141709Smlf cmlb_free_handle(&dkp->dk_cmlbhandle); 4151709Smlf (void) dadk_close(DKTP_DATA); 4161709Smlf fail2: 4171709Smlf cmdk_destroy_obj(dip, dkp); 4181709Smlf rw_destroy(&dkp->dk_bbh_mutex); 4191709Smlf mutex_exit(&dkp->dk_mutex); 4201709Smlf mutex_destroy(&dkp->dk_mutex); 4211709Smlf ddi_soft_state_free(cmdk_state, instance); 4221709Smlf return (DDI_FAILURE); 4231709Smlf } 4241709Smlf 4251709Smlf 4261709Smlf static int 4271709Smlf cmdkdetach(dev_info_t *dip, ddi_detach_cmd_t cmd) 4281709Smlf { 4291709Smlf struct cmdk *dkp; 4301709Smlf int instance; 4311709Smlf int max_instance; 4321709Smlf 433*5295Srandyf switch (cmd) { 434*5295Srandyf case DDI_DETACH: 435*5295Srandyf /* return (DDI_FAILURE); */ 436*5295Srandyf break; 437*5295Srandyf case DDI_SUSPEND: 438*5295Srandyf return (cmdksuspend(dip)); 439*5295Srandyf default: 4401709Smlf #ifdef CMDK_DEBUG 4411709Smlf if (cmdk_debug & DIO) { 4421709Smlf PRF("cmdkdetach: cmd = %d unknown\n", cmd); 4431709Smlf } 4441709Smlf #endif 4451709Smlf return (DDI_FAILURE); 4461709Smlf } 4471709Smlf 4481709Smlf mutex_enter(&cmdk_attach_mutex); 4491709Smlf max_instance = cmdk_max_instance; 4501709Smlf mutex_exit(&cmdk_attach_mutex); 4511709Smlf 4521709Smlf /* check if any instance of driver is open */ 4531709Smlf for (instance = 0; instance < max_instance; instance++) { 4541709Smlf dkp = ddi_get_soft_state(cmdk_state, instance); 4551709Smlf if (!dkp) 4561709Smlf continue; 4571709Smlf if (dkp->dk_flag & CMDK_OPEN) 4581709Smlf return (DDI_FAILURE); 4591709Smlf } 4601709Smlf 4611709Smlf instance = ddi_get_instance(dip); 4621709Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 4631709Smlf return (DDI_SUCCESS); 4641709Smlf 4651709Smlf mutex_enter(&dkp->dk_mutex); 4661709Smlf 4671709Smlf /* 4681709Smlf * The cmdk_part_info call at the end of cmdkattach may have 4691709Smlf * caused cmdk_reopen to do a TGDK_OPEN, make sure we close on 4701709Smlf * detach for case when cmdkopen/cmdkclose never occurs. 4711709Smlf */ 4721709Smlf if (dkp->dk_flag & CMDK_TGDK_OPEN) { 4731709Smlf dkp->dk_flag &= ~CMDK_TGDK_OPEN; 4741709Smlf (void) dadk_close(DKTP_DATA); 4751709Smlf } 4761709Smlf 4773525Sshidokht cmlb_detach(dkp->dk_cmlbhandle, 0); 4781709Smlf cmlb_free_handle(&dkp->dk_cmlbhandle); 4791709Smlf ddi_prop_remove_all(dip); 4801709Smlf 4811709Smlf cmdk_destroy_obj(dip, dkp); /* dadk/strategy linkage */ 4821709Smlf mutex_exit(&dkp->dk_mutex); 4831709Smlf mutex_destroy(&dkp->dk_mutex); 4841709Smlf rw_destroy(&dkp->dk_bbh_mutex); 485*5295Srandyf mutex_destroy(&dkp->dk_pm_mutex); 486*5295Srandyf cv_destroy(&dkp->dk_suspend_cv); 4871709Smlf ddi_soft_state_free(cmdk_state, instance); 4881709Smlf 4891709Smlf return (DDI_SUCCESS); 4901709Smlf } 4911709Smlf 4921709Smlf static int 4931709Smlf cmdkinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 4941709Smlf { 4951709Smlf dev_t dev = (dev_t)arg; 4961709Smlf int instance; 4971709Smlf struct cmdk *dkp; 4981709Smlf 4991709Smlf #ifdef lint 5001709Smlf dip = dip; /* no one ever uses this */ 5011709Smlf #endif 5021709Smlf #ifdef CMDK_DEBUG 5031709Smlf if (cmdk_debug & DENT) 5041709Smlf PRF("cmdkinfo: call\n"); 5051709Smlf #endif 5061709Smlf instance = CMDKUNIT(dev); 5071709Smlf 5081709Smlf switch (infocmd) { 5091709Smlf case DDI_INFO_DEVT2DEVINFO: 5101709Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 5111709Smlf return (DDI_FAILURE); 5121709Smlf *result = (void *) dkp->dk_dip; 5131709Smlf break; 5141709Smlf case DDI_INFO_DEVT2INSTANCE: 5151709Smlf *result = (void *)(intptr_t)instance; 5161709Smlf break; 5171709Smlf default: 5181709Smlf return (DDI_FAILURE); 5191709Smlf } 5201709Smlf return (DDI_SUCCESS); 5211709Smlf } 5221709Smlf 523*5295Srandyf /* 524*5295Srandyf * Initialize the power management components 525*5295Srandyf */ 526*5295Srandyf static void 527*5295Srandyf cmdk_setup_pm(dev_info_t *dip, struct cmdk *dkp) 528*5295Srandyf { 529*5295Srandyf char *pm_comp[] = { "NAME=cmdk", "0=off", "1=on", NULL }; 530*5295Srandyf 531*5295Srandyf /* 532*5295Srandyf * Since the cmdk device does not the 'reg' property, 533*5295Srandyf * cpr will not call its DDI_SUSPEND/DDI_RESUME entries. 534*5295Srandyf * The following code is to tell cpr that this device 535*5295Srandyf * DOES need to be suspended and resumed. 536*5295Srandyf */ 537*5295Srandyf (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip, 538*5295Srandyf "pm-hardware-state", "needs-suspend-resume"); 539*5295Srandyf 540*5295Srandyf if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip, 541*5295Srandyf "pm-components", pm_comp, 3) == DDI_PROP_SUCCESS) { 542*5295Srandyf if (pm_raise_power(dip, 0, CMDK_SPINDLE_ON) == DDI_SUCCESS) { 543*5295Srandyf mutex_enter(&dkp->dk_pm_mutex); 544*5295Srandyf dkp->dk_pm_level = CMDK_SPINDLE_ON; 545*5295Srandyf dkp->dk_pm_is_enabled = 1; 546*5295Srandyf mutex_exit(&dkp->dk_pm_mutex); 547*5295Srandyf } else { 548*5295Srandyf mutex_enter(&dkp->dk_pm_mutex); 549*5295Srandyf dkp->dk_pm_level = CMDK_SPINDLE_OFF; 550*5295Srandyf dkp->dk_pm_is_enabled = 0; 551*5295Srandyf mutex_exit(&dkp->dk_pm_mutex); 552*5295Srandyf } 553*5295Srandyf } else { 554*5295Srandyf mutex_enter(&dkp->dk_pm_mutex); 555*5295Srandyf dkp->dk_pm_level = CMDK_SPINDLE_UNINIT; 556*5295Srandyf dkp->dk_pm_is_enabled = 0; 557*5295Srandyf mutex_exit(&dkp->dk_pm_mutex); 558*5295Srandyf } 559*5295Srandyf } 560*5295Srandyf 561*5295Srandyf /* 562*5295Srandyf * suspend routine, it will be run when get the command 563*5295Srandyf * DDI_SUSPEND at detach(9E) from system power management 564*5295Srandyf */ 565*5295Srandyf static int 566*5295Srandyf cmdksuspend(dev_info_t *dip) 567*5295Srandyf { 568*5295Srandyf struct cmdk *dkp; 569*5295Srandyf int instance; 570*5295Srandyf clock_t count = 0; 571*5295Srandyf 572*5295Srandyf instance = ddi_get_instance(dip); 573*5295Srandyf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 574*5295Srandyf return (DDI_FAILURE); 575*5295Srandyf mutex_enter(&dkp->dk_mutex); 576*5295Srandyf if (dkp->dk_flag & CMDK_SUSPEND) { 577*5295Srandyf mutex_exit(&dkp->dk_mutex); 578*5295Srandyf return (DDI_SUCCESS); 579*5295Srandyf } 580*5295Srandyf dkp->dk_flag |= CMDK_SUSPEND; 581*5295Srandyf 582*5295Srandyf /* need to wait a while */ 583*5295Srandyf while (dadk_getcmds(DKTP_DATA) != 0) { 584*5295Srandyf delay(drv_usectohz(1000000)); 585*5295Srandyf if (count > 60) { 586*5295Srandyf dkp->dk_flag &= ~CMDK_SUSPEND; 587*5295Srandyf cv_broadcast(&dkp->dk_suspend_cv); 588*5295Srandyf mutex_exit(&dkp->dk_mutex); 589*5295Srandyf return (DDI_FAILURE); 590*5295Srandyf } 591*5295Srandyf count++; 592*5295Srandyf } 593*5295Srandyf mutex_exit(&dkp->dk_mutex); 594*5295Srandyf return (DDI_SUCCESS); 595*5295Srandyf } 596*5295Srandyf 597*5295Srandyf /* 598*5295Srandyf * resume routine, it will be run when get the command 599*5295Srandyf * DDI_RESUME at attach(9E) from system power management 600*5295Srandyf */ 601*5295Srandyf static int 602*5295Srandyf cmdkresume(dev_info_t *dip) 603*5295Srandyf { 604*5295Srandyf struct cmdk *dkp; 605*5295Srandyf int instance; 606*5295Srandyf 607*5295Srandyf instance = ddi_get_instance(dip); 608*5295Srandyf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 609*5295Srandyf return (DDI_FAILURE); 610*5295Srandyf mutex_enter(&dkp->dk_mutex); 611*5295Srandyf if (!(dkp->dk_flag & CMDK_SUSPEND)) { 612*5295Srandyf mutex_exit(&dkp->dk_mutex); 613*5295Srandyf return (DDI_FAILURE); 614*5295Srandyf } 615*5295Srandyf dkp->dk_pm_level = CMDK_SPINDLE_ON; 616*5295Srandyf dkp->dk_flag &= ~CMDK_SUSPEND; 617*5295Srandyf cv_broadcast(&dkp->dk_suspend_cv); 618*5295Srandyf mutex_exit(&dkp->dk_mutex); 619*5295Srandyf return (DDI_SUCCESS); 620*5295Srandyf 621*5295Srandyf } 622*5295Srandyf 623*5295Srandyf /* 624*5295Srandyf * power management entry point, it was used to 625*5295Srandyf * change power management component. 626*5295Srandyf * Actually, the real hard drive suspend/resume 627*5295Srandyf * was handled in ata, so this function is not 628*5295Srandyf * doing any real work other than verifying that 629*5295Srandyf * the disk is idle. 630*5295Srandyf */ 631*5295Srandyf static int 632*5295Srandyf cmdkpower(dev_info_t *dip, int component, int level) 633*5295Srandyf { 634*5295Srandyf struct cmdk *dkp; 635*5295Srandyf int instance; 636*5295Srandyf 637*5295Srandyf instance = ddi_get_instance(dip); 638*5295Srandyf if (!(dkp = ddi_get_soft_state(cmdk_state, instance)) || 639*5295Srandyf component != 0 || level > CMDK_SPINDLE_ON || 640*5295Srandyf level < CMDK_SPINDLE_OFF) { 641*5295Srandyf return (DDI_FAILURE); 642*5295Srandyf } 643*5295Srandyf 644*5295Srandyf mutex_enter(&dkp->dk_pm_mutex); 645*5295Srandyf if (dkp->dk_pm_is_enabled && dkp->dk_pm_level == level) { 646*5295Srandyf mutex_exit(&dkp->dk_pm_mutex); 647*5295Srandyf return (DDI_SUCCESS); 648*5295Srandyf } 649*5295Srandyf mutex_exit(&dkp->dk_pm_mutex); 650*5295Srandyf 651*5295Srandyf if ((level == CMDK_SPINDLE_OFF) && 652*5295Srandyf (dadk_getcmds(DKTP_DATA) != 0)) { 653*5295Srandyf return (DDI_FAILURE); 654*5295Srandyf } 655*5295Srandyf 656*5295Srandyf mutex_enter(&dkp->dk_pm_mutex); 657*5295Srandyf dkp->dk_pm_level = level; 658*5295Srandyf mutex_exit(&dkp->dk_pm_mutex); 659*5295Srandyf return (DDI_SUCCESS); 660*5295Srandyf } 661*5295Srandyf 6621709Smlf static int 6631709Smlf cmdk_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags, 6641709Smlf char *name, caddr_t valuep, int *lengthp) 6651709Smlf { 6661709Smlf struct cmdk *dkp; 6671709Smlf diskaddr_t p_lblksrt; 6681709Smlf diskaddr_t p_lblkcnt; 6691709Smlf 6701709Smlf #ifdef CMDK_DEBUG 6711709Smlf if (cmdk_debug & DENT) 6721709Smlf PRF("cmdk_prop_op: call\n"); 6731709Smlf #endif 6741709Smlf 6751709Smlf dkp = ddi_get_soft_state(cmdk_state, ddi_get_instance(dip)); 6761709Smlf 6771709Smlf /* 6781709Smlf * Our dynamic properties are all device specific and size oriented. 6791709Smlf * Requests issued under conditions where size is valid are passed 6801709Smlf * to ddi_prop_op_nblocks with the size information, otherwise the 6811709Smlf * request is passed to ddi_prop_op. Size depends on valid label. 6821709Smlf */ 6831709Smlf if ((dev != DDI_DEV_T_ANY) && (dkp != NULL)) { 6841709Smlf if (!cmlb_partinfo( 6851709Smlf dkp->dk_cmlbhandle, 6861709Smlf CMDKPART(dev), 6871709Smlf &p_lblkcnt, 6881709Smlf &p_lblksrt, 6891709Smlf NULL, 6903525Sshidokht NULL, 6913525Sshidokht 0)) 6921709Smlf return (ddi_prop_op_nblocks(dev, dip, 6931709Smlf prop_op, mod_flags, 6941709Smlf name, valuep, lengthp, 6951709Smlf (uint64_t)p_lblkcnt)); 6961709Smlf } 6971709Smlf 6981709Smlf return (ddi_prop_op(dev, dip, 6991709Smlf prop_op, mod_flags, 7001709Smlf name, valuep, lengthp)); 7011709Smlf } 7021709Smlf 7031709Smlf /* 7041709Smlf * dump routine 7051709Smlf */ 7061709Smlf static int 7071709Smlf cmdkdump(dev_t dev, caddr_t addr, daddr_t blkno, int nblk) 7081709Smlf { 7091709Smlf int instance; 7101709Smlf struct cmdk *dkp; 7111709Smlf diskaddr_t p_lblksrt; 7121709Smlf diskaddr_t p_lblkcnt; 7131709Smlf struct buf local; 7141709Smlf struct buf *bp; 7151709Smlf 7161709Smlf #ifdef CMDK_DEBUG 7171709Smlf if (cmdk_debug & DENT) 7181709Smlf PRF("cmdkdump: call\n"); 7191709Smlf #endif 7201709Smlf instance = CMDKUNIT(dev); 7211709Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance)) || (blkno < 0)) 7221709Smlf return (ENXIO); 7231709Smlf 7241709Smlf if (cmlb_partinfo( 7251709Smlf dkp->dk_cmlbhandle, 7261709Smlf CMDKPART(dev), 7271709Smlf &p_lblkcnt, 7281709Smlf &p_lblksrt, 7291709Smlf NULL, 7303525Sshidokht NULL, 7313525Sshidokht 0)) { 7321709Smlf return (ENXIO); 7331709Smlf } 7341709Smlf 7351709Smlf if ((blkno+nblk) > p_lblkcnt) 7361709Smlf return (EINVAL); 7371709Smlf 7381709Smlf cmdk_indump = 1; /* Tell disk targets we are panic dumpping */ 7391709Smlf 7401709Smlf bp = &local; 7411709Smlf bzero(bp, sizeof (*bp)); 7421709Smlf bp->b_flags = B_BUSY; 7431709Smlf bp->b_un.b_addr = addr; 7441709Smlf bp->b_bcount = nblk << SCTRSHFT; 7451709Smlf SET_BP_SEC(bp, ((ulong_t)(p_lblksrt + blkno))); 7461709Smlf 7471709Smlf (void) dadk_dump(DKTP_DATA, bp); 7481709Smlf return (bp->b_error); 7491709Smlf } 7501709Smlf 7511709Smlf /* 7521709Smlf * Copy in the dadkio_rwcmd according to the user's data model. If needed, 7531709Smlf * convert it for our internal use. 7541709Smlf */ 7551709Smlf static int 7561709Smlf rwcmd_copyin(struct dadkio_rwcmd *rwcmdp, caddr_t inaddr, int flag) 7571709Smlf { 7581709Smlf switch (ddi_model_convert_from(flag)) { 7591709Smlf case DDI_MODEL_ILP32: { 7601709Smlf struct dadkio_rwcmd32 cmd32; 7611709Smlf 7621709Smlf if (ddi_copyin(inaddr, &cmd32, 7631709Smlf sizeof (struct dadkio_rwcmd32), flag)) { 7641709Smlf return (EFAULT); 7651709Smlf } 7661709Smlf 7671709Smlf rwcmdp->cmd = cmd32.cmd; 7681709Smlf rwcmdp->flags = cmd32.flags; 7691709Smlf rwcmdp->blkaddr = (daddr_t)cmd32.blkaddr; 7701709Smlf rwcmdp->buflen = cmd32.buflen; 7711709Smlf rwcmdp->bufaddr = (caddr_t)(intptr_t)cmd32.bufaddr; 7721709Smlf /* 7731709Smlf * Note: we do not convert the 'status' field, 7741709Smlf * as it should not contain valid data at this 7751709Smlf * point. 7761709Smlf */ 7771709Smlf bzero(&rwcmdp->status, sizeof (rwcmdp->status)); 7781709Smlf break; 7791709Smlf } 7801709Smlf case DDI_MODEL_NONE: { 7811709Smlf if (ddi_copyin(inaddr, rwcmdp, 7821709Smlf sizeof (struct dadkio_rwcmd), flag)) { 7831709Smlf return (EFAULT); 7841709Smlf } 7851709Smlf } 7861709Smlf } 7871709Smlf return (0); 7881709Smlf } 7891709Smlf 7901709Smlf /* 7911709Smlf * If necessary, convert the internal rwcmdp and status to the appropriate 7921709Smlf * data model and copy it out to the user. 7931709Smlf */ 7941709Smlf static int 7951709Smlf rwcmd_copyout(struct dadkio_rwcmd *rwcmdp, caddr_t outaddr, int flag) 7961709Smlf { 7971709Smlf switch (ddi_model_convert_from(flag)) { 7981709Smlf case DDI_MODEL_ILP32: { 7991709Smlf struct dadkio_rwcmd32 cmd32; 8001709Smlf 8011709Smlf cmd32.cmd = rwcmdp->cmd; 8021709Smlf cmd32.flags = rwcmdp->flags; 8031709Smlf cmd32.blkaddr = rwcmdp->blkaddr; 8041709Smlf cmd32.buflen = rwcmdp->buflen; 8051709Smlf ASSERT64(((uintptr_t)rwcmdp->bufaddr >> 32) == 0); 8061709Smlf cmd32.bufaddr = (caddr32_t)(uintptr_t)rwcmdp->bufaddr; 8071709Smlf 8081709Smlf cmd32.status.status = rwcmdp->status.status; 8091709Smlf cmd32.status.resid = rwcmdp->status.resid; 8101709Smlf cmd32.status.failed_blk_is_valid = 8111709Smlf rwcmdp->status.failed_blk_is_valid; 8121709Smlf cmd32.status.failed_blk = rwcmdp->status.failed_blk; 8131709Smlf cmd32.status.fru_code_is_valid = 8141709Smlf rwcmdp->status.fru_code_is_valid; 8151709Smlf cmd32.status.fru_code = rwcmdp->status.fru_code; 8161709Smlf 8171709Smlf bcopy(rwcmdp->status.add_error_info, 8181709Smlf cmd32.status.add_error_info, DADKIO_ERROR_INFO_LEN); 8191709Smlf 8201709Smlf if (ddi_copyout(&cmd32, outaddr, 8211709Smlf sizeof (struct dadkio_rwcmd32), flag)) 8221709Smlf return (EFAULT); 8231709Smlf break; 8241709Smlf } 8251709Smlf case DDI_MODEL_NONE: { 8261709Smlf if (ddi_copyout(rwcmdp, outaddr, 8271709Smlf sizeof (struct dadkio_rwcmd), flag)) 8281709Smlf return (EFAULT); 8291709Smlf } 8301709Smlf } 8311709Smlf return (0); 8321709Smlf } 8331709Smlf 8341709Smlf /* 8351709Smlf * ioctl routine 8361709Smlf */ 8371709Smlf static int 8381709Smlf cmdkioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp, int *rvalp) 8391709Smlf { 8401709Smlf int instance; 8411709Smlf struct scsi_device *devp; 8421709Smlf struct cmdk *dkp; 8431709Smlf char data[NBPSCTR]; 8441709Smlf 8451709Smlf instance = CMDKUNIT(dev); 8461709Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 8471709Smlf return (ENXIO); 8481709Smlf 849*5295Srandyf mutex_enter(&dkp->dk_mutex); 850*5295Srandyf while (dkp->dk_flag & CMDK_SUSPEND) { 851*5295Srandyf cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex); 852*5295Srandyf } 853*5295Srandyf mutex_exit(&dkp->dk_mutex); 854*5295Srandyf 8551709Smlf bzero(data, sizeof (data)); 8561709Smlf 8571709Smlf switch (cmd) { 8581709Smlf 8591709Smlf case DKIOCGMEDIAINFO: { 8601709Smlf struct dk_minfo media_info; 8611709Smlf struct tgdk_geom phyg; 8621709Smlf 8631709Smlf /* dadk_getphygeom always returns success */ 8641709Smlf (void) dadk_getphygeom(DKTP_DATA, &phyg); 8651709Smlf 8661709Smlf media_info.dki_lbsize = phyg.g_secsiz; 8671709Smlf media_info.dki_capacity = phyg.g_cap; 8681709Smlf media_info.dki_media_type = DK_FIXED_DISK; 8691709Smlf 8701709Smlf if (ddi_copyout(&media_info, (void *)arg, 8711709Smlf sizeof (struct dk_minfo), flag)) { 8721709Smlf return (EFAULT); 8731709Smlf } else { 8741709Smlf return (0); 8751709Smlf } 8761709Smlf } 8771709Smlf 8781709Smlf case DKIOCINFO: { 8791709Smlf struct dk_cinfo *info = (struct dk_cinfo *)data; 8801709Smlf 8811709Smlf /* controller information */ 8821709Smlf info->dki_ctype = (DKTP_EXT->tg_ctype); 8831709Smlf info->dki_cnum = ddi_get_instance(ddi_get_parent(dkp->dk_dip)); 8841709Smlf (void) strcpy(info->dki_cname, 8851709Smlf ddi_get_name(ddi_get_parent(dkp->dk_dip))); 8861709Smlf 8871709Smlf /* Unit Information */ 8881709Smlf info->dki_unit = ddi_get_instance(dkp->dk_dip); 8891709Smlf devp = ddi_get_driver_private(dkp->dk_dip); 8901709Smlf info->dki_slave = (CMDEV_TARG(devp)<<3) | CMDEV_LUN(devp); 8911709Smlf (void) strcpy(info->dki_dname, ddi_driver_name(dkp->dk_dip)); 8921709Smlf info->dki_flags = DKI_FMTVOL; 8931709Smlf info->dki_partition = CMDKPART(dev); 8941709Smlf 8951709Smlf info->dki_maxtransfer = maxphys / DEV_BSIZE; 8961709Smlf info->dki_addr = 1; 8971709Smlf info->dki_space = 0; 8981709Smlf info->dki_prio = 0; 8991709Smlf info->dki_vec = 0; 9001709Smlf 9011709Smlf if (ddi_copyout(data, (void *)arg, sizeof (*info), flag)) 9021709Smlf return (EFAULT); 9031709Smlf else 9041709Smlf return (0); 9051709Smlf } 9061709Smlf 9071709Smlf case DKIOCSTATE: { 9081709Smlf int state; 9091709Smlf int rval; 9101709Smlf diskaddr_t p_lblksrt; 9111709Smlf diskaddr_t p_lblkcnt; 9121709Smlf 9131709Smlf if (ddi_copyin((void *)arg, &state, sizeof (int), flag)) 9141709Smlf return (EFAULT); 9151709Smlf 9161709Smlf /* dadk_check_media blocks until state changes */ 9171709Smlf if (rval = dadk_check_media(DKTP_DATA, &state)) 9181709Smlf return (rval); 9191709Smlf 9201709Smlf if (state == DKIO_INSERTED) { 9211709Smlf 9223525Sshidokht if (cmlb_validate(dkp->dk_cmlbhandle, 0, 0) != 0) 9231709Smlf return (ENXIO); 9241709Smlf 9251709Smlf if (cmlb_partinfo(dkp->dk_cmlbhandle, CMDKPART(dev), 9263525Sshidokht &p_lblkcnt, &p_lblksrt, NULL, NULL, 0)) 9271709Smlf return (ENXIO); 9281709Smlf 9291709Smlf if (p_lblkcnt <= 0) 9301709Smlf return (ENXIO); 9311709Smlf } 9321709Smlf 9331709Smlf if (ddi_copyout(&state, (caddr_t)arg, sizeof (int), flag)) 9341709Smlf return (EFAULT); 9351709Smlf 9361709Smlf return (0); 9371709Smlf } 9381709Smlf 9391709Smlf /* 9401709Smlf * is media removable? 9411709Smlf */ 9421709Smlf case DKIOCREMOVABLE: { 9431709Smlf int i; 9441709Smlf 9451709Smlf i = (DKTP_EXT->tg_rmb) ? 1 : 0; 9461709Smlf 9471709Smlf if (ddi_copyout(&i, (caddr_t)arg, sizeof (int), flag)) 9481709Smlf return (EFAULT); 9491709Smlf 9501709Smlf return (0); 9511709Smlf } 9521709Smlf 9531709Smlf case DKIOCADDBAD: 9541709Smlf /* 9551709Smlf * This is not an update mechanism to add bad blocks 9561709Smlf * to the bad block structures stored on disk. 9571709Smlf * 9581709Smlf * addbadsec(1M) will update the bad block data on disk 9591709Smlf * and use this ioctl to force the driver to re-initialize 9601709Smlf * the list of bad blocks in the driver. 9611709Smlf */ 9621709Smlf 9631709Smlf /* start BBH */ 9641709Smlf cmdk_bbh_reopen(dkp); 9651709Smlf return (0); 9661709Smlf 9671709Smlf case DKIOCG_PHYGEOM: 9681709Smlf case DKIOCG_VIRTGEOM: 9691709Smlf case DKIOCGGEOM: 9701709Smlf case DKIOCSGEOM: 9711709Smlf case DKIOCGAPART: 9721709Smlf case DKIOCSAPART: 9731709Smlf case DKIOCGVTOC: 9741709Smlf case DKIOCSVTOC: 9751709Smlf case DKIOCPARTINFO: 9761709Smlf case DKIOCGMBOOT: 9771709Smlf case DKIOCSMBOOT: 9781709Smlf case DKIOCGETEFI: 9791709Smlf case DKIOCSETEFI: 9801709Smlf case DKIOCPARTITION: 9811709Smlf { 9821709Smlf int rc; 9831709Smlf 9843525Sshidokht rc = cmlb_ioctl(dkp->dk_cmlbhandle, dev, cmd, arg, flag, 9853525Sshidokht credp, rvalp, 0); 9861709Smlf if (cmd == DKIOCSVTOC) 9871709Smlf cmdk_devid_setup(dkp); 9881709Smlf return (rc); 9891709Smlf } 9901709Smlf 9911709Smlf case DIOCTL_RWCMD: { 9921709Smlf struct dadkio_rwcmd *rwcmdp; 9931709Smlf int status; 9941709Smlf 9951709Smlf rwcmdp = kmem_alloc(sizeof (struct dadkio_rwcmd), KM_SLEEP); 9961709Smlf 9971709Smlf status = rwcmd_copyin(rwcmdp, (caddr_t)arg, flag); 9981709Smlf 9991709Smlf if (status == 0) { 10001709Smlf bzero(&(rwcmdp->status), sizeof (struct dadkio_status)); 10011709Smlf status = dadk_ioctl(DKTP_DATA, 10021709Smlf dev, 10031709Smlf cmd, 10041709Smlf (uintptr_t)rwcmdp, 10051709Smlf flag, 10061709Smlf credp, 10071709Smlf rvalp); 10081709Smlf } 10091709Smlf if (status == 0) 10101709Smlf status = rwcmd_copyout(rwcmdp, (caddr_t)arg, flag); 10111709Smlf 10121709Smlf kmem_free(rwcmdp, sizeof (struct dadkio_rwcmd)); 10131709Smlf return (status); 10141709Smlf } 10151709Smlf 10161709Smlf default: 10171709Smlf return (dadk_ioctl(DKTP_DATA, 10181709Smlf dev, 10191709Smlf cmd, 10201709Smlf arg, 10211709Smlf flag, 10221709Smlf credp, 10231709Smlf rvalp)); 10241709Smlf } 10251709Smlf } 10261709Smlf 10271709Smlf /*ARGSUSED1*/ 10281709Smlf static int 10291709Smlf cmdkclose(dev_t dev, int flag, int otyp, cred_t *credp) 10301709Smlf { 10311709Smlf int part; 10321709Smlf ulong_t partbit; 10331709Smlf int instance; 10341709Smlf struct cmdk *dkp; 10351709Smlf int lastclose = 1; 10361709Smlf int i; 10371709Smlf 10381709Smlf instance = CMDKUNIT(dev); 10391709Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance)) || 10401709Smlf (otyp >= OTYPCNT)) 10411709Smlf return (ENXIO); 10421709Smlf 10431709Smlf mutex_enter(&dkp->dk_mutex); 10441709Smlf 10451709Smlf /* check if device has been opened */ 10461709Smlf if (!(dkp->dk_flag & CMDK_OPEN)) { 10471709Smlf mutex_exit(&dkp->dk_mutex); 10481709Smlf return (ENXIO); 10491709Smlf } 10501709Smlf 1051*5295Srandyf while (dkp->dk_flag & CMDK_SUSPEND) { 1052*5295Srandyf cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex); 1053*5295Srandyf } 1054*5295Srandyf 10551709Smlf part = CMDKPART(dev); 10561709Smlf partbit = 1 << part; 10571709Smlf 10581709Smlf /* account for close */ 10591709Smlf if (otyp == OTYP_LYR) { 10601709Smlf if (dkp->dk_open_lyr[part]) 10611709Smlf dkp->dk_open_lyr[part]--; 10621709Smlf } else 10631709Smlf dkp->dk_open_reg[otyp] &= ~partbit; 10641709Smlf dkp->dk_open_exl &= ~partbit; 10651709Smlf 10661709Smlf for (i = 0; i < CMDK_MAXPART; i++) 10671709Smlf if (dkp->dk_open_lyr[i] != 0) { 10681709Smlf lastclose = 0; 10691709Smlf break; 10701709Smlf } 10711709Smlf 10721709Smlf if (lastclose) 10731709Smlf for (i = 0; i < OTYPCNT; i++) 10741709Smlf if (dkp->dk_open_reg[i] != 0) { 10751709Smlf lastclose = 0; 10761709Smlf break; 10771709Smlf } 10781709Smlf 10791709Smlf mutex_exit(&dkp->dk_mutex); 10801709Smlf 10811709Smlf if (lastclose) 10823525Sshidokht cmlb_invalidate(dkp->dk_cmlbhandle, 0); 10831709Smlf 10841709Smlf return (DDI_SUCCESS); 10851709Smlf } 10861709Smlf 10871709Smlf /*ARGSUSED3*/ 10881709Smlf static int 10891709Smlf cmdkopen(dev_t *dev_p, int flag, int otyp, cred_t *credp) 10901709Smlf { 10911709Smlf dev_t dev = *dev_p; 10921709Smlf int part; 10931709Smlf ulong_t partbit; 10941709Smlf int instance; 10951709Smlf struct cmdk *dkp; 10961709Smlf diskaddr_t p_lblksrt; 10971709Smlf diskaddr_t p_lblkcnt; 10981709Smlf int i; 10991709Smlf int nodelay; 11001709Smlf 11011709Smlf instance = CMDKUNIT(dev); 11021709Smlf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 11031709Smlf return (ENXIO); 11041709Smlf 11051709Smlf if (otyp >= OTYPCNT) 11061709Smlf return (EINVAL); 11071709Smlf 1108*5295Srandyf mutex_enter(&dkp->dk_mutex); 1109*5295Srandyf while (dkp->dk_flag & CMDK_SUSPEND) { 1110*5295Srandyf cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex); 1111*5295Srandyf } 1112*5295Srandyf mutex_exit(&dkp->dk_mutex); 1113*5295Srandyf 11141709Smlf part = CMDKPART(dev); 11151709Smlf partbit = 1 << part; 11161709Smlf nodelay = (flag & (FNDELAY | FNONBLOCK)); 11171709Smlf 11181709Smlf mutex_enter(&dkp->dk_mutex); 11191709Smlf 11203525Sshidokht if (cmlb_validate(dkp->dk_cmlbhandle, 0, 0) != 0) { 11211709Smlf 11221709Smlf /* fail if not doing non block open */ 11231709Smlf if (!nodelay) { 11241709Smlf mutex_exit(&dkp->dk_mutex); 11251709Smlf return (ENXIO); 11261709Smlf } 11271709Smlf } else if (cmlb_partinfo(dkp->dk_cmlbhandle, part, &p_lblkcnt, 11283525Sshidokht &p_lblksrt, NULL, NULL, 0) == 0) { 11291709Smlf 11301709Smlf if (p_lblkcnt <= 0 && (!nodelay || otyp != OTYP_CHR)) { 11311709Smlf mutex_exit(&dkp->dk_mutex); 11321709Smlf return (ENXIO); 11331709Smlf } 11341709Smlf } else { 11351709Smlf /* fail if not doing non block open */ 11361709Smlf if (!nodelay) { 11371709Smlf mutex_exit(&dkp->dk_mutex); 11381709Smlf return (ENXIO); 11391709Smlf } 11401709Smlf } 11411709Smlf 11421709Smlf if ((DKTP_EXT->tg_rdonly) && (flag & FWRITE)) { 11431709Smlf mutex_exit(&dkp->dk_mutex); 11441709Smlf return (EROFS); 11451709Smlf } 11461709Smlf 11471709Smlf /* check for part already opend exclusively */ 11481709Smlf if (dkp->dk_open_exl & partbit) 11491709Smlf goto excl_open_fail; 11501709Smlf 11511709Smlf /* check if we can establish exclusive open */ 11521709Smlf if (flag & FEXCL) { 11531709Smlf if (dkp->dk_open_lyr[part]) 11541709Smlf goto excl_open_fail; 11551709Smlf for (i = 0; i < OTYPCNT; i++) { 11561709Smlf if (dkp->dk_open_reg[i] & partbit) 11571709Smlf goto excl_open_fail; 11581709Smlf } 11591709Smlf } 11601709Smlf 11611709Smlf /* open will succeed, account for open */ 11621709Smlf dkp->dk_flag |= CMDK_OPEN; 11631709Smlf if (otyp == OTYP_LYR) 11641709Smlf dkp->dk_open_lyr[part]++; 11651709Smlf else 11661709Smlf dkp->dk_open_reg[otyp] |= partbit; 11671709Smlf if (flag & FEXCL) 11681709Smlf dkp->dk_open_exl |= partbit; 11691709Smlf 11701709Smlf mutex_exit(&dkp->dk_mutex); 11711709Smlf return (DDI_SUCCESS); 11721709Smlf 11731709Smlf excl_open_fail: 11741709Smlf mutex_exit(&dkp->dk_mutex); 11751709Smlf return (EBUSY); 11761709Smlf } 11771709Smlf 11781709Smlf /* 11791709Smlf * read routine 11801709Smlf */ 11811709Smlf /*ARGSUSED2*/ 11821709Smlf static int 11831709Smlf cmdkread(dev_t dev, struct uio *uio, cred_t *credp) 11841709Smlf { 11851709Smlf return (cmdkrw(dev, uio, B_READ)); 11861709Smlf } 11871709Smlf 11881709Smlf /* 11891709Smlf * async read routine 11901709Smlf */ 11911709Smlf /*ARGSUSED2*/ 11921709Smlf static int 11931709Smlf cmdkaread(dev_t dev, struct aio_req *aio, cred_t *credp) 11941709Smlf { 11951709Smlf return (cmdkarw(dev, aio, B_READ)); 11961709Smlf } 11971709Smlf 11981709Smlf /* 11991709Smlf * write routine 12001709Smlf */ 12011709Smlf /*ARGSUSED2*/ 12021709Smlf static int 12031709Smlf cmdkwrite(dev_t dev, struct uio *uio, cred_t *credp) 12041709Smlf { 12051709Smlf return (cmdkrw(dev, uio, B_WRITE)); 12061709Smlf } 12071709Smlf 12081709Smlf /* 12091709Smlf * async write routine 12101709Smlf */ 12111709Smlf /*ARGSUSED2*/ 12121709Smlf static int 12131709Smlf cmdkawrite(dev_t dev, struct aio_req *aio, cred_t *credp) 12141709Smlf { 12151709Smlf return (cmdkarw(dev, aio, B_WRITE)); 12161709Smlf } 12171709Smlf 12181709Smlf static void 12191709Smlf cmdkmin(struct buf *bp) 12201709Smlf { 12211709Smlf if (bp->b_bcount > DK_MAXRECSIZE) 12221709Smlf bp->b_bcount = DK_MAXRECSIZE; 12231709Smlf } 12241709Smlf 12251709Smlf static int 12261709Smlf cmdkrw(dev_t dev, struct uio *uio, int flag) 12271709Smlf { 1228*5295Srandyf int instance; 1229*5295Srandyf struct cmdk *dkp; 1230*5295Srandyf 1231*5295Srandyf instance = CMDKUNIT(dev); 1232*5295Srandyf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 1233*5295Srandyf return (ENXIO); 1234*5295Srandyf 1235*5295Srandyf mutex_enter(&dkp->dk_mutex); 1236*5295Srandyf while (dkp->dk_flag & CMDK_SUSPEND) { 1237*5295Srandyf cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex); 1238*5295Srandyf } 1239*5295Srandyf mutex_exit(&dkp->dk_mutex); 1240*5295Srandyf 12411709Smlf return (physio(cmdkstrategy, (struct buf *)0, dev, flag, cmdkmin, uio)); 12421709Smlf } 12431709Smlf 12441709Smlf static int 12451709Smlf cmdkarw(dev_t dev, struct aio_req *aio, int flag) 12461709Smlf { 1247*5295Srandyf int instance; 1248*5295Srandyf struct cmdk *dkp; 1249*5295Srandyf 1250*5295Srandyf instance = CMDKUNIT(dev); 1251*5295Srandyf if (!(dkp = ddi_get_soft_state(cmdk_state, instance))) 1252*5295Srandyf return (ENXIO); 1253*5295Srandyf 1254*5295Srandyf mutex_enter(&dkp->dk_mutex); 1255*5295Srandyf while (dkp->dk_flag & CMDK_SUSPEND) { 1256*5295Srandyf cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex); 1257*5295Srandyf } 1258*5295Srandyf mutex_exit(&dkp->dk_mutex); 1259*5295Srandyf 12601709Smlf return (aphysio(cmdkstrategy, anocancel, dev, flag, cmdkmin, aio)); 12611709Smlf } 12621709Smlf 12631709Smlf /* 12641709Smlf * strategy routine 12651709Smlf */ 12661709Smlf static int 12671709Smlf cmdkstrategy(struct buf *bp) 12681709Smlf { 12691709Smlf int instance; 12701709Smlf struct cmdk *dkp; 12711709Smlf long d_cnt; 12721709Smlf diskaddr_t p_lblksrt; 12731709Smlf diskaddr_t p_lblkcnt; 12741709Smlf 12751709Smlf instance = CMDKUNIT(bp->b_edev); 12761709Smlf if (cmdk_indump || !(dkp = ddi_get_soft_state(cmdk_state, instance)) || 12771709Smlf (dkblock(bp) < 0)) { 12781709Smlf bp->b_resid = bp->b_bcount; 12791709Smlf SETBPERR(bp, ENXIO); 12801709Smlf biodone(bp); 12811709Smlf return (0); 12821709Smlf } 12831709Smlf 1284*5295Srandyf mutex_enter(&dkp->dk_mutex); 1285*5295Srandyf while (dkp->dk_flag & CMDK_SUSPEND) { 1286*5295Srandyf cv_wait(&dkp->dk_suspend_cv, &dkp->dk_mutex); 1287*5295Srandyf } 1288*5295Srandyf mutex_exit(&dkp->dk_mutex); 1289*5295Srandyf 12901709Smlf bp->b_flags &= ~(B_DONE|B_ERROR); 12911709Smlf bp->b_resid = 0; 12921709Smlf bp->av_back = NULL; 12931709Smlf 12941709Smlf /* 12951709Smlf * only re-read the vtoc if necessary (force == FALSE) 12961709Smlf */ 12973525Sshidokht if (cmlb_partinfo(dkp->dk_cmlbhandle, CMDKPART(bp->b_edev), 12983525Sshidokht &p_lblkcnt, &p_lblksrt, NULL, NULL, 0)) { 12991709Smlf SETBPERR(bp, ENXIO); 13001709Smlf } 13011709Smlf 13021709Smlf if ((bp->b_bcount & (NBPSCTR-1)) || (dkblock(bp) > p_lblkcnt)) 13031709Smlf SETBPERR(bp, ENXIO); 13041709Smlf 13051709Smlf if ((bp->b_flags & B_ERROR) || (dkblock(bp) == p_lblkcnt)) { 13061709Smlf bp->b_resid = bp->b_bcount; 13071709Smlf biodone(bp); 13081709Smlf return (0); 13091709Smlf } 13101709Smlf 13111709Smlf d_cnt = bp->b_bcount >> SCTRSHFT; 13121709Smlf if ((dkblock(bp) + d_cnt) > p_lblkcnt) { 13131709Smlf bp->b_resid = ((dkblock(bp) + d_cnt) - p_lblkcnt) << SCTRSHFT; 13141709Smlf bp->b_bcount -= bp->b_resid; 13151709Smlf } 13161709Smlf 13171709Smlf SET_BP_SEC(bp, ((ulong_t)(p_lblksrt + dkblock(bp)))); 13181709Smlf if (dadk_strategy(DKTP_DATA, bp) != DDI_SUCCESS) { 13191709Smlf bp->b_resid += bp->b_bcount; 13201709Smlf biodone(bp); 13211709Smlf } 13221709Smlf return (0); 13231709Smlf } 13241709Smlf 13251709Smlf static int 13261709Smlf cmdk_create_obj(dev_info_t *dip, struct cmdk *dkp) 13271709Smlf { 13281709Smlf struct scsi_device *devp; 13291709Smlf opaque_t queobjp = NULL; 13301709Smlf opaque_t flcobjp = NULL; 13311709Smlf char que_keyvalp[64]; 13321709Smlf int que_keylen; 13331709Smlf char flc_keyvalp[64]; 13341709Smlf int flc_keylen; 13351709Smlf 13361709Smlf ASSERT(mutex_owned(&dkp->dk_mutex)); 13371709Smlf 13381709Smlf /* Create linkage to queueing routines based on property */ 13391709Smlf que_keylen = sizeof (que_keyvalp); 13401709Smlf if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF, 13411709Smlf DDI_PROP_CANSLEEP, "queue", que_keyvalp, &que_keylen) != 13421709Smlf DDI_PROP_SUCCESS) { 13431709Smlf cmn_err(CE_WARN, "cmdk_create_obj: queue property undefined"); 13441709Smlf return (DDI_FAILURE); 13451709Smlf } 13461709Smlf que_keyvalp[que_keylen] = (char)0; 13471709Smlf 13481709Smlf if (strcmp(que_keyvalp, "qfifo") == 0) { 13491709Smlf queobjp = (opaque_t)qfifo_create(); 13501709Smlf } else if (strcmp(que_keyvalp, "qsort") == 0) { 13511709Smlf queobjp = (opaque_t)qsort_create(); 13521709Smlf } else { 13531709Smlf return (DDI_FAILURE); 13541709Smlf } 13551709Smlf 13561709Smlf /* Create linkage to dequeueing routines based on property */ 13571709Smlf flc_keylen = sizeof (flc_keyvalp); 13581709Smlf if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF, 13591709Smlf DDI_PROP_CANSLEEP, "flow_control", flc_keyvalp, &flc_keylen) != 13601709Smlf DDI_PROP_SUCCESS) { 13611709Smlf cmn_err(CE_WARN, 13621709Smlf "cmdk_create_obj: flow-control property undefined"); 13631709Smlf return (DDI_FAILURE); 13641709Smlf } 13651709Smlf 13661709Smlf flc_keyvalp[flc_keylen] = (char)0; 13671709Smlf 13681709Smlf if (strcmp(flc_keyvalp, "dsngl") == 0) { 13691709Smlf flcobjp = (opaque_t)dsngl_create(); 13701709Smlf } else if (strcmp(flc_keyvalp, "dmult") == 0) { 13711709Smlf flcobjp = (opaque_t)dmult_create(); 13721709Smlf } else { 13731709Smlf return (DDI_FAILURE); 13741709Smlf } 13751709Smlf 13761709Smlf /* populate bbh_obj object stored in dkp */ 13771709Smlf dkp->dk_bbh_obj.bbh_data = dkp; 13781709Smlf dkp->dk_bbh_obj.bbh_ops = &cmdk_bbh_ops; 13791709Smlf 13801709Smlf /* create linkage to dadk */ 13811709Smlf dkp->dk_tgobjp = (opaque_t)dadk_create(); 13821709Smlf 13831709Smlf devp = ddi_get_driver_private(dip); 13841709Smlf (void) dadk_init(DKTP_DATA, devp, flcobjp, queobjp, &dkp->dk_bbh_obj, 13851709Smlf NULL); 13861709Smlf 13871709Smlf return (DDI_SUCCESS); 13881709Smlf } 13891709Smlf 13901709Smlf static void 13911709Smlf cmdk_destroy_obj(dev_info_t *dip, struct cmdk *dkp) 13921709Smlf { 13931709Smlf char que_keyvalp[64]; 13941709Smlf int que_keylen; 13951709Smlf char flc_keyvalp[64]; 13961709Smlf int flc_keylen; 13971709Smlf 13981709Smlf ASSERT(mutex_owned(&dkp->dk_mutex)); 13991709Smlf 14001709Smlf (void) dadk_free((dkp->dk_tgobjp)); 14011709Smlf dkp->dk_tgobjp = NULL; 14021709Smlf 14031709Smlf que_keylen = sizeof (que_keyvalp); 14041709Smlf if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF, 14051709Smlf DDI_PROP_CANSLEEP, "queue", que_keyvalp, &que_keylen) != 14061709Smlf DDI_PROP_SUCCESS) { 14071709Smlf cmn_err(CE_WARN, "cmdk_destroy_obj: queue property undefined"); 14081709Smlf return; 14091709Smlf } 14101709Smlf que_keyvalp[que_keylen] = (char)0; 14111709Smlf 14121709Smlf flc_keylen = sizeof (flc_keyvalp); 14131709Smlf if (ddi_prop_op(DDI_DEV_T_NONE, dip, PROP_LEN_AND_VAL_BUF, 14141709Smlf DDI_PROP_CANSLEEP, "flow_control", flc_keyvalp, &flc_keylen) != 14151709Smlf DDI_PROP_SUCCESS) { 14161709Smlf cmn_err(CE_WARN, 14171709Smlf "cmdk_destroy_obj: flow-control property undefined"); 14181709Smlf return; 14191709Smlf } 14201709Smlf flc_keyvalp[flc_keylen] = (char)0; 14211709Smlf } 14223525Sshidokht /*ARGSUSED5*/ 14231709Smlf static int 14243525Sshidokht cmdk_lb_rdwr(dev_info_t *dip, uchar_t cmd, void *bufaddr, 14253525Sshidokht diskaddr_t start, size_t count, void *tg_cookie) 14261709Smlf { 14271709Smlf struct cmdk *dkp; 14281709Smlf opaque_t handle; 14291709Smlf int rc = 0; 14301709Smlf char *bufa; 14311709Smlf 14321709Smlf dkp = ddi_get_soft_state(cmdk_state, ddi_get_instance(dip)); 14331709Smlf if (dkp == NULL) 14341709Smlf return (ENXIO); 14351709Smlf 14361709Smlf if (cmd != TG_READ && cmd != TG_WRITE) 14371709Smlf return (EINVAL); 14381709Smlf 14391709Smlf /* count must be multiple of 512 */ 14401709Smlf count = (count + NBPSCTR - 1) & -NBPSCTR; 14411709Smlf handle = dadk_iob_alloc(DKTP_DATA, start, count, KM_SLEEP); 14421709Smlf if (!handle) 14431709Smlf return (ENOMEM); 14441709Smlf 14451709Smlf if (cmd == TG_READ) { 14461709Smlf bufa = dadk_iob_xfer(DKTP_DATA, handle, B_READ); 14471709Smlf if (!bufa) 14481709Smlf rc = EIO; 14491709Smlf else 14501709Smlf bcopy(bufa, bufaddr, count); 14511709Smlf } else { 14521709Smlf bufa = dadk_iob_htoc(DKTP_DATA, handle); 14531709Smlf bcopy(bufaddr, bufa, count); 14541709Smlf bufa = dadk_iob_xfer(DKTP_DATA, handle, B_WRITE); 14551709Smlf if (!bufa) 14561709Smlf rc = EIO; 14571709Smlf } 14581709Smlf (void) dadk_iob_free(DKTP_DATA, handle); 14591709Smlf 14601709Smlf return (rc); 14611709Smlf } 14621709Smlf 14633525Sshidokht /*ARGSUSED3*/ 14641709Smlf static int 14653525Sshidokht cmdk_lb_getinfo(dev_info_t *dip, int cmd, void *arg, void *tg_cookie) 14661709Smlf { 14673525Sshidokht 14681709Smlf struct cmdk *dkp; 14691709Smlf struct tgdk_geom phyg; 14701709Smlf 14711709Smlf 14721709Smlf dkp = ddi_get_soft_state(cmdk_state, ddi_get_instance(dip)); 14731709Smlf if (dkp == NULL) 14741709Smlf return (ENXIO); 14751709Smlf 14763525Sshidokht switch (cmd) { 14773525Sshidokht case TG_GETPHYGEOM: { 14783525Sshidokht cmlb_geom_t *phygeomp = (cmlb_geom_t *)arg; 14793525Sshidokht 14803525Sshidokht /* dadk_getphygeom always returns success */ 14813525Sshidokht (void) dadk_getphygeom(DKTP_DATA, &phyg); 14823525Sshidokht 14833525Sshidokht phygeomp->g_capacity = phyg.g_cap; 14843525Sshidokht phygeomp->g_nsect = phyg.g_sec; 14853525Sshidokht phygeomp->g_nhead = phyg.g_head; 14863525Sshidokht phygeomp->g_acyl = phyg.g_acyl; 14873525Sshidokht phygeomp->g_ncyl = phyg.g_cyl; 14883525Sshidokht phygeomp->g_secsize = phyg.g_secsiz; 14893525Sshidokht phygeomp->g_intrlv = 1; 14903525Sshidokht phygeomp->g_rpm = 3600; 14911709Smlf 14923525Sshidokht return (0); 14933525Sshidokht } 14943525Sshidokht 14953525Sshidokht case TG_GETVIRTGEOM: { 14963525Sshidokht cmlb_geom_t *virtgeomp = (cmlb_geom_t *)arg; 14973525Sshidokht diskaddr_t capacity; 14983525Sshidokht 14993525Sshidokht (void) dadk_getgeom(DKTP_DATA, &phyg); 15003525Sshidokht capacity = phyg.g_cap; 15013525Sshidokht 15023525Sshidokht /* 15033525Sshidokht * If the controller returned us something that doesn't 15043525Sshidokht * really fit into an Int 13/function 8 geometry 15053525Sshidokht * result, just fail the ioctl. See PSARC 1998/313. 15063525Sshidokht */ 15073525Sshidokht if (capacity < 0 || capacity >= 63 * 254 * 1024) 15083525Sshidokht return (EINVAL); 15091709Smlf 15103525Sshidokht virtgeomp->g_capacity = capacity; 15113525Sshidokht virtgeomp->g_nsect = 63; 15123525Sshidokht virtgeomp->g_nhead = 254; 15133525Sshidokht virtgeomp->g_ncyl = capacity / (63 * 254); 15143525Sshidokht virtgeomp->g_acyl = 0; 15153525Sshidokht virtgeomp->g_secsize = 512; 15163525Sshidokht virtgeomp->g_intrlv = 1; 15173525Sshidokht virtgeomp->g_rpm = 3600; 15183525Sshidokht 15193525Sshidokht return (0); 15203525Sshidokht } 15213525Sshidokht 15223525Sshidokht case TG_GETCAPACITY: 15233525Sshidokht case TG_GETBLOCKSIZE: 15243525Sshidokht { 15251709Smlf 15263525Sshidokht /* dadk_getphygeom always returns success */ 15273525Sshidokht (void) dadk_getphygeom(DKTP_DATA, &phyg); 15283525Sshidokht if (cmd == TG_GETCAPACITY) 15293525Sshidokht *(diskaddr_t *)arg = phyg.g_cap; 15303525Sshidokht else 15313525Sshidokht *(uint32_t *)arg = (uint32_t)phyg.g_secsiz; 15323525Sshidokht 15333525Sshidokht return (0); 15343525Sshidokht } 15353525Sshidokht 15363525Sshidokht case TG_GETATTR: { 15373525Sshidokht tg_attribute_t *tgattribute = (tg_attribute_t *)arg; 15383525Sshidokht if ((DKTP_EXT->tg_rdonly)) 15393525Sshidokht tgattribute->media_is_writable = FALSE; 15403525Sshidokht else 15413525Sshidokht tgattribute->media_is_writable = TRUE; 15423525Sshidokht 15433525Sshidokht return (0); 15443525Sshidokht } 15453525Sshidokht 15463525Sshidokht default: 15473525Sshidokht return (ENOTTY); 15483525Sshidokht } 15491709Smlf } 15501709Smlf 15511709Smlf 15521709Smlf 15531709Smlf 15541709Smlf 15551709Smlf /* 15561709Smlf * Create and register the devid. 15571709Smlf * There are 4 different ways we can get a device id: 15581709Smlf * 1. Already have one - nothing to do 15591709Smlf * 2. Build one from the drive's model and serial numbers 15601709Smlf * 3. Read one from the disk (first sector of last track) 15611709Smlf * 4. Fabricate one and write it on the disk. 15621709Smlf * If any of these succeeds, register the deviceid 15631709Smlf */ 15641709Smlf static void 15651709Smlf cmdk_devid_setup(struct cmdk *dkp) 15661709Smlf { 15671709Smlf int rc; 15681709Smlf 15691709Smlf /* Try options until one succeeds, or all have failed */ 15701709Smlf 15711709Smlf /* 1. All done if already registered */ 15721709Smlf if (dkp->dk_devid != NULL) 15731709Smlf return; 15741709Smlf 15751709Smlf /* 2. Build a devid from the model and serial number */ 15761709Smlf rc = cmdk_devid_modser(dkp); 15771709Smlf if (rc != DDI_SUCCESS) { 15781709Smlf /* 3. Read devid from the disk, if present */ 15791709Smlf rc = cmdk_devid_read(dkp); 15801709Smlf 15811709Smlf /* 4. otherwise make one up and write it on the disk */ 15821709Smlf if (rc != DDI_SUCCESS) 15831709Smlf rc = cmdk_devid_fabricate(dkp); 15841709Smlf } 15851709Smlf 15861709Smlf /* If we managed to get a devid any of the above ways, register it */ 15871709Smlf if (rc == DDI_SUCCESS) 15881709Smlf (void) ddi_devid_register(dkp->dk_dip, dkp->dk_devid); 15891709Smlf 15901709Smlf } 15911709Smlf 15921709Smlf /* 15931709Smlf * Build a devid from the model and serial number 15941709Smlf * Return DDI_SUCCESS or DDI_FAILURE. 15951709Smlf */ 15961709Smlf static int 15971709Smlf cmdk_devid_modser(struct cmdk *dkp) 15981709Smlf { 15991709Smlf int rc = DDI_FAILURE; 16001709Smlf char *hwid; 16011709Smlf int modlen; 16021709Smlf int serlen; 16031709Smlf 16041709Smlf /* 16051709Smlf * device ID is a concatenation of model number, '=', serial number. 16061709Smlf */ 16071709Smlf hwid = kmem_alloc(CMDK_HWIDLEN, KM_SLEEP); 16081709Smlf modlen = cmdk_get_modser(dkp, DIOCTL_GETMODEL, hwid, CMDK_HWIDLEN); 16091709Smlf if (modlen == 0) { 16101709Smlf rc = DDI_FAILURE; 16111709Smlf goto err; 16121709Smlf } 16131709Smlf hwid[modlen++] = '='; 16141709Smlf serlen = cmdk_get_modser(dkp, DIOCTL_GETSERIAL, 16151709Smlf hwid + modlen, CMDK_HWIDLEN - modlen); 16161709Smlf if (serlen == 0) { 16171709Smlf rc = DDI_FAILURE; 16181709Smlf goto err; 16191709Smlf } 16201709Smlf hwid[modlen + serlen] = 0; 16211709Smlf 16221709Smlf /* Initialize the device ID, trailing NULL not included */ 16231709Smlf rc = ddi_devid_init(dkp->dk_dip, DEVID_ATA_SERIAL, modlen + serlen, 16241709Smlf hwid, (ddi_devid_t *)&dkp->dk_devid); 16251709Smlf if (rc != DDI_SUCCESS) { 16261709Smlf rc = DDI_FAILURE; 16271709Smlf goto err; 16281709Smlf } 16291709Smlf 16301709Smlf rc = DDI_SUCCESS; 16311709Smlf 16321709Smlf err: 16331709Smlf kmem_free(hwid, CMDK_HWIDLEN); 16341709Smlf return (rc); 16351709Smlf } 16361709Smlf 16371709Smlf static int 16381709Smlf cmdk_get_modser(struct cmdk *dkp, int ioccmd, char *buf, int len) 16391709Smlf { 16401709Smlf dadk_ioc_string_t strarg; 16411709Smlf int rval; 16421709Smlf char *s; 16431709Smlf char ch; 16441709Smlf boolean_t ret; 16451709Smlf int i; 16461709Smlf int tb; 16471709Smlf 16481709Smlf strarg.is_buf = buf; 16491709Smlf strarg.is_size = len; 16501709Smlf if (dadk_ioctl(DKTP_DATA, 16511709Smlf dkp->dk_dev, 16521709Smlf ioccmd, 16531709Smlf (uintptr_t)&strarg, 16541709Smlf FNATIVE | FKIOCTL, 16551709Smlf NULL, 16561709Smlf &rval) != 0) 16571709Smlf return (0); 16581709Smlf 16591709Smlf /* 16601709Smlf * valid model/serial string must contain a non-zero non-space 16611709Smlf * trim trailing spaces/NULL 16621709Smlf */ 16631709Smlf ret = B_FALSE; 16641709Smlf s = buf; 16651709Smlf for (i = 0; i < strarg.is_size; i++) { 16661709Smlf ch = *s++; 16671709Smlf if (ch != ' ' && ch != '\0') 16681709Smlf tb = i + 1; 16691709Smlf if (ch != ' ' && ch != '\0' && ch != '0') 16701709Smlf ret = B_TRUE; 16711709Smlf } 16721709Smlf 16731709Smlf if (ret == B_FALSE) 16741709Smlf return (0); 16751709Smlf 16761709Smlf return (tb); 16771709Smlf } 16781709Smlf 16791709Smlf /* 16801709Smlf * Read a devid from on the first block of the last track of 16811709Smlf * the last cylinder. Make sure what we read is a valid devid. 16821709Smlf * Return DDI_SUCCESS or DDI_FAILURE. 16831709Smlf */ 16841709Smlf static int 16851709Smlf cmdk_devid_read(struct cmdk *dkp) 16861709Smlf { 16871709Smlf diskaddr_t blk; 16881709Smlf struct dk_devid *dkdevidp; 16891709Smlf uint_t *ip; 16901709Smlf int chksum; 16911709Smlf int i, sz; 16921709Smlf tgdk_iob_handle handle; 16931709Smlf int rc = DDI_FAILURE; 16941709Smlf 16953525Sshidokht if (cmlb_get_devid_block(dkp->dk_cmlbhandle, &blk, 0)) 16961709Smlf goto err; 16971709Smlf 16981709Smlf /* read the devid */ 16991709Smlf handle = dadk_iob_alloc(DKTP_DATA, blk, NBPSCTR, KM_SLEEP); 17001709Smlf if (handle == NULL) 17011709Smlf goto err; 17021709Smlf 17031709Smlf dkdevidp = (struct dk_devid *)dadk_iob_xfer(DKTP_DATA, handle, B_READ); 17041709Smlf if (dkdevidp == NULL) 17051709Smlf goto err; 17061709Smlf 17071709Smlf /* Validate the revision */ 17081709Smlf if ((dkdevidp->dkd_rev_hi != DK_DEVID_REV_MSB) || 17091709Smlf (dkdevidp->dkd_rev_lo != DK_DEVID_REV_LSB)) 17101709Smlf goto err; 17111709Smlf 17121709Smlf /* Calculate the checksum */ 17131709Smlf chksum = 0; 17141709Smlf ip = (uint_t *)dkdevidp; 17151709Smlf for (i = 0; i < ((NBPSCTR - sizeof (int))/sizeof (int)); i++) 17161709Smlf chksum ^= ip[i]; 17171709Smlf if (DKD_GETCHKSUM(dkdevidp) != chksum) 17181709Smlf goto err; 17191709Smlf 17201709Smlf /* Validate the device id */ 17211709Smlf if (ddi_devid_valid((ddi_devid_t)dkdevidp->dkd_devid) != DDI_SUCCESS) 17221709Smlf goto err; 17231709Smlf 17241709Smlf /* keep a copy of the device id */ 17251709Smlf sz = ddi_devid_sizeof((ddi_devid_t)dkdevidp->dkd_devid); 17261709Smlf dkp->dk_devid = kmem_alloc(sz, KM_SLEEP); 17271709Smlf bcopy(dkdevidp->dkd_devid, dkp->dk_devid, sz); 17281709Smlf 17291709Smlf rc = DDI_SUCCESS; 17301709Smlf 17311709Smlf err: 17321709Smlf if (handle != NULL) 17331709Smlf (void) dadk_iob_free(DKTP_DATA, handle); 17341709Smlf return (rc); 17351709Smlf } 17361709Smlf 17371709Smlf /* 17381709Smlf * Create a devid and write it on the first block of the last track of 17391709Smlf * the last cylinder. 17401709Smlf * Return DDI_SUCCESS or DDI_FAILURE. 17411709Smlf */ 17421709Smlf static int 17431709Smlf cmdk_devid_fabricate(struct cmdk *dkp) 17441709Smlf { 17451709Smlf ddi_devid_t devid = NULL; /* devid made by ddi_devid_init */ 17461709Smlf struct dk_devid *dkdevidp; /* devid struct stored on disk */ 17471709Smlf diskaddr_t blk; 17481709Smlf tgdk_iob_handle handle = NULL; 17491709Smlf uint_t *ip, chksum; 17501709Smlf int i; 17511709Smlf int rc; 17521709Smlf 17531709Smlf rc = ddi_devid_init(dkp->dk_dip, DEVID_FAB, 0, NULL, &devid); 17541709Smlf if (rc != DDI_SUCCESS) 17551709Smlf goto err; 17561709Smlf 17573525Sshidokht if (cmlb_get_devid_block(dkp->dk_cmlbhandle, &blk, 0)) { 17581709Smlf /* no device id block address */ 17591709Smlf return (DDI_FAILURE); 17601709Smlf } 17611709Smlf 17621709Smlf handle = dadk_iob_alloc(DKTP_DATA, blk, NBPSCTR, KM_SLEEP); 17631709Smlf if (!handle) 17641709Smlf goto err; 17651709Smlf 17661709Smlf /* Locate the buffer */ 17671709Smlf dkdevidp = (struct dk_devid *)dadk_iob_htoc(DKTP_DATA, handle); 17681709Smlf 17691709Smlf /* Fill in the revision */ 17701709Smlf bzero(dkdevidp, NBPSCTR); 17711709Smlf dkdevidp->dkd_rev_hi = DK_DEVID_REV_MSB; 17721709Smlf dkdevidp->dkd_rev_lo = DK_DEVID_REV_LSB; 17731709Smlf 17741709Smlf /* Copy in the device id */ 17751709Smlf i = ddi_devid_sizeof(devid); 17761709Smlf if (i > DK_DEVID_SIZE) 17771709Smlf goto err; 17781709Smlf bcopy(devid, dkdevidp->dkd_devid, i); 17791709Smlf 17801709Smlf /* Calculate the chksum */ 17811709Smlf chksum = 0; 17821709Smlf ip = (uint_t *)dkdevidp; 17831709Smlf for (i = 0; i < ((NBPSCTR - sizeof (int))/sizeof (int)); i++) 17841709Smlf chksum ^= ip[i]; 17851709Smlf 17861709Smlf /* Fill in the checksum */ 17871709Smlf DKD_FORMCHKSUM(chksum, dkdevidp); 17881709Smlf 17891709Smlf /* write the devid */ 17901709Smlf (void) dadk_iob_xfer(DKTP_DATA, handle, B_WRITE); 17911709Smlf 17921709Smlf dkp->dk_devid = devid; 17931709Smlf 17941709Smlf rc = DDI_SUCCESS; 17951709Smlf 17961709Smlf err: 17971709Smlf if (handle != NULL) 17981709Smlf (void) dadk_iob_free(DKTP_DATA, handle); 17991709Smlf 18001709Smlf if (rc != DDI_SUCCESS && devid != NULL) 18011709Smlf ddi_devid_free(devid); 18021709Smlf 18031709Smlf return (rc); 18041709Smlf } 18051709Smlf 18061709Smlf static void 18071709Smlf cmdk_bbh_free_alts(struct cmdk *dkp) 18081709Smlf { 18091709Smlf if (dkp->dk_alts_hdl) { 18101709Smlf (void) dadk_iob_free(DKTP_DATA, dkp->dk_alts_hdl); 18111709Smlf kmem_free(dkp->dk_slc_cnt, 18121709Smlf NDKMAP * (sizeof (uint32_t) + sizeof (struct alts_ent *))); 18131709Smlf dkp->dk_alts_hdl = NULL; 18141709Smlf } 18151709Smlf } 18161709Smlf 18171709Smlf static void 18181709Smlf cmdk_bbh_reopen(struct cmdk *dkp) 18191709Smlf { 18201709Smlf tgdk_iob_handle handle = NULL; 18211709Smlf diskaddr_t slcb, slcn, slce; 18221709Smlf struct alts_parttbl *ap; 18231709Smlf struct alts_ent *enttblp; 18241709Smlf uint32_t altused; 18251709Smlf uint32_t altbase; 18261709Smlf uint32_t altlast; 18271709Smlf int alts; 18281709Smlf uint16_t vtoctag; 18291709Smlf int i, j; 18301709Smlf 18311709Smlf /* find slice with V_ALTSCTR tag */ 18321709Smlf for (alts = 0; alts < NDKMAP; alts++) { 18331709Smlf if (cmlb_partinfo( 18341709Smlf dkp->dk_cmlbhandle, 18351709Smlf alts, 18361709Smlf &slcn, 18371709Smlf &slcb, 18381709Smlf NULL, 18393525Sshidokht &vtoctag, 18403525Sshidokht 0)) { 18411709Smlf goto empty; /* no partition table exists */ 18421709Smlf } 18431709Smlf 18441709Smlf if (vtoctag == V_ALTSCTR && slcn > 1) 18451709Smlf break; 18461709Smlf } 18471709Smlf if (alts >= NDKMAP) { 18481709Smlf goto empty; /* no V_ALTSCTR slice defined */ 18491709Smlf } 18501709Smlf 18511709Smlf /* read in ALTS label block */ 18521709Smlf handle = dadk_iob_alloc(DKTP_DATA, slcb, NBPSCTR, KM_SLEEP); 18531709Smlf if (!handle) { 18541709Smlf goto empty; 18551709Smlf } 18561709Smlf 18571709Smlf ap = (struct alts_parttbl *)dadk_iob_xfer(DKTP_DATA, handle, B_READ); 18581709Smlf if (!ap || (ap->alts_sanity != ALTS_SANITY)) { 18591709Smlf goto empty; 18601709Smlf } 18611709Smlf 18621709Smlf altused = ap->alts_ent_used; /* number of BB entries */ 18631709Smlf altbase = ap->alts_ent_base; /* blk offset from begin slice */ 18641709Smlf altlast = ap->alts_ent_end; /* blk offset to last block */ 18651709Smlf /* ((altused * sizeof (struct alts_ent) + NBPSCTR - 1) & ~NBPSCTR) */ 18661709Smlf 18671709Smlf if (altused == 0 || 18681709Smlf altbase < 1 || 18691709Smlf altbase > altlast || 18701709Smlf altlast >= slcn) { 18711709Smlf goto empty; 18721709Smlf } 18731709Smlf (void) dadk_iob_free(DKTP_DATA, handle); 18741709Smlf 18751709Smlf /* read in ALTS remapping table */ 18761709Smlf handle = dadk_iob_alloc(DKTP_DATA, 18771709Smlf slcb + altbase, 18781709Smlf (altlast - altbase + 1) << SCTRSHFT, KM_SLEEP); 18791709Smlf if (!handle) { 18801709Smlf goto empty; 18811709Smlf } 18821709Smlf 18831709Smlf enttblp = (struct alts_ent *)dadk_iob_xfer(DKTP_DATA, handle, B_READ); 18841709Smlf if (!enttblp) { 18851709Smlf goto empty; 18861709Smlf } 18871709Smlf 18881709Smlf rw_enter(&dkp->dk_bbh_mutex, RW_WRITER); 18891709Smlf 18901709Smlf /* allocate space for dk_slc_cnt and dk_slc_ent tables */ 18911709Smlf if (dkp->dk_slc_cnt == NULL) { 18921709Smlf dkp->dk_slc_cnt = kmem_alloc(NDKMAP * 18931709Smlf (sizeof (long) + sizeof (struct alts_ent *)), KM_SLEEP); 18941709Smlf } 18951709Smlf dkp->dk_slc_ent = (struct alts_ent **)(dkp->dk_slc_cnt + NDKMAP); 18961709Smlf 18971709Smlf /* free previous BB table (if any) */ 18981709Smlf if (dkp->dk_alts_hdl) { 18991709Smlf (void) dadk_iob_free(DKTP_DATA, dkp->dk_alts_hdl); 19001709Smlf dkp->dk_alts_hdl = NULL; 19011709Smlf dkp->dk_altused = 0; 19021709Smlf } 19031709Smlf 19041709Smlf /* save linkage to new BB table */ 19051709Smlf dkp->dk_alts_hdl = handle; 19061709Smlf dkp->dk_altused = altused; 19071709Smlf 19081709Smlf /* 19091709Smlf * build indexes to BB table by slice 19101709Smlf * effectively we have 19111709Smlf * struct alts_ent *enttblp[altused]; 19121709Smlf * 19131709Smlf * uint32_t dk_slc_cnt[NDKMAP]; 19141709Smlf * struct alts_ent *dk_slc_ent[NDKMAP]; 19151709Smlf */ 19161709Smlf for (i = 0; i < NDKMAP; i++) { 19171709Smlf if (cmlb_partinfo( 19181709Smlf dkp->dk_cmlbhandle, 19191709Smlf i, 19201709Smlf &slcn, 19211709Smlf &slcb, 19221709Smlf NULL, 19233525Sshidokht NULL, 19243525Sshidokht 0)) { 19251709Smlf goto empty1; 19261709Smlf } 19271709Smlf 19281709Smlf dkp->dk_slc_cnt[i] = 0; 19291709Smlf if (slcn == 0) 19301709Smlf continue; /* slice is not allocated */ 19311709Smlf 19321709Smlf /* last block in slice */ 19331709Smlf slce = slcb + slcn - 1; 19341709Smlf 19351709Smlf /* find first remap entry in after beginnning of slice */ 19361709Smlf for (j = 0; j < altused; j++) { 19371709Smlf if (enttblp[j].bad_start + enttblp[j].bad_end >= slcb) 19381709Smlf break; 19391709Smlf } 19401709Smlf dkp->dk_slc_ent[i] = enttblp + j; 19411709Smlf 19421709Smlf /* count remap entrys until end of slice */ 19431709Smlf for (; j < altused && enttblp[j].bad_start <= slce; j++) { 19441709Smlf dkp->dk_slc_cnt[i] += 1; 19451709Smlf } 19461709Smlf } 19471709Smlf 19481709Smlf rw_exit(&dkp->dk_bbh_mutex); 19491709Smlf return; 19501709Smlf 19511709Smlf empty: 19521709Smlf rw_enter(&dkp->dk_bbh_mutex, RW_WRITER); 19531709Smlf empty1: 19541709Smlf if (handle && handle != dkp->dk_alts_hdl) 19551709Smlf (void) dadk_iob_free(DKTP_DATA, handle); 19561709Smlf 19571709Smlf if (dkp->dk_alts_hdl) { 19581709Smlf (void) dadk_iob_free(DKTP_DATA, dkp->dk_alts_hdl); 19591709Smlf dkp->dk_alts_hdl = NULL; 19601709Smlf } 19611709Smlf 19621709Smlf rw_exit(&dkp->dk_bbh_mutex); 19631709Smlf } 19641709Smlf 19651709Smlf /*ARGSUSED*/ 19661709Smlf static bbh_cookie_t 19671709Smlf cmdk_bbh_htoc(opaque_t bbh_data, opaque_t handle) 19681709Smlf { 19691709Smlf struct bbh_handle *hp; 19701709Smlf bbh_cookie_t ckp; 19711709Smlf 19721709Smlf hp = (struct bbh_handle *)handle; 19731709Smlf ckp = hp->h_cktab + hp->h_idx; 19741709Smlf hp->h_idx++; 19751709Smlf return (ckp); 19761709Smlf } 19771709Smlf 19781709Smlf /*ARGSUSED*/ 19791709Smlf static void 19801709Smlf cmdk_bbh_freehandle(opaque_t bbh_data, opaque_t handle) 19811709Smlf { 19821709Smlf struct bbh_handle *hp; 19831709Smlf 19841709Smlf hp = (struct bbh_handle *)handle; 19851709Smlf kmem_free(handle, (sizeof (struct bbh_handle) + 19861709Smlf (hp->h_totck * (sizeof (struct bbh_cookie))))); 19871709Smlf } 19881709Smlf 19891709Smlf 19901709Smlf /* 19911709Smlf * cmdk_bbh_gethandle remaps the bad sectors to alternates. 19921709Smlf * There are 7 different cases when the comparison is made 19931709Smlf * between the bad sector cluster and the disk section. 19941709Smlf * 19951709Smlf * bad sector cluster gggggggggggbbbbbbbggggggggggg 19961709Smlf * case 1: ddddd 19971709Smlf * case 2: -d----- 19981709Smlf * case 3: ddddd 19991709Smlf * case 4: dddddddddddd 20001709Smlf * case 5: ddddddd----- 20011709Smlf * case 6: ---ddddddd 20021709Smlf * case 7: ddddddd 20031709Smlf * 20041709Smlf * where: g = good sector, b = bad sector 20051709Smlf * d = sector in disk section 20061709Smlf * - = disk section may be extended to cover those disk area 20071709Smlf */ 20081709Smlf 20091709Smlf static opaque_t 20101709Smlf cmdk_bbh_gethandle(opaque_t bbh_data, struct buf *bp) 20111709Smlf { 20121709Smlf struct cmdk *dkp = (struct cmdk *)bbh_data; 20131709Smlf struct bbh_handle *hp; 20141709Smlf struct bbh_cookie *ckp; 20151709Smlf struct alts_ent *altp; 20161709Smlf uint32_t alts_used; 20171709Smlf uint32_t part = CMDKPART(bp->b_edev); 20181709Smlf daddr32_t lastsec; 20191709Smlf long d_count; 20201709Smlf int i; 20211709Smlf int idx; 20221709Smlf int cnt; 20231709Smlf 20241709Smlf if (part >= V_NUMPAR) 20251709Smlf return (NULL); 20261709Smlf 20271709Smlf /* 20281709Smlf * This if statement is atomic and it will succeed 20291709Smlf * if there are no bad blocks (almost always) 20301709Smlf * 20311709Smlf * so this if is performed outside of the rw_enter for speed 20321709Smlf * and then repeated inside the rw_enter for safety 20331709Smlf */ 20341709Smlf if (!dkp->dk_alts_hdl) { 20351709Smlf return (NULL); 20361709Smlf } 20371709Smlf 20381709Smlf rw_enter(&dkp->dk_bbh_mutex, RW_READER); 20391709Smlf 20401709Smlf if (dkp->dk_alts_hdl == NULL) { 20411709Smlf rw_exit(&dkp->dk_bbh_mutex); 20421709Smlf return (NULL); 20431709Smlf } 20441709Smlf 20451709Smlf alts_used = dkp->dk_slc_cnt[part]; 20461709Smlf if (alts_used == 0) { 20471709Smlf rw_exit(&dkp->dk_bbh_mutex); 20481709Smlf return (NULL); 20491709Smlf } 20501709Smlf altp = dkp->dk_slc_ent[part]; 20511709Smlf 20521709Smlf /* 20531709Smlf * binary search for the largest bad sector index in the alternate 20541709Smlf * entry table which overlaps or larger than the starting d_sec 20551709Smlf */ 20561709Smlf i = cmdk_bbh_bsearch(altp, alts_used, GET_BP_SEC(bp)); 20571709Smlf /* if starting sector is > the largest bad sector, return */ 20581709Smlf if (i == -1) { 20591709Smlf rw_exit(&dkp->dk_bbh_mutex); 20601709Smlf return (NULL); 20611709Smlf } 20621709Smlf /* i is the starting index. Set altp to the starting entry addr */ 20631709Smlf altp += i; 20641709Smlf 20651709Smlf d_count = bp->b_bcount >> SCTRSHFT; 20661709Smlf lastsec = GET_BP_SEC(bp) + d_count - 1; 20671709Smlf 20681709Smlf /* calculate the number of bad sectors */ 20691709Smlf for (idx = i, cnt = 0; idx < alts_used; idx++, altp++, cnt++) { 20701709Smlf if (lastsec < altp->bad_start) 20711709Smlf break; 20721709Smlf } 20731709Smlf 20741709Smlf if (!cnt) { 20751709Smlf rw_exit(&dkp->dk_bbh_mutex); 20761709Smlf return (NULL); 20771709Smlf } 20781709Smlf 20791709Smlf /* calculate the maximum number of reserved cookies */ 20801709Smlf cnt <<= 1; 20811709Smlf cnt++; 20821709Smlf 20831709Smlf /* allocate the handle */ 20841709Smlf hp = (struct bbh_handle *)kmem_zalloc((sizeof (*hp) + 20851709Smlf (cnt * sizeof (*ckp))), KM_SLEEP); 20861709Smlf 20871709Smlf hp->h_idx = 0; 20881709Smlf hp->h_totck = cnt; 20891709Smlf ckp = hp->h_cktab = (struct bbh_cookie *)(hp + 1); 20901709Smlf ckp[0].ck_sector = GET_BP_SEC(bp); 20911709Smlf ckp[0].ck_seclen = d_count; 20921709Smlf 20931709Smlf altp = dkp->dk_slc_ent[part]; 20941709Smlf altp += i; 20951709Smlf for (idx = 0; i < alts_used; i++, altp++) { 20961709Smlf /* CASE 1: */ 20971709Smlf if (lastsec < altp->bad_start) 20981709Smlf break; 20991709Smlf 21001709Smlf /* CASE 3: */ 21011709Smlf if (ckp[idx].ck_sector > altp->bad_end) 21021709Smlf continue; 21031709Smlf 21041709Smlf /* CASE 2 and 7: */ 21051709Smlf if ((ckp[idx].ck_sector >= altp->bad_start) && 21061709Smlf (lastsec <= altp->bad_end)) { 21071709Smlf ckp[idx].ck_sector = altp->good_start + 21081709Smlf ckp[idx].ck_sector - altp->bad_start; 21091709Smlf break; 21101709Smlf } 21111709Smlf 21121709Smlf /* at least one bad sector in our section. break it. */ 21131709Smlf /* CASE 5: */ 21141709Smlf if ((lastsec >= altp->bad_start) && 2115*5295Srandyf (lastsec <= altp->bad_end)) { 21161709Smlf ckp[idx+1].ck_seclen = lastsec - altp->bad_start + 1; 21171709Smlf ckp[idx].ck_seclen -= ckp[idx+1].ck_seclen; 21181709Smlf ckp[idx+1].ck_sector = altp->good_start; 21191709Smlf break; 21201709Smlf } 21211709Smlf /* CASE 6: */ 21221709Smlf if ((ckp[idx].ck_sector <= altp->bad_end) && 21231709Smlf (ckp[idx].ck_sector >= altp->bad_start)) { 21241709Smlf ckp[idx+1].ck_seclen = ckp[idx].ck_seclen; 21251709Smlf ckp[idx].ck_seclen = altp->bad_end - 21261709Smlf ckp[idx].ck_sector + 1; 21271709Smlf ckp[idx+1].ck_seclen -= ckp[idx].ck_seclen; 21281709Smlf ckp[idx].ck_sector = altp->good_start + 21291709Smlf ckp[idx].ck_sector - altp->bad_start; 21301709Smlf idx++; 21311709Smlf ckp[idx].ck_sector = altp->bad_end + 1; 21321709Smlf continue; /* check rest of section */ 21331709Smlf } 21341709Smlf 21351709Smlf /* CASE 4: */ 21361709Smlf ckp[idx].ck_seclen = altp->bad_start - ckp[idx].ck_sector; 21371709Smlf ckp[idx+1].ck_sector = altp->good_start; 21381709Smlf ckp[idx+1].ck_seclen = altp->bad_end - altp->bad_start + 1; 21391709Smlf idx += 2; 21401709Smlf ckp[idx].ck_sector = altp->bad_end + 1; 21411709Smlf ckp[idx].ck_seclen = lastsec - altp->bad_end; 21421709Smlf } 21431709Smlf 21441709Smlf rw_exit(&dkp->dk_bbh_mutex); 21451709Smlf return ((opaque_t)hp); 21461709Smlf } 21471709Smlf 21481709Smlf static int 21491709Smlf cmdk_bbh_bsearch(struct alts_ent *buf, int cnt, daddr32_t key) 21501709Smlf { 21511709Smlf int i; 21521709Smlf int ind; 21531709Smlf int interval; 21541709Smlf int mystatus = -1; 21551709Smlf 21561709Smlf if (!cnt) 21571709Smlf return (mystatus); 21581709Smlf 21591709Smlf ind = 1; /* compiler complains about possible uninitialized var */ 21601709Smlf for (i = 1; i <= cnt; i <<= 1) 21611709Smlf ind = i; 21621709Smlf 21631709Smlf for (interval = ind; interval; ) { 21641709Smlf if ((key >= buf[ind-1].bad_start) && 21651709Smlf (key <= buf[ind-1].bad_end)) { 21661709Smlf return (ind-1); 21671709Smlf } else { 21681709Smlf interval >>= 1; 21691709Smlf if (key < buf[ind-1].bad_start) { 21701709Smlf /* record the largest bad sector index */ 21711709Smlf mystatus = ind-1; 21721709Smlf if (!interval) 21731709Smlf break; 21741709Smlf ind = ind - interval; 21751709Smlf } else { 21761709Smlf /* 21771709Smlf * if key is larger than the last element 21781709Smlf * then break 21791709Smlf */ 21801709Smlf if ((ind == cnt) || !interval) 21811709Smlf break; 21821709Smlf if ((ind+interval) <= cnt) 21831709Smlf ind += interval; 21841709Smlf } 21851709Smlf } 21861709Smlf } 21871709Smlf return (mystatus); 21881709Smlf } 2189